@foldkit/ui 0.163.0 → 0.164.0-canary.c9c641bf8179

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 (79) hide show
  1. package/dist/anchor/anchor.d.ts +33 -7
  2. package/dist/anchor/anchor.d.ts.map +1 -1
  3. package/dist/anchor/anchor.js +92 -14
  4. package/dist/anchor/public.d.ts +1 -1
  5. package/dist/anchor/public.d.ts.map +1 -1
  6. package/dist/anchor/public.js +1 -1
  7. package/dist/animation/index.d.ts +3 -0
  8. package/dist/animation/index.d.ts.map +1 -1
  9. package/dist/animation/schema.d.ts +13 -4
  10. package/dist/animation/schema.d.ts.map +1 -1
  11. package/dist/animation/schema.js +8 -4
  12. package/dist/animation/update.d.ts +15 -5
  13. package/dist/animation/update.d.ts.map +1 -1
  14. package/dist/animation/update.js +56 -28
  15. package/dist/combobox/multi.d.ts +5 -0
  16. package/dist/combobox/multi.d.ts.map +1 -1
  17. package/dist/combobox/shared.d.ts +19 -7
  18. package/dist/combobox/shared.d.ts.map +1 -1
  19. package/dist/combobox/shared.js +13 -13
  20. package/dist/combobox/single.d.ts +5 -0
  21. package/dist/combobox/single.d.ts.map +1 -1
  22. package/dist/datePicker/index.d.ts +13 -2
  23. package/dist/datePicker/index.d.ts.map +1 -1
  24. package/dist/dialog/index.d.ts +13 -2
  25. package/dist/dialog/index.d.ts.map +1 -1
  26. package/dist/dialog/index.js +22 -8
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/internal/accessibleName.d.ts +9 -0
  31. package/dist/internal/accessibleName.d.ts.map +1 -0
  32. package/dist/internal/accessibleName.js +12 -0
  33. package/dist/internal/range.d.ts +7 -0
  34. package/dist/internal/range.d.ts.map +1 -0
  35. package/dist/internal/range.js +12 -0
  36. package/dist/listbox/multi.d.ts +5 -0
  37. package/dist/listbox/multi.d.ts.map +1 -1
  38. package/dist/listbox/shared.d.ts +15 -4
  39. package/dist/listbox/shared.d.ts.map +1 -1
  40. package/dist/listbox/shared.js +12 -11
  41. package/dist/listbox/single.d.ts +5 -0
  42. package/dist/listbox/single.d.ts.map +1 -1
  43. package/dist/menu/index.d.ts +16 -4
  44. package/dist/menu/index.d.ts.map +1 -1
  45. package/dist/menu/index.js +12 -11
  46. package/dist/meter/index.d.ts +26 -0
  47. package/dist/meter/index.d.ts.map +1 -0
  48. package/dist/meter/index.js +67 -0
  49. package/dist/meter/public.d.ts +3 -0
  50. package/dist/meter/public.d.ts.map +1 -0
  51. package/dist/meter/public.js +1 -0
  52. package/dist/popover/index.d.ts +20 -4
  53. package/dist/popover/index.d.ts.map +1 -1
  54. package/dist/popover/index.js +8 -8
  55. package/dist/progress/index.d.ts +24 -0
  56. package/dist/progress/index.d.ts.map +1 -0
  57. package/dist/progress/index.js +85 -0
  58. package/dist/progress/public.d.ts +3 -0
  59. package/dist/progress/public.d.ts.map +1 -0
  60. package/dist/progress/public.js +1 -0
  61. package/dist/slider/index.d.ts +61 -28
  62. package/dist/slider/index.d.ts.map +1 -1
  63. package/dist/slider/index.js +157 -81
  64. package/dist/slider/public.d.ts +1 -1
  65. package/dist/slider/public.d.ts.map +1 -1
  66. package/dist/slider/public.js +1 -1
  67. package/dist/test/apps/disabledButton.d.ts +14 -6
  68. package/dist/test/apps/disabledButton.d.ts.map +1 -1
  69. package/dist/toast/index.d.ts +89 -44
  70. package/dist/toast/index.d.ts.map +1 -1
  71. package/dist/toast/schema.d.ts +15 -4
  72. package/dist/toast/schema.d.ts.map +1 -1
  73. package/dist/toast/test.d.ts +6 -0
  74. package/dist/toast/test.d.ts.map +1 -1
  75. package/dist/toast/test.js +36 -2
  76. package/dist/toast/update.d.ts +42 -2
  77. package/dist/toast/update.d.ts.map +1 -1
  78. package/dist/tooltip/tooltip.d.ts +7 -7
  79. package/package.json +9 -9
@@ -27,14 +27,40 @@ export declare const AnchorConfig: Schema.Struct<{
27
27
  readonly isPlacementLocked: Schema.optional<Schema.Boolean>;
28
28
  }>;
29
29
  export type AnchorConfig = typeof AnchorConfig.Type;
30
- /** Relocates an element into the shared `foldkit-portal-root` div within its
31
- * containing root: the shadow root when mounted inside one, otherwise
32
- * `document.body`. Escapes any ancestor stacking context while keeping the
33
- * element under that root's scoped styles. Returns a cleanup function that
34
- * removes the element from the portal root. Designed to be called from inside
35
- * an `OnMount` action: the consumer wraps the call in `Effect.sync` and
36
- * stashes the returned cleanup in the `Mount` result. */
30
+ /** Relocates an element into a portal root and returns a cleanup function
31
+ * that removes it again. Inside a `<dialog>`, the portal root is a div
32
+ * appended to that dialog, so the element stays above the dialog's content
33
+ * and interactive while a modal dialog makes everything outside it inert.
34
+ * The cleanup removes that div once it is empty. Otherwise the portal root
35
+ * is the shared `foldkit-portal-root` div within the element's containing
36
+ * root: the shadow root when mounted inside one, otherwise `document.body`.
37
+ * Either way the element escapes the clipping and stacking contexts of the
38
+ * ancestors it leaves, and keeps its root's scoped styles. Use
39
+ * `portalBackdrop` for a click-outside backdrop. Designed to be called from
40
+ * inside an `OnMount` action: the consumer wraps the call in `Effect.sync`
41
+ * and stashes the returned cleanup in the `Mount` result. */
37
42
  export declare const portalToContainingRoot: (element: Element) => (() => void);
