@astryxdesign/lab 0.4.0-canary.e144ea7 → 0.4.0-canary.faedff7

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 (50) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +5 -3
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +23 -9
  4. package/dist/index.d.ts +0 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -3
  7. package/dist/lab.css +0 -28
  8. package/package.json +5 -62
  9. package/src/BottomSheet/BottomSheet.doc.mjs +84 -25
  10. package/src/BottomSheet/BottomSheet.test.tsx +53 -0
  11. package/src/BottomSheet/BottomSheet.tsx +25 -10
  12. package/src/index.ts +4 -28
  13. package/dist/RichTextEditor/RichTextEditor.d.ts +0 -222
  14. package/dist/RichTextEditor/RichTextEditor.d.ts.map +0 -1
  15. package/dist/RichTextEditor/RichTextEditor.js +0 -489
  16. package/dist/RichTextEditor/RichTextEditorAutoLinkPlugin.d.ts +0 -84
  17. package/dist/RichTextEditor/RichTextEditorAutoLinkPlugin.d.ts.map +0 -1
  18. package/dist/RichTextEditor/RichTextEditorAutoLinkPlugin.js +0 -94
  19. package/dist/RichTextEditor/RichTextEditorToolbar.d.ts +0 -126
  20. package/dist/RichTextEditor/RichTextEditorToolbar.d.ts.map +0 -1
  21. package/dist/RichTextEditor/RichTextEditorToolbar.js +0 -633
  22. package/dist/RichTextEditor/RichTextView.d.ts +0 -65
  23. package/dist/RichTextEditor/RichTextView.d.ts.map +0 -1
  24. package/dist/RichTextEditor/RichTextView.js +0 -168
  25. package/dist/RichTextEditor/editorNodes.d.ts +0 -8
  26. package/dist/RichTextEditor/editorNodes.d.ts.map +0 -1
  27. package/dist/RichTextEditor/editorNodes.js +0 -23
  28. package/dist/RichTextEditor/editorTheme.d.ts +0 -7
  29. package/dist/RichTextEditor/editorTheme.d.ts.map +0 -1
  30. package/dist/RichTextEditor/editorTheme.js +0 -101
  31. package/dist/RichTextEditor/index.d.ts +0 -22
  32. package/dist/RichTextEditor/index.d.ts.map +0 -1
  33. package/dist/RichTextEditor/index.js +0 -20
  34. package/dist/RichTextEditor/linkUtils.d.ts +0 -22
  35. package/dist/RichTextEditor/linkUtils.d.ts.map +0 -1
  36. package/dist/RichTextEditor/linkUtils.js +0 -91
  37. package/dist/RichTextEditor/markdownSerializers.d.ts +0 -40
  38. package/dist/RichTextEditor/markdownSerializers.d.ts.map +0 -1
  39. package/dist/RichTextEditor/markdownSerializers.js +0 -85
  40. package/src/RichTextEditor/RichTextEditor.doc.mjs +0 -197
  41. package/src/RichTextEditor/RichTextEditor.test.tsx +0 -1389
  42. package/src/RichTextEditor/RichTextEditor.tsx +0 -840
  43. package/src/RichTextEditor/RichTextEditorAutoLinkPlugin.tsx +0 -115
  44. package/src/RichTextEditor/RichTextEditorToolbar.tsx +0 -789
  45. package/src/RichTextEditor/RichTextView.tsx +0 -227
  46. package/src/RichTextEditor/editorNodes.ts +0 -34
  47. package/src/RichTextEditor/editorTheme.ts +0 -180
  48. package/src/RichTextEditor/index.ts +0 -54
  49. package/src/RichTextEditor/linkUtils.ts +0 -93
  50. package/src/RichTextEditor/markdownSerializers.ts +0 -105
@@ -17,7 +17,8 @@
17
17
  * layer, focus trap, scrim, scroll lock, background inert); `false` uses
18
18
  * `show()` for a non-modal sheet with no scrim, leaving the page behind
19
19
  * interactive and scrollable (the transparent shell is pointer-events:none so
20
- * taps pass through).
20
+ * taps pass through). Both modes keep the native dialog presented but inert
21
+ * until the slide-out transition ends.
21
22
  *
22
23
  * The drag/snap/dismiss machinery lives in `useSheetGestures`; the offset
23
24
  * geometry lives in the pure, tested `snapOffsets` module. Both are internal
@@ -82,9 +83,10 @@ export interface BottomSheetProps extends BaseProps<HTMLDialogElement> {
82
83
  * - `true` (default) — `showModal()`: renders in the top layer with a focus
83
84
  * trap, a `::backdrop` scrim, body scroll lock, and tap-scrim-to-dismiss.
84
85
  * The background is inert. Use for focused tasks (filters, forms).
85
- * - `false` — `show()`: a non-modal sheet with **no scrim**. The page behind
86
+ * - `false`: `show()` renders a viewport-anchored overlay with **no scrim**. It is
87
+ * still layered above the page, not rendered inline, but the page behind
86
88
  * stays interactive and scrollable (like Material's *standard* bottom
87
- * sheet, or an iOS undimmed detent). Escape still closes while focus is
89
+ * sheet or an iOS undimmed detent). Escape still closes while focus is
88
90
  * inside the sheet, and drag/flick-to-dismiss still work. Use for a peek
89
91
  * surface that coexists with the page (e.g. a panel over a live map).
90
92
  * @default true
