Skip to content

Commit 7cb4da8

Browse files
committed
feat(async-stack): return cleanup callback for onResolve
1 parent a70e65b commit 7cb4da8

4 files changed

Lines changed: 32 additions & 16 deletions

File tree

.changeset/olive-roses-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@svelte-put/async-stack': minor
3+
---
4+
5+
(experimental) `onResolve` now returns callback that removes the listener

packages/async-stack/src/helpers/enhance-dialog.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,28 @@ export function enhanceDialog(item, options) {
3030
[createAttachmentKey()]: function (dialog) {
3131
dialog.showModal();
3232

33+
// set up listener when user calls item.resolve manually
3334
/** @type {undefined | (() => void)} */
3435
let resumeResolution = undefined;
36+
/** @type {undefined | (() => void)} */
37+
let offResolve = undefined;
38+
/** @returns {Promise<void>} */
39+
function onResolve() {
40+
return new Promise((resolvePromise) => {
41+
if (dialog.open) {
42+
// user calls `item.resolve(...)`
43+
dialog.removeEventListener('close', onclose);
44+
if ('requestClose' in dialog) {
45+
dialog.requestClose();
46+
} else {
47+
dialog.close();
48+
}
49+
}
50+
resumeResolution = resolvePromise;
51+
});
52+
}
3553
if (options?.delayResolution) {
36-
item.onResolve(
37-
() =>
38-
new Promise((resolve) => {
39-
if (dialog.open) {
40-
// user calls `item.resolve(...)`
41-
dialog.removeEventListener('close', onclose);
42-
if ('requestClose' in dialog) {
43-
dialog.requestClose();
44-
} else {
45-
dialog.close();
46-
}
47-
}
48-
resumeResolution = resolve;
49-
}),
50-
);
54+
offResolve = item.onResolve(onResolve);
5155
}
5256
function onanimationend() {
5357
if (dialog.open) return;
@@ -71,6 +75,7 @@ export function enhanceDialog(item, options) {
7175
dialog.addEventListener('close', onclose);
7276

7377
return () => {
78+
offResolve?.();
7479
resumeResolution?.();
7580
dialog.removeEventListener('animationend', onanimationend);
7681
dialog.removeEventListener('click', onclick);

packages/async-stack/src/stack-item.svelte.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ export class StackItem<
4545
* to stop the resolution flow. Note, however, that other resolve listeners
4646
* will still run to completion.
4747
*
48+
* This also returns a function that can be called to remove the listener.
49+
*
4850
* Note: this feature is experimental and may change at any time.
4951
*/
50-
onResolve: (callback: StackItemResolveListener<Resolved>) => void;
52+
onResolve: (callback: StackItemResolveListener<Resolved>) => () => void;
5153
}

packages/async-stack/src/stack-item.svelte.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,12 @@ export class StackItem {
7777

7878
/**
7979
* @param {import('./types.public').StackItemResolveListener<Resolved>} callback
80+
* @returns {() => void}
8081
*/
8182
onResolve = (callback) => {
8283
this.#internals.resolveListeners.add(callback);
84+
return () => {
85+
this.#internals.resolveListeners.delete(callback);
86+
};
8387
};
8488
}

0 commit comments

Comments
 (0)