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

fix(core): rework refresh animation and behaviour (embedded async flow) + remove redundant normalization for HTML #704

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 15 additions & 30 deletions src/core/preview/preview.less
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,30 @@
}

&-inner {
position: relative;
grid-area: uip-content;
max-width: 100%;
max-height: 100%;

opacity: 1;
transition: opacity 0.2s linear;
}

&[loading] &-inner {
opacity: 0;
}

&-iframe {
display: block;
width: 100%;
height: 100%;
border: none;

animation: uip-iframe-fade-in 0.4s ease-in;
&[hidden] {
display: none;
animation: ui-iframe-fade-out 0.4s ease-out;
}
}
&[loading] &-iframe {
position: absolute;
visibility: hidden;
max-height: 100%;
inset: 0;
}

&.centered-content &-inner {
Expand Down Expand Up @@ -85,27 +94,3 @@
}
}
}

@keyframes uip-iframe-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@keyframes uip-iframe-fade-out {
from {
display: block;
opacity: 1;
}
99% {
display: block;
opacity: 0;
}
to {
display: none;
opacity: 0;
}
}
43 changes: 30 additions & 13 deletions src/core/preview/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import React from 'jsx-dom';
import {attr, listen, memoize, prop} from '@exadel/esl/modules/esl-utils/decorators';
import {ESLIntersectionTarget} from '@exadel/esl/modules/esl-event-listener/core';
import {parseBoolean, toBooleanAttribute} from '@exadel/esl/modules/esl-utils/misc';
import {afterNextRender, skipOneRender} from '@exadel/esl/modules/esl-utils/async';
import {
afterNextRender,
promisifyEvent,
promisifyNextRender,
promisifyTimeout,
} from '@exadel/esl/modules/esl-utils/async';

import {UIPPlugin} from '../base/plugin';
import {UIPRenderingTemplatesService} from '../processors/templates';
Expand All @@ -26,6 +31,9 @@ export class UIPPreview extends UIPPlugin {
/** Marker to force iframe rerendering */
@attr({parser: parseBoolean, serializer: toBooleanAttribute}) public forceUpdate: boolean;

/** Delay to show new content after isolated full refresh */
@attr({defaultValue: 150, parser: parseInt}) public refreshDelay: number;

protected _iframeResizeRAF: number = 0;

/** {@link UIPPlugin} section wrapper */
Expand Down Expand Up @@ -68,30 +76,34 @@ export class UIPPreview extends UIPPlugin {
if (attrName === 'dir') this.updateDir();
}

protected update(e?: UIPChangeEvent): void {
protected async update(e?: UIPChangeEvent): Promise<void> {
const isolated = this.model!.activeSnippet?.isolated || false;

if (!isolated) return this.writeContent();
if (!e || this.forceUpdate || e.force) return this.writeIsolatedContent();
this.updateIsolatedContent();
return this.updateIsolatedContent();
}

/** Writes the content directly to the inner area (non-isolated frame) */
protected writeContent(): void {
protected async writeContent(): Promise<void> {
this.$inner.innerHTML = UIPHTMLRenderingPreprocessors.preprocess(this.model!.html);
this.stopIframeResizeLoop();
return promisifyNextRender();
}

protected updateIsolatedContent(): void {
protected async updateIsolatedContent(): Promise<void> {
if (!this.$iframe.contentWindow) return;
const $document = this.$iframe.contentWindow?.document;
const $root = $document?.querySelector('[uip-content-root]') || $document?.body;

if ($root) $root.innerHTML = UIPHTMLRenderingPreprocessors.preprocess(this.model!.html);
if ($root) {
$root.innerHTML = UIPHTMLRenderingPreprocessors.preprocess(this.model!.html);
return promisifyNextRender();
}
}

/** Writes the content to the iframe inner (isolated frame) */
protected writeIsolatedContent(): void {
protected async writeIsolatedContent(): Promise<void> {
if (this.$iframe.parentElement !== this.$inner) {
this.$inner.innerHTML = '';
this.$inner.appendChild(this.$iframe);
Expand All @@ -100,6 +112,9 @@ export class UIPPreview extends UIPPlugin {
this.$iframe.src = 'about:blank';
this.$iframe.hidden = true;
this.startIframeResizeLoop();

await promisifyEvent(this.$iframe, 'load');
await promisifyTimeout(this.refreshDelay);
}

/** Start and do a resize sync-loop iteration. Recall itself on the next frame. */
Expand Down Expand Up @@ -150,19 +165,21 @@ export class UIPPreview extends UIPPlugin {
this.$iframe.contentWindow?.document.close();
this.$iframe.contentWindow?.document.write(html);
this.$iframe.contentWindow?.document.close();
this.$iframe.hidden = false;
this.$iframe.title = title;

setTimeout(() => this.$iframe.hidden = false, 100);
}

/** Updates preview content from the model state changes */
@listen({event: 'uip:change', target: ($this: UIPPreview) => $this.$root})
protected _onRootStateChange(e?: UIPChangeEvent): void {
protected async _onRootStateChange(e?: UIPChangeEvent): Promise<void> {
this.$container.style.minHeight = `${this.$inner.offsetHeight}px`;
this.update(e);
this.$$attr('loading', true);

await this.update(e);

afterNextRender(() => this.$container.style.minHeight = '0px');
skipOneRender(() => {
this.$container.style.minHeight = '0px';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.$container.style.minHeight = '0px';
this.$container.style.minHeight = '0';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to #705 as well (not sure if that redundant or was left due to animation problem)

this.$$attr('loading', false);
afterNextRender(() => {
if (this.$container.clientHeight !== this.$inner.offsetHeight) return;
this.$container.style.removeProperty('min-height');
});
Expand Down
3 changes: 0 additions & 3 deletions src/core/processors/normalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,3 @@ UIPNoteNormalizationPreprocessors.add('remove-leading-indent', removeIndent);
UIPJSNormalizationPreprocessors.add('trim', (content: string) => content.trim());
UIPHTMLNormalizationPreprocessors.add('trim', (content: string) => content.trim());
UIPNoteNormalizationPreprocessors.add('trim', (content: string) => content.trim());

/** Removes extra spaces inside the content. Applicable for HTML only */
UIPHTMLNormalizationPreprocessors.addRegexReplacer('remove-trailing', /\s*?$/gm, ''); // TODO: possibly problem here
Loading