foldkit 0.85.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/devTools/overlay.d.ts.map +1 -1
  2. package/dist/devTools/overlay.js +1 -1
  3. package/dist/{task → dom}/dom.d.ts +10 -10
  4. package/dist/dom/dom.d.ts.map +1 -0
  5. package/dist/{task → dom}/dom.js +15 -22
  6. package/dist/{task → dom}/elementMovement.d.ts +1 -1
  7. package/dist/dom/elementMovement.d.ts.map +1 -0
  8. package/dist/{task → dom}/elementMovement.js +5 -6
  9. package/dist/{task → dom}/error.d.ts +0 -8
  10. package/dist/dom/error.d.ts.map +1 -0
  11. package/dist/{task → dom}/error.js +0 -3
  12. package/dist/dom/index.d.ts +8 -0
  13. package/dist/dom/index.d.ts.map +1 -0
  14. package/dist/dom/index.js +6 -0
  15. package/dist/{task → dom}/inert.d.ts +4 -3
  16. package/dist/dom/inert.d.ts.map +1 -0
  17. package/dist/{task → dom}/inert.js +4 -3
  18. package/dist/dom/public.d.ts +3 -0
  19. package/dist/dom/public.d.ts.map +1 -0
  20. package/dist/dom/public.js +1 -0
  21. package/dist/{task → dom}/scrollLock.d.ts +3 -3
  22. package/dist/dom/scrollLock.d.ts.map +1 -0
  23. package/dist/{task → dom}/scrollLock.js +3 -3
  24. package/dist/dom/waitForAnimation.d.ts +17 -0
  25. package/dist/dom/waitForAnimation.d.ts.map +1 -0
  26. package/dist/dom/waitForAnimation.js +23 -0
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -1
  30. package/dist/render/index.d.ts +2 -0
  31. package/dist/render/index.d.ts.map +1 -0
  32. package/dist/render/index.js +1 -0
  33. package/dist/render/public.d.ts +2 -0
  34. package/dist/render/public.d.ts.map +1 -0
  35. package/dist/render/public.js +1 -0
  36. package/dist/render/render.d.ts +40 -0
  37. package/dist/render/render.d.ts.map +1 -0
  38. package/dist/render/render.js +48 -0
  39. package/dist/ui/animation/update.d.ts.map +1 -1
  40. package/dist/ui/animation/update.js +5 -4
  41. package/dist/ui/calendar/index.d.ts.map +1 -1
  42. package/dist/ui/calendar/index.js +2 -2
  43. package/dist/ui/combobox/shared.d.ts.map +1 -1
  44. package/dist/ui/combobox/shared.js +10 -10
  45. package/dist/ui/dialog/index.d.ts.map +1 -1
  46. package/dist/ui/dialog/index.js +3 -3
  47. package/dist/ui/disclosure/index.d.ts.map +1 -1
  48. package/dist/ui/disclosure/index.js +3 -3
  49. package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
  50. package/dist/ui/dragAndDrop/index.js +2 -2
  51. package/dist/ui/listbox/multi.d.ts +1 -1
  52. package/dist/ui/listbox/shared.d.ts +1 -1
  53. package/dist/ui/listbox/shared.d.ts.map +1 -1
  54. package/dist/ui/listbox/shared.js +12 -12
  55. package/dist/ui/listbox/single.d.ts +1 -1
  56. package/dist/ui/menu/index.d.ts.map +1 -1
  57. package/dist/ui/menu/index.js +13 -13
  58. package/dist/ui/popover/index.d.ts.map +1 -1
  59. package/dist/ui/popover/index.js +8 -8
  60. package/dist/ui/radioGroup/index.d.ts.map +1 -1
  61. package/dist/ui/radioGroup/index.js +2 -2
  62. package/dist/ui/tabs/index.d.ts.map +1 -1
  63. package/dist/ui/tabs/index.js +3 -3
  64. package/dist/ui/toast/update.d.ts.map +1 -1
  65. package/dist/ui/toast/update.js +1 -2
  66. package/dist/ui/tooltip/index.d.ts.map +1 -1
  67. package/dist/ui/tooltip/index.js +1 -2
  68. package/package.json +9 -5
  69. package/dist/task/dom.d.ts.map +0 -1
  70. package/dist/task/elementMovement.d.ts.map +0 -1
  71. package/dist/task/error.d.ts.map +0 -1
  72. package/dist/task/index.d.ts +0 -10
  73. package/dist/task/index.d.ts.map +0 -1
  74. package/dist/task/index.js +0 -8
  75. package/dist/task/inert.d.ts.map +0 -1
  76. package/dist/task/public.d.ts +0 -2
  77. package/dist/task/public.d.ts.map +0 -1
  78. package/dist/task/public.js +0 -1
  79. package/dist/task/random.d.ts +0 -21
  80. package/dist/task/random.d.ts.map +0 -1
  81. package/dist/task/random.js +0 -20
  82. package/dist/task/scrollLock.d.ts.map +0 -1
  83. package/dist/task/time.d.ts +0 -43
  84. package/dist/task/time.d.ts.map +0 -1
  85. package/dist/task/time.js +0 -53
  86. package/dist/task/timing.d.ts +0 -39
  87. package/dist/task/timing.d.ts.map +0 -1
  88. package/dist/task/timing.js +0 -51
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAGN,OAAO,EAGP,MAAM,EAUP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAW9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAQ3E,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,YAAY,CAAA;AAqO5E,eAAO,MAAM,MAAM;;EAA0C,CAAA;AAC7D,eAAO,MAAM,YAAY;;;;;;EAGxB,CAAA;AACD,eAAO,MAAM,aAAa;;;;;;EAGzB,CAAA;AACD,eAAO,MAAM,MAAM;;EAA4C,CAAA;AAC/D,eAAO,MAAM,KAAK;;EAA0C,CAAA;AAC5D,eAAO,MAAM,UAAU;;EAA6C,CAAA;AACpE,eAAO,MAAM,YAAY;;EAAiD,CAAA;AAC1E,eAAO,MAAM,WAAW;;EAA+C,CAAA;AAs9CvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAoDhC,CAAA"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/devTools/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,MAAM,EAGN,OAAO,EAGP,MAAM,EAUP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAY9C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO3E,OAAO,EAAE,KAAK,aAAa,EAA+B,MAAM,YAAY,CAAA;AAqO5E,eAAO,MAAM,MAAM;;EAA0C,CAAA;AAC7D,eAAO,MAAM,YAAY;;;;;;EAGxB,CAAA;AACD,eAAO,MAAM,aAAa;;;;;;EAGzB,CAAA;AACD,eAAO,MAAM,MAAM;;EAA4C,CAAA;AAC/D,eAAO,MAAM,KAAK;;EAA0C,CAAA;AAC5D,eAAO,MAAM,UAAU;;EAA6C,CAAA;AACpE,eAAO,MAAM,YAAY;;EAAiD,CAAA;AAC1E,eAAO,MAAM,WAAW;;EAA+C,CAAA;AAs9CvE,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,sCAoDhC,CAAA"}
@@ -1,13 +1,13 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { Array as Array_, Effect, Equal, Function, HashSet, Match as M, Number as Number_, Option, Order, Predicate, Queue, Record, Schema as S, Stream, String as String_, SubscriptionRef, pipe, } from 'effect';
3
3
  import * as Command from '../command/index.js';