@@ -1 +1 @@
1
- {"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AA2BlD;;;;;;GAMG;AACH,QAAA,MAAM,cAAc;;;;CAIV,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,cAAc,CAAC;AAiL5D,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACpE,wDAAwD;IACxD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAEnC,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAExC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;IAE7C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,MAAiB,EACjB,QAAe,EACf,MAAM,EACN,GAAG,KAAK,EACT,EAAE,gBAAgB,+BA0LlB;yBApMe,WAAW"}
1
+ {"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAA2C,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAE/E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AA2BlD;;;;;;GAMG;AACH,QAAA,MAAM,cAAc;;;;CAIV,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,cAAc,CAAC;AAoL5D,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACpE,wDAAwD;IACxD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAEnC,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAExC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;IAE7C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,MAAiB,EACjB,QAAe,EACf,MAAM,EACN,GAAG,KAAK,EACT,EAAE,gBAAgB,+BAoMlB;yBA9Me,WAAW"}
@@ -21,7 +21,8 @@
21
21
  * layer, focus trap, scrim, scroll lock, background inert); `false` uses
22
22
  * `show()` for a non-modal sheet with no scrim, leaving the page behind
23
23
  * interactive and scrollable (the transparent shell is pointer-events:none so
24
- * taps pass through).
24
+ * taps pass through). Both modes keep the native dialog presented but inert
25
+ * until the slide-out transition ends.
25
26
  *
26
27
  * The drag/snap/dismiss machinery lives in `useSheetGestures`; the offset
27
28
  * geometry lives in the pure, tested `snapOffsets` module. Both are internal
@@ -33,7 +34,7 @@
33
34
  * - /packages/lab/src/BottomSheet/index.ts (exports if types change)
34
35
  * - /apps/storybook/stories/BottomSheet.stories.tsx (examples and visual coverage)
35
36
  */
36
- import { useCallback, useEffect, useRef } from 'react';
37
+ import { useCallback, useEffect, useRef, useState } from 'react';
37
38
  import * as stylex from '@stylexjs/stylex';
38
39
  import '@astryxdesign/core/theme/tokens.stylex';
39
40
  import { colorVars, durationVars, easeVars, radiusVars, shadowVars, sizeVars, spacingVars } from '@astryxdesign/core/theme/tokens.stylex';
@@ -116,6 +117,10 @@ const styles = {
116
117
  k3aq6I: "x1weeur4",
117
118
  $$css: true
118
119
  },
