|
|
|
|
@ -20,7 +20,7 @@ import {
|
|
|
|
|
import { linkPreviewMorfo } from '../../../morfo/components/link-preview';
|
|
|
|
|
import { Soma } from '../../core/soma.svelte';
|
|
|
|
|
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
|
|
|
|
|
import type { TimerHandle } from '$timer';
|
|
|
|
|
|
|
|
|
|
// ── Root ─────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
@ -55,8 +55,8 @@ export class LinkPreviewProvider {
|
|
|
|
|
readonly floatingProvider: FloatingProvider;
|
|
|
|
|
readonly contentPresence: Presence;
|
|
|
|
|
|
|
|
|
|
private openTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
private closeTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
private openTimer: TimerHandle | null = null;
|
|
|
|
|
private closeTimer: TimerHandle | null = null;
|
|
|
|
|
|
|
|
|
|
contentId = state('');
|
|
|
|
|
triggerId = state('');
|
|
|
|
|
@ -94,55 +94,73 @@ export class LinkPreviewProvider {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
return () => this.clearTimeouts();
|
|
|
|
|
return () => this.clearTimers();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleOpen() {
|
|
|
|
|
if (this.opts.disabled.current) return;
|
|
|
|
|
this.clearTimeouts();
|
|
|
|
|
this.openTimeout = setTimeout(() => {
|
|
|
|
|
this.openTimeout = null;
|
|
|
|
|
this.clearTimers();
|
|
|
|
|
this.openTimer = this.soma.uix.timers.schedule(
|
|
|
|
|
this.openTimerKey,
|
|
|
|
|
this.opts.openDelay.current,
|
|
|
|
|
() => {
|
|
|
|
|
this.openTimer = null;
|
|
|
|
|
this.opts.open.current = true;
|
|
|
|
|
}, this.opts.openDelay.current);
|
|
|
|
|
},
|
|
|
|
|
{ replace: true, meta: { component: 'link-preview', action: 'open-delay' } }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Close after closeDelay (or immediately when bypass=true, e.g. SafePolygon exit). */
|
|
|
|
|
handleClose(bypass = false) {
|
|
|
|
|
this.clearTimeouts();
|
|
|
|
|
this.clearTimers();
|
|
|
|
|
if (bypass || this.opts.closeDelay.current <= 0) {
|
|
|
|
|
this.opts.open.current = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.closeTimeout = setTimeout(() => {
|
|
|
|
|
this.closeTimeout = null;
|
|
|
|
|
this.closeTimer = this.soma.uix.timers.schedule(
|
|
|
|
|
this.closeTimerKey,
|
|
|
|
|
this.opts.closeDelay.current,
|
|
|
|
|
() => {
|
|
|
|
|
this.closeTimer = null;
|
|
|
|
|
this.opts.open.current = false;
|
|
|
|
|
}, this.opts.closeDelay.current);
|
|
|
|
|
},
|
|
|
|
|
{ replace: true, meta: { component: 'link-preview', action: 'close-delay' } }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Cancel a pending close (when pointer enters the content). */
|
|
|
|
|
cancelClose() {
|
|
|
|
|
if (this.closeTimeout !== null) {
|
|
|
|
|
clearTimeout(this.closeTimeout);
|
|
|
|
|
this.closeTimeout = null;
|
|
|
|
|
if (this.closeTimer !== null) {
|
|
|
|
|
this.closeTimer.cancel();
|
|
|
|
|
this.closeTimer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Immediate close bypassing delays (Escape, outside click). */
|
|
|
|
|
forceClose() {
|
|
|
|
|
this.clearTimeouts();
|
|
|
|
|
this.clearTimers();
|
|
|
|
|
this.opts.open.current = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private clearTimeouts() {
|
|
|
|
|
if (this.openTimeout !== null) {
|
|
|
|
|
clearTimeout(this.openTimeout);
|
|
|
|
|
this.openTimeout = null;
|
|
|
|
|
private clearTimers() {
|
|
|
|
|
if (this.openTimer !== null) {
|
|
|
|
|
this.openTimer.cancel();
|
|
|
|
|
this.openTimer = null;
|
|
|
|
|
}
|
|
|
|
|
if (this.closeTimer !== null) {
|
|
|
|
|
this.closeTimer.cancel();
|
|
|
|
|
this.closeTimer = null;
|
|
|
|
|
}
|
|
|
|
|
if (this.closeTimeout !== null) {
|
|
|
|
|
clearTimeout(this.closeTimeout);
|
|
|
|
|
this.closeTimeout = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get openTimerKey() {
|
|
|
|
|
return `soma:link-preview:${this.opts.id.current}:open`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get closeTimerKey() {
|
|
|
|
|
return `soma:link-preview:${this.opts.id.current}:close`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setContentRef(el: HTMLElement | null) {
|
|
|
|
|
|