4
+ import { lockScroll, unlockScroll } from '../dom/scrollLock.js';
4
5
  import { OptionExt } from '../effectExtensions/index.js';
5
6
  import { createKeyedLazy, createLazy, html, } from '../html/index.js';
6
7
  import { m } from '../message/index.js';
7
8
  import { makeProgram } from '../runtime/runtime.js';
8
9
  import { makeSubscriptions } from '../runtime/subscription.js';
9
10
  import { evo } from '../struct/index.js';
10
- import { lockScroll, unlockScroll } from '../task/scrollLock.js';
11
11
  import * as Listbox from '../ui/listbox/public.js';
12
12
  import * as Tabs from '../ui/tabs/public.js';
13
13
  import { overlayStyles } from './overlay-styles.js';
@@ -4,7 +4,7 @@ import { ElementNotFound } from './error.js';
4
4
  * Focuses an element matching the given selector after the next render has
5
5
  * committed.
6
6
  *
7
- * Use `Task.focus` inside a Command for focus that's caused by a Message
7
+ * Use `Dom.focus` inside a Command for focus that's caused by a Message
8
8
  * dispatching: a dialog opening, an input becoming the active step in a
9
9
  * form, returning focus to a trigger button after a popover closes,
10
10
  * keyboard navigation across a stable layout. The Command fires from
@@ -20,14 +20,14 @@ import { ElementNotFound } from './error.js';
20
20
  *
21
21
  * @example
22
22
  * ```typescript
23
- * Task.focus('#email-input').pipe(Effect.ignore, Effect.as(CompletedFocusInput()))
23
+ * Dom.focus('#email-input').pipe(Effect.ignore, Effect.as(CompletedFocusInput()))
24
24
  * ```
25
25
  */
26
26
  export declare const focus: (selector: string) => Effect.Effect<void, ElementNotFound>;
