@astryxdesign/core 0.4.4-canary.39d8a5a → 0.4.4-canary.46b0532
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/dist/BottomSheet/BottomSheet.d.ts +11 -2
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +4 -0
- package/dist/BottomSheet/BottomSheetPanel.d.ts +5 -2
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +56 -13
- package/dist/BottomSheet/index.d.ts +1 -1
- package/dist/BottomSheet/index.d.ts.map +1 -1
- package/dist/BottomSheet/snapOffsets.d.ts +57 -20
- package/dist/BottomSheet/snapOffsets.d.ts.map +1 -1
- package/dist/BottomSheet/snapOffsets.js +106 -30
- package/dist/BottomSheet/useSheetGestures.d.ts +13 -8
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +111 -62
- package/dist/Calendar/Calendar.d.ts +17 -0
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +34 -3
- package/dist/Calendar/getStandaloneShortWeekdayNames.d.ts +14 -0
- package/dist/Calendar/getStandaloneShortWeekdayNames.d.ts.map +1 -0
- package/dist/Calendar/getStandaloneShortWeekdayNames.js +26 -0
- package/dist/Calendar/hooks/useCalendarConstraints.d.ts +22 -1
- package/dist/Calendar/hooks/useCalendarConstraints.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarConstraints.js +26 -4
- package/dist/Calendar/hooks/useCalendarDays.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarDays.js +14 -10
- package/dist/Calendar/standaloneShortWeekdayNames.generated.d.ts +47 -0
- package/dist/Calendar/standaloneShortWeekdayNames.generated.d.ts.map +1 -0
- package/dist/Calendar/standaloneShortWeekdayNames.generated.js +40 -0
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +9 -0
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +6 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +6 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +38 -3
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +7 -2
- package/dist/Field/FieldLabel.d.ts +2 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +21 -3
- package/dist/FormLayout/FormLayout.d.ts +24 -2
- package/dist/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/FormLayout/FormLayout.js +7 -2
- package/dist/FormLayout/FormLayoutContext.d.ts +15 -2
- package/dist/FormLayout/FormLayoutContext.d.ts.map +1 -1
- package/dist/FormLayout/FormLayoutContext.js +19 -4
- package/dist/FormLayout/index.d.ts +1 -1
- package/dist/FormLayout/index.d.ts.map +1 -1
- package/dist/Markdown/Markdown.d.ts +8 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +31 -3
- package/dist/Markdown/parser.d.ts +14 -2
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +50 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +6 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +6 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts +2 -0
- package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.js +5 -31
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +12 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +6 -1
- package/dist/StatusDot/StatusDot.d.ts +43 -3
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +42 -5
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +9 -0
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +6 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +6 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +6 -1
- package/dist/hooks/useResolvedRequired.d.ts +19 -0
- package/dist/hooks/useResolvedRequired.d.ts.map +1 -0
- package/dist/hooks/useResolvedRequired.js +40 -0
- package/dist/utils/plainDate.d.ts +6 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +12 -0
- package/locales/en.json +4 -0
- package/locales/pseudo.json +3 -0
- package/package.json +2 -2
- package/src/BottomSheet/BottomSheet.doc.mjs +36 -3
- package/src/BottomSheet/BottomSheet.test.tsx +153 -2
- package/src/BottomSheet/BottomSheet.tsx +16 -2
- package/src/BottomSheet/BottomSheetPanel.tsx +67 -13
- package/src/BottomSheet/index.ts +5 -1
- package/src/BottomSheet/snapOffsets.test.ts +114 -47
- package/src/BottomSheet/snapOffsets.ts +119 -33
- package/src/BottomSheet/useSheetGestures.test.ts +68 -15
- package/src/BottomSheet/useSheetGestures.ts +142 -98
- package/src/Calendar/Calendar.doc.mjs +16 -0
- package/src/Calendar/Calendar.test.tsx +137 -0
- package/src/Calendar/Calendar.tsx +65 -2
- package/src/Calendar/getStandaloneShortWeekdayNames.test.ts +54 -0
- package/src/Calendar/getStandaloneShortWeekdayNames.ts +38 -0
- package/src/Calendar/hooks/useCalendarConstraints.ts +54 -3
- package/src/Calendar/hooks/useCalendarDays.ts +13 -10
- package/src/Calendar/standaloneShortWeekdayNames.generated.ts +50 -0
- package/src/CheckboxInput/CheckboxInput.tsx +6 -0
- package/src/ComplexSelector/ComplexSelector.tsx +3 -1
- package/src/DateInput/DateInput.tsx +3 -1
- package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +81 -1
- package/src/DateRangeInput/DateRangeInput.tsx +72 -1
- package/src/DateTimeInput/DateTimeInput.tsx +4 -2
- package/src/Field/FieldLabel.tsx +20 -4
- package/src/FormLayout/FormLayout.doc.mjs +13 -0
- package/src/FormLayout/FormLayout.test.tsx +181 -4
- package/src/FormLayout/FormLayout.tsx +33 -2
- package/src/FormLayout/FormLayoutContext.ts +22 -7
- package/src/FormLayout/index.ts +1 -1
- package/src/Markdown/Markdown.doc.mjs +3 -0
- package/src/Markdown/Markdown.test.tsx +78 -0
- package/src/Markdown/Markdown.tsx +41 -1
- package/src/Markdown/parser.ts +60 -2
- package/src/MultiSelector/MultiSelector.tsx +3 -1
- package/src/NumberInput/NumberInput.tsx +3 -1
- package/src/Outline/Outline.doc.mjs +2 -0
- package/src/Outline/parseOutlineFromMarkdown.ts +10 -40
- package/src/RadioList/RadioList.tsx +9 -1
- package/src/Selector/Selector.tsx +3 -1
- package/src/StatusDot/StatusDot.doc.mjs +13 -0
- package/src/StatusDot/StatusDot.test.tsx +115 -8
- package/src/StatusDot/StatusDot.tsx +74 -9
- package/src/Switch/Switch.tsx +6 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +20 -2
- package/src/TextArea/TextArea.tsx +3 -1
- package/src/TextInput/TextInput.tsx +3 -1
- package/src/TimeInput/TimeInput.tsx +3 -1
- package/src/hooks/useResolvedRequired.ts +42 -0
- package/src/utils/plainDate.test.ts +50 -0
- package/src/utils/plainDate.ts +12 -0
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
import { type ReactNode } from 'react';
|
|
23
23
|
import type { BaseProps } from '../BaseProps';
|
|
24
24
|
import type { DialogPurpose } from '../Dialog';
|
|
25
|
-
export type { BottomSheetHeight } from './BottomSheetPanel';
|
|
26
|
-
import type { BottomSheetHeight } from './BottomSheetPanel';
|
|
25
|
+
export type { BottomSheetHeight, BottomSheetSnapPoint } from './BottomSheetPanel';
|
|
26
|
+
import type { BottomSheetHeight, BottomSheetSnapPoint } from './BottomSheetPanel';
|
|
27
27
|
interface BottomSheetSharedProps extends BaseProps<HTMLDivElement> {
|
|
28
28
|
/** Ref forwarded to the visual sheet panel <div>. */
|
|
29
29
|
ref?: React.Ref<HTMLDivElement>;
|
|
@@ -33,6 +33,15 @@ interface BottomSheetSharedProps extends BaseProps<HTMLDivElement> {
|
|
|
33
33
|
children: ReactNode;
|
|
34
34
|
/** Height budget or custom CSS length. Only fully expanded Tall is keyboard-aware. @default 'capped' */
|
|
35
35
|
height?: BottomSheetHeight | number | string;
|
|
36
|
+
/**
|
|
37
|
+
* Extra heights the sheet can rest at when dragged; its own height is always
|
|
38
|
+
* the tallest stop, and omitting this gives a sheet that only opens and
|
|
39
|
+
* closes. Each stop is the sheet's visible height: a number is a viewport
|
|
40
|
+
* fraction (`0.5` is half the screen), `'50%'` the same in CSS, `'320px'` an
|
|
41
|
+
* absolute length. A stop of a quarter of the sheet or less is a peek — it
|
|
42
|
+
* slides away instead of reflowing, and thins the scrim.
|
|
43
|
+
*/
|
|
44
|
+
snapPoints?: ReadonlyArray<BottomSheetSnapPoint>;
|
|
36
45
|
/**
|
|
37
46
|
* Configures implicit dismissal behavior, matching Dialog.
|
|
38
47
|
* - required: Blocks swipe, scrim click, and Escape
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,WAAW,CAAC;AAc7C,YAAY,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheet.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,WAAW,CAAC;AAc7C,YAAY,EAAC,iBAAiB,EAAE,oBAAoB,EAAC,MAAM,oBAAoB,CAAC;AAChF,OAAO,KAAK,EAAC,iBAAiB,EAAE,oBAAoB,EAAC,MAAM,oBAAoB,CAAC;AA2DhF,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,wGAAwG;IACxG,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;IAE7C;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;IAEjD;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;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;AA4WxD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BA6BlD;yBA7Be,WAAW"}
|
|
@@ -89,6 +89,7 @@ function StandaloneBottomSheet({
|
|
|
89
89
|
label,
|
|
90
90
|
children,
|
|
91
91
|
height = 'capped',
|
|
92
|
+
snapPoints,
|
|
92
93
|
hasScrim = true,
|
|
93
94
|
purpose = 'info',
|
|
94
95
|
xstyle,
|
|
@@ -224,6 +225,7 @@ function StandaloneBottomSheet({
|
|
|
224
225
|
ref: ref,
|
|
225
226
|
state: panelState,
|
|
226
227
|
height: height,
|
|
228
|
+
snapPoints: snapPoints,
|
|
227
229
|
isSwipeDismissAllowed: purpose === 'info',
|
|
228
230
|
isPageScrollLocked: shouldPresent && hasScrim,
|
|
229
231
|
xstyle: xstyle,
|
|
@@ -243,6 +245,7 @@ function SwitcherBottomSheetItem({
|
|
|
243
245
|
label,
|
|
244
246
|
children,
|
|
245
247
|
height = 'capped',
|
|
248
|
+
snapPoints,
|
|
246
249
|
purpose = 'info',
|
|
247
250
|
xstyle,
|
|
248
251
|
...props
|
|
@@ -353,6 +356,7 @@ function SwitcherBottomSheetItem({
|
|
|
353
356
|
ref: ref,
|
|
354
357
|
state: panelState,
|
|
355
358
|
height: height,
|
|
359
|
+
snapPoints: snapPoints,
|
|
356
360
|
isSwipeDismissAllowed: purpose === 'info',
|
|
357
361
|
isPageScrollLocked: hasScrim,
|
|
358
362
|
xstyle: xstyle,
|
|
@@ -12,17 +12,20 @@
|
|
|
12
12
|
* SYNC: When modified, update these files to stay in sync:
|
|
13
13
|
* - /packages/core/src/BottomSheet/BottomSheet.tsx
|
|
14
14
|
* - /packages/core/src/BottomSheet/BottomSheetPanel.test.tsx
|
|
15
|
+
* - /packages/core/src/BottomSheet/snapOffsets.ts
|
|
15
16
|
* - /packages/core/src/BottomSheet/useMobileKeyboard.ts
|
|
16
17
|
* - /packages/core/src/BottomSheet/useSheetGestures.ts
|
|
17
18
|
*/
|
|
18
19
|
import { type ReactNode } from 'react';
|
|
19
20
|
import type { BaseProps } from '../BaseProps';
|
|
21
|
+
import { type BottomSheetSnapPoint } from './snapOffsets';
|
|
20
22
|
declare const HEIGHT_BUDGETS: {
|
|
21
23
|
readonly hug: "92dvh";
|
|
22
24
|
readonly capped: "62dvh";
|
|
23
25
|
readonly tall: "92dvh";
|
|
24
26
|
};
|
|
25
27
|
export type BottomSheetHeight = keyof typeof HEIGHT_BUDGETS;
|
|
28
|
+
export type { BottomSheetSnapPoint };
|
|
26
29
|
export type BottomSheetPanelMotion = 'entering' | 'aligning' | 'fading' | 'exiting';
|
|
27
30
|
export type BottomSheetPanelState = {
|
|
28
31
|
kind: 'hidden';
|
|
@@ -42,6 +45,7 @@ interface BottomSheetPanelProps extends BaseProps<HTMLDivElement> {
|
|
|
42
45
|
state: BottomSheetPanelState;
|
|
43
46
|
height: BottomSheetHeight | number | string;
|
|
44
47
|
children: ReactNode;
|
|
48
|
+
snapPoints?: ReadonlyArray<BottomSheetSnapPoint>;
|
|
45
49
|
isSwipeDismissAllowed?: boolean;
|
|
46
50
|
/** Whether the host has locked page scrolling (a modal, scrim-backed sheet). */
|
|
47
51
|
isPageScrollLocked?: boolean;
|
|
@@ -52,9 +56,8 @@ interface BottomSheetPanelProps extends BaseProps<HTMLDivElement> {
|
|
|
52
56
|
onMotionComplete?: (motion: BottomSheetPanelMotion) => void;
|
|
53
57
|
}
|
|
54
58
|
/** Internal visual and gesture surface shared by every BottomSheet host. */
|
|
55
|
-
export declare function BottomSheetPanel({ ref, state, height, children, className, style, tabIndex, xstyle, isSwipeDismissAllowed, isPageScrollLocked, onDismiss, onScrimOpacity, onElementChange, onMotionStart, onMotionComplete, ...props }: BottomSheetPanelProps): import("react").JSX.Element;
|
|
59
|
+
export declare function BottomSheetPanel({ ref, state, height, children, snapPoints, className, style, tabIndex, xstyle, isSwipeDismissAllowed, isPageScrollLocked, onDismiss, onScrimOpacity, onElementChange, onMotionStart, onMotionComplete, ...props }: BottomSheetPanelProps): import("react").JSX.Element;
|
|
56
60
|
export declare namespace BottomSheetPanel {
|
|
57
61
|
var displayName: string;
|
|
58
62
|
}
|
|
59
|
-
export {};
|
|
60
63
|
//# sourceMappingURL=BottomSheetPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheetPanel.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheetPanel.tsx"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"BottomSheetPanel.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/BottomSheetPanel.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAY5C,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAIvB,QAAA,MAAM,cAAc;;;;CAIV,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,cAAc,CAAC;AAC5D,YAAY,EAAC,oBAAoB,EAAC,CAAC;AAoHnC,MAAM,MAAM,sBAAsB,GAChC,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEjD,MAAM,MAAM,qBAAqB,GAC7B;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GAChB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAC,GACjC;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;CACzB,GACD;IAAC,IAAI,EAAE,SAAS,CAAA;CAAC,CAAC;AAEtB,UAAU,qBAAsB,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC/D,+CAA+C;IAC/C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;IAC5C,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACjD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3D,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACzD,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC7D;AA+GD,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,KAAK,EACL,MAAM,EACN,QAAQ,EACR,UAAU,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,MAAM,EACN,qBAA4B,EAC5B,kBAA0B,EAC1B,SAAS,EACT,cAAc,EACd,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,GAAG,KAAK,EACT,EAAE,qBAAqB,+BAwQvB;yBA1Re,gBAAgB"}
|
|
@@ -16,18 +16,20 @@
|
|
|
16
16
|
* SYNC: When modified, update these files to stay in sync:
|
|
17
17
|
* - /packages/core/src/BottomSheet/BottomSheet.tsx
|
|
18
18
|
* - /packages/core/src/BottomSheet/BottomSheetPanel.test.tsx
|
|
19
|
+
* - /packages/core/src/BottomSheet/snapOffsets.ts
|
|
19
20
|
* - /packages/core/src/BottomSheet/useMobileKeyboard.ts
|
|
20
21
|
* - /packages/core/src/BottomSheet/useSheetGestures.ts
|
|
21
22
|
*/
|
|
22
|
-
import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef } from 'react';
|
|
23
|
+
import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef } from 'react';
|
|
23
24
|
import * as stylex from '@stylexjs/stylex';
|
|
25
|
+
import { useDevWarning } from "../hooks/index.js";
|
|
24
26
|
import "../theme/tokens.stylex.js";
|
|
25
27
|
import { colorVars, durationVars, easeVars, radiusVars, shadowVars, sizeVars, spacingVars } from "../theme/tokens.stylex.js";
|
|
26
28
|
import { mergeProps, themeProps } from "../utils/index.js";
|
|
29
|
+
import { isValidSnapPoint, resolveSnapPoints } from "./snapOffsets.js";
|
|
27
30
|
import { useMobileKeyboard } from "./useMobileKeyboard.js";
|
|
28
31
|
import { useSheetGestures } from "./useSheetGestures.js";
|
|
29
32
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
30
|
-
const SNAP_FRACTIONS = [0.14, 0.5, 0.92];
|
|
31
33
|
const HEIGHT_BUDGETS = {
|
|
32
34
|
hug: '92dvh',
|
|
33
35
|
capped: '62dvh',
|
|
@@ -37,17 +39,31 @@ const HEIGHT_BUDGETS = {
|
|
|
37
39
|
const OVERSCROLL_PADDING = 48;
|
|
38
40
|
const MOBILE_KEYBOARD_BOTTOM_CLEARANCE = 48;
|
|
39
41
|
const TRANSITION_BACKSTOP_BUFFER_MS = 50;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
// Measure the same viewport the height budgets are written against. Those are
|
|
44
|
+
// `dvh`, which the virtual keyboard does not shrink, so reading
|
|
45
|
+
// `visualViewport` here would make the two disagree by exactly the keyboard's
|
|
46
|
+
// height: every detent would move while the sheet it measures did not. A
|
|
47
|
+
// keyboard is `useMobileKeyboard`'s business — it holds the sheet still and
|
|
48
|
+
// scrolls the body — and it does not redefine the sheet's detents.
|
|
49
|
+
function layoutViewportHeight() {
|
|
50
|
+
return typeof window === 'undefined' ? 0 : window.innerHeight;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A stable identity for a set of snap points. Type-tagged, so the fraction
|
|
55
|
+
* `0.5` and the (invalid) string `'0.5'` cannot collide on one key.
|
|
56
|
+
*
|
|
57
|
+
* Recomputed every render — the panel re-renders on every frame of a drag — so
|
|
58
|
+
* it stays a single pass over a handful of values, and everything derived from
|
|
59
|
+
* the points hangs off it instead of being rebuilt per frame.
|
|
60
|
+
*/
|
|
61
|
+
function snapPointsKeyFor(points) {
|
|
62
|
+
let key = '';
|
|
63
|
+
for (const point of points ?? []) {
|
|
64
|
+
key += `${typeof point}:${point}|`;
|
|
43
65
|
}
|
|
44
|
-
|
|
45
|
-
// are `dvh`, which the virtual keyboard does not shrink, so reading
|
|
46
|
-
// `visualViewport` here made the two disagree by exactly the keyboard's
|
|
47
|
-
// height: every detent moved while the sheet it was measuring did not. A
|
|
48
|
-
// keyboard is `useMobileKeyboard`'s business — it holds the sheet still and
|
|
49
|
-
// scrolls the body — and it does not redefine the sheet's detents.
|
|
50
|
-
return SNAP_FRACTIONS.map(fraction => fraction * window.innerHeight);
|
|
66
|
+
return key;
|
|
51
67
|
}
|
|
52
68
|
const styles = {
|
|
53
69
|
sheet: {
|
|
@@ -190,6 +206,7 @@ export function BottomSheetPanel({
|
|
|
190
206
|
state,
|
|
191
207
|
height,
|
|
192
208
|
children,
|
|
209
|
+
snapPoints,
|
|
193
210
|
className,
|
|
194
211
|
style,
|
|
195
212
|
tabIndex,
|
|
@@ -230,6 +247,32 @@ export function BottomSheetPanel({
|
|
|
230
247
|
const isClosing = state.kind === 'exiting';
|
|
231
248
|
const isFading = isRetained && state.motion === 'fading';
|
|
232
249
|
const alignmentOffset = isRetained ? state.alignmentOffset : 0;
|
|
250
|
+
|
|
251
|
+
// Everything derived from the snap points keys off their identity, not the
|
|
252
|
+
// array's: the resolver's identity is the hook's signal that the stops
|
|
253
|
+
// changed, so it must not churn on a re-render the drag caused. The memo
|
|
254
|
+
// reads the points through a ref, so the resolver resolves them at call time
|
|
255
|
+
// — against whatever the viewport is then, not what it was at memo time.
|
|
256
|
+
const snapPointsKey = snapPointsKeyFor(snapPoints);
|
|
257
|
+
const snapPointsRef = useRef(snapPoints);
|
|
258
|
+
snapPointsRef.current = snapPoints;
|
|
259
|
+
const {
|
|
260
|
+
snapHeights,
|
|
261
|
+
ignoredSnapPointsMessage
|
|
262
|
+
} = useMemo(() => {
|
|
263
|
+
if (snapPointsKey === '') {
|
|
264
|
+
return {
|
|
265
|
+
snapHeights: undefined,
|
|
266
|
+
ignoredSnapPointsMessage: ''
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const ignored = (snapPointsRef.current ?? []).filter(point => !isValidSnapPoint(point));
|
|
270
|
+
return {
|
|
271
|
+
snapHeights: () => resolveSnapPoints(snapPointsRef.current ?? [], layoutViewportHeight()),
|
|
272
|
+
ignoredSnapPointsMessage: ignored.length === 0 ? '' : `snapPoints ignored ${JSON.stringify(ignored)}. A snap point is a viewport fraction above 0 and up to 1 (0.5 is half the screen), a px length ('320px'), or a percentage ('50%').`
|
|
273
|
+
};
|
|
274
|
+
}, [snapPointsKey]);
|
|
275
|
+
useDevWarning('BottomSheet', ignoredSnapPointsMessage, ignoredSnapPointsMessage !== '');
|
|
233
276
|
const {
|
|
234
277
|
contentProps,
|
|
235
278
|
handleProps,
|
|
@@ -249,7 +292,7 @@ export function BottomSheetPanel({
|
|
|
249
292
|
canDismiss: isSwipeDismissAllowed,
|
|
250
293
|
offscreenBlockEndInset: OVERSCROLL_PADDING,
|
|
251
294
|
onDismiss,
|
|
252
|
-
snapHeights
|
|
295
|
+
snapHeights,
|
|
253
296
|
onScrimOpacity
|
|
254
297
|
});
|
|
255
298
|
const setElement = useCallback(element => {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @position Component entry point; re-exported by /packages/core/src/index.ts
|
|
6
6
|
*/
|
|
7
7
|
export { BottomSheet } from './BottomSheet';
|
|
8
|
-
export type { BottomSheetHeight, BottomSheetProps } from './BottomSheet';
|
|
8
|
+
export type { BottomSheetHeight, BottomSheetProps, BottomSheetSnapPoint, } from './BottomSheet';
|
|
9
9
|
export { BottomSheetSwitcher } from './BottomSheetSwitcher';
|
|
10
10
|
export type { BottomSheetSwitcherProps } from './BottomSheetSwitcher';
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/index.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC1C,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/index.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC1C,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAC,wBAAwB,EAAC,MAAM,uBAAuB,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file snapOffsets.ts
|
|
3
3
|
* @input Pure geometry helpers — no React, no DOM.
|
|
4
|
-
* @output
|
|
5
|
-
* @position Internal to BottomSheet; consumed by useSheetGestures
|
|
6
|
-
* snapOffsets.test.ts.
|
|
4
|
+
* @output Resolves snap points and converts them to translateY offsets.
|
|
5
|
+
* @position Internal to BottomSheet; consumed by useSheetGestures and
|
|
6
|
+
* BottomSheetPanel, tested by snapOffsets.test.ts.
|
|
7
7
|
*
|
|
8
8
|
* A detent is represented as an offset in px from the fully-open position
|
|
9
9
|
* (0 = fully open, larger = more collapsed). The panel may render that offset
|
|
@@ -11,6 +11,20 @@
|
|
|
11
11
|
* helpers turn snap points into the shared offset list; they are pure so the
|
|
12
12
|
* geometry can be unit-tested without a DOM.
|
|
13
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* A height the sheet can rest at, expressed as the sheet's VISIBLE height:
|
|
16
|
+
*
|
|
17
|
+
* - a number in `(0, 1]` — a fraction of the viewport (`0.5` is half the
|
|
18
|
+
* screen), so the stop tracks rotation and window resizes;
|
|
19
|
+
* - a `'<n>%'` string — the same thing spelled in CSS;
|
|
20
|
+
* - a `'<n>px'` string — an absolute height that does not scale.
|
|
21
|
+
*
|
|
22
|
+
* Anything else — a unitless string, `calc()`, `vh`, `rem`, a number outside
|
|
23
|
+
* `(0, 1]` — is ignored with a dev warning. Percentages resolve against the
|
|
24
|
+
* layout viewport (`window.innerHeight`), the same box the height budgets are
|
|
25
|
+
* written against, so the mobile keyboard never moves a stop.
|
|
26
|
+
*/
|
|
27
|
+
export type BottomSheetSnapPoint = number | string;
|
|
14
28
|
/**
|
|
15
29
|
* Detents whose resting offsets land within this many px of each other are
|
|
16
30
|
* treated as the same stop (the taller one wins). Stops the sheet from having
|
|
@@ -18,8 +32,24 @@
|
|
|
18
32
|
* a hair away from a fractional snap point.
|
|
19
33
|
*/
|
|
20
34
|
export declare const DETENT_DEDUP_PX = 48;
|
|
21
|
-
/**
|
|
22
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Largest share of the fully open sheet the shortest stop may fill and still
|
|
37
|
+
* be a peek. Above it the stop is a working surface — it lays its content out
|
|
38
|
+
* and keeps a full scrim — so a two-stop sheet like `[0.5]` behaves like the
|
|
39
|
+
* half-height panel it asks for rather than like a glance.
|
|
40
|
+
*/
|
|
41
|
+
export declare const PEEK_MAX_HEIGHT_RATIO = 0.25;
|
|
42
|
+
/**
|
|
43
|
+
* Whether a snap point can be resolved at all. The viewport only scales the
|
|
44
|
+
* result, so validity is independent of it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isValidSnapPoint(point: BottomSheetSnapPoint): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve snap points to candidate visible heights in px, dropping the ones
|
|
49
|
+
* this sheet cannot honor. Callers warn about those separately — this stays
|
|
50
|
+
* silent because it runs on every drag frame.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveSnapPoints(points: ReadonlyArray<BottomSheetSnapPoint>, viewportPx: number): number[];
|
|
23
53
|
/**
|
|
24
54
|
* Given the sheet's full height (px, as rendered fully open) and a set of
|
|
25
55
|
* candidate detent *visible heights* (px), return the resting offsets from
|
|
@@ -42,26 +72,33 @@ export declare function nearestOffset(value: number, offsets: ReadonlyArray<numb
|
|
|
42
72
|
*/
|
|
43
73
|
export declare const MIN_PEEK_SCRIM_OPACITY = 0.3;
|
|
44
74
|
/**
|
|
45
|
-
*
|
|
46
|
-
* glance rather than a working surface. A sheet with no collapsed stop at all
|
|
47
|
-
* has no peek — the same rule `scrimOpacityForOffset` thins the scrim by.
|
|
75
|
+
* The peek detent's offset, or `null` when this sheet has no peek.
|
|
48
76
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
77
|
+
* A peek is the shortest stop AND a sliver — at most `PEEK_MAX_HEIGHT_RATIO`
|
|
78
|
+
* of the fully open sheet. It is the one detent the sheet does NOT express as
|
|
79
|
+
* layout height: at a sliver there is nothing useful to lay out, and reflowing
|
|
80
|
+
* the content into it (then back out on the way up) is churn the user sees, so
|
|
81
|
+
* it keeps the full layout height and slides below the viewport instead. It is
|
|
82
|
+
* also the only stop that thins the scrim.
|
|
83
|
+
*
|
|
84
|
+
* A sheet whose shortest stop is a working height — `[0.5]`, say — has no
|
|
85
|
+
* peek: half a screen of content deserves to be laid out at half a screen, and
|
|
86
|
+
* a scrim that thinned there would read as a dismissed sheet.
|
|
53
87
|
*/
|
|
54
|
-
export declare function
|
|
88
|
+
export declare function peekOffsetFor(offsets: ReadonlyArray<number>, visibleSheetHeight: number): number | null;
|
|
55
89
|
/**
|
|
56
90
|
* Scrim opacity (1 = fully visible) for a drag/settle `offset`.
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
91
|
+
*
|
|
92
|
+
* The scrim is full down to the shortest stop that is still a working surface,
|
|
93
|
+
* and only thins past it — onto a peek, where it holds at
|
|
94
|
+
* `MIN_PEEK_SCRIM_OPACITY` (a glance state, and the sheet is still modal), or
|
|
95
|
+
* out through the dismiss overshoot toward `dismissOffset`, where it clears
|
|
96
|
+
* completely because the sheet is leaving.
|
|
97
|
+
*
|
|
98
|
+
* So a sheet whose stops are all working heights keeps a full scrim at every
|
|
99
|
+
* one of them; only the sliver of a peek, or a sheet on its way out, dims less.
|
|
63
100
|
*/
|
|
64
|
-
export declare function scrimOpacityForOffset(offset: number, offsets: ReadonlyArray<number>, dismissOffset: number): number;
|
|
101
|
+
export declare function scrimOpacityForOffset(offset: number, offsets: ReadonlyArray<number>, dismissOffset: number, peekOffset: number | null): number;
|
|
65
102
|
/**
|
|
66
103
|
* Settle target for a released drag. Restricts candidates to the drag
|
|
67
104
|
* direction so a committed drag never snaps *back past* where it started
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapOffsets.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/snapOffsets.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,
|
|
1
|
+
{"version":3,"file":"snapOffsets.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/snapOffsets.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAkC1C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAErE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,CAAC,oBAAoB,CAAC,EAC3C,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CASV;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,EACpC,OAAO,GAAE,MAAwB,GAChC,MAAM,EAAE,CAcV;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAC7B,MAAM,CAKR;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,kBAAkB,EAAE,MAAM,GACzB,MAAM,GAAG,IAAI,CASf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,MAAM,CAgBR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAcR"}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file snapOffsets.ts
|
|
5
5
|
* @input Pure geometry helpers — no React, no DOM.
|
|
6
|
-
* @output
|
|
7
|
-
* @position Internal to BottomSheet; consumed by useSheetGestures
|
|
8
|
-
* snapOffsets.test.ts.
|
|
6
|
+
* @output Resolves snap points and converts them to translateY offsets.
|
|
7
|
+
* @position Internal to BottomSheet; consumed by useSheetGestures and
|
|
8
|
+
* BottomSheetPanel, tested by snapOffsets.test.ts.
|
|
9
9
|
*
|
|
10
10
|
* A detent is represented as an offset in px from the fully-open position
|
|
11
11
|
* (0 = fully open, larger = more collapsed). The panel may render that offset
|
|
@@ -14,6 +14,20 @@
|
|
|
14
14
|
* geometry can be unit-tested without a DOM.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* A height the sheet can rest at, expressed as the sheet's VISIBLE height:
|
|
19
|
+
*
|
|
20
|
+
* - a number in `(0, 1]` — a fraction of the viewport (`0.5` is half the
|
|
21
|
+
* screen), so the stop tracks rotation and window resizes;
|
|
22
|
+
* - a `'<n>%'` string — the same thing spelled in CSS;
|
|
23
|
+
* - a `'<n>px'` string — an absolute height that does not scale.
|
|
24
|
+
*
|
|
25
|
+
* Anything else — a unitless string, `calc()`, `vh`, `rem`, a number outside
|
|
26
|
+
* `(0, 1]` — is ignored with a dev warning. Percentages resolve against the
|
|
27
|
+
* layout viewport (`window.innerHeight`), the same box the height budgets are
|
|
28
|
+
* written against, so the mobile keyboard never moves a stop.
|
|
29
|
+
*/
|
|
30
|
+
|
|
17
31
|
/**
|
|
18
32
|
* Detents whose resting offsets land within this many px of each other are
|
|
19
33
|
* treated as the same stop (the taller one wins). Stops the sheet from having
|
|
@@ -22,9 +36,63 @@
|
|
|
22
36
|
*/
|
|
23
37
|
export const DETENT_DEDUP_PX = 48;
|
|
24
38
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Largest share of the fully open sheet the shortest stop may fill and still
|
|
41
|
+
* be a peek. Above it the stop is a working surface — it lays its content out
|
|
42
|
+
* and keeps a full scrim — so a two-stop sheet like `[0.5]` behaves like the
|
|
43
|
+
* half-height panel it asks for rather than like a glance.
|
|
44
|
+
*/
|
|
45
|
+
export const PEEK_MAX_HEIGHT_RATIO = 0.25;
|
|
46
|
+
|
|
47
|
+
// A snap point string: a positive number with a `px` or `%` unit. Deliberately
|
|
48
|
+
// narrow — every accepted unit has to be resolvable by arithmetic on the
|
|
49
|
+
// viewport height, because this runs inside the drag loop. Units that need the
|
|
50
|
+
// DOM to resolve (`rem`, `em`, `calc()`) would cost a layout per frame.
|
|
51
|
+
const SNAP_POINT_PATTERN = /^(\d+(?:\.\d+)?|\.\d+)(px|%)$/i;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve one snap point to a visible height in px, or `null` when it is not a
|
|
55
|
+
* snap point this sheet can honor.
|
|
56
|
+
*/
|
|
57
|
+
function parseSnapPoint(point, viewportPx) {
|
|
58
|
+
if (typeof point === 'number') {
|
|
59
|
+
// A bare number is a viewport fraction. Anything above 1 is a px value in
|
|
60
|
+
// disguise; the caller warns rather than guessing which was meant.
|
|
61
|
+
return Number.isFinite(point) && point > 0 && point <= 1 ? point * viewportPx : null;
|
|
62
|
+
}
|
|
63
|
+
const match = SNAP_POINT_PATTERN.exec(point.trim());
|
|
64
|
+
if (match === null) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const value = Number.parseFloat(match[1]);
|
|
68
|
+
if (!(value > 0)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return match[2].toLowerCase() === '%' ? value / 100 * viewportPx : value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether a snap point can be resolved at all. The viewport only scales the
|
|
76
|
+
* result, so validity is independent of it.
|
|
77
|
+
*/
|
|
78
|
+
export function isValidSnapPoint(point) {
|
|
79
|
+
return parseSnapPoint(point, 1) !== null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Resolve snap points to candidate visible heights in px, dropping the ones
|
|
84
|
+
* this sheet cannot honor. Callers warn about those separately — this stays
|
|
85
|
+
* silent because it runs on every drag frame.
|
|
86
|
+
*/
|
|
87
|
+
export function resolveSnapPoints(points, viewportPx) {
|
|
88
|
+
const heights = [];
|
|
89
|
+
for (const point of points) {
|
|
90
|
+
const height = parseSnapPoint(point, viewportPx);
|
|
91
|
+
if (height !== null) {
|
|
92
|
+
heights.push(height);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return heights;
|
|
28
96
|
}
|
|
29
97
|
|
|
30
98
|
/**
|
|
@@ -65,38 +133,46 @@ export function nearestOffset(value, offsets) {
|
|
|
65
133
|
export const MIN_PEEK_SCRIM_OPACITY = 0.3;
|
|
66
134
|
|
|
67
135
|
/**
|
|
68
|
-
*
|
|
69
|
-
* glance rather than a working surface. A sheet with no collapsed stop at all
|
|
70
|
-
* has no peek — the same rule `scrimOpacityForOffset` thins the scrim by.
|
|
136
|
+
* The peek detent's offset, or `null` when this sheet has no peek.
|
|
71
137
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
138
|
+
* A peek is the shortest stop AND a sliver — at most `PEEK_MAX_HEIGHT_RATIO`
|
|
139
|
+
* of the fully open sheet. It is the one detent the sheet does NOT express as
|
|
140
|
+
* layout height: at a sliver there is nothing useful to lay out, and reflowing
|
|
141
|
+
* the content into it (then back out on the way up) is churn the user sees, so
|
|
142
|
+
* it keeps the full layout height and slides below the viewport instead. It is
|
|
143
|
+
* also the only stop that thins the scrim.
|
|
144
|
+
*
|
|
145
|
+
* A sheet whose shortest stop is a working height — `[0.5]`, say — has no
|
|
146
|
+
* peek: half a screen of content deserves to be laid out at half a screen, and
|
|
147
|
+
* a scrim that thinned there would read as a dismissed sheet.
|
|
76
148
|
*/
|
|
77
|
-
export function
|
|
78
|
-
if (offsets.length < 2) {
|
|
79
|
-
return
|
|
149
|
+
export function peekOffsetFor(offsets, visibleSheetHeight) {
|
|
150
|
+
if (offsets.length < 2 || visibleSheetHeight <= 0) {
|
|
151
|
+
return null;
|
|
80
152
|
}
|
|
81
|
-
|
|
153
|
+
const shortest = offsets[offsets.length - 1];
|
|
154
|
+
const heightAtShortest = visibleSheetHeight - shortest;
|
|
155
|
+
return heightAtShortest <= PEEK_MAX_HEIGHT_RATIO * visibleSheetHeight ? shortest : null;
|
|
82
156
|
}
|
|
83
157
|
|
|
84
158
|
/**
|
|
85
159
|
* Scrim opacity (1 = fully visible) for a drag/settle `offset`.
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
160
|
+
*
|
|
161
|
+
* The scrim is full down to the shortest stop that is still a working surface,
|
|
162
|
+
* and only thins past it — onto a peek, where it holds at
|
|
163
|
+
* `MIN_PEEK_SCRIM_OPACITY` (a glance state, and the sheet is still modal), or
|
|
164
|
+
* out through the dismiss overshoot toward `dismissOffset`, where it clears
|
|
165
|
+
* completely because the sheet is leaving.
|
|
166
|
+
*
|
|
167
|
+
* So a sheet whose stops are all working heights keeps a full scrim at every
|
|
168
|
+
* one of them; only the sliver of a peek, or a sheet on its way out, dims less.
|
|
92
169
|
*/
|
|
93
|
-
export function scrimOpacityForOffset(offset, offsets, dismissOffset) {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
// dismiss overshoot is a sheet on its way out, so let it clear completely.
|
|
170
|
+
export function scrimOpacityForOffset(offset, offsets, dismissOffset, peekOffset) {
|
|
171
|
+
const hasPeek = peekOffset !== null;
|
|
172
|
+
// The last stop that is still a working surface — the peek's neighbor when
|
|
173
|
+
// there is a peek, otherwise the shortest stop itself.
|
|
174
|
+
const fadeStart = hasPeek ? offsets[offsets.length - 2] : offsets[offsets.length - 1];
|
|
175
|
+
const fadeEnd = hasPeek ? peekOffset : dismissOffset;
|
|
100
176
|
const floor = hasPeek ? MIN_PEEK_SCRIM_OPACITY : 0;
|
|
101
177
|
if (offset <= fadeStart) {
|
|
102
178
|
return 1;
|
|
@@ -15,14 +15,16 @@
|
|
|
15
15
|
* the part the scrolling area gives up as layout height, and the remainder is
|
|
16
16
|
* a transform. Gestures and snaps only ever move the transform, so they stay
|
|
17
17
|
* on the compositor; layout height changes at rest, in one transition-free
|
|
18
|
-
* render whose visible geometry is identical.
|
|
19
|
-
*
|
|
18
|
+
* render whose visible geometry is identical. A peek detent — a stop that is
|
|
19
|
+
* only a sliver of the sheet — keeps the full height and slides below the
|
|
20
|
+
* viewport instead of reflowing to that sliver.
|
|
20
21
|
*
|
|
21
|
-
* Those are pixels, and the
|
|
22
|
-
* sheet at rest re-resolves its detent on `resize` / `orientationchange
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* Those are pixels, and the stops behind them are relative to the viewport, so
|
|
23
|
+
* a sheet at rest re-resolves its detent on `resize` / `orientationchange`,
|
|
24
|
+
* and whenever the host swaps the snap points, and re-anchors to the new
|
|
25
|
+
* geometry without animating. The detent it returns to is tracked by index:
|
|
26
|
+
* the pixels stop meaning the same thing when the viewport changes, the stop
|
|
27
|
+
* the user chose does not.
|
|
26
28
|
*
|
|
27
29
|
* On touch, the scrolling body hands the gesture to the sheet at a scroll
|
|
28
30
|
* edge. Two shapes, because the browser only offers one of them a choice: a
|
|
@@ -70,6 +72,9 @@ export interface UseSheetGesturesOptions {
|
|
|
70
72
|
* (rotation, a resized desktop window, collapsing browser chrome). The fully
|
|
71
73
|
* open height is always the tallest detent. Omit for a single-height sheet
|
|
72
74
|
* (a drag then only dismisses or springs back).
|
|
75
|
+
*
|
|
76
|
+
* Keep the identity stable: a new function is read as new stops, and
|
|
77
|
+
* re-anchors a resting sheet to them.
|
|
73
78
|
*/
|
|
74
79
|
snapHeights?: () => number[];
|
|
75
80
|
/** Notified when the settled visible detent height (px) changes. */
|
|
@@ -153,7 +158,7 @@ export interface UseSheetGesturesResult {
|
|
|
153
158
|
/**
|
|
154
159
|
* How much of `settledOffset` is expressed as layout height rather than as a
|
|
155
160
|
* transform. Equals `settledOffset` at the resizing detents; 0 at fully open
|
|
156
|
-
* and at the peek, which keep the sheet's full height (see
|
|
161
|
+
* and at the peek, which keep the sheet's full height (see peekOffsetFor).
|
|
157
162
|
*/
|
|
158
163
|
settledLayoutOffset: number;
|
|
159
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSheetGestures.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/useSheetGestures.ts"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"useSheetGestures.d.ts","sourceRoot":"","sources":["../../src/BottomSheet/useSheetGestures.ts"],"names":[],"mappings":"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"}
|