43
+ /** Relocates a click-outside backdrop and returns a cleanup function that
44
+ * removes it again. Outside a `<dialog>`, it does what
45
+ * `portalToContainingRoot` does. Inside a `<dialog>`, the backdrop moves to
46
+ * directly before the element it was rendered in, which is the component
47
+ * wrapper that holds the trigger. The backdrop then covers the dialog's
48
+ * content, and the wrapper stays above it, so a click on a Combobox input
49
+ * reaches the input while a click anywhere else in the dialog reaches the
50
+ * backdrop. The wrapper must be positioned, for example `position:
51
+ * relative`, which is also what keeps it above a backdrop in the containing
52
+ * root. While the backdrop is there, it is a sibling of the wrapper, so
53
+ * sibling-based selectors such as `:first-child` or Tailwind's `divide-y`
54
+ * count it. Some CSS on an ancestor between the wrapper and the dialog
55
+ * confines the backdrop to that ancestor: anything that makes the ancestor
56
+ * the containing block for fixed-position elements, for example
57
+ * `transform`, `scale`, `filter`, `backdrop-filter`, or `container-type`.
58
+ * A click outside that ancestor then leaves the overlay open, and if it
59
+ * also lands outside the dialog panel, it closes the whole dialog. A
60
+ * backdrop rendered directly in the dialog goes into the dialog's portal
61
+ * root instead. Designed to be called from inside an `OnMount` action,
62
+ * like `portalToContainingRoot`. */
63
+ export declare const portalBackdrop: (element: Element) => (() => void);
38
64
  /** Config for `anchorSetup`.
39
65
  *
40
66
  * - `buttonId`: id of the trigger to position against, resolved through the
@@ -1 +1 @@
1
- {"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../src/anchor/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,MAAM,EAAgB,MAAM,QAAQ,CAAA;AAatE;mFACmF;AACnF,eAAO,MAAM,SAAS,0KAapB,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C;+DAC+D;AAC/D,eAAO,MAAM,OAAO;;;;;IAQlB,CAAA;AAEF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,oGAAoG;AACpG,eAAO,MAAM,YAAY;;;;;;;;;;;;EAOvB,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAkCnD;;;;;;0DAM0D;AAC1D,eAAO,MAAM,sBAAsB,YAAa,OAAO,KAAG,CAAC,MAAM,IAAI,CAWpE,CAAA;AAUD;;;;;;;;;;;;;;;;;;;;;0BAqB0B;AAC1B,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,YAAY,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAsBF;;;;;;;;;;;;;;;;;;;;;;;gFAuBgF;AAChF,eAAO,MAAM,WAAW,YACb,OAAO,UACR,WAAW,KAClB,CAAC,MAAM,IAAI,CAkQb,CAAA"}
1
+ {"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../src/anchor/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,MAAM,EAAgB,MAAM,QAAQ,CAAA;AAatE;mFACmF;AACnF,eAAO,MAAM,SAAS,0KAapB,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C;+DAC+D;AAC/D,eAAO,MAAM,OAAO;;;;;IAQlB,CAAA;AAEF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,oGAAoG;AACpG,eAAO,MAAM,YAAY;;;;;;;;;;;;EAOvB,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAwEnD;;;;;;;;;;;8DAW8D;AAC9D,eAAO,MAAM,sBAAsB,YAAa,OAAO,KAAG,CAAC,MAAM,IAAI,CAsBpE,CAAA;AAWD;;;;;;;;;;;;;;;;;;;qCAmBqC;AACrC,eAAO,MAAM,cAAc,YAAa,OAAO,KAAG,CAAC,MAAM,IAAI,CAczD,CAAA;AAUJ;;;;;;;;;;;;;;;;;;;;;0BAqB0B;AAC1B,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,YAAY,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAsBF;;;;;;;;;;;;;;;;;;;;;;;gFAuBgF;AAChF,eAAO,MAAM,WAAW,YACb,OAAO,UACR,WAAW,KAClB,CAAC,MAAM,IAAI,CAkQb,CAAA"}
@@ -38,7 +38,8 @@ export const AnchorConfig = Schema.Struct({
38
38
  isPlacementLocked: Schema.optional(Schema.Boolean),
39
39
  });
40
40
  const PORTAL_ROOT_ID = 'foldkit-portal-root';
41
- const getOrCreatePortalRoot = (element) => {
41
+ const DIALOG_PORTAL_ROOT_ATTRIBUTE = 'data-foldkit-portal-root';
42
+ const getOrCreateContainingRootPortalRoot = (element) => {
42
43
  // NOTE: portal into the element's containing root, the shadow root when the
43
44
  // app is mounted inside one (e.g. the DevTools overlay) or `document.body`
44
45
  // otherwise, so the panel keeps that root's scoped styles while still
@@ -50,7 +51,7 @@ const getOrCreatePortalRoot = (element) => {
50
51
  const parent = inShadow ? root : document.body;
51
52
  const existing = owner.getElementById(PORTAL_ROOT_ID);
52
53
  if (existing) {
53
- return __foldkitBrandViewResult((existing), "@foldkit/ui/anchor/anchor.js#getOrCreatePortalRoot");
54
+ return __foldkitBrandViewResult((existing), "@foldkit/ui/anchor/anchor.js#getOrCreateContainingRootPortalRoot");
54
55
  }
55
56
  const portalRoot = document.createElement('div');
56
57
  portalRoot.id = PORTAL_ROOT_ID;
@@ -61,17 +62,48 @@ const getOrCreatePortalRoot = (element) => {
61
62
  // breaking click-outside detection. Prepending makes wrappers paint
62
63
  // above the backdrop, while panels (z-10) still win via step 9.
63
64
  parent.prepend(portalRoot);
64
- return __foldkitBrandViewResult((portalRoot), "@foldkit/ui/anchor/anchor.js#getOrCreatePortalRoot");
65
+ return __foldkitBrandViewResult((portalRoot), "@foldkit/ui/anchor/anchor.js#getOrCreateContainingRootPortalRoot");
65
66
  };
66
- /** Relocates an element into the shared `foldkit-portal-root` div within its
67
- * containing root: the shadow root when mounted inside one, otherwise
68
- * `document.body`. Escapes any ancestor stacking context while keeping the
69
- * element under that root's scoped styles. Returns a cleanup function that
70
- * removes the element from the portal root. Designed to be called from inside
71
- * an `OnMount` action: the consumer wraps the call in `Effect.sync` and
72
- * stashes the returned cleanup in the `Mount` result. */
67
+ const getOrCreateDialogPortalRoot = (dialog) => {
68
+ const existing = dialog.querySelector(`:scope > [${DIALOG_PORTAL_ROOT_ATTRIBUTE}]`);
69
+ if (existing instanceof HTMLElement) {
70
+ return __foldkitBrandViewResult((existing), "@foldkit/ui/anchor/anchor.js#getOrCreateDialogPortalRoot");
71
+ }
72
+ const portalRoot = document.createElement('div');
73
+ portalRoot.setAttribute(DIALOG_PORTAL_ROOT_ATTRIBUTE, '');
74
+ // NOTE: appended, unlike the containing root's portal root. A dialog's
75
+ // content is usually one positioned panel, and an element prepended before
76
+ // it paints under that panel unless it has its own z-index. Backdrops do not
77
+ // come here: `portalBackdrop` places them next to their wrapper instead.
78
+ dialog.append(portalRoot);
79
+ return __foldkitBrandViewResult((portalRoot), "@foldkit/ui/anchor/anchor.js#getOrCreateDialogPortalRoot");
80
+ };
81
+ const isDialogPortalRoot = (element) => __foldkitBrandViewResult((element.hasAttribute(DIALOG_PORTAL_ROOT_ATTRIBUTE)), "@foldkit/ui/anchor/anchor.js#isDialogPortalRoot");
82
+ // NOTE: a dialog is its own stacking level (`Dom.showDialog` gives it a
83
+ // near-maximal z-index, `showModal()` puts it in the top layer) and the only
84
+ // subtree a modal dialog leaves interactive. An element portaled out of it is
85
+ // painted behind the dialog and made inert, so an element inside a dialog is
86
+ // portaled into that dialog instead. `closest` must be read here, before the
87
+ // element is relocated out of the mounting tree.
88
+ const getOrCreatePortalRoot = (element) => __foldkitBrandViewResult((Option.match(Option.fromNullishOr(element.closest('dialog')), {
89
+ onNone: () => __foldkitBrandViewResult((getOrCreateContainingRootPortalRoot(element)), "@foldkit/ui/anchor/anchor.js#onNone"),
90
+ onSome: getOrCreateDialogPortalRoot,
91
+ })), "@foldkit/ui/anchor/anchor.js#getOrCreatePortalRoot");
92
+ /** Relocates an element into a portal root and returns a cleanup function
93
+ * that removes it again. Inside a `<dialog>`, the portal root is a div
94
+ * appended to that dialog, so the element stays above the dialog's content
95
+ * and interactive while a modal dialog makes everything outside it inert.
96
+ * The cleanup removes that div once it is empty. Otherwise the portal root
97
+ * is the shared `foldkit-portal-root` div within the element's containing
98
+ * root: the shadow root when mounted inside one, otherwise `document.body`.
99
+ * Either way the element escapes the clipping and stacking contexts of the
100
+ * ancestors it leaves, and keeps its root's scoped styles. Use
101
+ * `portalBackdrop` for a click-outside backdrop. Designed to be called from
102
+ * inside an `OnMount` action: the consumer wraps the call in `Effect.sync`
103
+ * and stashes the returned cleanup in the `Mount` result. */
73
104
  export const portalToContainingRoot = (element) => {
74
- getOrCreatePortalRoot(element).appendChild(element);
105
+ const portalRoot = getOrCreatePortalRoot(element);
106
+ portalRoot.appendChild(element);
75
107
  return __foldkitBrandViewResult((() => {
76
108
  try {
77
109
  element.remove();
@@ -81,8 +113,54 @@ export const portalToContainingRoot = (element) => {
81
113
  // so the remove() call can throw on a node that's already been removed.
82
114
  // Swallow the error.
83
115
  }
116
+ // NOTE: a dialog's children are usually rendered only while it is open,
117
+ // so after a close an empty portal root would be the dialog's only child,
118
+ // and on the next open the dialog's content would be inserted after it.
119
+ // Removing it lets the next element portaled into this dialog append a
120
+ // fresh root after the content.
121
+ if (isDialogPortalRoot(portalRoot) && !portalRoot.hasChildNodes()) {
122
+ portalRoot.remove();
123
+ }
84
124
  }), "@foldkit/ui/anchor/anchor.js#portalToContainingRoot");
85
125
  };
126
+ const findWrapperInsideDialog = (element) => {
127
+ const dialog = element.closest('dialog');
128
+ return __foldkitBrandViewResult((pipe(Option.fromNullishOr(element.parentElement), Option.filter(parent => __foldkitBrandViewResult((dialog !== null && parent !== dialog), "@foldkit/ui/anchor/anchor.js#anonymous~2")))), "@foldkit/ui/anchor/anchor.js#findWrapperInsideDialog");
129
+ };
130
+ /** Relocates a click-outside backdrop and returns a cleanup function that
131
+ * removes it again. Outside a `<dialog>`, it does what
132
+ * `portalToContainingRoot` does. Inside a `<dialog>`, the backdrop moves to
133
+ * directly before the element it was rendered in, which is the component
134
+ * wrapper that holds the trigger. The backdrop then covers the dialog's
135
+ * content, and the wrapper stays above it, so a click on a Combobox input
136
+ * reaches the input while a click anywhere else in the dialog reaches the
137
+ * backdrop. The wrapper must be positioned, for example `position:
138
+ * relative`, which is also what keeps it above a backdrop in the containing
139
+ * root. While the backdrop is there, it is a sibling of the wrapper, so
140
+ * sibling-based selectors such as `:first-child` or Tailwind's `divide-y`
141
+ * count it. Some CSS on an ancestor between the wrapper and the dialog
142
+ * confines the backdrop to that ancestor: anything that makes the ancestor
143
+ * the containing block for fixed-position elements, for example
144
+ * `transform`, `scale`, `filter`, `backdrop-filter`, or `container-type`.
145
+ * A click outside that ancestor then leaves the overlay open, and if it
146
+ * also lands outside the dialog panel, it closes the whole dialog. A
147
+ * backdrop rendered directly in the dialog goes into the dialog's portal
148
+ * root instead. Designed to be called from inside an `OnMount` action,
149
+ * like `portalToContainingRoot`. */
150
+ export const portalBackdrop = (element) => __foldkitBrandViewResult((Option.match(findWrapperInsideDialog(element), {
151
+ onNone: () => __foldkitBrandViewResult((portalToContainingRoot(element)), "@foldkit/ui/anchor/anchor.js#onNone~2"),
152
+ onSome: wrapper => {
153
+ // NOTE: positioned elements without a z-index paint in tree order, and
154
+ // every non-positioned element paints before them. Placed directly
155
+ // before the positioned wrapper, the backdrop paints over the dialog
156
+ // panel and its content but under the wrapper and the trigger inside it.
157
+ // The dialog portal root cannot give both: appended, the backdrop would
158
+ // cover the trigger too, and prepended, the dialog panel would cover the
159
+ // backdrop. `closest` and `parentElement` must be read before the move.
160
+ wrapper.before(element);
161
+ return __foldkitBrandViewResult((() => __foldkitBrandViewResult((element.remove()), "@foldkit/ui/anchor/anchor.js#anonymous~3")), "@foldkit/ui/anchor/anchor.js#onSome");
162
+ },
163
+ })), "@foldkit/ui/anchor/anchor.js#portalBackdrop");
86
164
  const isInsideFixedContainer = (element) => __foldkitBrandViewResult((element !== null &&
87
165
  (getComputedStyle(element).position === 'fixed' ||
88
166
  isInsideFixedContainer(element.parentElement))), "@foldkit/ui/anchor/anchor.js#isInsideFixedContainer");
@@ -172,12 +250,12 @@ export const anchorSetup = (element, config) => {
172
250
  // inside the panel. The candidate is not narrowed to `HTMLElement`, since
173
251
  // Floating UI's `arrow` takes any `Element` and a triangle arrow is usually
174
252
  // an `<svg>`.
175
- const maybeArrowElement = pipe(Option.fromNullishOr(config.arrowId), Option.flatMapNullishOr(arrowId => __foldkitBrandViewResult((owner.getElementById(arrowId)), "@foldkit/ui/anchor/anchor.js#anonymous~2")), Option.filter(candidate => __foldkitBrandViewResult((element.contains(candidate)), "@foldkit/ui/anchor/anchor.js#anonymous~3")));
253
+ const maybeArrowElement = pipe(Option.fromNullishOr(config.arrowId), Option.flatMapNullishOr(arrowId => __foldkitBrandViewResult((owner.getElementById(arrowId)), "@foldkit/ui/anchor/anchor.js#anonymous~4")), Option.filter(candidate => __foldkitBrandViewResult((element.contains(candidate)), "@foldkit/ui/anchor/anchor.js#anonymous~5")));
176
254
  const arrowMiddleware = Option.match(maybeArrowElement, {
177
- onNone: () => __foldkitBrandViewResult(([]), "@foldkit/ui/anchor/anchor.js#onNone"),
255
+ onNone: () => __foldkitBrandViewResult(([]), "@foldkit/ui/anchor/anchor.js#onNone~3"),
178
256
  onSome: arrowElement => __foldkitBrandViewResult(([
179
257
  arrow({ element: arrowElement, padding: config.arrowPadding ?? 0 }),
180
- ]), "@foldkit/ui/anchor/anchor.js#onSome"),
258
+ ]), "@foldkit/ui/anchor/anchor.js#onSome~2"),
181
259
  });
