Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement d&d pages animation #6049

Merged
merged 27 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2c6577c
Start working: implement base animations for deleting/adding pages
dk981234 Oct 16, 2024
97a2100
Remove extra scroll for page component
dk981234 Oct 16, 2024
1a46bed
Implement ghost page while dragging pages
dk981234 Oct 25, 2024
88b85d5
Fix variables
dk981234 Oct 25, 2024
0fe557b
Small refactor
dk981234 Oct 25, 2024
46dd13e
Merge branch 'master' into feature/5948
dk981234 Oct 30, 2024
6b6b24f
Fix page select transition
dk981234 Oct 31, 2024
e4d0e21
Fix animaiton error
dk981234 Oct 31, 2024
705b0a9
Fix pages are not synced on initial rendering
dk981234 Oct 31, 2024
d2f75c5
Fix scroll margin for page adorner
dk981234 Oct 31, 2024
1347ef8
Fix key of pages are depend on index
dk981234 Oct 31, 2024
17620c3
Block expand animation for reordered page
dk981234 Nov 1, 2024
720769b
Fix d&d position sometimes is incorrect
dk981234 Nov 4, 2024
1d707cb
Revert "Remove extra scroll for page component"
dk981234 Nov 4, 2024
10b708e
Remove extra scroll for page component
dk981234 Nov 4, 2024
0fc7660
Merge branch 'master' into feature/5948
dk981234 Nov 4, 2024
4810069
Small refactor
dk981234 Nov 4, 2024
18f5c58
Add unit tests
dk981234 Nov 4, 2024
fb55685
Implement in vue3
dk981234 Nov 4, 2024
5c07021
Implement in angular
dk981234 Nov 4, 2024
b77e0a5
Move newPage in model array
dk981234 Nov 4, 2024
0827a1c
Make pages animation take into account animationEnabled flag
dk981234 Nov 5, 2024
d569f83
Fix for #5948: make page adorner take into account isGhost changes
dk981234 Nov 5, 2024
6b051ba
Fix root element of adorner may be undefined
dk981234 Nov 7, 2024
73abe6e
Fix angular functional tests
dk981234 Nov 8, 2024
6471797
Fix knockout unit tests
dk981234 Nov 8, 2024
386d9cd
Fix by page mode in knockout
dk981234 Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/survey-creator-angular/src/page.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div *ngIf="model && adorner && (isGhost === undefined || isGhost === adorner.isGhost)" class="svc-page__content"
[class]="adorner.css" [key2click] (click)="adorner.select(adorner, $event)" (dblclick)="adorner.dblclick($event)"
<div *ngIf="model && adorner" class="svc-page__content" [class]="adorner.css" [key2click]
(click)="adorner.select(adorner, $event)" (dblclick)="adorner.dblclick($event)"
(mouseover)="adorner.hover($event, $event.currentTarget)" (mouseleave)="adorner.hover($event, $event.target)"
[id]="adorner.page.id" [attr.data-sv-drop-target-survey-page]="adorner.dropTargetName" #container>
<div class="svc-question__drop-indicator svc-question__drop-indicator--top"></div>
Expand Down
9 changes: 8 additions & 1 deletion packages/survey-creator-angular/src/page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class PageDesignerComponent extends CreatorModelComponent<PageAdorner> {
@Input() model!: PageModel;
@Input() survey!: SurveyModel;
@Input() creator!: SurveyCreatorModel;
@Input() isGhost?: boolean;
@Input() isGhost!: boolean;
@ViewChild("container", { read: ElementRef }) container!: ElementRef<HTMLDivElement>
public adorner!: PageAdorner;
protected createModel(): void {
Expand All @@ -22,6 +22,13 @@ export class PageDesignerComponent extends CreatorModelComponent<PageAdorner> {
}
if (this.model) {
this.adorner = new PageAdorner(this.creator, this.model);
this.adorner.isGhost = this.isGhost;
}
}
override ngDoCheck(): void {
super.ngDoCheck();
if(this.adorner) {
this.adorner.isGhost = this.isGhost;
}
}
protected getModel(): PageAdorner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<div class="svc-page" [attr.data-sv-drop-target-survey-element]="model.displayPageDropTarget"
[attr.data-sv-drop-target-page]="model.pagesController.page2Display.name">
<ng-template
[component]="{ name: 'svc-page', data: { model: model.pagesController.page2Display, creator, survey }}"></ng-template>
[component]="{ name: 'svc-page', data: { model: model.pagesController.page2Display, creator, survey, isGhost: model.pagesController.page2Display == model.newPage }}"></ng-template>
</div>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
</div>

<ng-container *ngIf="creator.pageEditMode !== 'bypage'">
<ng-container *ngFor="let page of survey.pages">
<ng-container *ngIf="!model.showNewPage || page !== model.newPage">
<ng-container *ngTemplateOutlet="pageContainer; context: { page, isGhost: false }"></ng-container>
<ng-container *ngFor="let page of model.pages; trackBy: trackPageBy ">
<ng-container>
<ng-container
*ngTemplateOutlet="pageContainer; context: { page, isGhost: model.newPage == page }"></ng-container>
</ng-container>
</ng-container>
<ng-container *ngIf="model.showNewPage && model.newPage">
<ng-container *ngTemplateOutlet="pageContainer; context: { page: model.newPage, isGhost: true }"></ng-container>
</ng-container>
</ng-container>
<ng-container *ngIf="model.pagesController.page2Display && creator.pageEditMode === 'bypage'">
<svc-designer-pages [model]="model"></svc-designer-pages>
Expand All @@ -33,6 +31,7 @@
<ng-template let-page="page" let-isGhost="isGhost" #pageContainer>
<div class="svc-page" [attr.data-sv-drop-target-survey-element]="isGhost ? 'newGhostPage' : page.name"
[attr.data-sv-drop-target-page]="page.name">
<ng-template [component]="{ name: 'svc-page', data: { model: page, creator, survey, isGhost }}"></ng-template>
<ng-template
[component]="{ name: 'svc-page', data: { model: page, creator, survey, isGhost: isGhost }}"></ng-template>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input } from "@angular/core";
import { SurveyModel } from "survey-core";
import { PageModel, SurveyModel } from "survey-core";
import { TabDesignerViewModel } from "survey-creator-core";
import { BaseAngular } from "survey-angular-ui";

