@astryxdesign/lab 0.4.1-canary.9e8a72a → 0.4.1-canary.e07f38f

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 (31) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +36 -118
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +264 -302
  4. package/dist/BottomSheet/BottomSheetPanel.d.ts +57 -0
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -0
  6. package/dist/BottomSheet/BottomSheetPanel.js +337 -0
  7. package/dist/BottomSheet/BottomSheetSwitcher.d.ts +60 -0
  8. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -0
  9. package/dist/BottomSheet/BottomSheetSwitcher.js +373 -0
  10. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +19 -0
  11. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -0
  12. package/dist/BottomSheet/BottomSheetSwitcherContext.js +13 -0
  13. package/dist/BottomSheet/index.d.ts +4 -2
  14. package/dist/BottomSheet/index.d.ts.map +1 -1
  15. package/dist/BottomSheet/index.js +4 -3
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/lab.css +2 -1
  20. package/package.json +3 -3
  21. package/src/BottomSheet/BottomSheet.doc.mjs +37 -6
  22. package/src/BottomSheet/BottomSheet.test.tsx +40 -17
  23. package/src/BottomSheet/BottomSheet.tsx +342 -449
  24. package/src/BottomSheet/BottomSheetPanel.test.tsx +240 -0
  25. package/src/BottomSheet/BottomSheetPanel.tsx +472 -0
  26. package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +140 -0
  27. package/src/BottomSheet/BottomSheetSwitcher.test.tsx +749 -0
  28. package/src/BottomSheet/BottomSheetSwitcher.tsx +597 -0
  29. package/src/BottomSheet/BottomSheetSwitcherContext.ts +46 -0
  30. package/src/BottomSheet/index.ts +4 -2
  31. package/src/index.ts +6 -1
@@ -1,138 +1,56 @@
1
1
  /**
2
2
  * @file BottomSheet.tsx
3
- * @input Uses React, StyleX, theme tokens, core hooks (useScrollLock), utils, useMobileKeyboard, useSheetGestures
3
+ * @input Uses React, StyleX, core hooks/utils, BottomSheetPanel, BottomSheetSwitcherContext
4
4
  * @output Exports BottomSheet component and BottomSheetProps
5
- * @position Lab implementation; consumed by index.ts, tested by BottomSheet.test.tsx, demonstrated in Storybook
5
+ * @position Public BottomSheet router plus private standalone/switcher hosts
6
6
  *
7
- * A mobile touch surface that rises from the bottom edge: grab handle, snap
8
- * points, and swipe-to-dismiss. It owns a native `<dialog>` directly and
9
- * composes core primitives (`useScrollLock`, `<dialog>.showModal()` for the
10
- * top layer + focus trap, a `::backdrop` scrim) rather than delegating to a
11
- * heavier overlay component — so it controls its own sizing and can render a
12
- * full-height transparent shell with the visible sheet bottom-anchored inside.
13
- * That shell is what lets the sheet translate freely (including a little past
14
- * fully-open) without clipping against a fixed dialog edge.
15
- *
16
- * Form controls stay usable above mobile on-screen keyboards: the outer sheet
17
- * keeps its measured height while visual-viewport overlap extends the internal
18
- * scroll range and focused controls scroll into view. Short sheets lift only
19
- * far enough to expose a usable focus area. Starting sheet travel or closing
20
- * the sheet blurs the field to dismiss the keyboard.
21
- *
22
- * `hasScrim` picks the presentation: `true` (default) uses `showModal()` (top
23
- * layer, focus trap, scrim, scroll lock, background inert); `false` uses
24
- * `show()` for a non-modal sheet with no scrim, leaving the page behind
25
- * interactive and scrollable (the transparent shell is pointer-events:none so
26
- * taps pass through). Both modes keep the native dialog presented but inert
27
- * until the slide-out transition ends.
28
- *
29
- * The drag/snap/dismiss machinery lives in `useSheetGestures`; the offset
30
- * geometry lives in the pure, tested `snapOffsets` module. Both are internal
31
- * to BottomSheet and not exported from the lab entry point.
7
+ * BottomSheet selects one of two focused hosts. A standalone host owns its
8
+ * native dialog lifecycle; a switcher item participates in the parent's shared
9
+ * dialog and transition state machine. Both render the same BottomSheetPanel,
10
+ * which owns sheet presentation, gestures, mobile-keyboard accommodation, and
11
+ * motion completion.
32
12
  *
33
13
  * SYNC: When modified, update these files to stay in sync:
34
- * - /packages/lab/src/BottomSheet/BottomSheet.doc.mjs (props table, features, usage)
35
- * - /packages/lab/src/BottomSheet/BottomSheet.test.tsx (tests for new/changed behavior)
36
- * - /packages/lab/src/BottomSheet/index.ts (exports if types change)
37
- * - /apps/storybook/stories/BottomSheet.stories.tsx (examples and visual coverage)
14
+ * - /packages/lab/src/BottomSheet/BottomSheetPanel.tsx
15
+ * - /packages/lab/src/BottomSheet/BottomSheet.doc.mjs
16
+ * - /packages/lab/src/BottomSheet/BottomSheet.test.tsx
17
+ * - /packages/lab/src/BottomSheet/BottomSheetSwitcher.tsx
18
+ * - /packages/lab/src/BottomSheet/BottomSheetSwitcher.test.tsx
19
+ * - /apps/storybook/stories/BottomSheet.stories.tsx
38
20
  */