120
+ sheetExiting: {
121
+ kfzvcC: "x47corl",
122
+ $$css: true
123
+ },
119
124
  budget: {
120
125
  kZKoxP: "x1tpcejd",
121
126
  $$css: true
@@ -159,6 +164,8 @@ export function BottomSheet({
159
164
  xstyle,
160
165
  ...props
161
166
  }) {
167
+ const [isPresented, setIsPresented] = useState(isOpen);
168
+ const isExiting = !isOpen && isPresented;
162
169
  const dialogRef = useRef(null);
163
170
  const triggerRef = useRef(null);
164
171
  const sheetNodeRef = useRef(null);
@@ -191,6 +198,7 @@ export function BottomSheet({
191
198
  return;
192
199
  }
193
200
  if (isOpen) {
201
+ setIsPresented(true);
194
202
  dialog.style.setProperty('--_sheet-scrim-opacity', '1');
195
203
  if (!dialog.open) {
196
204
  // Only remember/restore focus for modal sheets; a non-modal sheet must
@@ -211,6 +219,9 @@ export function BottomSheet({
211
219
  }
212
220
  }
213
221
  } else if (dialog.open) {
222
+ if (hasScrim) {
223
+ dialog.style.setProperty('--_sheet-scrim-opacity', '0');
224
+ }
214
225
  // Wait for the slide-out (sheetClosing, applied this render) before
215
226
  // close() releases the top layer. Timeout backstops a missing
216
227
  // transitionend (reduced motion, hidden tab).
@@ -226,6 +237,7 @@ export function BottomSheet({
226
237
  if (dialog.open) {
227
238
  dialog.close();
228
239
  }
240
+ setIsPresented(false);
229
241
  triggerRef.current?.focus();
230
242
  triggerRef.current = null;
231
243
  };
@@ -235,8 +247,8 @@ export function BottomSheet({
235
247
  }
236
248
  };
237
249
  sheet?.addEventListener('transitionend', onEnd);
238
- // Backstop above --duration-medium (410ms) so transitionend normally
239
- // fires first; this only covers environments that don't emit it.
250
+ // Backstop above --duration-medium so transitionend normally fires
251
+ // first; this only covers environments that don't emit it.
240
252
  const timer = setTimeout(finish, 450);
241
253
  return () => {
242
254
  clearTimeout(timer);
@@ -247,7 +259,7 @@ export function BottomSheet({
247
259
 
248
260
  // Only a modal sheet locks body scroll; a non-modal sheet leaves the page
249
261
  // scrollable behind it.
250
- useScrollLock(isOpen && hasScrim);
262
+ useScrollLock(isPresented && hasScrim);
251
263
 
252
264
  // Enforce an accessible name: label is required by types, but a JS caller
253
265
  // can still pass an empty string, leaving the sheet unnamed.
@@ -302,10 +314,12 @@ export function BottomSheet({
302
314
  7: {
303
315
  className: "xixxii4 x10a8y8t x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1a2a7pz x1lliihq xnixb3f xni466t xxiuuzi xc0dz0a xft5bk6 x15h3t91 x142juwg x1viac0w x47corl xfo81ep xh8yej3 x5yr21d"
304
316
  }
305
- }[!!isOpen << 2 | !!hasScrim << 1 | !!!hasScrim << 0],
317
+ }[!!(isOpen || isPresented) << 2 | !!hasScrim << 1 | !!!hasScrim << 0],
306
318
  ref: mergeRefs(ref, dialogRef),
307
319
  "aria-label": label,
308
- "aria-modal": hasScrim ? 'true' : undefined,
320
+ "aria-hidden": isExiting ? 'true' : undefined,
321
+ "aria-modal": hasScrim && isOpen ? 'true' : undefined,
322
+ inert: isExiting ? true : undefined,
309
323
  onCancel: handleCancel,
310
324
  onClick: handleClick,
311
325
  onKeyDown: handleKeyDown,
@@ -317,9 +331,9 @@ export function BottomSheet({
317
331
  children: /*#__PURE__*/_jsxs("div", {
318
332
  ref: mergeRefs(sheetRef, sheetNodeRef),
319
333
  tabIndex: -1,
320
- ...mergeProps(themeProps('bottom-sheet'), stylex.props(styles.sheet, isHug ? styles.hugHeight : styles.budget, !isOpen && styles.sheetClosing, xstyle), undefined, {
334
+ ...mergeProps(themeProps('bottom-sheet'), stylex.props(styles.sheet, isHug ? styles.hugHeight : styles.budget, !isOpen && styles.sheetClosing, isExiting && styles.sheetExiting, xstyle), undefined, {
321
335
  ['--_sheet-budget']: budget,
322
- ...contentProps.style
336
+ ...(isOpen ? contentProps.style : {})
323
337
  }),
324
338
  children: [/*#__PURE__*/_jsx("div", {
325
339
  ...{
package/dist/index.d.ts CHANGED
@@ -30,5 +30,4 @@ export * from './Stepper';
30
30
  export * from './CircularProgress';
31
31
  export * from './ListInput';
32
32
  export { LogStream, type LogStreamProps, type LogEntry, type LogStreamLevel, } from './LogStream';
33
- export { RichTextEditor, type RichTextEditorProps, type RichTextEditorRef, type RichTextEditorStatus, type RichTextEditorStatusType, type RichTextEditorSize, type Transformer, RichTextView, type RichTextViewProps, sharedEditorTheme, markdownToEditorStateJSON, editorStateJSONToMarkdown, type MarkdownSerializerOptions, RichTextEditorToolbar, type RichTextEditorToolbarProps, RICHTEXT_ICON_KEYS, RichTextEditorAutoLinkPlugin, type RichTextEditorAutoLinkPluginProps, DEFAULT_LINK_MATCHERS, NEW_TAB_LINK_ATTRIBUTES, sanitizeUrl, validateUrl, URL_MATCHER, EMAIL_MATCHER, } from './RichTextEditor';
34
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -70,6 +70,7 @@ export * from "./ListInput/index.js";
70
70
  // LogStream — experimental streaming log viewer
71
71
  export { LogStream } from "./LogStream/index.js";
72
72
 
73
- // RichTextEditor — experimental Lexical WYSIWYG editor (RFC facebook/astryx#3899)
74
- // Optional peer deps: lexical + @lexical/*. Read-only rendering via RichTextView.
75
- export { RichTextEditor, RichTextView, sharedEditorTheme, markdownToEditorStateJSON, editorStateJSONToMarkdown, RichTextEditorToolbar, RICHTEXT_ICON_KEYS, RichTextEditorAutoLinkPlugin, DEFAULT_LINK_MATCHERS, NEW_TAB_LINK_ATTRIBUTES, sanitizeUrl, validateUrl, URL_MATCHER, EMAIL_MATCHER } from "./RichTextEditor/index.js";
73
+ // RichTextEditor (RFC facebook/astryx#3899) has graduated out of @astryxdesign/lab
74
+ // into its own canary-only package, @astryxdesign/richtext, so it can be canaried
75
+ // independently (e.g. into EPS/Nest). Import it from there:
76
+ // import {RichTextEditor, RichTextView} from '@astryxdesign/richtext';
package/dist/lab.css CHANGED
@@ -122,12 +122,8 @@
122
122
  .x15daork:not(#\#):not(#\#){grid-row:auto}
123
123
  .x33j1x8:not(#\#):not(#\#){grid-row:var(--x-gridRow)}
124
124
  .x17y0mx6:not(#\#):not(#\#){inset-inline:0}
125
- .x10im51j:not(#\#):not(#\#){margin-block:0}
126
125
  .x1yqqeh1:not(#\#):not(#\#){margin-block:var(--spacing-0-5)}
127
- .xsq74q5:not(#\#):not(#\#){margin-block:var(--spacing-1)}
128
- .x1g06x3t:not(#\#):not(#\#){margin-block:var(--spacing-2)}
129
126
  .x1oqu0vw:not(#\#):not(#\#){margin-block:var(--x-marginBlock)}
130
- .xrxpjvj:not(#\#):not(#\#){margin-inline:0}
131
127
  .x1a2a7pz:not(#\#):not(#\#){outline:none}
132
128
  .xysyzu8:not(#\#):not(#\#){overflow:auto}
133
129
  .xb3r6kr:not(#\#):not(#\#){overflow:hidden}
@@ -149,9 +145,7 @@
149
145
  .x1pzlopt:not(#\#):not(#\#){padding-inline:var(--spacing-4)}
150
146
  .x30g6up:not(#\#):not(#\#){padding-inline:var(--x-paddingInline)}
151
147
  .x1ku5rj1:not(#\#):not(#\#){place-items:center}
152
- .xmqliwb:not(#\#):not(#\#){text-decoration:line-through}
153
148
  .x1hl2dhg:not(#\#):not(#\#){text-decoration:none}
154
- .x1bvjpef:not(#\#):not(#\#){text-decoration:underline}
155
149
  .xb0j27v:not(#\#):not(#\#){transition:grid-template-rows var(--duration-medium) var(--ease-standard)}
156
150
  .x1ob6yzd:not(#\#):not(#\#){transition:transform var(--duration-fast) var(--ease-standard)}
157
151
  .x1xfd4ba:hover:not(#\#):not(#\#){border-color:transparent}
@@ -256,10 +250,8 @@
256
250
  .x18b5jzi:not(#\#):not(#\#):not(#\#){border-inline-end-style:solid}
257
251
  .x10w94by:not(#\#):not(#\#):not(#\#){border-inline-end-width:0}
258
252
  .xw8tdv1:not(#\#):not(#\#):not(#\#){border-inline-end-width:var(--border-width)}
259
- .x14ydlgx:not(#\#):not(#\#):not(#\#){border-inline-start-color:var(--color-border-emphasized)}
260
253
  .x1j92z86:not(#\#):not(#\#):not(#\#){border-inline-start-color:var(--color-border)}
261
254
  .x1t7ytsu:not(#\#):not(#\#):not(#\#){border-inline-start-style:solid}
262
- .xct1zlm:not(#\#):not(#\#):not(#\#){border-inline-start-width:3px}
263
255
  .xgbv0en:not(#\#):not(#\#):not(#\#){border-inline-start-width:var(--border-width)}
264
256
  .x7hs6f1:not(#\#):not(#\#):not(#\#){border-start-end-radius:var(--radius-container)}
265
257
  .x81l70g:not(#\#):not(#\#):not(#\#){border-start-start-radius:var(--radius-container)}
@@ -326,7 +318,6 @@
326
318
  .xb5mbof:not(#\#):not(#\#):not(#\#){content-visibility:auto}
327
319
  .x1jm3nie:not(#\#):not(#\#):not(#\#){cursor:grab}
328
320
  .xi9pz9s:not(#\#):not(#\#):not(#\#){cursor:grabbing}
329
- .x1h6gzvc:not(#\#):not(#\#):not(#\#){cursor:not-allowed}
330
321
  .x1ypdohk:not(#\#):not(#\#):not(#\#){cursor:pointer}
331
322
  .x1lliihq:not(#\#):not(#\#):not(#\#){display:block}
332
323
  .xjp7ctv:not(#\#):not(#\#):not(#\#){display:contents}
@@ -346,10 +337,6 @@
346
337
  .x9ynric:not(#\#):not(#\#):not(#\#){font-family:var(--font-family-body)}
347
338
  .x9m5x89:not(#\#):not(#\#):not(#\#){font-family:var(--font-family-code)}
348
339
  .x1g81bgm:not(#\#):not(#\#):not(#\#){font-family:var(--font-family-heading)}
349
- .xeb7xqv:not(#\#):not(#\#):not(#\#){font-size:.9em}
350
- .x1c3i2sq:not(#\#):not(#\#):not(#\#){font-size:1.125rem}
351
- .x1603h9y:not(#\#):not(#\#):not(#\#){font-size:1.25rem}
352
- .xngnso2:not(#\#):not(#\#):not(#\#){font-size:1.5rem}
353
340
  .x1jvydc1:not(#\#):not(#\#):not(#\#){font-size:15px}
354
341
  .xosj86m:not(#\#):not(#\#):not(#\#){font-size:18px}
355
342
  .xhs0kqb:not(#\#):not(#\#):not(#\#){font-size:var(--font-size-2xl)}
@@ -361,7 +348,6 @@
361
348
  .xjm74w1:not(#\#):not(#\#):not(#\#){font-size:var(--text-body-size)}
362
349
  .xcr08ib:not(#\#):not(#\#):not(#\#){font-size:var(--text-label-size)}
363
350
  .x141an7d:not(#\#):not(#\#):not(#\#){font-size:var(--text-supporting-size)}
364
- .x1k4tb9n:not(#\#):not(#\#):not(#\#){font-style:italic}
365
351
  .xss6m8b:not(#\#):not(#\#):not(#\#){font-variant-numeric:tabular-nums}
366
352
  .x1lvx875:not(#\#):not(#\#):not(#\#){font-weight:var(--font-weight-bold)}
367
353
  .x1e4wzip:not(#\#):not(#\#):not(#\#){font-weight:var(--font-weight-medium)}
@@ -417,15 +403,7 @@
417
403
  .x1cpk1wn:not(#\#):not(#\#):not(#\#){line-height:var(--text-heading-2-leading)}
418
404
  .x1kq96og:not(#\#):not(#\#):not(#\#){line-height:var(--text-label-leading)}
419
405
  .x1ltkj2j:not(#\#):not(#\#):not(#\#){line-height:var(--text-supporting-leading)}
420
- .x43c9pm:not(#\#):not(#\#):not(#\#){list-style-position:outside}
421
- .xrylv2j:not(#\#):not(#\#):not(#\#){list-style-type:circle}
422
- .x3yw8vx:not(#\#):not(#\#):not(#\#){list-style-type:decimal}
423
- .xtaz4m5:not(#\#):not(#\#):not(#\#){list-style-type:disc}
424
- .x1sle589:not(#\#):not(#\#):not(#\#){list-style-type:inherit}
425
- .x1rrqm6h:not(#\#):not(#\#):not(#\#){list-style-type:lower-alpha}
426
- .x19k9dhg:not(#\#):not(#\#):not(#\#){list-style-type:lower-roman}
427
406
  .x3ct3a4:not(#\#):not(#\#):not(#\#){list-style-type:none}
428
- .x152237o:not(#\#):not(#\#):not(#\#){list-style-type:square}
429
407
  .x1h1dc9q:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(var(--spacing-0-5) + var(--border-width))}
430
408
  .x1pezmd8:not(#\#):not(#\#):not(#\#){margin-inline-end:var(--spacing-2)}
431
409
  .x1m70ojl:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--spacing-1-5))}
@@ -447,8 +425,6 @@
447
425
  .xmarwi5:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--icon-inline-offset)}
448
426
  .x18gyask:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-0)}
449
427
  .x1vsv5vr:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-1)}
450
- .x12gdq22:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-2)}
451
- .x126nfab:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-3)}
452
428
  .x1rey3nv:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-4)}
453
429
  .x31w388:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-6)}
454
430
  .xchaq28:not(#\#):not(#\#):not(#\#){padding-inline-start:var(--spacing-7)}
@@ -532,7 +508,6 @@
532
508
  @media (prefers-reduced-motion: reduce){.xnh0sag.xnh0sag:not(#\#):not(#\#):not(#\#){animation-duration:3s}}
533
509
  @media (prefers-reduced-motion: reduce){.xy02sl2.xy02sl2:not(#\#):not(#\#):not(#\#){animation-duration:4s}}
534
510
  @media (prefers-reduced-motion: reduce){.x1aquc0h.x1aquc0h:not(#\#):not(#\#):not(#\#){animation-name:none}}
535
- @media (pointer: coarse){.x6pjikd.x6pjikd:not(#\#):not(#\#):not(#\#){font-size:max(1rem,var(--text-body-size))}}
536
511
  @media (prefers-reduced-motion: reduce){.xsagj69.xsagj69:not(#\#):not(#\#):not(#\#){transition-duration:.01ms}}
537
512
  @media (prefers-reduced-motion: reduce){.xzg1mie.xzg1mie:not(#\#):not(#\#):not(#\#){transition-duration:.01s}}
538
513
  @media (prefers-reduced-motion: reduce){.x12w9bfk.x12w9bfk:not(#\#):not(#\#):not(#\#){transition-duration:0s}}
@@ -607,8 +582,6 @@
607
582
  .xisnujt:not(#\#):not(#\#):not(#\#):not(#\#){min-height:20px}
608
583
  .xjwf9q1:not(#\#):not(#\#):not(#\#):not(#\#){min-height:24px}
609
584
  .x1cy360x:not(#\#):not(#\#):not(#\#):not(#\#){min-height:3em}
610
- .x17qorbb:not(#\#):not(#\#):not(#\#):not(#\#){min-height:4.5rem}
611
- .x65nank:not(#\#):not(#\#):not(#\#):not(#\#){min-height:auto}
612
585
  .x1uogy3y:not(#\#):not(#\#):not(#\#):not(#\#){min-height:var(--size-element-md)}
613
586
  .x175cymr:not(#\#):not(#\#):not(#\#):not(#\#){min-height:var(--spacing-2)}
614
587
  .xu95rz8:not(#\#):not(#\#):not(#\#):not(#\#){min-height:var(--transfer-list-panel-min-block-size)}
@@ -629,7 +602,6 @@
629
602
  .x1xye8es:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:var(--spacing-2)}
630
603
  .x13vifvy:not(#\#):not(#\#):not(#\#):not(#\#){top:0}
631
604
  .x80663w:not(#\#):not(#\#):not(#\#):not(#\#){top:auto}
632
- .x8d4r5l:not(#\#):not(#\#):not(#\#):not(#\#){top:var(--spacing-1)}
633
605
  .xctzyg:not(#\#):not(#\#):not(#\#):not(#\#){top:var(--spacing-2)}
634
606
  .xyx6v2t:not(#\#):not(#\#):not(#\#):not(#\#){top:var(--spacing-3)}
635
607
  .xjbys53:not(#\#):not(#\#):not(#\#):not(#\#){top:var(--x-top)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/lab",
3
- "version": "0.4.0-canary.e144ea7",
3
+ "version": "0.4.0-canary.faedff7",
4
4
  "description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
5
5
  "author": "Meta Open Source",
6
6
  "license": "MIT",
@@ -45,20 +45,9 @@
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@stylexjs/stylex": ">=0.10.0",
48
- "@astryxdesign/core": "0.4.0-canary.e144ea7",
48
+ "@astryxdesign/core": "0.4.0-canary.faedff7",
49
49
  "react": ">=19.0.0",
50
- "react-dom": ">=19.0.0",
51
- "lexical": "^0.46.0",
52
- "@lexical/react": "^0.46.0",
53
- "@lexical/markdown": "^0.46.0",
54
- "@lexical/headless": "^0.46.0",
55
- "@lexical/html": "^0.46.0",
56
- "@lexical/link": "^0.46.0",
57
- "@lexical/list": "^0.46.0",
58
- "@lexical/rich-text": "^0.46.0",
59
- "@lexical/selection": "^0.46.0",
60
- "@lexical/code": "^0.46.0",
61
- "@lexical/utils": "^0.46.0"
50
+ "react-dom": ">=19.0.0"
62
51
  },
63
52
  "dependencies": {
64
53
  "d3-array": "^3.2.4",
@@ -66,56 +55,10 @@
66
55
  "d3-shape": "^3.2.0"
67
56
  },
68
57
  "devDependencies": {
69
- "@astryxdesign/cli": "0.4.0-canary.e144ea7",
70
- "@lexical/code": "^0.46.0",
71
- "@lexical/headless": "^0.46.0",
72
- "@lexical/html": "^0.46.0",
73
- "@lexical/link": "^0.46.0",
74
- "@lexical/list": "^0.46.0",
75
- "@lexical/markdown": "^0.46.0",
76
- "@lexical/react": "^0.46.0",
77
- "@lexical/rich-text": "^0.46.0",
78
- "@lexical/selection": "^0.46.0",
79
- "@lexical/utils": "^0.46.0",
58
+ "@astryxdesign/cli": "0.4.0-canary.faedff7",
80
59
  "@types/d3-array": "^3.2.2",
81
60
  "@types/d3-scale": "^4.0.9",
82
- "@types/d3-shape": "^3.1.8",
83
- "lexical": "^0.46.0"
84
- },
85
- "peerDependenciesMeta": {
86
- "lexical": {
87
- "optional": true
88
- },
89
- "@lexical/react": {
90
- "optional": true
91
- },
92
- "@lexical/markdown": {
93
- "optional": true
94
- },
95
- "@lexical/headless": {
96
- "optional": true
97
- },
98
- "@lexical/html": {
99
- "optional": true
100
- },
101
- "@lexical/link": {
102
- "optional": true
103
- },
104
- "@lexical/list": {
105
- "optional": true
106
- },
107
- "@lexical/rich-text": {
108
- "optional": true
109
- },
110
- "@lexical/selection": {
111
- "optional": true
112
- },
113
- "@lexical/code": {
114
- "optional": true
115
- },
116
- "@lexical/utils": {
117
- "optional": true
118
- }
61
+ "@types/d3-shape": "^3.1.8"
119
62
  },
120
63
  "scripts": {
121
64
  "build": "rm -rf dist && pnpm build:esm && tsc --project tsconfig.build.json && pnpm build:css && node ../../scripts/check-no-dev-jsx.mjs && node ../../scripts/check-fully-specified.mjs",
@@ -6,59 +6,97 @@ export const docs = {
6
6
  displayName: 'BottomSheet',
7
7
  group: 'BottomSheet',
8
8
  category: 'Overlay',
9
- keywords: ["bottom sheet","sheet","mobile","touch","drag","swipe","dismiss","grab handle","dialog","overlay","modal"],
9
+ keywords: [
10
+ 'bottom sheet',
11
+ 'sheet',
12
+ 'mobile',
13
+ 'touch',
14
+ 'drag',
15
+ 'swipe',
16
+ 'dismiss',
17
+ 'grab handle',
18
+ 'dialog',
19
+ 'overlay',
20
+ 'modal',
21
+ ],
10
22
  theming: {
11
- targets: [
12
- {className: 'astryx-bottom-sheet', visualProps: []},
13
- ],
23
+ targets: [{className: 'astryx-bottom-sheet', visualProps: []}],
14
24
  },
15
- description: 'A mobile touch sheet that rises from the bottom edge, with a grab handle, drag-to-resize snap points, and swipe-to-dismiss. Built on a native modal <dialog>.',
25
+ description:
26
+ 'A mobile touch sheet that rises from the bottom edge, with animated entrance and exit, a grab handle, drag-to-resize snap points, and swipe-to-dismiss. Built on a native modal <dialog>.',
16
27
  props: [
17
28
  {
18
29
  name: 'isOpen',
19
30
  type: 'boolean',
20
- description: 'Whether the sheet is open. Fully controlled; pair with onOpenChange.',
31
+ description:
32
+ 'Whether the sheet is open. Fully controlled; pair with onOpenChange.',
21
33
  required: true,
22
34
  },
23
35
  {
24
36
  name: 'onOpenChange',
25
37
  type: '(isOpen: boolean) => void',
26
- description: 'Called when the sheet opens or closes. The boolean is the requested next state (false on Escape, scrim click, or a swipe past the dismiss threshold). The caller owns the open state.',
38
+ description:
39
+ 'Called when the sheet opens or closes. The boolean is the requested next state (false on Escape, scrim click, or a swipe past the dismiss threshold). The caller owns the open state.',
27
40
  required: true,
28
41
  },
29
42
  {
30
43
  name: 'label',
31
44
  type: 'string',
32
- description: 'Accessible label for the sheet. Required; the sheet has no built-in heading to derive a name from.',
45
+ description:
46
+ 'Accessible label for the sheet. Required; the sheet has no built-in heading to derive a name from.',
33
47
  required: true,
34
48
  },
35
49
  {
36
50
  name: 'children',
37
51
  type: 'ReactNode',
38
- description: 'Sheet content, rendered below the grab handle in a scrollable area.',
52
+ description:
53
+ 'Sheet content, rendered below the grab handle in a scrollable area.',
39
54
  required: true,
40
55
  },
41
56
  {
42
57
  name: 'height',
43
58
  type: "'hug' | 'capped' | 'tall' | number | string",
44
- description: "How tall the sheet is. Named budgets: 'hug' fits its content up to 92% of the viewport, 'capped' is a scrolling mid-height panel (~62%), and 'tall' is a pinned near-full panel (~92%) for content that streams in. Or pass a number (px) / CSS length for a custom budget. The user can drag between snap points regardless. On shorter viewports the sheet fills the available height.",
59
+ description:
60
+ "How tall the sheet is. Named budgets: 'hug' fits its content up to 92% of the viewport, 'capped' is a scrolling mid-height panel (~62%), and 'tall' is a pinned near-full panel (~92%) for content that streams in. Or pass a number (px) / CSS length for a custom budget. The user can drag between snap points regardless. On shorter viewports the sheet fills the available height.",
45
61
  default: "'capped'",
46
62
  },
47
63
  {
48
64
  name: 'hasScrim',
49
65
  type: 'boolean',
50
- description: "Whether to render a modal scrim behind the sheet. true (default) uses showModal(): top layer, focus trap, ::backdrop scrim, body scroll lock, and tap-scrim-to-dismiss, with the background inert. false uses show(): a non-modal sheet with no scrim, leaving the page behind interactive and scrollable (like Material's standard bottom sheet or an iOS undimmed detent). Escape still closes while focus is inside, and drag/flick-to-dismiss still work.",
66
+ description:
67
+ 'Whether to render a scrim, the semi-transparent overlay that covers and blocks the background, behind the sheet. true (default) uses showModal(): top layer, focus trap, ::backdrop scrim, body scroll lock, and tap-scrim-to-dismiss, with the background inert. false still renders a viewport-anchored overlay above the page, not inline content, but uses show() with no scrim, leaving the page behind interactive and scrollable. Escape still closes while focus is inside, and drag/flick-to-dismiss still work.',
51
68
  default: 'true',
52
69
  },
53
70
  ],
54
71
  usage: {
55
- description: 'A mobile touch surface for filters, actions, and detail views that should rise from the bottom of the screen. Drag the grab handle to resize: a slow drag settles to the nearest snap point (a short peek, ~half, and ~full detent, filtered to those shorter than the sheet), a fast flick down dismisses, a fast flick up expands. Pulling down on the content when it is scrolled to the top also drags the sheet, giving a larger, more forgiving target. The scrim thins to a faint glance state (but never fully clears) as the sheet collapses onto its shortest "peek" detent; the sheet stays modal, so the background remains inert until dismissed; a residual dim keeps that legible. The sheet is modal: focus is trapped while open and restored to the opener on close, and Escape dismisses, so the swipe gesture always has a keyboard equivalent. Content padding clears the home indicator via env(safe-area-inset-bottom).',
72
+ description:
73
+ 'A mobile touch surface for filters, actions, and detail views that should rise from the bottom of the screen. Opening slides the sheet in; closing keeps its native dialog presented but inert until the slide-out and scrim fade complete. Drag the grab handle to resize: a slow drag settles to the nearest snap point (a short peek, ~half, and ~full detent, filtered to those shorter than the sheet), a fast flick down dismisses, a fast flick up expands. Pulling down on the content when it is scrolled to the top also drags the sheet, giving a larger, more forgiving target. The scrim thins to a faint glance state (but never fully clears) as the sheet collapses onto its shortest "peek" detent; the sheet stays modal, so the background remains inert until dismissed; a residual dim keeps that legible. The sheet is modal: focus is trapped while open and restored to the opener after its exit, and Escape dismisses, so the swipe gesture always has a keyboard equivalent. Content padding clears the home indicator via env(safe-area-inset-bottom).',
56
74
  bestPractices: [
57
- { guidance: true, description: 'Use for mobile-first surfaces (filters, share sheets, quick actions) where the content should rise from the bottom edge.' },
58
- { guidance: true, description: 'Keep the caller as the source of truth: derive isOpen from state and clear it in onOpenChange.' },
59
- { guidance: true, description: "Pick the starting height that fits the content: 'hug' for short bounded content, 'capped' for lists, 'tall' for streaming/resizing content; the user can then drag between snap points." },
60
- { guidance: true, description: "Use hasScrim={false} (non-modal, no scrim) for a peek surface that must coexist with a live page behind it (e.g. a panel over a map); keep the default (hasScrim) for focused tasks where the background should be inert." },
61
- { guidance: false, description: 'Use a BottomSheet for desktop inspectors or master-detail; use Drawer (side="end", hasScrim={false}) instead.' },
75
+ {
76
+ guidance: true,
77
+ description:
78
+ 'Use for mobile-first surfaces (filters, share sheets, quick actions) where the content should rise from the bottom edge.',
79
+ },
80
+ {
81
+ guidance: true,
82
+ description:
83
+ 'Keep the caller as the source of truth: derive isOpen from state and clear it in onOpenChange.',
84
+ },
85
+ {
86
+ guidance: true,
87
+ description:
88
+ "Pick the starting height that fits the content: 'hug' for short bounded content, 'capped' for lists, 'tall' for streaming/resizing content; the user can then drag between snap points.",
89
+ },
90
+ {
91
+ guidance: true,
92
+ description:
93
+ 'Use hasScrim={false} for a floating, no-scrim overlay that must coexist with a live page behind it (e.g. a panel over a map). It remains viewport-anchored rather than rendering inline. Keep the default for focused tasks where the background should be inert.',
94
+ },
95
+ {
96
+ guidance: false,
97
+ description:
98
+ 'Use a BottomSheet for desktop inspectors or master-detail; use Drawer (side="end", hasScrim={false}) instead.',
99
+ },
62
100
  ],
63
101
  },
64
102
  examples: [
@@ -95,7 +133,7 @@ export const docs = {
95
133
  </BottomSheet>`,
96
134
  },
97
135
  {
98
- label: 'Non-modal sheet (no scrim): page stays interactive',
136
+ label: 'No scrim',
99
137
  code: `const [isOpen, setIsOpen] = useState(true);
100
138
  <BottomSheet
101
139
  isOpen={isOpen}
@@ -110,15 +148,36 @@ export const docs = {
110
148
 
111
149
  /** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
112
150
  export const docsDense = {
113
- description: 'mobile touch sheet rising from the bottom edge (native <dialog>): grab handle, drag-to-resize snap points, swipe-to-dismiss, named height scale, modal (default) or non-modal (hasScrim={false}) presentation',
151
+ description:
152
+ 'mobile touch sheet rising from the bottom edge (native <dialog>): grab handle, drag-to-resize snap points, swipe-to-dismiss, named height scale, modal (default) or non-modal (hasScrim={false}) presentation',
114
153
  usage: {
115
- description: 'Mobile surface for filters, actions, and detail views. Drag the handle to resize between snap points; flick down to dismiss, up to expand. Modal: focus trap + restore, and Escape dismisses so swipe has a keyboard equivalent. Content clears the home indicator via safe-area inset.',
154
+ description:
155
+ 'Mobile surface for filters, actions, and detail views. Drag the handle to resize between snap points; flick down to dismiss, up to expand. Modal: focus trap + restore, and Escape dismisses so swipe has a keyboard equivalent. Content clears the home indicator via safe-area inset.',
116
156
  bestPractices: [
117
- { guidance: true, description: 'Use for mobile-first bottom surfaces (filters, share sheets, quick actions).' },
118
- { guidance: true, description: 'Derive isOpen from state; clear it in onOpenChange.' },
119
- { guidance: true, description: "Pick a height that fits: 'hug' for short content, 'capped' for lists, 'tall' for streaming content." },
120
- { guidance: true, description: "hasScrim={false} for a non-modal peek over a live page; default (hasScrim) for focused tasks (inert background)." },
121
- { guidance: false, description: 'Use for desktop inspectors or master-detail; use Drawer instead.' },
157
+ {
158
+ guidance: true,
159
+ description:
160
+ 'Use for mobile-first bottom surfaces (filters, share sheets, quick actions).',
161
+ },
162
+ {
163
+ guidance: true,
164
+ description: 'Derive isOpen from state; clear it in onOpenChange.',
165
+ },
166
+ {
167
+ guidance: true,
168
+ description:
169
+ "Pick a height that fits: 'hug' for short content, 'capped' for lists, 'tall' for streaming content.",
170
+ },
171
+ {
172
+ guidance: true,
173
+ description:
174
+ 'hasScrim={false} for a floating no-scrim overlay over a live page; it is not inline. Keep the default for focused tasks (inert background).',
175
+ },
176
+ {
177
+ guidance: false,
178
+ description:
179
+ 'Use for desktop inspectors or master-detail; use Drawer instead.',
180
+ },
122
181
  ],
123
182
  },
124
183
  };
@@ -59,6 +59,25 @@ function getSheet(): HTMLElement {
59
59
  return sheet;
60
60
  }
61
61
 
62
+ function finishSheetExit() {
63
+ fireEvent.transitionEnd(getSheet(), {propertyName: 'transform'});
64
+ }
65
+
66
+ function ExitHarness({hasScrim}: {hasScrim?: boolean}) {
67
+ const [isOpen, setIsOpen] = useState(true);
68
+ return (
69
+ <BottomSheet
70
+ isOpen={isOpen}
71
+ onOpenChange={setIsOpen}
72
+ label="Filters"
73
+ hasScrim={hasScrim}>
74
+ <button type="button" onClick={() => setIsOpen(false)}>
75
+ Close sheet
76
+ </button>
77
+ </BottomSheet>
78
+ );
79
+ }
80
+
62
81
  // The grab handle is the panel's first child (decorative, aria-hidden).
63
82
  function getHandle(): HTMLElement {
64
83
  const handle = getSheet().querySelector<HTMLElement>('[aria-hidden="true"]');
@@ -134,6 +153,25 @@ describe('BottomSheet', () => {
134
153
  expect(onOpenChange).toHaveBeenCalledWith(false);
135
154
  });
136
155
 
156
+ it('keeps a standalone modal sheet presented through its exit animation', () => {
157
+ render(<ExitHarness />);
158
+ const dialog = screen.getByRole('dialog', {name: 'Filters'});
159
+
160
+ fireEvent.click(screen.getByRole('button', {name: 'Close sheet'}));
161
+
162
+ expect(dialog).toHaveAttribute('open');
163
+ expect(dialog).toHaveAttribute('inert');
164
+ expect(dialog).toHaveAttribute('aria-hidden', 'true');
165
+ expect(dialog).not.toHaveAttribute('aria-modal');
166
+ expect(dialog).toHaveStyle({'--_sheet-scrim-opacity': '0'});
167
+ expect(document.body.style.position).toBe('fixed');
168
+
169
+ finishSheetExit();
170
+
171
+ expect(dialog).not.toHaveAttribute('open');
172
+ expect(document.body.style.position).not.toBe('fixed');
173
+ });
174
+
137
175
  it('does not dismiss when the sheet surface itself is clicked', () => {
138
176
  const onOpenChange = vi.fn();
139
177
  render(
@@ -238,6 +276,21 @@ describe('BottomSheet', () => {
238
276
  screen.getByRole('textbox', {name: 'Search'}),
239
277
  );
240
278
  });
279
+
280
+ it('keeps a standalone non-modal sheet visible until its exit ends', () => {
281
+ render(<ExitHarness hasScrim={false} />);
282
+ const dialog = screen.getByRole('dialog', {name: 'Filters'});
283
+
284
+ fireEvent.click(screen.getByRole('button', {name: 'Close sheet'}));
285
+
286
+ expect(dialog).toHaveAttribute('open');
287
+ expect(dialog).toHaveAttribute('inert');
288
+ expect(document.body.style.position).not.toBe('fixed');
289
+
290
+ finishSheetExit();
291
+
292
+ expect(dialog).not.toHaveAttribute('open');
293
+ });
241
294
  });
242
295
 
243
296
  describe('grab handle', () => {