Expand All @@ -19,4 +19,7 @@ export class DesignerSurveyComponent extends BaseAngular<SurveyModel> {
public get survey() {
return this.creator.survey;
}
public trackPageBy(index: number, page: PageModel): string {
return page.id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<svc-surface-placeholder [name]="'designer'" [placeholderTitleText]="model.placeholderTitleText"
[placeholderDescriptionText]="model.placeholderDescriptionText">
</svc-surface-placeholder>
<svc-page class="svc-designer-placeholder-page" [model]="model.newPage" [survey]="survey"
[creator]="creator"></svc-page>
<svc-page class="svc-designer-placeholder-page" [model]="model.newPage" [survey]="survey" [creator]="creator"
[isGhost]="true"></svc-page>
</div>
</ng-container>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,16 @@ export class SurveyElementAdornerBase<T extends SurveyElement = SurveyElement> e
};
const afterRunAnimation = (el: HTMLElement, animatingClassName: string) => {
this.expandCollapseAnimationRunning = false;
cleanHtmlElementAfterAnimation(el);
const innerAnimatedElements = this.getInnerAnimatedElements();
innerAnimatedElements.forEach((elem: HTMLElement) => {
cleanHtmlElementAfterAnimation(elem);
});
innerAnimatedElements.forEach((elem: HTMLElement) => {
elem.classList.remove(animatingClassName);
});
if(this.surveyElement) {
cleanHtmlElementAfterAnimation(el);
const innerAnimatedElements = this.getInnerAnimatedElements();
innerAnimatedElements.forEach((elem: HTMLElement) => {
cleanHtmlElementAfterAnimation(elem);
});
innerAnimatedElements.forEach((elem: HTMLElement) => {
elem.classList.remove(animatingClassName);
});
}
};
return {
getRerenderEvent: () => this.onElementRerendered,
Expand Down
107 changes: 91 additions & 16 deletions packages/survey-creator-core/src/components/page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,22 @@ svc-page {
padding: calcSize(1) calcSize(0) calcSize(3);
box-sizing: border-box;
width: 100%;
outline: none;
transition: background $creator-transition-duration, box-shadow $creator-transition-duration;
outline-color: transparent;
outline: 2px transparent dashed;
transition-property: background-color, box-shadow, outline-color;
transition-duration: $creator-transition-duration;

.sd-page {
margin: 0;
padding: calcSize(1) calcSize(3) 0;
}

&>.svc-question__drag-area {
& > .svc-question__drag-area {
padding-top: calcSize(1.25);

.svc-question__drag-element {
transition: opacity $creator-transition-duration;
}
}
}

Expand Down Expand Up @@ -125,6 +131,7 @@ svc-page {
box-shadow: 0 0 0 2px $secondary-light;
background: var(--ctr-survey-page-background-color-hovered, $secondary-backcolor-semi-light);
}

.svc-page__content--new.svc-page__content--new {
box-shadow: none;
background-color: transparent;
Expand All @@ -136,7 +143,7 @@ svc-page {
opacity: 1;
}

&>.svc-question__drag-area {
& > .svc-question__drag-area {
z-index: 1;

.svc-question__drag-element {
Expand All @@ -150,12 +157,12 @@ svc-page {
background: $secondary-backcolor-semi-light;
}


.svc-page__content--animation-running {
.svc-row {
.svc-question--enter {
animation: none;
}
}

.svc-question--leave {
animation-name: moveInWithOverflow;
animation-direction: reverse;
Expand All @@ -164,29 +171,34 @@ svc-page {
animation-duration: $svc-collapse-move-out-duration;
animation-delay: $svc-collapse-move-out-delay;
}
}
}
}

.svc-creator--disable-animations {
.svc-row {
.svc-question--leave {
animation: none;
}
}
}
}
.svc-page__content--collapse-onhover, .svc-page__content--collapse-always {

.svc-page__content--collapse-onhover,
.svc-page__content--collapse-always {
outline: 2px transparent dashed;
transition: outline-color $creator-transition-duration;

&.svc-page__content--selected,
&.svc-page__content.svc-hovered {
outline-color: transparent;
}

&.svc-page__content--collapsed-drag-over-inside {
box-shadow: 0 0 0 2px $primary;
background: $primary-light;
animation: collapsed-drag-over-inside-blinking 1s infinite;
outline-color: transparent;
}
}
}

.svc-page__content--collapsed {
outline-color: $border;
}
Expand Down Expand Up @@ -321,20 +333,20 @@ svc-page {
pointer-events: none;
}

.sv-list__item.sv-list__item--selected.sv-list__item--group>.sv-list__item-body {
.sv-list__item.sv-list__item--selected.sv-list__item--group > .sv-list__item-body {
@include ctrDefaultBoldFont;
background-color: $primary;
color: $primary-foreground;
}

.sv-list__item.sv-list__item--selected.sv-list__item--group>.sv-list__item-body use {
.sv-list__item.sv-list__item--selected.sv-list__item--group > .sv-list__item-body use {
fill: $background;
}
}
}

.svc-page__content--collapsed {
&>.sv-action-bar {
& > .sv-action-bar {
display: none;
}

Expand All @@ -349,7 +361,7 @@ svc-page {
.sd-page {
display: flex;

&>* {
& > * {
display: none;
}

Expand Down Expand Up @@ -396,4 +408,67 @@ svc-page {
}
}
}
}
}

$svc-page-fade-in-duration: var(--sjs-svc-page-fade-in-duration, 250ms);
$svc-page-move-in-duration: var(--sjs-svc-page-move-in-duration, 250ms);
$svc-page-fade-in-delay: var(--sjs-svc-page-fade-in-delay, 100ms);
$svc-page-fade-out-duration: var(--sjs-svc-page-fade-out-duration, 250ms);
$svc-page-move-out-duration: var(--sjs-svc-page-move-out-duration, 250ms);
$svc-page-move-out-delay: var(--sjs-svc-page-move-out-delay, 100ms);

.svc-page--enter,
.svc-page--leave {
animation-name: fadeIn, moveInWithOverflow;
animation-fill-mode: forwards;
animation-duration: var(--fade-animation-duration), var(--move-animation-duration);
animation-direction: var(--animation-direction);
animation-timing-function: var(--animation-timing-function);
animation-delay: var(--fade-animation-delay), var(--move-animation-delay);
}

.svc-page--enter {
opacity: 0;
--animation-direction: normal;
--animation-timing-function: #{$ease-out};
--fade-animation-duration: #{$svc-page-fade-in-duration};
--move-animation-duration: #{$svc-page-move-in-duration};
--fade-animation-delay: #{$svc-page-fade-in-delay};
--move-animation-delay: 0s;
}

.svc-page--leave {
--animation-direction: reverse;
--animation-timing-function: #{$reverse-ease-out};
--fade-animation-duration: #{$svc-page-fade-out-duration};
--move-animation-duration: #{$svc-page-move-out-duration};
--fade-animation-delay: 0s;
--move-animation-delay: #{$svc-page-move-out-delay};
}
.svc-creator--disable-animations {
.svc-page--enter,
.svc-page--leave {
animation: none;
}
}

.svc-page--enter.svc-page--enter {
.svc-page__content-actions {
opacity: 0;
}

.svc-page__content {
box-shadow: 0 0 0 2px transparent;
background-color: transparent;

& > .svc-question__drag-area {
.svc-question__drag-element {
opacity: 0;
}
}
}
}

.svc-page {
scroll-margin-top: calcSize(1);
}
Loading