@astryxdesign/lab 0.2.0-canary.fc53ff7 → 0.3.0-canary.82d4dab
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.
- package/README.md +6 -0
- package/dist/BottomSheet/BottomSheet.d.ts +63 -35
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +271 -75
- package/dist/BottomSheet/snapOffsets.d.ts +62 -0
- package/dist/BottomSheet/snapOffsets.d.ts.map +1 -0
- package/dist/BottomSheet/snapOffsets.js +114 -0
- package/dist/BottomSheet/useSheetGestures.d.ts +55 -12
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +383 -40
- package/dist/Chart/index.d.ts +1 -1
- package/dist/Chart/index.d.ts.map +1 -1
- package/dist/Chart/index.js +1 -1
- package/dist/ChatReasoning/ChatReasoning.d.ts.map +1 -1
- package/dist/ChatReasoning/ChatReasoning.js +10 -1
- package/dist/LogStream/LogStream.d.ts +4 -0
- package/dist/LogStream/LogStream.d.ts.map +1 -1
- package/dist/LogStream/LogStream.js +12 -1
- package/dist/RichTextEditor/RichTextEditor.d.ts +18 -2
- package/dist/RichTextEditor/RichTextEditor.d.ts.map +1 -1
- package/dist/RichTextEditor/RichTextEditor.js +87 -13
- package/dist/RichTextEditor/RichTextEditorAutoLinkPlugin.d.ts +85 -0
- package/dist/RichTextEditor/RichTextEditorAutoLinkPlugin.d.ts.map +1 -0
- package/dist/RichTextEditor/RichTextEditorAutoLinkPlugin.js +95 -0
- package/dist/RichTextEditor/RichTextEditorToolbar.d.ts +126 -0
- package/dist/RichTextEditor/RichTextEditorToolbar.d.ts.map +1 -0
- package/dist/RichTextEditor/RichTextEditorToolbar.js +633 -0
- package/dist/RichTextEditor/RichTextView.d.ts.map +1 -1
- package/dist/RichTextEditor/RichTextView.js +48 -2
- package/dist/RichTextEditor/editorNodes.d.ts +8 -0
- package/dist/RichTextEditor/editorNodes.d.ts.map +1 -0
- package/dist/RichTextEditor/editorNodes.js +23 -0
- package/dist/RichTextEditor/index.d.ts +7 -0
- package/dist/RichTextEditor/index.d.ts.map +1 -1
- package/dist/RichTextEditor/index.js +5 -1
- package/dist/RichTextEditor/linkUtils.d.ts +22 -0
- package/dist/RichTextEditor/linkUtils.d.ts.map +1 -0
- package/dist/RichTextEditor/linkUtils.js +91 -0
- package/dist/RichTextEditor/markdownSerializers.d.ts +40 -0
- package/dist/RichTextEditor/markdownSerializers.d.ts.map +1 -0
- package/dist/RichTextEditor/markdownSerializers.js +85 -0
- package/dist/SVGIcon/SVGIcon.d.ts.map +1 -1
- package/dist/SVGIcon/SVGIcon.js +14 -1
- package/dist/Stepper/Step.d.ts +6 -1
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +34 -7
- package/dist/Stepper/Stepper.d.ts +1 -1
- package/dist/Stepper/Stepper.js +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/lab.css +16 -7
- package/package.json +19 -3
- package/src/BottomSheet/BottomSheet.doc.mjs +32 -13
- package/src/BottomSheet/BottomSheet.test.tsx +174 -4
- package/src/BottomSheet/BottomSheet.tsx +404 -97
- package/src/BottomSheet/snapOffsets.test.ts +152 -0
- package/src/BottomSheet/snapOffsets.ts +139 -0
- package/src/BottomSheet/useSheetGestures.doc.mjs +7 -6
- package/src/BottomSheet/useSheetGestures.test.ts +316 -65
- package/src/BottomSheet/useSheetGestures.ts +515 -55
- package/src/Chart/ChartArea.doc.mjs +1 -1
- package/src/Chart/ChartBar.doc.mjs +1 -1
- package/src/Chart/ChartCandlestick.doc.mjs +1 -1
- package/src/Chart/ChartDot.doc.mjs +1 -1
- package/src/Chart/ChartDotGL.doc.mjs +1 -1
- package/src/Chart/ChartDotGLInteractive.doc.mjs +1 -1
- package/src/Chart/ChartHeatmapGL.doc.mjs +1 -1
- package/src/Chart/ChartLine.doc.mjs +1 -1
- package/src/Chart/ChartStreamGL.doc.mjs +1 -1
- package/src/Chart/index.ts +0 -1
- package/src/Chat/ChatEmojiPicker.doc.mjs +1 -1
- package/src/Chat/ChatReactionBar.doc.mjs +1 -1
- package/src/Chat/ChatTypingIndicator.doc.mjs +1 -1
- package/src/Chat/ChatUnreadDivider.doc.mjs +1 -1
- package/src/ChatReasoning/ChatReasoning.doc.mjs +1 -1
- package/src/ChatReasoning/ChatReasoning.test.tsx +25 -0
- package/src/ChatReasoning/ChatReasoning.tsx +9 -1
- package/src/CircularProgress/CircularProgress.doc.mjs +3 -3
- package/src/CodeEditor/CodeEditor.doc.mjs +1 -1
- package/src/Drawer/Drawer.doc.mjs +3 -3
- package/src/InfoTip/InfoTip.doc.mjs +3 -3
- package/src/LogStream/LogStream.doc.mjs +2 -2
- package/src/LogStream/LogStream.test.tsx +25 -0
- package/src/LogStream/LogStream.tsx +10 -0
- package/src/Radial/RadialChart.doc.mjs +1 -1
- package/src/RichTextEditor/RichTextEditor.doc.mjs +34 -2
- package/src/RichTextEditor/RichTextEditor.test.tsx +761 -22
- package/src/RichTextEditor/RichTextEditor.tsx +138 -22
- package/src/RichTextEditor/RichTextEditorAutoLinkPlugin.tsx +116 -0
- package/src/RichTextEditor/RichTextEditorToolbar.tsx +789 -0
- package/src/RichTextEditor/RichTextView.tsx +44 -1
- package/src/RichTextEditor/editorNodes.ts +34 -0
- package/src/RichTextEditor/index.ts +26 -0
- package/src/RichTextEditor/linkUtils.ts +93 -0
- package/src/RichTextEditor/markdownSerializers.ts +105 -0
- package/src/SVGIcon/SVGIcon.doc.mjs +1 -1
- package/src/SVGIcon/SVGIcon.test.tsx +40 -0
- package/src/SVGIcon/SVGIcon.tsx +14 -6
- package/src/Sankey/SankeyChart.doc.mjs +1 -1
- package/src/Schedule/Schedule.doc.mjs +1 -1
- package/src/Stat/Stat.doc.mjs +3 -3
- package/src/Stepper/Step.doc.mjs +1 -1
- package/src/Stepper/Step.tsx +45 -5
- package/src/Stepper/Stepper.doc.mjs +3 -3
- package/src/Stepper/Stepper.test.tsx +84 -3
- package/src/Stepper/Stepper.tsx +1 -1
- package/src/ThreeD/3DBar.doc.mjs +1 -1
- package/src/ThreeD/3DChart.doc.mjs +1 -1
- package/src/ThreeD/3DScatter.doc.mjs +1 -1
- package/src/ThreeD/3DScatterGL.doc.mjs +1 -1
- package/src/ThreeD/3DSurface.doc.mjs +1 -1
- package/src/index.ts +15 -2
- package/dist/CodeBlock/index.d.ts +0 -8
- package/dist/CodeBlock/index.d.ts.map +0 -1
- package/dist/CodeBlock/index.js +0 -9
- package/src/CodeBlock/index.ts +0 -10
package/README.md
CHANGED
|
@@ -20,6 +20,12 @@ See the **[Component Lifecycle](https://github.com/facebook/astryx/wiki/Componen
|
|
|
20
20
|
|
|
21
21
|
**Core:** Full keyboard/a11y, hover guards, theming story, status states, spec compliance, vibe tested. Shipped to consumers on `latest`.
|
|
22
22
|
|
|
23
|
+
## Promotion gate: accessibility
|
|
24
|
+
|
|
25
|
+
The [Accessibility Checklist](https://github.com/facebook/astryx/wiki/Accessibility-Checklist) is a hard requirement for graduating to core — every item, verified in the promotion PR, alongside the hardening bar linked above.
|
|
26
|
+
|
|
27
|
+
Lab components get the same scan coverage as core (the `pr-a11y` axe audit and the weekly full scan run against lab too), but a11y findings on a lab component do not block lab merges — they block **promotion**. Iterate freely in lab; clear the checklist to graduate.
|
|
28
|
+
|
|
23
29
|
## Usage
|
|
24
30
|
|
|
25
31
|
Inside the monorepo (storybook/sandbox), imports resolve via pnpm workspaces:
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file BottomSheet.tsx
|
|
3
|
-
* @input Uses React, StyleX, theme tokens,
|
|
3
|
+
* @input Uses React, StyleX, theme tokens, core hooks (useScrollLock), utils, useSheetGestures
|
|
4
4
|
* @output Exports BottomSheet component and BottomSheetProps
|
|
5
5
|
* @position Lab implementation; consumed by index.ts, tested by BottomSheet.test.tsx, demonstrated in Storybook
|
|
6
6
|
*
|
|
7
|
-
* A mobile touch surface that rises from the bottom edge
|
|
8
|
-
* and swipe-to-dismiss.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* `hasScrim` picks the presentation: `true` (default) uses `showModal()` (top
|
|
17
|
+
* layer, focus trap, scrim, scroll lock, background inert); `false` uses
|
|
18
|
+
* `show()` for a non-modal sheet with no scrim, leaving the page behind
|
|
19
|
+
* interactive and scrollable (the transparent shell is pointer-events:none so
|
|
20
|
+
* taps pass through).
|
|
21
|
+
*
|
|
22
|
+
* The drag/snap/dismiss machinery lives in `useSheetGestures`; the offset
|
|
23
|
+
* geometry lives in the pure, tested `snapOffsets` module. Both are internal
|
|
24
|
+
* to BottomSheet and not exported from the lab entry point.
|
|
18
25
|
*
|
|
19
26
|
* SYNC: When modified, update these files to stay in sync:
|
|
20
27
|
* - /packages/lab/src/BottomSheet/BottomSheet.doc.mjs (props table, features, usage)
|
|
@@ -25,15 +32,16 @@
|
|
|
25
32
|
import { type ReactNode } from 'react';
|
|
26
33
|
import type { BaseProps } from '@astryxdesign/core';
|
|
27
34
|
/**
|
|
28
|
-
* Height budget for each named size
|
|
29
|
-
*
|
|
30
|
-
*
|
|
35
|
+
* Height budget for each named size, as a fraction of the viewport:
|
|
36
|
+
* - `hug` — fits its content, never taller than 92%.
|
|
37
|
+
* - `capped` — a scrolling mid-height panel (62%).
|
|
38
|
+
* - `tall` — a pinned near-full panel (92%); use when content streams in so
|
|
39
|
+
* the sheet doesn't resize under the user.
|
|
31
40
|
*/
|
|
32
41
|
declare const HEIGHT_BUDGETS: {
|
|
33
|
-
readonly
|
|
34
|
-
readonly
|
|
35
|
-
readonly tall: "
|
|
36
|
-
readonly auto: "90dvh";
|
|
42
|
+
readonly hug: "92dvh";
|
|
43
|
+
readonly capped: "62dvh";
|
|
44
|
+
readonly tall: "92dvh";
|
|
37
45
|
};
|
|
38
46
|
export type BottomSheetHeight = keyof typeof HEIGHT_BUDGETS;
|
|
39
47
|
export interface BottomSheetProps extends BaseProps<HTMLDialogElement> {
|
|
@@ -42,8 +50,8 @@ export interface BottomSheetProps extends BaseProps<HTMLDialogElement> {
|
|
|
42
50
|
/** Whether the sheet is open. Fully controlled — pair with `onOpenChange`. */
|
|
43
51
|
isOpen: boolean;
|
|
44
52
|
/**
|
|
45
|
-
* Called when the sheet opens or closes. The boolean is the requested
|
|
46
|
-
*
|
|
53
|
+
* Called when the sheet opens or closes. The boolean is the requested next
|
|
54
|
+
* state (`false` on Escape, scrim click, or a swipe past the dismiss
|
|
47
55
|
* threshold). The caller owns the open state.
|
|
48
56
|
*/
|
|
49
57
|
onOpenChange: (isOpen: boolean) => void;
|
|
@@ -55,26 +63,46 @@ export interface BottomSheetProps extends BaseProps<HTMLDialogElement> {
|
|
|
55
63
|
/** Sheet content, rendered below the grab handle in a scrollable area. */
|
|
56
64
|
children: ReactNode;
|
|
57
65
|
/**
|
|
58
|
-
* How tall the sheet is:
|
|
59
|
-
* - `'
|
|
60
|
-
* - `'
|
|
61
|
-
* - `'tall'` —
|
|
62
|
-
*
|
|
66
|
+
* How tall the sheet is. A named budget, or any explicit height:
|
|
67
|
+
* - `'hug'` — fits its content, never taller than 92% of the viewport.
|
|
68
|
+
* - `'capped'` — a scrolling mid-height panel (~62%).
|
|
69
|
+
* - `'tall'` — a pinned near-full panel (~92%); use when content streams in
|
|
70
|
+
* so the sheet doesn't resize under the user.
|
|
71
|
+
* - a `number` (px) or CSS length string (e.g. `'70dvh'`, `480`) for a
|
|
72
|
+
* custom budget.
|
|
63
73
|
*
|
|
64
|
-
*
|
|
65
|
-
* height.
|
|
66
|
-
*
|
|
74
|
+
* The user can still drag between snap points regardless of the starting
|
|
75
|
+
* height. On viewports shorter than the budget the sheet fills the
|
|
76
|
+
* available height.
|
|
77
|
+
* @default 'capped'
|
|
78
|
+
*/
|
|
79
|
+
height?: BottomSheetHeight | number | string;
|
|
80
|
+
/**
|
|
81
|
+
* Whether to render a modal scrim behind the sheet.
|
|
82
|
+
* - `true` (default) — `showModal()`: renders in the top layer with a focus
|
|
83
|
+
* trap, a `::backdrop` scrim, body scroll lock, and tap-scrim-to-dismiss.
|
|
84
|
+
* The background is inert. Use for focused tasks (filters, forms).
|
|
85
|
+
* - `false` — `show()`: a non-modal sheet with **no scrim**. The page behind
|
|
86
|
+
* stays interactive and scrollable (like Material's *standard* bottom
|
|
87
|
+
* sheet, or an iOS undimmed detent). Escape still closes while focus is
|
|
88
|
+
* inside the sheet, and drag/flick-to-dismiss still work. Use for a peek
|
|
89
|
+
* surface that coexists with the page (e.g. a panel over a live map).
|
|
90
|
+
* @default true
|
|
67
91
|
*/
|
|
68
|
-
|
|
92
|
+
hasScrim?: boolean;
|
|
69
93
|
/** Test ID for the root element. */
|
|
70
94
|
'data-testid'?: string;
|
|
71
95
|
}
|
|
72
96
|
/**
|
|
73
|
-
* A mobile touch sheet that rises from the bottom edge, with a grab handle
|
|
74
|
-
* and swipe-to-dismiss.
|
|
75
|
-
* (`
|
|
76
|
-
*
|
|
77
|
-
*
|
|
97
|
+
* A mobile touch sheet that rises from the bottom edge, with a grab handle,
|
|
98
|
+
* drag-to-resize snap points, and swipe-to-dismiss. It owns a native
|
|
99
|
+
* `<dialog>` and, by default (`hasScrim`), enters the top layer with a focus
|
|
100
|
+
* trap + `::backdrop` scrim and locks body scroll; a slow drag settles to the
|
|
101
|
+
* nearest snap point, a flick down dismisses, and Escape closes — so the swipe
|
|
102
|
+
* always has a keyboard equivalent.
|
|
103
|
+
*
|
|
104
|
+
* With `hasScrim={false}` it opens non-modally (`show()`, no scrim), leaving
|
|
105
|
+
* the page behind interactive and scrollable.
|
|
78
106
|
*
|
|
79
107
|
* @example
|
|
80
108
|
* ```
|
|
@@ -87,7 +115,7 @@ export interface BottomSheetProps extends BaseProps<HTMLDialogElement> {
|
|
|
87
115
|
* </BottomSheet>
|
|
88
116
|
* ```
|
|
89
117
|
*/
|
|
90
|
-
export declare function BottomSheet({ isOpen, onOpenChange, label, children, height, xstyle, ...props }: BottomSheetProps): import("react").JSX.Element;
|
|
118
|
+
export declare function BottomSheet({ ref, isOpen, onOpenChange, label, children, height, hasScrim, xstyle, ...props }: BottomSheetProps): import("react").JSX.Element;
|
|
91
119
|
export declare namespace BottomSheet {
|
|
92
120
|
var displayName: string;
|
|
93
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA
|
|
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"}
|
|
@@ -4,21 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file BottomSheet.tsx
|
|
7
|
-
* @input Uses React, StyleX, theme tokens,
|
|
7
|
+
* @input Uses React, StyleX, theme tokens, core hooks (useScrollLock), utils, useSheetGestures
|
|
8
8
|
* @output Exports BottomSheet component and BottomSheetProps
|
|
9
9
|
* @position Lab implementation; consumed by index.ts, tested by BottomSheet.test.tsx, demonstrated in Storybook
|
|
10
10
|
*
|
|
11
|
-
* A mobile touch surface that rises from the bottom edge
|
|
12
|
-
* and swipe-to-dismiss.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
11
|
+
* A mobile touch surface that rises from the bottom edge: grab handle, snap
|
|
12
|
+
* points, and swipe-to-dismiss. It owns a native `<dialog>` directly and
|
|
13
|
+
* composes core primitives (`useScrollLock`, `<dialog>.showModal()` for the
|
|
14
|
+
* top layer + focus trap, a `::backdrop` scrim) rather than delegating to a
|
|
15
|
+
* heavier overlay component — so it controls its own sizing and can render a
|
|
16
|
+
* full-height transparent shell with the visible sheet bottom-anchored inside.
|
|
17
|
+
* That shell is what lets the sheet translate freely (including a little past
|
|
18
|
+
* fully-open) without clipping against a fixed dialog edge.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* `hasScrim` picks the presentation: `true` (default) uses `showModal()` (top
|
|
21
|
+
* layer, focus trap, scrim, scroll lock, background inert); `false` uses
|
|
22
|
+
* `show()` for a non-modal sheet with no scrim, leaving the page behind
|
|
23
|
+
* interactive and scrollable (the transparent shell is pointer-events:none so
|
|
24
|
+
* taps pass through).
|
|
25
|
+
*
|
|
26
|
+
* The drag/snap/dismiss machinery lives in `useSheetGestures`; the offset
|
|
27
|
+
* geometry lives in the pure, tested `snapOffsets` module. Both are internal
|
|
28
|
+
* to BottomSheet and not exported from the lab entry point.
|
|
22
29
|
*
|
|
23
30
|
* SYNC: When modified, update these files to stay in sync:
|
|
24
31
|
* - /packages/lab/src/BottomSheet/BottomSheet.doc.mjs (props table, features, usage)
|
|
@@ -26,64 +33,109 @@
|
|
|
26
33
|
* - /packages/lab/src/BottomSheet/index.ts (exports if types change)
|
|
27
34
|
* - /apps/storybook/stories/BottomSheet.stories.tsx (examples and visual coverage)
|
|
28
35
|
*/
|
|
36
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
29
37
|
import * as stylex from '@stylexjs/stylex';
|
|
30
38
|
import '@astryxdesign/core/theme/tokens.stylex';
|
|
31
|
-
import { colorVars, radiusVars, spacingVars } from '@astryxdesign/core/theme/tokens.stylex';
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
39
|
+
import { colorVars, durationVars, easeVars, radiusVars, shadowVars, sizeVars, spacingVars } from '@astryxdesign/core/theme/tokens.stylex';
|
|
40
|
+
import { useDevWarning, useScrollLock } from '@astryxdesign/core/hooks';
|
|
41
|
+
import { mergeProps, mergeRefs, themeProps } from '@astryxdesign/core/utils';
|
|
34
42
|
import { useSheetGestures } from "./useSheetGestures.js";
|
|
35
43
|
|
|
44
|
+
// A non-modal sheet (hasScrim={false}) uses show() instead of showModal(), so
|
|
45
|
+
// it isn't in the native top layer and needs an explicit z-index to sit above
|
|
46
|
+
// page content. No z-index token exists in the theme; 1000 matches the Drawer
|
|
47
|
+
// / app-level overlay convention.
|
|
48
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
49
|
+
const NON_MODAL_Z = 1000;
|
|
50
|
+
|
|
51
|
+
// Detent fractions of the viewport, ascending (peek / mid / full). Detents
|
|
52
|
+
// that land within DETENT_DEDUP_PX of each other (e.g. a hug height next to a
|
|
53
|
+
// snap) are de-duped in the gesture hook, and any taller than the sheet are
|
|
54
|
+
// dropped, so a full set is safe to offer. The shortest is a glance "peek";
|
|
55
|
+
// the scrim hides as the sheet collapses onto it (see onScrimOpacity).
|
|
56
|
+
const SNAP_FRACTIONS = [0.14, 0.5, 0.92];
|
|
57
|
+
|
|
36
58
|
/**
|
|
37
|
-
* Height budget for each named size
|
|
38
|
-
*
|
|
39
|
-
*
|
|
59
|
+
* Height budget for each named size, as a fraction of the viewport:
|
|
60
|
+
* - `hug` — fits its content, never taller than 92%.
|
|
61
|
+
* - `capped` — a scrolling mid-height panel (62%).
|
|
62
|
+
* - `tall` — a pinned near-full panel (92%); use when content streams in so
|
|
63
|
+
* the sheet doesn't resize under the user.
|
|
40
64
|
*/
|
|
41
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
42
65
|
const HEIGHT_BUDGETS = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
hug: '92dvh',
|
|
67
|
+
// upper bound only; the sheet hugs its content beneath it
|
|
68
|
+
capped: '62dvh',
|
|
69
|
+
tall: '92dvh'
|
|
47
70
|
};
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
const
|
|
71
|
+
// px the sheet extends below its budget as reserved padding, revealed by an
|
|
72
|
+
// upward overdrag rather than showing a gap.
|
|
73
|
+
// SYNC: must match OVERSCROLL_MAX in useSheetGestures.ts (the drag cap).
|
|
74
|
+
const OVERSCROLL_PADDING = 48;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Default snap detents in px, resolved against the *visual* viewport (like iOS
|
|
78
|
+
* detents), so a mid rest point is ~half the screen regardless of the sheet's
|
|
79
|
+
* own height budget. Read lazily at drag start (no persistent listener) so it
|
|
80
|
+
* reflects the live viewport after a rotation or the virtual keyboard opening.
|
|
81
|
+
* SSR-safe: returns `[]` off the client.
|
|
82
|
+
*/
|
|
83
|
+
function defaultSnapHeights() {
|
|
84
|
+
if (typeof window === 'undefined') {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const vh = window.visualViewport?.height ?? window.innerHeight;
|
|
88
|
+
return SNAP_FRACTIONS.map(f => f * vh);
|
|
89
|
+
}
|
|
52
90
|
const styles = {
|
|
53
91
|
sheet: {
|
|
92
|
+
kfzvcC: "x67bb7w",
|
|
93
|
+
kB7OPa: "x9f619",
|
|
54
94
|
k1xSpc: "x78zum5",
|
|
55
95
|
kXwgrk: "xdt5ytf",
|
|
56
96
|
kAzted: "x2lwn1j",
|
|
57
|
-
kZKoxP: "x5yr21d",
|
|
58
97
|
kzqmXN: "xh8yej3",
|
|
59
98
|
ks0D6T: "x11gisft",
|
|
60
|
-
kUOVxO: "xvueqy4",
|
|
61
99
|
kWkggS: "x10xzikg",
|
|
62
|
-
krdFHd: "
|
|
63
|
-
kfmiAY: "
|
|
100
|
+
krdFHd: "x81l70g",
|
|
101
|
+
kfmiAY: "x7hs6f1",
|
|
102
|
+
kGVxlE: "x1kcpxr7",
|
|
103
|
+
kI3sdo: "x1a2a7pz",
|
|
64
104
|
kVQacm: "xb3r6kr",
|
|
65
|
-
kGO01o: "
|
|
105
|
+
kGO01o: "x1wkw6tp",
|
|
106
|
+
k1K539: "x1if0o47",
|
|
107
|
+
k3aq6I: "xnn1q72 xhbqy3z",
|
|
108
|
+
k1ekBW: "x11xpdln",
|
|
109
|
+
kIyJzY: "x80gvsz",
|
|
110
|
+
kAMwcw: "xlr8y92",
|
|
66
111
|
k6sLGO: "x1so62im",
|
|
112
|
+
k6CgDc: "xzg1mie",
|
|
113
|
+
$$css: true
|
|
114
|
+
},
|
|
115
|
+
sheetClosing: {
|
|
116
|
+
k3aq6I: "x1weeur4",
|
|
67
117
|
$$css: true
|
|
68
118
|
},
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
kGVxlE: "x1gnnqk1",
|
|
72
|
-
kEafiO: "x972fbf",
|
|
119
|
+
budget: {
|
|
120
|
+
kZKoxP: "x1tpcejd",
|
|
73
121
|
$$css: true
|
|
74
122
|
},
|
|
75
|
-
|
|
123
|
+
hugHeight: {
|
|
76
124
|
kZKoxP: "xg7h5cd",
|
|
77
|
-
kskxy: "
|
|
125
|
+
kskxy: "x14bu9tk",
|
|
78
126
|
$$css: true
|
|
79
127
|
}
|
|
80
128
|
};
|
|
81
129
|
/**
|
|
82
|
-
* A mobile touch sheet that rises from the bottom edge, with a grab handle
|
|
83
|
-
* and swipe-to-dismiss.
|
|
84
|
-
* (`
|
|
85
|
-
*
|
|
86
|
-
*
|
|
130
|
+
* A mobile touch sheet that rises from the bottom edge, with a grab handle,
|
|
131
|
+
* drag-to-resize snap points, and swipe-to-dismiss. It owns a native
|
|
132
|
+
* `<dialog>` and, by default (`hasScrim`), enters the top layer with a focus
|
|
133
|
+
* trap + `::backdrop` scrim and locks body scroll; a slow drag settles to the
|
|
134
|
+
* nearest snap point, a flick down dismisses, and Escape closes — so the swipe
|
|
135
|
+
* always has a keyboard equivalent.
|
|
136
|
+
*
|
|
137
|
+
* With `hasScrim={false}` it opens non-modally (`show()`, no scrim), leaving
|
|
138
|
+
* the page behind interactive and scrollable.
|
|
87
139
|
*
|
|
88
140
|
* @example
|
|
89
141
|
* ```
|
|
@@ -97,53 +149,197 @@ const styles = {
|
|
|
97
149
|
* ```
|
|
98
150
|
*/
|
|
99
151
|
export function BottomSheet({
|
|
152
|
+
ref,
|
|
100
153
|
isOpen,
|
|
101
154
|
onOpenChange,
|
|
102
155
|
label,
|
|
103
156
|
children,
|
|
104
|
-
height = '
|
|
157
|
+
height = 'capped',
|
|
158
|
+
hasScrim = true,
|
|
105
159
|
xstyle,
|
|
106
160
|
...props
|
|
107
161
|
}) {
|
|
108
|
-
const
|
|
162
|
+
const dialogRef = useRef(null);
|
|
163
|
+
const triggerRef = useRef(null);
|
|
164
|
+
const sheetNodeRef = useRef(null);
|
|
165
|
+
const close = useCallback(() => onOpenChange(false), [onOpenChange]);
|
|
166
|
+
|
|
167
|
+
// Set imperatively (not via state) so a 60fps drag doesn't re-render. The
|
|
168
|
+
// hook reports the scrim opacity for the current detent (a faint floor at the peek).
|
|
169
|
+
const handleScrimOpacity = useCallback(opacity => {
|
|
170
|
+
dialogRef.current?.style.setProperty('--_sheet-scrim-opacity', String(opacity));
|
|
171
|
+
}, []);
|
|
109
172
|
const {
|
|
110
173
|
contentProps,
|
|
111
|
-
handleProps
|
|
174
|
+
handleProps,
|
|
175
|
+
bodyProps,
|
|
176
|
+
sheetRef
|
|
112
177
|
} = useSheetGestures({
|
|
113
178
|
isOpen,
|
|
114
|
-
onDismiss: close
|
|
179
|
+
onDismiss: close,
|
|
180
|
+
snapHeights: defaultSnapHeights,
|
|
181
|
+
onScrimOpacity: handleScrimOpacity
|
|
115
182
|
});
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
183
|
+
|
|
184
|
+
// Modal: showModal() enters the top layer with a focus trap + ::backdrop and
|
|
185
|
+
// we restore focus to the opener on close. Standard: show() is non-modal, so
|
|
186
|
+
// we neither trap nor steal focus (the background stays interactive) — we
|
|
187
|
+
// only honor an explicit data-autofocus.
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
const dialog = dialogRef.current;
|
|
190
|
+
if (!dialog) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (isOpen) {
|
|
194
|
+
dialog.style.setProperty('--_sheet-scrim-opacity', '1');
|
|
195
|
+
if (!dialog.open) {
|
|
196
|
+
// Only remember/restore focus for modal sheets; a non-modal sheet must
|
|
197
|
+
// not yank focus back from whatever the user does in the live page.
|
|
198
|
+
if (hasScrim) {
|
|
199
|
+
triggerRef.current = document.activeElement;
|
|
200
|
+
dialog.showModal();
|
|
201
|
+
} else {
|
|
202
|
+
dialog.show();
|
|
203
|
+
}
|
|
204
|
+
// Land on the panel (so AT reads from the label) for modal sheets;
|
|
205
|
+
// otherwise only honor a descendant data-autofocus.
|
|
206
|
+
const autofocus = dialog.querySelector('[data-autofocus]');
|
|
207
|
+
if (autofocus) {
|
|
208
|
+
autofocus.focus();
|
|
209
|
+
} else if (hasScrim) {
|
|
210
|
+
sheetNodeRef.current?.focus();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} else if (dialog.open) {
|
|
214
|
+
// Wait for the slide-out (sheetClosing, applied this render) before
|
|
215
|
+
// close() releases the top layer. Timeout backstops a missing
|
|
216
|
+
// transitionend (reduced motion, hidden tab).
|
|
217
|
+
const sheet = sheetNodeRef.current;
|
|
218
|
+
let done = false;
|
|
219
|
+
const finish = () => {
|
|
220
|
+
if (done) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
done = true;
|
|
224
|
+
clearTimeout(timer);
|
|
225
|
+
sheet?.removeEventListener('transitionend', onEnd);
|
|
226
|
+
if (dialog.open) {
|
|
227
|
+
dialog.close();
|
|
228
|
+
}
|
|
229
|
+
triggerRef.current?.focus();
|
|
230
|
+
triggerRef.current = null;
|
|
231
|
+
};
|
|
232
|
+
const onEnd = event => {
|
|
233
|
+
if (event.target === sheet && event.propertyName === 'transform') {
|
|
234
|
+
finish();
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
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.
|
|
240
|
+
const timer = setTimeout(finish, 450);
|
|
241
|
+
return () => {
|
|
242
|
+
clearTimeout(timer);
|
|
243
|
+
sheet?.removeEventListener('transitionend', onEnd);
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}, [isOpen, hasScrim]);
|
|
247
|
+
|
|
248
|
+
// Only a modal sheet locks body scroll; a non-modal sheet leaves the page
|
|
249
|
+
// scrollable behind it.
|
|
250
|
+
useScrollLock(isOpen && hasScrim);
|
|
251
|
+
|
|
252
|
+
// Enforce an accessible name: label is required by types, but a JS caller
|
|
253
|
+
// can still pass an empty string, leaving the sheet unnamed.
|
|
254
|
+
useDevWarning('BottomSheet', 'requires a non-empty `label` for an accessible name; the open sheet ' + 'has no built-in heading to derive one from.', isOpen && !label);
|
|
255
|
+
const handleCancel = useCallback(event => {
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
close();
|
|
258
|
+
}, [close]);
|
|
259
|
+
// Explicit Escape handler in addition to the native `cancel` event, for
|
|
260
|
+
// environments that don't synthesize `cancel` (and the show() path, which
|
|
261
|
+
// never fires `cancel`). Only fires when focus is inside the sheet.
|
|
262
|
+
const handleKeyDown = useCallback(event => {
|
|
263
|
+
if (event.key === 'Escape') {
|
|
264
|
+
event.preventDefault();
|
|
265
|
+
close();
|
|
266
|
+
}
|
|
267
|
+
}, [close]);
|
|
268
|
+
// Tap-outside-to-dismiss only applies to modal sheets (the scrim). A non-modal
|
|
269
|
+
// sheet has no scrim and its transparent shell is pointer-events:none, so taps
|
|
270
|
+
// pass through to the page rather than dismissing.
|
|
271
|
+
const handleClick = useCallback(event => {
|
|
272
|
+
if (hasScrim && event.target === event.currentTarget) {
|
|
273
|
+
close();
|
|
274
|
+
}
|
|
275
|
+
}, [close, hasScrim]);
|
|
276
|
+
const isNamed = typeof height === 'string' && height in HEIGHT_BUDGETS;
|
|
277
|
+
const budget = isNamed ? HEIGHT_BUDGETS[height] : typeof height === 'number' ? `${height}px` : height;
|
|
278
|
+
const isHug = height === 'hug';
|
|
279
|
+
return /*#__PURE__*/_jsx("dialog", {
|
|
280
|
+
...{
|
|
281
|
+
0: {
|
|
282
|
+
className: "xixxii4 x10a8y8t x1o6l61p xtdtrs8 x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1s85apg x1a2a7pz"
|
|
283
|
+
},
|
|
284
|
+
4: {
|
|
285
|
+
className: "xixxii4 x10a8y8t x1o6l61p xtdtrs8 x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1a2a7pz x1lliihq"
|
|
286
|
+
},
|
|
287
|
+
2: {
|
|
288
|
+
className: "xixxii4 x10a8y8t x1o6l61p xtdtrs8 x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1s85apg x1a2a7pz xnixb3f xni466t xxiuuzi xc0dz0a xft5bk6 x15h3t91 x142juwg x1viac0w"
|
|
289
|
+
},
|
|
290
|
+
6: {
|
|
291
|
+
className: "xixxii4 x10a8y8t x1o6l61p xtdtrs8 x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1a2a7pz x1lliihq xnixb3f xni466t xxiuuzi xc0dz0a xft5bk6 x15h3t91 x142juwg x1viac0w"
|
|
292
|
+
},
|
|
293
|
+
1: {
|
|
294
|
+
className: "xixxii4 x10a8y8t x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1s85apg x1a2a7pz x47corl xfo81ep xh8yej3 x5yr21d"
|
|
295
|
+
},
|
|
296
|
+
5: {
|
|
297
|
+
className: "xixxii4 x10a8y8t x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1a2a7pz x1lliihq x47corl xfo81ep xh8yej3 x5yr21d"
|
|
298
|
+
},
|
|
299
|
+
3: {
|
|
300
|
+
className: "xixxii4 x10a8y8t x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1s85apg x1a2a7pz xnixb3f xni466t xxiuuzi xc0dz0a xft5bk6 x15h3t91 x142juwg x1viac0w x47corl xfo81ep xh8yej3 x5yr21d"
|
|
301
|
+
},
|
|
302
|
+
7: {
|
|
303
|
+
className: "xixxii4 x10a8y8t x1x1rfll x7ab17h x1ghz6dp x1717udv xjbqb8w x1rea2x4 x1a2a7pz x1lliihq xnixb3f xni466t xxiuuzi xc0dz0a xft5bk6 x15h3t91 x142juwg x1viac0w x47corl xfo81ep xh8yej3 x5yr21d"
|
|
304
|
+
}
|
|
305
|
+
}[!!isOpen << 2 | !!hasScrim << 1 | !!!hasScrim << 0],
|
|
306
|
+
ref: mergeRefs(ref, dialogRef),
|
|
307
|
+
"aria-label": label,
|
|
308
|
+
"aria-modal": hasScrim ? 'true' : undefined,
|
|
309
|
+
onCancel: handleCancel,
|
|
310
|
+
onClick: handleClick,
|
|
311
|
+
onKeyDown: handleKeyDown,
|
|
125
312
|
...props,
|
|
126
|
-
children: /*#__PURE__*/
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
313
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
314
|
+
...{
|
|
315
|
+
className: "x10l6tqk x17y0mx6 x1ey2m1c x78zum5 xl56j7k x47corl"
|
|
316
|
+
},
|
|
317
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
318
|
+
ref: mergeRefs(sheetRef, sheetNodeRef),
|
|
319
|
+
tabIndex: -1,
|
|
320
|
+
...mergeProps(themeProps('bottom-sheet'), stylex.props(styles.sheet, isHug ? styles.hugHeight : styles.budget, !isOpen && styles.sheetClosing, xstyle), undefined, {
|
|
321
|
+
['--_sheet-budget']: budget,
|
|
322
|
+
...contentProps.style
|
|
323
|
+
}),
|
|
324
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
325
|
+
...{
|
|
326
|
+
className: "x2lah0s x78zum5 x6s0dn4 xl56j7k x1k15mir x5ve5x3 x1jm3nie"
|
|
327
|
+
},
|
|
328
|
+
...handleProps,
|
|
329
|
+
"aria-hidden": "true",
|
|
330
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
331
|
+
...{
|
|
332
|
+
className: "x1m747yf x11c6zpc xjspbzw x1m4xfpy"
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
137
336
|
...{
|
|
138
|
-
className: "
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
children: children
|
|
146
|
-
})]
|
|
337
|
+
className: "x1iyjqo2 x2lwn1j x1odjw0f x8du1vd xx69xxh"
|
|
338
|
+
},
|
|
339
|
+
...bodyProps,
|
|
340
|
+
children: children
|
|
341
|
+
})]
|
|
342
|
+
})
|
|
147
343
|
})
|
|
148
344
|
});
|
|
149
345
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file snapOffsets.ts
|
|
3
|
+
* @input Pure geometry helpers — no React, no DOM.
|
|
4
|
+
* @output Converts snap points to translateY offsets for the sheet surface.
|
|
5
|
+
* @position Internal to BottomSheet; consumed by useSheetGestures, tested by
|
|
6
|
+
* snapOffsets.test.ts.
|
|
7
|
+
*
|
|
8
|
+
* The sheet is rendered at its full (fully-open) height and *translated down*
|
|
9
|
+
* to express shorter detents — translate is GPU-composited, so this is cheaper
|
|
10
|
+
* than animating layout height. A detent is therefore a translateY offset in
|
|
11
|
+
* px from the fully-open position (0 = fully open, larger = more collapsed).
|
|
12
|
+
* These helpers turn snap points into that offset list; they are pure so the
|
|
13
|
+
* geometry can be unit-tested without a DOM.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Detents whose resting offsets land within this many px of each other are
|
|
17
|
+
* treated as the same stop (the taller one wins). Stops the sheet from having
|
|
18
|
+
* two near-identical rest positions — e.g. when a content-hugging height sits
|
|
19
|
+
* a hair away from a fractional snap point.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DETENT_DEDUP_PX = 48;
|
|
22
|
+
/** Resolve snap points given as viewport fractions (0, 1] to px heights. */
|
|
23
|
+
export declare function snapFractionsToHeights(fractions: readonly number[], viewportPx: number): number[];
|
|
24
|
+
/**
|
|
25
|
+
* Given the sheet's full height (px, as rendered fully open) and a set of
|
|
26
|
+
* candidate detent *visible heights* (px), return the resting translateY
|
|
27
|
+
* offsets from fully-open, ascending and de-duplicated.
|
|
28
|
+
*
|
|
29
|
+
* - `0` (fully open) is always the first detent.
|
|
30
|
+
* - Only heights strictly shorter than the sheet become collapsed detents; a
|
|
31
|
+
* height >= the sheet can't be shown by translating down, so it's dropped.
|
|
32
|
+
* - Offsets closer than `dedupPx` collapse to the smaller (taller) offset, so
|
|
33
|
+
* near-identical detents — e.g. a hug height ≈ a snap point — become one stop.
|
|
34
|
+
*/
|
|
35
|
+
export declare function computeDetentOffsets(sheetHeight: number, detentHeights: readonly number[], dedupPx?: number): number[];
|
|
36
|
+
/** Nearest value in `offsets` to `value` (offsets must be non-empty). */
|
|
37
|
+
export declare function nearestOffset(value: number, offsets: readonly number[]): number;
|
|
38
|
+
/**
|
|
39
|
+
* Minimum scrim opacity at the peek detent. The scrim thins to a glance state
|
|
40
|
+
* but never fully vanishes, because a modal sheet keeps the background inert —
|
|
41
|
+
* a fully clear backdrop would read as "interactive" when it isn't. (For a
|
|
42
|
+
* genuinely interactive, undimmed peek, use a non-modal sheet, `hasScrim=false`.)
|
|
43
|
+
*/
|
|
44
|
+
export declare const MIN_PEEK_SCRIM_OPACITY = 0.3;
|
|
45
|
+
/**
|
|
46
|
+
* Scrim opacity (1 = fully visible) for a drag/settle `offset`.
|
|
47
|
+
* The scrim stays full while the sheet is at or above its second-shortest
|
|
48
|
+
* detent, then fades as it collapses onto the shortest ("peek") detent — a
|
|
49
|
+
* glance state that thins the backdrop to `MIN_PEEK_SCRIM_OPACITY` (not fully
|
|
50
|
+
* gone, since the sheet is still modal) and holds there below it.
|
|
51
|
+
* A single-detent sheet has no peek, so it instead fades all the way to 0
|
|
52
|
+
* across the dismiss overshoot toward `dismissOffset` (the sheet is leaving).
|
|
53
|
+
*/
|
|
54
|
+
export declare function scrimOpacityForOffset(offset: number, offsets: readonly number[], dismissOffset: number): number;
|
|
55
|
+
/**
|
|
56
|
+
* Settle target for a released drag. Restricts candidates to the drag
|
|
57
|
+
* direction so a committed drag never snaps *back past* where it started
|
|
58
|
+
* (a down-drag settles at/below the start, an up-drag at/above), then picks
|
|
59
|
+
* the nearest remaining detent. `dir`: 1 = dragged down, -1 = up, 0 = neither.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveSettleOffset(value: number, offsets: readonly number[], dir: number, baseOffset: number): number;
|
|
62
|
+
//# sourceMappingURL=snapOffsets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapOffsets.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/snapOffsets.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,4EAA4E;AAC5E,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAEV;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,OAAO,GAAE,MAAwB,GAChC,MAAM,EAAE,CAcV;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,CAKR;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,aAAa,EAAE,MAAM,GACpB,MAAM,CAeR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAcR"}
|