39
21
  import { type ReactNode } from 'react';
40
22
  import type { BaseProps } from '@astryxdesign/core';
41
- /**
42
- * Height budget for each named size, as a fraction of the viewport:
43
- * - `hug` — fits its content, never taller than 92%.
44
- * - `capped` — a scrolling mid-height panel (62%).
45
- * - `tall` — a pinned near-full panel (92%); use when content streams in so
46
- * the sheet doesn't resize under the user.
47
- */
48
- declare const HEIGHT_BUDGETS: {
49
- readonly hug: "92dvh";
50
- readonly capped: "62dvh";
51
- readonly tall: "92dvh";
52
- };
53
- export type BottomSheetHeight = keyof typeof HEIGHT_BUDGETS;
54
- export interface BottomSheetProps extends BaseProps<HTMLDialogElement> {
55
- /** Ref forwarded to the underlying <dialog> element. */
56
- ref?: React.Ref<HTMLDialogElement>;
57
- /** Whether the sheet is open. Fully controlled — pair with `onOpenChange`. */
58
- isOpen: boolean;
59
- /**
60
- * Called when the sheet opens or closes. The boolean is the requested next
61
- * state (`false` on Escape, scrim click, or a swipe past the dismiss
62
- * threshold). The caller owns the open state.
63
- */
64
- onOpenChange: (isOpen: boolean) => void;
65
- /**
66
- * Accessible label for the sheet (required — the sheet has no built-in
67
- * heading to derive a name from).
68
- */
23
+ export type { BottomSheetHeight } from './BottomSheetPanel';
24
+ import type { BottomSheetHeight } from './BottomSheetPanel';
25
+ interface BottomSheetSharedProps extends BaseProps<HTMLDivElement> {
26
+ /** Ref forwarded to the visual sheet panel <div>. */
27
+ ref?: React.Ref<HTMLDivElement>;
28
+ /** Accessible label for the sheet. */
69
29
  label: string;
70
- /**
71
- * Sheet content, rendered below the grab handle in a scrollable,
72
- * mobile-keyboard-aware area.
73
- */
30
+ /** Sheet content, rendered below the grab handle in a scrollable area. */
74
31
  children: ReactNode;
75
- /**
76
- * How tall the sheet is. A named budget, or any explicit height:
77
- * - `'hug'` — fits its content, never taller than 92% of the viewport.
78
- * - `'capped'` — a scrolling mid-height panel (~62%).
79
- * - `'tall'` — a pinned near-full panel (~92%); use when content streams in
80
- * so the sheet doesn't resize under the user.
81
- * - a `number` (px) or CSS length string (e.g. `'70dvh'`, `480`) for a
82
- * custom budget.
83
- *
84
- * The user can still drag between snap points regardless of the starting
85
- * height. On viewports shorter than the budget the sheet fills the
86
- * available height.
87
- * @default 'capped'
88
- */
32
+ /** Height budget or custom CSS length. @default 'capped' */
89
33
  height?: BottomSheetHeight | number | string;
90
- /**
91
- * Whether to render a modal scrim behind the sheet.
92
- * - `true` (default) — `showModal()`: renders in the top layer with a focus
93
- * trap, a `::backdrop` scrim, body scroll lock, and tap-scrim-to-dismiss.
94
- * The background is inert. Use for focused tasks (filters, forms).
95
- * - `false`: `show()` renders a viewport-anchored overlay with **no scrim**. It is
96
- * still layered above the page, not rendered inline, but the page behind
97
- * stays interactive and scrollable (like Material's *standard* bottom
98
- * sheet or an iOS undimmed detent). Escape still closes while focus is
99
- * inside the sheet, and drag/flick-to-dismiss still work. Use for a peek
100
- * surface that coexists with the page (e.g. a panel over a live map).
101
- * @default true
102
- */
34
+ }
35
+ interface StandaloneBottomSheetProps extends BottomSheetSharedProps {
36
+ isOpen: boolean;
37
+ onOpenChange: (isOpen: boolean) => void;
103
38
  hasScrim?: boolean;
104
- /** Test ID for the root element. */
105
- 'data-testid'?: string;
39
+ sheetId?: never;
40
+ }
41
+ interface SwitcherBottomSheetProps extends BottomSheetSharedProps {
42
+ sheetId: string;
43
+ isOpen?: never;
44
+ onOpenChange?: never;
45
+ hasScrim?: never;
106
46
  }
47
+ export type BottomSheetProps = StandaloneBottomSheetProps | SwitcherBottomSheetProps;
107
48
  /**
108
- * A mobile touch sheet that rises from the bottom edge, with a grab handle,
109
- * drag-to-resize snap points, and swipe-to-dismiss. It owns a native
110
- * `<dialog>` and, by default (`hasScrim`), enters the top layer with a focus
111
- * trap + `::backdrop` scrim and locks body scroll; a slow drag settles to the
112
- * nearest snap point, a flick down dismisses, and Escape closes — so the swipe
113
- * always has a keyboard equivalent.
114
- *
115
- * With `hasScrim={false}` it opens non-modally (`show()`, no scrim), leaving
116
- * the page behind interactive and scrollable.
117
- *
118
- * Focused form controls scroll above the mobile on-screen keyboard without
119
- * resizing the sheet. A short sheet temporarily lifts when it has no usable
120
- * area above the keyboard. Moving the sheet dismisses the keyboard.
121
- *
122
- * @example
123
- * ```
124
- * const [isOpen, setIsOpen] = useState(false);
125
- * <BottomSheet
126
- * isOpen={isOpen}
127
- * onOpenChange={setIsOpen}
128
- * label="Filters">
129
- * <FilterControls />
130
- * </BottomSheet>
131
- * ```
49
+ * A mobile touch sheet that either owns a native dialog or participates in a
50
+ * BottomSheetSwitcher shared dialog when given a sheetId inside that context.
132
51
  */
133
- export declare function BottomSheet({ ref, isOpen, onOpenChange, label, children, height, hasScrim, xstyle, ...props }: BottomSheetProps): import("react").JSX.Element;
52
+ export declare function BottomSheet(props: BottomSheetProps): import("react").JSX.Element;
134
53
  export declare namespace BottomSheet {
135
54
  var displayName: string;
136
55
  }
137
- export {};
138
56
  //# sourceMappingURL=BottomSheet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AA4BlD;;;;;;GAMG;AACH,QAAA,MAAM,cAAc;;;;CAIV,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,cAAc,CAAC;AA2M5D,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;;;OAGG;IACH,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;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;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,+BA+NlB;yBAzOe,WAAW"}
1
+ {"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAkBlD,YAAY,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AA4D1D,UAAU,sBAAuB,SAAQ,SAAS,CAAC,cAAc,CAAC;IAChE,qDAAqD;IACrD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEhC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IAEd,0EAA0E;IAC1E,QAAQ,EAAE,SAAS,CAAC;IAEpB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;CAC9C;AAED,UAAU,0BAA2B,SAAQ,sBAAsB;IACjE,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,UAAU,wBAAyB,SAAQ,sBAAsB;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB;AAED,MAAM,MAAM,gBAAgB,GAC1B,0BAA0B,GAAG,wBAAwB,CAAC;AA6UxD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BA6BlD;yBA7Be,WAAW"}