27
27
  /**
28
28
  * Opens a dialog element using `show()` with high z-index, focus trapping,
29
29
  * and Escape key handling. Uses `show()` instead of `showModal()` so that
30
- * DevTools (and any other high-z-index overlay) remains interactive — the
30
+ * DevTools (and any other high-z-index overlay) remains interactive. The
31
31
  * Dialog component provides its own backdrop, scroll locking, and transitions.
32
32
  * Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
33
33
  *
@@ -35,8 +35,8 @@ export declare const focus: (selector: string) => Effect.Effect<void, ElementNot
35
35
  *
36
36
  * @example
37
37
  * ```typescript
38
- * Task.showModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
39
- * Task.showModal('#my-dialog', { focusSelector: '#search-input' }).pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
38
+ * Dom.showModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
39
+ * Dom.showModal('#my-dialog', { focusSelector: '#search-input' }).pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
40
40
  * ```
41
41
  */
42
42
  export declare const showModal: (selector: string, options?: Readonly<{
@@ -49,7 +49,7 @@ export declare const showModal: (selector: string, options?: Readonly<{
49
49
  *
50
50
  * @example
51
51
  * ```typescript
52
- * Task.closeModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedCloseDialog()))
52
+ * Dom.closeModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedCloseDialog()))
53
53
  * ```
54
54
  */
55
55
  export declare const closeModal: (selector: string) => Effect.Effect<void, ElementNotFound>;
@@ -59,7 +59,7 @@ export declare const closeModal: (selector: string) => Effect.Effect<void, Eleme
59
59
  *
60
60
  * @example
61
61
  * ```typescript
62
- * Task.clickElement('#menu-item-2').pipe(Effect.ignore, Effect.as(CompletedClickItem()))
62
+ * Dom.clickElement('#menu-item-2').pipe(Effect.ignore, Effect.as(CompletedClickItem()))
63
63
  * ```
64
64
  */
65
65
  export declare const clickElement: (selector: string) => Effect.Effect<void, ElementNotFound>;
@@ -69,11 +69,11 @@ export declare const clickElement: (selector: string) => Effect.Effect<void, Ele
69
69
  *
70
70
  * @example
71
71
  * ```typescript
72
- * Task.scrollIntoView('#active-item').pipe(Effect.ignore, Effect.as(CompletedScrollIntoView()))
72
+ * Dom.scrollIntoView('#active-item').pipe(Effect.ignore, Effect.as(CompletedScrollIntoView()))
73
73
  * ```
74
74
  */
75
75
  export declare const scrollIntoView: (selector: string) => Effect.Effect<void, ElementNotFound>;
76
- /** Direction for focus advancement forward or backward in tab order. */
76
+ /** Direction for focus advancement: forward or backward in tab order. */
77
77
  export type FocusDirection = 'Next' | 'Previous';
78
78
  /**
79
79
  * Focuses the next or previous focusable element in the document relative to the element matching the given selector.
@@ -81,7 +81,7 @@ export type FocusDirection = 'Next' | 'Previous';
81
81
  *
82
82
  * @example
83
83
  * ```typescript
84
- * Task.advanceFocus('#menu-button', 'Next').pipe(Effect.ignore, Effect.as(CompletedAdvanceFocus()))
84
+ * Dom.advanceFocus('#menu-button', 'Next').pipe(Effect.ignore, Effect.as(CompletedAdvanceFocus()))
85
85
  * ```
86
86
  */
87
87
  export declare const advanceFocus: (selector: string, direction: FocusDirection) => Effect.Effect<void, ElementNotFound>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/dom/dom.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,MAAM,EAMP,MAAM,QAAQ,CAAA;AAGf,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA6B5C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,KAAK,GAAI,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAKxE,CAAA;AAEJ;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,SAAS,GACpB,UAAU,MAAM,EAChB,UAAU,QAAQ,CAAC;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,KAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAgDlC,CAAA;AAuBJ;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GACrB,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAclC,CAAA;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAKlC,CAAA;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GACzB,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAKlC,CAAA;AAEJ,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAA;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,EAChB,WAAW,cAAc,KACxB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAiClC,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { Array, Effect, Equal, Function, Match as M, Number, Option, } from 'effect';
2
+ import { afterCommit } from '../render/render.js';
2
3
  import { ElementNotFound } from './error.js';
3
4
  const BASE_DIALOG_Z_INDEX = 2147483600;
4
5
  let openDialogCount = 0;
@@ -11,14 +12,6 @@ const FOCUSABLE_SELECTOR = Array.join([
11
12
  'textarea:not([disabled]):not([tabindex="-1"])',
12
13
  '[tabindex]:not([tabindex="-1"])',
13
14
  ], ', ');
14
- // NOTE: DOM tasks await one rAF before walking the tree. The runtime defers
15
- // renders to the next animation frame and forks Commands on the microtask
16
- // queue, so without this wait a Task that runs immediately after a dirtying
17
- // Message would query the DOM before the matching VDOM patch has committed.
18
- const awaitNextFrame = Effect.callback(resume => {
19
- const handle = requestAnimationFrame(() => resume(Effect.void));
20
- return Effect.sync(() => cancelAnimationFrame(handle));
21
- });
22
15
  const queryHTMLElement = (selector) => Effect.suspend(() => {
23
16
  const element = document.querySelector(selector);
24
17
  return element instanceof HTMLElement
@@ -29,7 +22,7 @@ const queryHTMLElement = (selector) => Effect.suspend(() => {
29
22
  * Focuses an element matching the given selector after the next render has
30
23
  * committed.
31
24
  *
32
- * Use `Task.focus` inside a Command for focus that's caused by a Message
25
+ * Use `Dom.focus` inside a Command for focus that's caused by a Message
33
26
  * dispatching: a dialog opening, an input becoming the active step in a
34
27
  * form, returning focus to a trigger button after a popover closes,
35
28
  * keyboard navigation across a stable layout. The Command fires from
@@ -45,18 +38,18 @@ const queryHTMLElement = (selector) => Effect.suspend(() => {
45
38
  *
46
39
  * @example
47
40
  * ```typescript
48
- * Task.focus('#email-input').pipe(Effect.ignore, Effect.as(CompletedFocusInput()))
41
+ * Dom.focus('#email-input').pipe(Effect.ignore, Effect.as(CompletedFocusInput()))
49
42
  * ```
50
43
  */
51
44
  export const focus = (selector) => Effect.gen(function* () {
52
- yield* awaitNextFrame;
45
+ yield* afterCommit;
53
46
  const element = yield* queryHTMLElement(selector);
54
47
  element.focus();
55
48
  });
56
49
  /**
57
50
  * Opens a dialog element using `show()` with high z-index, focus trapping,
58
51
  * and Escape key handling. Uses `show()` instead of `showModal()` so that
59
- * DevTools (and any other high-z-index overlay) remains interactive — the
52
+ * DevTools (and any other high-z-index overlay) remains interactive. The
60
53
  * Dialog component provides its own backdrop, scroll locking, and transitions.
61
54
  * Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
62
55
  *
@@ -64,12 +57,12 @@ export const focus = (selector) => Effect.gen(function* () {
64
57
  *
65
58
  * @example
66
59
  * ```typescript
67
- * Task.showModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
68
- * Task.showModal('#my-dialog', { focusSelector: '#search-input' }).pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
60
+ * Dom.showModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
61
+ * Dom.showModal('#my-dialog', { focusSelector: '#search-input' }).pipe(Effect.ignore, Effect.as(CompletedShowDialog()))
69
62
  * ```
70
63
  */
71
64
  export const showModal = (selector, options) => Effect.gen(function* () {
72
- yield* awaitNextFrame;
65
+ yield* afterCommit;
73
66
  const element = document.querySelector(selector);
74
67
  if (!(element instanceof HTMLDialogElement)) {
75
68
  return yield* Effect.fail(new ElementNotFound({ selector }));
@@ -124,7 +117,7 @@ const trapFocusWithinDialog = (event, dialog) => {
124
117
  *
125
118
  * @example
126
119
  * ```typescript
127
- * Task.closeModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedCloseDialog()))
120
+ * Dom.closeModal('#my-dialog').pipe(Effect.ignore, Effect.as(CompletedCloseDialog()))
128
121
  * ```
129
122
  */
130
123
  export const closeModal = (selector) => Effect.suspend(() => {
@@ -147,11 +140,11 @@ export const closeModal = (selector) => Effect.suspend(() => {
147
140
  *
148
141
  * @example
149
142
  * ```typescript
150
- * Task.clickElement('#menu-item-2').pipe(Effect.ignore, Effect.as(CompletedClickItem()))
143
+ * Dom.clickElement('#menu-item-2').pipe(Effect.ignore, Effect.as(CompletedClickItem()))
151
144
  * ```
152
145
  */
153
146
  export const clickElement = (selector) => Effect.gen(function* () {
154
- yield* awaitNextFrame;
147
+ yield* afterCommit;
155
148
  const element = yield* queryHTMLElement(selector);
156
149
  element.click();
157
150
  });
@@ -161,11 +154,11 @@ export const clickElement = (selector) => Effect.gen(function* () {
161
154
  *
162
155
  * @example
163
156
  * ```typescript
164
- * Task.scrollIntoView('#active-item').pipe(Effect.ignore, Effect.as(CompletedScrollIntoView()))
157
+ * Dom.scrollIntoView('#active-item').pipe(Effect.ignore, Effect.as(CompletedScrollIntoView()))
165
158
  * ```
166
159
  */
167
160
  export const scrollIntoView = (selector) => Effect.gen(function* () {
168
- yield* awaitNextFrame;
161
+ yield* afterCommit;
169
162
  const element = yield* queryHTMLElement(selector);
170
163
  element.scrollIntoView({ block: 'nearest' });
171
164
  });
@@ -175,11 +168,11 @@ export const scrollIntoView = (selector) => Effect.gen(function* () {
175
168
  *
176
169
  * @example
177
170
  * ```typescript
178
- * Task.advanceFocus('#menu-button', 'Next').pipe(Effect.ignore, Effect.as(CompletedAdvanceFocus()))
171
+ * Dom.advanceFocus('#menu-button', 'Next').pipe(Effect.ignore, Effect.as(CompletedAdvanceFocus()))
179
172
  * ```
180
173
  */
181
174
  export const advanceFocus = (selector, direction) => Effect.gen(function* () {
182
- yield* awaitNextFrame;
175
+ yield* afterCommit;
183
176
  const reference = yield* queryHTMLElement(selector);
184
177
  const focusableElements = Array.fromIterable(document.querySelectorAll(FOCUSABLE_SELECTOR));
185
178
  const referenceElementIndex = Array.findFirstIndex(focusableElements, Equal.equals(reference));
@@ -12,7 +12,7 @@ import { Effect } from 'effect';
12
12
  *
13
13
  * @example
14
14
  * ```typescript
15
- * Task.detectElementMovement('#menu-button').pipe(
15
+ * Dom.detectElementMovement('#menu-button').pipe(
16
16
  * Effect.as(DetectedButtonMovement()),
17
17
  * )
18
18
  * ```
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elementMovement.d.ts","sourceRoot":"","sources":["../../src/dom/elementMovement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAM/B;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAmCvE,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { Effect } from 'effect';
2
+ import { afterCommit } from '../render/render.js';
2
3
  const rectToPosition = (rect) => `${rect.x},${rect.y}`;
3
4
  /**
4
5
  * Detects if the element matching the given selector moves in the viewport.
@@ -13,16 +14,14 @@ const rectToPosition = (rect) => `${rect.x},${rect.y}`;
13
14
  *
14
15
  * @example
15
16
  * ```typescript
16
- * Task.detectElementMovement('#menu-button').pipe(
17
+ * Dom.detectElementMovement('#menu-button').pipe(
17
18
  * Effect.as(DetectedButtonMovement()),
18
19
  * )
19
20
  * ```
20
21
  */
21
- export const detectElementMovement = (selector) => Effect.callback((resume, signal) => {
22
- requestAnimationFrame(() => {
23
- if (signal.aborted) {
24
- return;
25
- }
22
+ export const detectElementMovement = (selector) => Effect.gen(function* () {
23
+ yield* afterCommit;
24
+ return yield* Effect.callback((resume, signal) => {
26
25
  const element = document.querySelector(selector);
27
26
  if (!(element instanceof HTMLElement)) {
28
27
  return resume(Effect.void);
@@ -6,13 +6,5 @@ export declare class ElementNotFound extends ElementNotFound_base<{
6
6
  readonly selector: string;
7
7
  }> {
8
8
  }
9
- declare const TimeZoneError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
10
- readonly _tag: "TimeZoneError";
11
- } & Readonly<A>;
12
- /** Error indicating that the given timezone ID is invalid. */
13
- export declare class TimeZoneError extends TimeZoneError_base<{
14
- readonly zoneId: string;
15
- }> {
16
- }
17
9
  export {};
18
10
  //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/dom/error.ts"],"names":[],"mappings":";;;AAEA,qFAAqF;AACrF,qBAAa,eAAgB,SAAQ,qBAAoC;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,CAAC;CAAG"}
@@ -2,6 +2,3 @@ import { Data } from 'effect';
2
2
  /** Error indicating that a DOM element matching the given selector was not found. */
3
3
  export class ElementNotFound extends Data.TaggedError('ElementNotFound') {
4
4
  }
5
- /** Error indicating that the given timezone ID is invalid. */
6
- export class TimeZoneError extends Data.TaggedError('TimeZoneError') {
7
- }
@@ -0,0 +1,8 @@
1
+ export { ElementNotFound } from './error.js';
2
+ export { advanceFocus, clickElement, closeModal, focus, scrollIntoView, showModal, } from './dom.js';
3
+ export type { FocusDirection } from './dom.js';
4
+ export { detectElementMovement } from './elementMovement.js';
5
+ export { inertOthers, restoreInert } from './inert.js';
6
+ export { lockScroll, unlockScroll } from './scrollLock.js';
7
+ export { waitForAnimationSettled } from './waitForAnimation.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dom/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,KAAK,EACL,cAAc,EACd,SAAS,GACV,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { ElementNotFound } from './error.js';
2
+ export { advanceFocus, clickElement, closeModal, focus, scrollIntoView, showModal, } from './dom.js';
3
+ export { detectElementMovement } from './elementMovement.js';
4
+ export { inertOthers, restoreInert } from './inert.js';
5
+ export { lockScroll, unlockScroll } from './scrollLock.js';
6
+ export { waitForAnimationSettled } from './waitForAnimation.js';
@@ -7,7 +7,7 @@ import { Effect } from 'effect';
7
7
  *
8
8
  * @example
9
9
  * ```typescript
10
- * Task.inertOthers('my-menu', ['#menu-button', '#menu-items']).pipe(
10
+ * Dom.inertOthers('my-menu', ['#menu-button', '#menu-items']).pipe(
11
11
  * Effect.as(CompletedSetupInert()),
12
12
  * )
13
13
  * ```
@@ -15,11 +15,12 @@ import { Effect } from 'effect';
15
15
  export declare const inertOthers: (id: string, allowedSelectors: ReadonlyArray<string>) => Effect.Effect<void>;
16
16
  /**
17
17
  * Restores all elements previously marked inert by `inertOthers` for the
18
- * given ID. Safe to call without a preceding `inertOthers` acts as a no-op.
18
+ * given ID. Safe to call without a preceding `inertOthers`. Acts as a no-op
19
+ * in that case.
19
20
  *
20
21
  * @example
21
22
  * ```typescript
22
- * Task.restoreInert('my-menu').pipe(Effect.as(CompletedTeardownInert()))
23
+ * Dom.restoreInert('my-menu').pipe(Effect.as(CompletedTeardownInert()))
23
24
  * ```
24
25
  */
25
26
  export declare const restoreInert: (id: string) => Effect.Effect<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inert.d.ts","sourceRoot":"","sources":["../../src/dom/inert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAA2C,MAAM,QAAQ,CAAA;AAuF/E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GACtB,IAAI,MAAM,EACV,kBAAkB,aAAa,CAAC,MAAM,CAAC,KACtC,MAAM,CAAC,MAAM,CAAC,IAAI,CAajB,CAAA;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,GAAI,IAAI,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAQxD,CAAA"}
@@ -56,7 +56,7 @@ const inertableSiblings = (parent, allowedElements) => pipe(parent.children, Arr
56
56
  *
57
57
  * @example
58
58
  * ```typescript
59
- * Task.inertOthers('my-menu', ['#menu-button', '#menu-items']).pipe(
59
+ * Dom.inertOthers('my-menu', ['#menu-button', '#menu-items']).pipe(
60
60
  * Effect.as(CompletedSetupInert()),
61
61
  * )
62
62
  * ```
@@ -68,11 +68,12 @@ export const inertOthers = (id, allowedSelectors) => Effect.sync(() => {
68
68
  });
69
69
  /**
70
70
  * Restores all elements previously marked inert by `inertOthers` for the
71
- * given ID. Safe to call without a preceding `inertOthers` acts as a no-op.
71
+ * given ID. Safe to call without a preceding `inertOthers`. Acts as a no-op
72
+ * in that case.
72
73
  *
73
74
  * @example
74
75
  * ```typescript
75
- * Task.restoreInert('my-menu').pipe(Effect.as(CompletedTeardownInert()))
76
+ * Dom.restoreInert('my-menu').pipe(Effect.as(CompletedTeardownInert()))
76
77
  * ```
77
78
  */
78
79
  export const restoreInert = (id) => Effect.sync(() => {
@@ -0,0 +1,3 @@
1
+ export { ElementNotFound, advanceFocus, clickElement, closeModal, detectElementMovement, focus, inertOthers, lockScroll, restoreInert, scrollIntoView, showModal, unlockScroll, waitForAnimationSettled, } from './index.js';
2
+ export type { FocusDirection } from './index.js';
3
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/dom/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,qBAAqB,EACrB,KAAK,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,EACZ,uBAAuB,GACxB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1 @@
1
+ export { ElementNotFound, advanceFocus, clickElement, closeModal, detectElementMovement, focus, inertOthers, lockScroll, restoreInert, scrollIntoView, showModal, unlockScroll, waitForAnimationSettled, } from './index.js';
@@ -4,12 +4,12 @@ import { Effect } from 'effect';
4
4
  * Compensates for scrollbar width with padding to prevent layout shift.
5
5
  * On iOS Safari, intercepts `touchmove` events to prevent page scroll
6
6
  * while allowing scrolling within overflow containers.
7
- * Uses reference counting so nested locks are safe the page only unlocks
7
+ * Uses reference counting so nested locks are safe. The page only unlocks
8
8
  * when every lock has been released.
9
9
  *
10
10
  * @example
11
11
  * ```typescript
12
- * Task.lockScroll.pipe(Effect.as(CompletedLockScroll()))
12
+ * Dom.lockScroll.pipe(Effect.as(CompletedLockScroll()))
13
13
  * ```
14
14
  */
15
15
  export declare const lockScroll: Effect.Effect<void>;
@@ -20,7 +20,7 @@ export declare const lockScroll: Effect.Effect<void>;
20
20
  *
21
21
  * @example
22
22
  * ```typescript
23
- * Task.unlockScroll.pipe(Effect.as(CompletedUnlockScroll()))
23
+ * Dom.unlockScroll.pipe(Effect.as(CompletedUnlockScroll()))
24
24
  * ```
25
25
  */
26
26
  export declare const unlockScroll: Effect.Effect<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrollLock.d.ts","sourceRoot":"","sources":["../../src/dom/scrollLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AA6CvC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAwBzC,CAAA;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAW3C,CAAA"}
@@ -41,12 +41,12 @@ const handleTouchMove = (event) => {
41
41
  * Compensates for scrollbar width with padding to prevent layout shift.
42
42
  * On iOS Safari, intercepts `touchmove` events to prevent page scroll
43
43
  * while allowing scrolling within overflow containers.
44
- * Uses reference counting so nested locks are safe the page only unlocks
44
+ * Uses reference counting so nested locks are safe. The page only unlocks
45
45
  * when every lock has been released.
46
46
  *
47
47
  * @example
48
48
  * ```typescript
49
- * Task.lockScroll.pipe(Effect.as(CompletedLockScroll()))
49
+ * Dom.lockScroll.pipe(Effect.as(CompletedLockScroll()))
50
50
  * ```
51
51
  */
52
52
  export const lockScroll = Effect.sync(() => {
@@ -73,7 +73,7 @@ export const lockScroll = Effect.sync(() => {
73
73
  *
74
74
  * @example
75
75
  * ```typescript
76
- * Task.unlockScroll.pipe(Effect.as(CompletedUnlockScroll()))
76
+ * Dom.unlockScroll.pipe(Effect.as(CompletedUnlockScroll()))
77
77
  * ```
78
78
  */
79
79
  export const unlockScroll = Effect.sync(() => {
@@ -0,0 +1,17 @@
1
+ import { Effect } from 'effect';
2
+ /**
3
+ * Waits for all CSS animations on the element matching the selector to settle.
4
+ * Covers both CSS transitions and CSS keyframe animations via the Web Animations
5
+ * API. Falls back to completing immediately if the element is missing or has no
6
+ * active animations.
7
+ *
8
+ * Leave animations must be finite. `animation-iteration-count: infinite` will
9
+ * keep the underlying `.finished` promise pending and hang the caller.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * Dom.waitForAnimationSettled('#menu-items').pipe(Effect.as(EndedAnimation()))
14
+ * ```
15
+ */
16
+ export declare const waitForAnimationSettled: (selector: string) => Effect.Effect<void>;
17
+ //# sourceMappingURL=waitForAnimation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitForAnimation.d.ts","sourceRoot":"","sources":["../../src/dom/waitForAnimation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,CAYjB,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { Effect } from 'effect';
2
+ /**
3
+ * Waits for all CSS animations on the element matching the selector to settle.
4
+ * Covers both CSS transitions and CSS keyframe animations via the Web Animations
5
+ * API. Falls back to completing immediately if the element is missing or has no
6
+ * active animations.
7
+ *
8
+ * Leave animations must be finite. `animation-iteration-count: infinite` will
9
+ * keep the underlying `.finished` promise pending and hang the caller.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * Dom.waitForAnimationSettled('#menu-items').pipe(Effect.as(EndedAnimation()))
14
+ * ```
15
+ */
16
+ export const waitForAnimationSettled = (selector) => Effect.callback(resume => {
17
+ requestAnimationFrame(async () => {
18
+ const element = document.querySelector(selector);
19
+ const animations = element instanceof HTMLElement ? element.getAnimations() : [];
20
+ await Promise.allSettled(animations.map(({ finished }) => finished));
21
+ resume(Effect.void);
22
+ });
23
+ });
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * as Calendar from './calendar/public.js';
2
2
  export * as Command from './command/public.js';
3
+ export * as Dom from './dom/public.js';
3
4
  export * as ManagedResource from './managedResource/public.js';
4
5
  export * as FieldValidation from './fieldValidation/public.js';
5
6
  export * as File from './file/public.js';
@@ -7,12 +8,12 @@ export * as Html from './html/public.js';
7
8
  export * as Message from './message/public.js';
8
9
  export * as Mount from './mount/public.js';
9
10
  export * as Navigation from './navigation/public.js';
11
+ export * as Render from './render/public.js';
10
12
  export * as Route from './route/public.js';
11
13
  export * as Runtime from './runtime/public.js';
12
14
  export * as Schema from './schema/public.js';
13
15
  export * as Struct from './struct/public.js';
14
16
  export * as Subscription from './subscription/public.js';
15
- export * as Task from './task/public.js';
16
17
  export * as Scene from './test/scene.js';
17
18
  export * as Story from './test/story.js';
18
19
  export * as Ui from './ui/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAA;AAChD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,eAAe,CAAA;AACnC,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAA;AAChD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,eAAe,CAAA;AACnC,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * as Calendar from './calendar/public.js';
2
2
  export * as Command from './command/public.js';
3
+ export * as Dom from './dom/public.js';
3
4
  export * as ManagedResource from './managedResource/public.js';
4
5
  export * as FieldValidation from './fieldValidation/public.js';
5
6
  export * as File from './file/public.js';
@@ -7,12 +8,12 @@ export * as Html from './html/public.js';
7
8
  export * as Message from './message/public.js';
8
9
  export * as Mount from './mount/public.js';
9
10
  export * as Navigation from './navigation/public.js';
11
+ export * as Render from './render/public.js';
10
12
  export * as Route from './route/public.js';
11
13
  export * as Runtime from './runtime/public.js';
12
14
  export * as Schema from './schema/public.js';
13
15
  export * as Struct from './struct/public.js';
14
16
  export * as Subscription from './subscription/public.js';
15
- export * as Task from './task/public.js';
16
17
  export * as Scene from './test/scene.js';
17
18
  export * as Story from './test/story.js';
18
19
  export * as Ui from './ui/index.js';
@@ -0,0 +1,2 @@
1
+ export { afterCommit, afterPaint } from './render.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1 @@
1
+ export { afterCommit, afterPaint } from './render.js';
@@ -0,0 +1,2 @@
1
+ export { afterCommit, afterPaint } from './index.js';
2
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/render/public.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1 @@
1
+ export { afterCommit, afterPaint } from './index.js';
@@ -0,0 +1,40 @@
1
+ import { Effect } from 'effect';
2
+ /**
3
+ * Completes after the runtime's next render commits. The runtime batches
4
+ * renders to `requestAnimationFrame`, so a Command, Subscription, or other
5
+ * Effect that runs immediately after a dirtying Message would otherwise
6
+ * query the DOM before the matching VDOM patch has applied. Yield this
7
+ * before any DOM read or write whose target was just brought into existence
8
+ * (or moved, or had its attributes changed) by the same Message.
9
+ *
10
+ * The `Dom` helpers (`focus`, `clickElement`, `scrollIntoView`, etc.)
11
+ * already gate themselves with this internally; reach for `afterCommit`
12
+ * directly when building custom Commands or DOM-observing Subscriptions
13
+ * that need the same guarantee.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * Effect.gen(function* () {
18
+ * yield* Render.afterCommit
19
+ * const element = document.getElementById(id)
20
+ * // element reflects the post-Message DOM
21
+ * })
22
+ * ```
23
+ */
24
+ export declare const afterCommit: Effect.Effect<void>;
25
+ /**
26
+ * Completes after the prior state has been painted to the screen. Waits two
27
+ * animation frames: the first lets the runtime commit the latest model to
28
+ * the DOM and the browser paint it, the second resumes once that paint is
29
+ * visible. Use this for CSS transition orchestration where the from-state
30
+ * must be displayed before the to-state changes are applied, otherwise the
31
+ * browser collapses both states into a single frame and the transition does
32
+ * not play.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * Render.afterPaint.pipe(Effect.as(TransitionFrameAdvanced()))
37
+ * ```
38
+ */
39
+ export declare const afterPaint: Effect.Effect<void>;
40
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/render/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAK3C,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAMzC,CAAA"}