182
260
  const { placement, gap, offset: crossAxis, padding, isPlacementLocked, } = config.anchor;
183
261
  const shouldInterceptTab = config.interceptTab ?? true;
@@ -1,3 +1,3 @@
1
- export { anchorSetup, portalToContainingRoot, AnchorConfig, Placement, Padding, } from './index.js';
1
+ export { anchorSetup, portalBackdrop, portalToContainingRoot, AnchorConfig, Placement, Padding, } from './index.js';
2
2
  export type { SetupConfig } from './index.js';
3
3
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/anchor/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,SAAS,EACT,OAAO,GACR,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/anchor/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,SAAS,EACT,OAAO,GACR,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
@@ -1 +1 @@
1
- export { anchorSetup, portalToContainingRoot, AnchorConfig, Placement, Padding, } from './index.js';
1
+ export { anchorSetup, portalBackdrop, portalToContainingRoot, AnchorConfig, Placement, Padding, } from './index.js';
@@ -28,10 +28,13 @@ export declare const view: import("foldkit/submodel").View<{
28
28
  readonly id: string;
29
29
  readonly isShowing: boolean;
30
30
  readonly transitionState: "EnterAnimating" | "EnterStart" | "Idle" | "LeaveAnimating" | "LeaveStart";
31
+ readonly transitionGeneration: number;
31
32
  }, {
32
33
  readonly _tag: "CompletedWaitForPaint";
34
+ readonly generation: number;
33
35
  } | {
34
36
  readonly _tag: "EndedAnimation";
37
+ readonly generation: number;
35
38
  } | {
36
39
  readonly _tag: "Hid";
37
40
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAC/E,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,EACP,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAE5D,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,GACP,CAAA;AAID,qFAAqF;AACrF,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,OAAO,EAAE,IAAI,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IACtC;;2EAEuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAC,CAAA;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;aAnBN,IAAI;gBACD,MAAM;iBACL,aAAa,CAAC,cAAc,CAAC;cAChC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC;IACtC;;2EAEuE;kBACzD,OAAO;GA2GtB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animation/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAC/E,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,EACP,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAE5D,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,GACP,CAAA;AAID,qFAAqF;AACrF,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,OAAO,EAAE,IAAI,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAA;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IACtC;;2EAEuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAC,CAAA;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;aAnBN,IAAI;gBACD,MAAM;iBACL,aAAa,CAAC,cAAc,CAAC;cAChC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC;IACtC;;2EAEuE;kBACzD,OAAO;GA2GtB,CAAA"}
@@ -2,25 +2,34 @@ import { Schema } from 'effect';
2
2
  /** Schema for the animation lifecycle state, tracking enter/leave phases. */
3
3
  export declare const TransitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
4
4
  export type TransitionState = typeof TransitionState.Type;
5
- /** Schema for the animation component's state, tracking its unique ID, visibility intent, and lifecycle phase. */
5
+ /** Schema for Animation state, including the transition generation used to reject
6
+ * stale Command results. */
6
7
  export declare const Model: Schema.Struct<{
7
8
  readonly id: Schema.String;
8
9
  readonly isShowing: Schema.Boolean;
9
10
  readonly transitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
11
+ readonly transitionGeneration: Schema.Number;
10
12
  }>;
11
13
  export type Model = typeof Model.Type;
12
14
  /** Union of all messages the animation component can produce. */
13
15
  export declare const Message: import("foldkit/message").MessageUnion<{
14
16
  readonly Showed: {};
15
17
  readonly Hid: {};
16
- readonly CompletedWaitForPaint: {};
17
- readonly EndedAnimation: {};
18
+ readonly CompletedWaitForPaint: {
19
+ generation: Schema.Number;
20
+ };
21
+ readonly EndedAnimation: {
22
+ generation: Schema.Number;
23
+ };
18
24
  }>;
19
25
  export type Message = typeof Message.Type;
20
26
  export type Showed = typeof Message.Showed.Type;
21
27
  export type Hid = typeof Message.Hid.Type;
28
+ /** Union of the facts Animation reports to its parent. */
22
29
  export declare const OutMessage: import("foldkit/message").MessageUnion<{
23
- readonly StartedLeaveAnimating: {};
30
+ readonly StartedLeaveAnimating: {
31
+ generation: Schema.Number;
32
+ };
24
33
  readonly TransitionedOut: {};
25
34
  }>;
26
35
  export type OutMessage = typeof OutMessage.Type;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/animation/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAK/B,6EAA6E;AAC7E,eAAO,MAAM,eAAe,oGAM1B,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAIzD,kHAAkH;AAClH,eAAO,MAAM,KAAK;;;;EAIhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iEAAiE;AACjE,eAAO,MAAM,OAAO;;;;;EAKlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,MAAM,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAA;AAC/C,MAAM,MAAM,GAAG,GAAG,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAA;AAIzC,eAAO,MAAM,UAAU;;;EAGrB,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA;AAI/C,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAC,CAAA;AAEF,4EAA4E;AAC5E,eAAO,MAAM,IAAI,WAAY,UAAU,KAAG,KAIxC,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/animation/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAK/B,6EAA6E;AAC7E,eAAO,MAAM,eAAe,oGAM1B,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAIzD;6BAC6B;AAC7B,eAAO,MAAM,KAAK;;;;;EAKhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iEAAiE;AACjE,eAAO,MAAM,OAAO;;;;QAGO,UAAU;;;QACjB,UAAU;;EAC5B,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,MAAM,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAA;AAC/C,MAAM,MAAM,GAAG,GAAG,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAA;AAIzC,0DAA0D;AAC1D,eAAO,MAAM,UAAU;;QACI,UAAU;;;EAEnC,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA;AAI/C,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAC,CAAA;AAEF,4EAA4E;AAC5E,eAAO,MAAM,IAAI,WAAY,UAAU,KAAG,KAKxC,CAAA"}
@@ -11,23 +11,26 @@ export const TransitionState = Schema.Literals([
11
11
  'LeaveAnimating',
12
12
  ]);
13
13
  // MODEL
14
- /** Schema for the animation component's state, tracking its unique ID, visibility intent, and lifecycle phase. */
14
+ /** Schema for Animation state, including the transition generation used to reject
15
+ * stale Command results. */
15
16
  export const Model = Schema.Struct({
16
17
  id: Schema.String,
17
18
  isShowing: Schema.Boolean,
18
19
  transitionState: TransitionState,
20
+ transitionGeneration: Schema.Number,
19
21
  });
20
22
  // MESSAGE
21
23
  /** Union of all messages the animation component can produce. */
22
24
  export const Message = defineMessageUnion({
23
25
  Showed: {},
24
26
  Hid: {},
25
- CompletedWaitForPaint: {},
26
- EndedAnimation: {},
27
+ CompletedWaitForPaint: { generation: Schema.Number },
28
+ EndedAnimation: { generation: Schema.Number },
27
29
  });
28
30
  // OUT MESSAGE
31
+ /** Union of the facts Animation reports to its parent. */
29
32
  export const OutMessage = defineMessageUnion({
30
- StartedLeaveAnimating: {},
33
+ StartedLeaveAnimating: { generation: Schema.Number },
31
34
  TransitionedOut: {},
32
35
  });
33
36
  /** Creates an initial animation model from a config. Defaults to hidden. */
@@ -35,4 +38,5 @@ export const init = (config) => (__foldkitBrandViewResult(({
35
38
  id: config.id,
36
39
  isShowing: config.isShowing ?? false,
37
40
  transitionState: 'Idle',
41
+ transitionGeneration: 0,
38
42
  }), "@foldkit/ui/animation/schema.js#init"));
@@ -3,20 +3,28 @@ import { type Update } from 'foldkit';
3
3
  import * as Command from 'foldkit/command';
4
4
  import { type Hid, Message, type Model, OutMessage, type Showed } from './schema.js';
5
5
  type UpdateReturn = Update.ReturnWithOutMessage<Model, Message, OutMessage>;
6
- /** Waits for paint via double-rAF before the enter/leave lifecycle advances. */
7
- export declare const WaitForPaint: Command.CommandDefinitionNoArgs<"WaitForPaint", Effect.Effect<{
6
+ /** Waits for paint via double-rAF, then reports the transition generation that
7
+ * scheduled the wait. */
8
+ export declare const WaitForPaint: Command.CommandDefinitionWithArgs<"WaitForPaint", {
9
+ generation: Schema.Number;
10
+ }, Effect.Effect<{
8
11
  readonly _tag: "CompletedWaitForPaint";
12
+ readonly generation: number;
9
13
  }, never, never>>;
10
- /** Waits for all CSS animations on the element to settle. Covers both CSS transitions and CSS keyframe animations. */
14
+ /** Waits for all CSS transitions and keyframe animations on the element to
15
+ * settle, then reports the transition generation that scheduled the wait. */
11
16
  export declare const WaitForAnimationSettled: Command.CommandDefinitionWithArgs<"WaitForAnimationSettled", {
12
17
  id: Schema.String;
18
+ generation: Schema.Number;
13
19
  }, Effect.Effect<{
14
20
  readonly _tag: "EndedAnimation";
21
+ readonly generation: number;
15
22
  }, never, never>>;
16
23
  /** Processes an Animation Message and returns the next Model, optional
17
24
  * Commands, and an optional OutMessage. `Showed` and `Hid` start a transition
18
25
  * but cannot finish one, so direct calls with either Message return a plain
19
- * update result. */
26
+ * update result. Results from an earlier transition generation leave the Model
27
+ * unchanged. */
20
28
  export declare function update(model: Model, message: Showed | Hid): Update.Return<Model, Message>;
21
29
  export declare function update(model: Model, message: Message): UpdateReturn;
22
30
  /** Programmatically starts the enter lifecycle. */
@@ -25,7 +33,9 @@ export declare const show: (model: Model) => Update.Return<Model, Message>;
25
33
  export declare const hide: (model: Model) => Update.Return<Model, Message>;
26
34
  /** Toggles the animation between its shown and hidden states. */
27
35
  export declare const toggle: (model: Model) => Update.Return<Model, Message>;
28
- /** Creates the standard leave-phase command that waits for CSS animations on the element to settle. Use this when handling the `StartedLeaveAnimating` OutMessage for components that don't need custom leave behavior. */
36
+ /** Creates the standard leave Command for the Model's current transition. Use
37
+ * this when handling `StartedLeaveAnimating` unless the component needs its
38
+ * own settlement strategy. */
29
39
  export declare const defaultLeaveCommand: (model: Model) => Command.Command<Message>;
30
40
  export {};
31
41
  //# sourceMappingURL=update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/animation/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC9C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAA;AAM1C,OAAO,EACL,KAAK,GAAG,EACR,OAAO,EACP,KAAK,KAAK,EACV,UAAU,EACV,KAAK,MAAM,EACZ,MAAM,aAAa,CAAA;AAMpB,KAAK,YAAY,GAAG,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;AAG3E,gFAAgF;AAChF,eAAO,MAAM,YAAY;;iBAGvB,CAAA;AACF,sHAAsH;AACtH,eAAO,MAAM,uBAAuB;;;;iBAUnC,CAAA;AAED;;;qBAGqB;AACrB,wBAAgB,MAAM,CACpB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,GAAG,GAAG,GACpB,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAChC,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY,CAAA;AAsEpE,mDAAmD;AACnD,eAAO,MAAM,IAAI,UAAW,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAC/B,CAAA;AAEjC,mDAAmD;AACnD,eAAO,MAAM,IAAI,UAAW,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAClC,CAAA;AAE9B,iEAAiE;AACjE,eAAO,MAAM,MAAM,UAAW,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAMjE,CAAA;AAED,2NAA2N;AAC3N,eAAO,MAAM,mBAAmB,UAAW,KAAK,KAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAC/B,CAAA"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/animation/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,EAAE,MAAM,QAAQ,CAAA;AACtD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAA;AAM1C,OAAO,EACL,KAAK,GAAG,EACR,OAAO,EACP,KAAK,KAAK,EACV,UAAU,EACV,KAAK,MAAM,EACZ,MAAM,aAAa,CAAA;AAMpB,KAAK,YAAY,GAAG,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;AAG3E;0BAC0B;AAC1B,eAAO,MAAM,YAAY;;;;;iBAOvB,CAAA;AACF;8EAC8E;AAC9E,eAAO,MAAM,uBAAuB;;;;;;iBAUnC,CAAA;AAED;;;;iBAIiB;AACjB,wBAAgB,MAAM,CACpB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,GAAG,GAAG,GACpB,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAChC,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY,CAAA;AA+FpE,mDAAmD;AACnD,eAAO,MAAM,IAAI,UAAW,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAC/B,CAAA;AAEjC,mDAAmD;AACnD,eAAO,MAAM,IAAI,UAAW,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAClC,CAAA;AAE9B,iEAAiE;AACjE,eAAO,MAAM,MAAM,UAAW,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAMjE,CAAA;AAED;;+BAE+B;AAC/B,eAAO,MAAM,mBAAmB,UAAW,KAAK,KAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAItE,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
- import { Effect, Match, Schema } from 'effect';
2
+ import { Effect, Match, Number, Schema } from 'effect';
3
3
  import * as Command from 'foldkit/command';
4
4
  import * as Dom from 'foldkit/dom';
5
5
  import * as Render from 'foldkit/render';
@@ -9,30 +9,34 @@ import { Message, OutMessage, } from './schema.js';
9
9
  // UPDATE
10
10
  const elementSelector = (id) => __foldkitBrandViewResult((idSelector(id)), "@foldkit/ui/animation/update.js#elementSelector");
11
11
  const withUpdateReturn = Match.withReturnType();
12
- /** Waits for paint via double-rAF before the enter/leave lifecycle advances. */
12
+ /** Waits for paint via double-rAF, then reports the transition generation that
13
+ * scheduled the wait. */
13
14
  export const WaitForPaint = Command.define('WaitForPaint', {
15
+ args: { generation: Schema.Number },
14
16
  messages: [Message.CompletedWaitForPaint],
15
- execute: Render.afterPaint.pipe(Effect.as(Message.CompletedWaitForPaint())),
17
+ execute: ({ generation }) => __foldkitBrandViewResult((Render.afterPaint.pipe(Effect.as(Message.CompletedWaitForPaint({ generation })))), "@foldkit/ui/animation/update.js#execute"),
16
18
  });
17
- /** Waits for all CSS animations on the element to settle. Covers both CSS transitions and CSS keyframe animations. */
19
+ /** Waits for all CSS transitions and keyframe animations on the element to
20
+ * settle, then reports the transition generation that scheduled the wait. */
18
21
  export const WaitForAnimationSettled = Command.define('WaitForAnimationSettled', {
19
- args: { id: Schema.String },
22
+ args: { id: Schema.String, generation: Schema.Number },
20
23
  messages: [Message.EndedAnimation],
21
- execute: ({ id }) => __foldkitBrandViewResult((Dom.waitForAnimationSettled(elementSelector(id)).pipe(Effect.as(Message.EndedAnimation()))), "@foldkit/ui/animation/update.js#execute"),
24
+ execute: ({ id, generation }) => __foldkitBrandViewResult((Dom.waitForAnimationSettled(elementSelector(id)).pipe(Effect.as(Message.EndedAnimation({ generation })))), "@foldkit/ui/animation/update.js#execute~2"),
22
25
  });
23
26
  export function update(model, message) {
24
- const maybeNextFrame = WaitForPaint();
25
27
  return __foldkitBrandViewResult((Message.match(message, {
26
28
  Showed: () => {
27
29
  if (model.isShowing) {
28
30
  return __foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#Showed");
29
31
  }
32
+ const nextTransitionGeneration = Number.increment(model.transitionGeneration);
30
33
  return __foldkitBrandViewResult(({
31
34
  model: modifyFields(model, {
32
35
  isShowing: () => __foldkitBrandViewResult((true), "@foldkit/ui/animation/update.js#isShowing"),
33
36
  transitionState: () => __foldkitBrandViewResult(('EnterStart'), "@foldkit/ui/animation/update.js#transitionState"),
37
+ transitionGeneration: () => __foldkitBrandViewResult((nextTransitionGeneration), "@foldkit/ui/animation/update.js#transitionGeneration"),
34
38
  }),
35
- commands: [maybeNextFrame],
39
+ commands: [WaitForPaint({ generation: nextTransitionGeneration })],
36
40
  }), "@foldkit/ui/animation/update.js#Showed");
37
41
  },
38
42
  Hid: () => {
@@ -41,31 +45,50 @@ export function update(model, message) {
41
45
  if (isLeaving || !model.isShowing) {
42
46
  return __foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#Hid");
43
47
  }
48
+ const nextTransitionGeneration = Number.increment(model.transitionGeneration);
44
49
  return __foldkitBrandViewResult(({
45
50
  model: modifyFields(model, {
46
51
  isShowing: () => __foldkitBrandViewResult((false), "@foldkit/ui/animation/update.js#isShowing~2"),
47
52
  transitionState: () => __foldkitBrandViewResult(('LeaveStart'), "@foldkit/ui/animation/update.js#transitionState~2"),
53
+ transitionGeneration: () => __foldkitBrandViewResult((nextTransitionGeneration), "@foldkit/ui/animation/update.js#transitionGeneration~2"),
48
54
  }),
49
- commands: [maybeNextFrame],
55
+ commands: [WaitForPaint({ generation: nextTransitionGeneration })],
50
56
  }), "@foldkit/ui/animation/update.js#Hid");
51
57
  },
52
- CompletedWaitForPaint: () => __foldkitBrandViewResult((Match.value(model.transitionState).pipe(withUpdateReturn, Match.when('EnterStart', () => (__foldkitBrandViewResult(({
53
- model: modifyFields(model, {
54
- transitionState: () => __foldkitBrandViewResult(('EnterAnimating'), "@foldkit/ui/animation/update.js#transitionState~3"),
55
- }),
56
- commands: [WaitForAnimationSettled({ id: model.id })],
57
- }), "@foldkit/ui/animation/update.js#anonymous"))), Match.when('LeaveStart', () => (__foldkitBrandViewResult(({
58
- model: modifyFields(model, {
59
- transitionState: () => __foldkitBrandViewResult(('LeaveAnimating'), "@foldkit/ui/animation/update.js#transitionState~4"),
60
- }),
61
- outMessage: OutMessage.StartedLeaveAnimating(),
62
- }), "@foldkit/ui/animation/update.js#anonymous~2"))), Match.orElse(() => (__foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#anonymous~3"))))), "@foldkit/ui/animation/update.js#CompletedWaitForPaint"),
63
- EndedAnimation: () => __foldkitBrandViewResult((Match.value(model.transitionState).pipe(withUpdateReturn, Match.when('EnterAnimating', () => (__foldkitBrandViewResult(({
64
- model: modifyFields(model, { transitionState: () => __foldkitBrandViewResult(('Idle'), "@foldkit/ui/animation/update.js#transitionState~5") }),
65
- }), "@foldkit/ui/animation/update.js#anonymous~4"))), Match.when('LeaveAnimating', () => (__foldkitBrandViewResult(({
66
- model: modifyFields(model, { transitionState: () => __foldkitBrandViewResult(('Idle'), "@foldkit/ui/animation/update.js#transitionState~6") }),
67
- outMessage: OutMessage.TransitionedOut(),
68
- }), "@foldkit/ui/animation/update.js#anonymous~5"))), Match.orElse(() => (__foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#anonymous~6"))))), "@foldkit/ui/animation/update.js#EndedAnimation"),
58
+ CompletedWaitForPaint: ({ generation }) => {
59
+ if (generation !== model.transitionGeneration) {
60
+ return __foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#CompletedWaitForPaint");
61
+ }
62
+ return __foldkitBrandViewResult((Match.value(model.transitionState).pipe(withUpdateReturn, Match.when('EnterStart', () => (__foldkitBrandViewResult(({
63
+ model: modifyFields(model, {
64
+ transitionState: () => __foldkitBrandViewResult(('EnterAnimating'), "@foldkit/ui/animation/update.js#transitionState~3"),
65
+ }),
66
+ commands: [
67
+ WaitForAnimationSettled({
68
+ id: model.id,
69
+ generation: model.transitionGeneration,
70
+ }),
71
+ ],
72
+ }), "@foldkit/ui/animation/update.js#anonymous"))), Match.when('LeaveStart', () => (__foldkitBrandViewResult(({
73
+ model: modifyFields(model, {
74
+ transitionState: () => __foldkitBrandViewResult(('LeaveAnimating'), "@foldkit/ui/animation/update.js#transitionState~4"),
75
+ }),
76
+ outMessage: OutMessage.StartedLeaveAnimating({
77
+ generation: model.transitionGeneration,
78
+ }),
79
+ }), "@foldkit/ui/animation/update.js#anonymous~2"))), Match.orElse(() => (__foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#anonymous~3"))))), "@foldkit/ui/animation/update.js#CompletedWaitForPaint");
80
+ },
81
+ EndedAnimation: ({ generation }) => {
82
+ if (generation !== model.transitionGeneration) {
83
+ return __foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#EndedAnimation");
84
+ }
85
+ return __foldkitBrandViewResult((Match.value(model.transitionState).pipe(withUpdateReturn, Match.when('EnterAnimating', () => (__foldkitBrandViewResult(({
86
+ model: modifyFields(model, { transitionState: () => __foldkitBrandViewResult(('Idle'), "@foldkit/ui/animation/update.js#transitionState~5") }),
87
+ }), "@foldkit/ui/animation/update.js#anonymous~4"))), Match.when('LeaveAnimating', () => (__foldkitBrandViewResult(({
88
+ model: modifyFields(model, { transitionState: () => __foldkitBrandViewResult(('Idle'), "@foldkit/ui/animation/update.js#transitionState~6") }),
89
+ outMessage: OutMessage.TransitionedOut(),
90
+ }), "@foldkit/ui/animation/update.js#anonymous~5"))), Match.orElse(() => (__foldkitBrandViewResult(({ model }), "@foldkit/ui/animation/update.js#anonymous~6"))))), "@foldkit/ui/animation/update.js#EndedAnimation");
91
+ },
69
92
  })), "@foldkit/ui/animation/update.js#update");
70
93
  }
71
94
  /** Programmatically starts the enter lifecycle. */
@@ -81,5 +104,10 @@ export const toggle = (model) => {
81
104
  return __foldkitBrandViewResult((show(model)), "@foldkit/ui/animation/update.js#toggle");
82
105
  }
83
106
  };
84
- /** Creates the standard leave-phase command that waits for CSS animations on the element to settle. Use this when handling the `StartedLeaveAnimating` OutMessage for components that don't need custom leave behavior. */
85
- export const defaultLeaveCommand = (model) => __foldkitBrandViewResult((WaitForAnimationSettled({ id: model.id })), "@foldkit/ui/animation/update.js#defaultLeaveCommand");
107
+ /** Creates the standard leave Command for the Model's current transition. Use
108
+ * this when handling `StartedLeaveAnimating` unless the component needs its
109
+ * own settlement strategy. */
110
+ export const defaultLeaveCommand = (model) => __foldkitBrandViewResult((WaitForAnimationSettled({
111
+ id: model.id,
112
+ generation: model.transitionGeneration,
113
+ })), "@foldkit/ui/animation/update.js#defaultLeaveCommand");
@@ -15,6 +15,7 @@ export declare const Model: Schema.Struct<{
15
15
  readonly id: Schema.String;
16
16
  readonly isShowing: Schema.Boolean;
17
17
  readonly transitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
18
+ readonly transitionGeneration: Schema.Number;
18
19
  }>;
19
20
  readonly maybeActiveItemIndex: Schema.Option<Schema.Number>;
20
21
  readonly activationTrigger: Schema.Literals<readonly ["Pointer", "Keyboard"]>;
@@ -47,6 +48,7 @@ export declare const update: (model: {
47
48
  readonly id: string;
48
49
  readonly isShowing: boolean;
49
50
  readonly transitionState: "EnterAnimating" | "EnterStart" | "Idle" | "LeaveAnimating" | "LeaveStart";
51
+ readonly transitionGeneration: number;
50
52
  };
51
53
  readonly maybeActiveItemIndex: Option.Option<number>;
52
54
  readonly activationTrigger: "Keyboard" | "Pointer";
@@ -68,6 +70,7 @@ export declare const update: (model: {
68
70
  readonly id: string;
69
71
  readonly isShowing: boolean;
70
72
  readonly transitionState: "EnterAnimating" | "EnterStart" | "Idle" | "LeaveAnimating" | "LeaveStart";
73
+ readonly transitionGeneration: number;
71
74
  };
72
75
  readonly maybeActiveItemIndex: Option.Option<number>;
73
76
  readonly activationTrigger: "Keyboard" | "Pointer";
@@ -120,8 +123,10 @@ export declare const update: (model: {
120
123
  readonly _tag: "GotAnimationMessage";
121
124
  readonly message: {
122
125
  readonly _tag: "CompletedWaitForPaint";
126
+ readonly generation: number;
123
127
  } | {
124
128
  readonly _tag: "EndedAnimation";
129
+ readonly generation: number;
125
130
  } | {
126
131
  readonly _tag: "Hid";
127
132
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"multi.d.ts","sourceRoot":"","sources":["../../src/combobox/multi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE5D,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EACnB,OAAO,EACP,UAAU,EAKX,MAAM,aAAa,CAAA;AAIpB,qOAAqO;AACrO,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;EAEhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,mOAAmO;AACnO,MAAM,MAAM,UAAU,GAAG,cAAc,CAAA;AAEvC,+HAA+H;AAC/H,eAAO,MAAM,IAAI,WAAY,UAAU,KAAG,KAAyB,CAAA;AAInE;;;;;8DAK8D;AAC9D,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcjB,CAAA;AAEF,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;AAE7C;mEACmE;AACnE,eAAO,MAAM,IAAI,UAAW,KAAK,KAAG,YACoC,CAAA;AAExE;;sEAEsE;AACtE,eAAO,MAAM,KAAK,UAAW,KAAK,KAAG,YACwC,CAAA;AAE7E;wEACwE;AACxE,eAAO,MAAM,UAAU,UAAW,KAAK,QAAQ,MAAM,KAAG,YAIrD,CAAA;AAIH,uFAAuF;AACvF,MAAM,MAAM,UAAU,CAAC,IAAI,SAAS,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,CAAA;AAIlE,KAAK,kBAAkB,CAAC,IAAI,SAAS,MAAM,IAAI,MAAM,CAAC,oBAAoB,CACxE,KAAK,EACL,OAAO,EACP,UAAU,CAAC,IAAI,CAAC,CACjB,CAAA;AAED;;;;+BAI+B;AAC/B,MAAM,MAAM,MAAM,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAC1D,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;IACpD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACpE,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAClE,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAChD,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;CAClD,CAAC,CAAA;AAEF;;wEAEwE;AACxE,eAAO,MAAM,MAAM,GAAI,IAAI,SAAS,MAAM,GAAG,MAAM,OAAK,MAAM,CAAC,IAAI,CA2BlE,CAAA"}
1
+ {"version":3,"file":"multi.d.ts","sourceRoot":"","sources":["../../src/combobox/multi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAA;AAErC,OAAO,KAAK,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE5D,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EACnB,OAAO,EACP,UAAU,EAKX,MAAM,aAAa,CAAA;AAIpB,qOAAqO;AACrO,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;EAEhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,mOAAmO;AACnO,MAAM,MAAM,UAAU,GAAG,cAAc,CAAA;AAEvC,+HAA+H;AAC/H,eAAO,MAAM,IAAI,WAAY,UAAU,KAAG,KAAyB,CAAA;AAInE;;;;;8DAK8D;AAC9D,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcjB,CAAA;AAEF,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;AAE7C;mEACmE;AACnE,eAAO,MAAM,IAAI,UAAW,KAAK,KAAG,YACoC,CAAA;AAExE;;sEAEsE;AACtE,eAAO,MAAM,KAAK,UAAW,KAAK,KAAG,YACwC,CAAA;AAE7E;wEACwE;AACxE,eAAO,MAAM,UAAU,UAAW,KAAK,QAAQ,MAAM,KAAG,YAIrD,CAAA;AAIH,uFAAuF;AACvF,MAAM,MAAM,UAAU,CAAC,IAAI,SAAS,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,CAAA;AAIlE,KAAK,kBAAkB,CAAC,IAAI,SAAS,MAAM,IAAI,MAAM,CAAC,oBAAoB,CACxE,KAAK,EACL,OAAO,EACP,UAAU,CAAC,IAAI,CAAC,CACjB,CAAA;AAED;;;;+BAI+B;AAC/B,MAAM,MAAM,MAAM,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAC1D,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;IACpD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACpE,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAClE,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAChD,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,kBAAkB,CAAC,IAAI,CAAC,CAAA;CAClD,CAAC,CAAA;AAEF;;wEAEwE;AACxE,eAAO,MAAM,MAAM,GAAI,IAAI,SAAS,MAAM,GAAG,MAAM,OAAK,MAAM,CAAC,IAAI,CA2BlE,CAAA"}