@ponti-studios/ui 2.0.1 → 3.0.0
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 +36 -3
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +3 -0
- package/dist/components/data-display/accordion.d.ts +10 -0
- package/dist/components/data-display/accordion.js +53 -0
- package/{src/components/data-display/index.ts → dist/components/data-display/index.d.ts} +1 -10
- package/dist/components/data-display/index.js +8 -0
- package/dist/components/data-display/metric-card.d.ts +9 -0
- package/dist/components/data-display/metric-card.js +25 -0
- package/dist/components/data-display/sort-controls.d.ts +13 -0
- package/dist/components/data-display/sort-controls.js +57 -0
- package/dist/components/data-display/sort-row.d.ts +10 -0
- package/dist/components/data-display/sort-row.js +52 -0
- package/dist/components/data-display/table.d.ts +10 -0
- package/dist/components/data-display/table.js +57 -0
- package/dist/components/feedback/alert.d.ts +9 -0
- package/dist/components/feedback/alert.js +38 -0
- package/dist/components/feedback/empty-state.d.ts +18 -0
- package/dist/components/feedback/empty-state.js +36 -0
- package/{src/components/feedback/index.ts → dist/components/feedback/index.d.ts} +2 -0
- package/dist/components/feedback/index.js +7 -0
- package/dist/components/feedback/progress.d.ts +6 -0
- package/dist/components/feedback/progress.js +25 -0
- package/dist/components/feedback/skeleton.d.ts +2 -0
- package/dist/components/feedback/skeleton.js +11 -0
- package/dist/components/feedback/spinner.d.ts +14 -0
- package/dist/components/feedback/spinner.js +27 -0
- package/dist/components/feedback/update-guard.d.ts +13 -0
- package/dist/components/feedback/update-guard.js +38 -0
- package/dist/components/filters/active-filters-bar.d.ts +14 -0
- package/dist/components/filters/active-filters-bar.js +44 -0
- package/dist/components/filters/filter-chip.d.ts +11 -0
- package/dist/components/filters/filter-chip.js +33 -0
- package/dist/components/filters/filter-select.d.ts +17 -0
- package/dist/components/filters/filter-select.js +46 -0
- package/dist/components/filters/index.js +4 -0
- package/dist/components/forms/checkbox.d.ts +4 -0
- package/dist/components/forms/checkbox.js +24 -0
- package/dist/components/forms/date-month-select.d.ts +11 -0
- package/dist/components/forms/date-month-select.js +47 -0
- package/dist/components/forms/date-picker.d.ts +60 -0
- package/dist/components/forms/date-picker.js +193 -0
- package/dist/components/forms/date-utils.d.ts +14 -0
- package/dist/components/forms/date-utils.js +18 -0
- package/dist/components/forms/drop-zone.d.ts +42 -0
- package/dist/components/forms/drop-zone.js +184 -0
- package/{src/components/forms/index.ts → dist/components/forms/index.d.ts} +3 -9
- package/dist/components/forms/index.js +17 -0
- package/dist/components/forms/input.d.ts +3 -0
- package/dist/components/forms/input.js +15 -0
- package/dist/components/forms/label.d.ts +3 -0
- package/dist/components/forms/label.js +14 -0
- package/dist/components/forms/passkey-management.d.ts +14 -0
- package/dist/components/forms/passkey-management.js +132 -0
- package/dist/components/forms/radio-group.d.ts +6 -0
- package/dist/components/forms/radio-group.js +28 -0
- package/dist/components/forms/select.d.ts +18 -0
- package/dist/components/forms/select.js +103 -0
- package/dist/components/forms/slider.d.ts +9 -0
- package/dist/components/forms/slider.js +25 -0
- package/dist/components/forms/stepper.d.ts +15 -0
- package/dist/components/forms/stepper.js +41 -0
- package/dist/components/forms/switch.d.ts +6 -0
- package/dist/components/forms/switch.js +21 -0
- package/dist/components/forms/text-field.d.ts +15 -0
- package/dist/components/forms/text-field.js +46 -0
- package/dist/components/forms/text-field.types.d.ts +8 -0
- package/dist/components/forms/textarea.d.ts +3 -0
- package/dist/components/forms/textarea.js +14 -0
- package/dist/components/layout/index.js +5 -0
- package/dist/components/layout/particle-background.d.ts +19 -0
- package/dist/components/layout/particle-background.js +171 -0
- package/dist/components/layout/scroll-area.d.ts +9 -0
- package/dist/components/layout/scroll-area.js +35 -0
- package/dist/components/layout/section-intro.d.ts +12 -0
- package/dist/components/layout/section-intro.js +28 -0
- package/dist/components/layout/surface-panel.d.ts +7 -0
- package/dist/components/layout/surface-panel.js +11 -0
- package/dist/components/navigation/app-navigation.d.ts +67 -0
- package/dist/components/navigation/app-navigation.js +106 -0
- package/{src/components/navigation/index.ts → dist/components/navigation/index.d.ts} +1 -7
- package/dist/components/navigation/index.js +4 -0
- package/dist/components/navigation/pagination-controls.d.ts +7 -0
- package/dist/components/navigation/pagination-controls.js +50 -0
- package/dist/components/navigation/tabs.d.ts +7 -0
- package/dist/components/navigation/tabs.js +35 -0
- package/dist/components/overlays/bottom-sheet.d.ts +20 -0
- package/dist/components/overlays/bottom-sheet.js +101 -0
- package/dist/components/overlays/command.d.ts +29 -0
- package/dist/components/overlays/command.js +123 -0
- package/dist/components/overlays/dialog.d.ts +30 -0
- package/dist/components/overlays/dialog.js +105 -0
- package/dist/components/overlays/dropdown-menu.d.ts +29 -0
- package/dist/components/overlays/dropdown-menu.js +128 -0
- package/dist/components/overlays/index.d.ts +7 -0
- package/dist/components/overlays/index.js +8 -0
- package/dist/components/overlays/popover.d.ts +14 -0
- package/dist/components/overlays/popover.js +56 -0
- package/dist/components/overlays/sheet.d.ts +27 -0
- package/dist/components/overlays/sheet.js +81 -0
- package/dist/components/overlays/tooltip.d.ts +10 -0
- package/dist/components/overlays/tooltip.js +23 -0
- package/dist/components/primitives/avatar.d.ts +14 -0
- package/dist/components/primitives/avatar.js +72 -0
- package/dist/components/primitives/badge.d.ts +7 -0
- package/dist/components/primitives/badge.js +27 -0
- package/dist/components/primitives/button.d.ts +13 -0
- package/dist/components/primitives/button.js +113 -0
- package/{src/components/primitives/button.types.ts → dist/components/primitives/button.types.d.ts} +4 -6
- package/dist/components/primitives/card.d.ts +9 -0
- package/dist/components/primitives/card.js +56 -0
- package/{src/components/primitives/index.ts → dist/components/primitives/index.d.ts} +1 -9
- package/dist/components/primitives/index.js +7 -0
- package/dist/components/primitives/segmented-control.d.ts +20 -0
- package/dist/components/primitives/segmented-control.js +27 -0
- package/dist/components/primitives/separator.d.ts +4 -0
- package/dist/components/primitives/separator.js +16 -0
- package/dist/constants/chart-colors.d.ts +33 -0
- package/dist/constants/chart-colors.js +31 -0
- package/dist/hooks/index.js +9 -0
- package/{src/hooks/sort.types.ts → dist/hooks/sort.types.d.ts} +2 -4
- package/dist/hooks/use-api-client.d.ts +30 -0
- package/dist/hooks/use-api-client.js +106 -0
- package/dist/hooks/use-debounced-value.d.ts +1 -0
- package/dist/hooks/use-debounced-value.js +12 -0
- package/dist/hooks/use-derived-filter-state.d.ts +20 -0
- package/dist/hooks/use-derived-filter-state.js +39 -0
- package/dist/hooks/use-filter-state.d.ts +12 -0
- package/dist/hooks/use-filter-state.js +37 -0
- package/dist/hooks/use-media-query.d.ts +6 -0
- package/dist/hooks/use-media-query.js +27 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +14 -0
- package/dist/hooks/use-sort.d.ts +11 -0
- package/dist/hooks/use-sort.js +14 -0
- package/{src/index.ts → dist/index.d.ts} +4 -32
- package/dist/index.js +15 -0
- package/dist/integrations/service-worker.d.ts +2 -0
- package/dist/integrations/service-worker.js +2 -0
- package/dist/lib/auth.d.ts +2 -0
- package/dist/lib/auth.js +7 -0
- package/dist/lib/clipboard.d.ts +1 -0
- package/dist/lib/clipboard.js +10 -0
- package/dist/lib/index.js +4 -0
- package/{src/lib/slot.tsx → dist/lib/slot.d.ts} +2 -15
- package/dist/lib/slot.js +14 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +8 -0
- package/dist/native/components.d.ts +41 -0
- package/dist/native/components.js +135 -0
- package/dist/native/index.js +3 -0
- package/dist/native/theme.d.ts +19 -0
- package/dist/native/theme.js +58 -0
- package/dist/styles/tokens/css-vars.d.ts +7 -0
- package/dist/styles/tokens/css-vars.js +5 -0
- package/dist/styles/tokens/generated/dark.colors.generated.d.ts +40 -0
- package/dist/styles/tokens/generated/dark.colors.generated.js +39 -0
- package/dist/styles/tokens/generated/foundations.generated.d.ts +323 -0
- package/dist/styles/tokens/generated/foundations.generated.js +453 -0
- package/dist/styles/tokens/generated/light.colors.generated.d.ts +40 -0
- package/dist/styles/tokens/generated/light.colors.generated.js +39 -0
- package/dist/styles/tokens/index.d.ts +317 -0
- package/dist/styles/tokens/index.js +14 -0
- package/dist/styles.css +1 -1
- package/dist/translations/en.d.ts +34 -0
- package/dist/translations/index.d.ts +39 -0
- package/dist/translations/ui-provider.d.ts +9 -0
- package/dist/translations/ui-provider.js +16 -0
- package/dist/types/upload.d.ts +36 -0
- package/package.json +50 -33
- package/src/components/data-display/accordion.stories.tsx +0 -57
- package/src/components/data-display/accordion.tsx +0 -86
- package/src/components/data-display/metric-card.stories.tsx +0 -48
- package/src/components/data-display/metric-card.tsx +0 -20
- package/src/components/data-display/sort-controls.stories.tsx +0 -45
- package/src/components/data-display/sort-controls.tsx +0 -96
- package/src/components/data-display/sort-row.tsx +0 -88
- package/src/components/data-display/table.stories.tsx +0 -75
- package/src/components/data-display/table.tsx +0 -80
- package/src/components/feedback/alert.stories.tsx +0 -51
- package/src/components/feedback/alert.tsx +0 -64
- package/src/components/feedback/empty-state.tsx +0 -76
- package/src/components/feedback/progress.stories.tsx +0 -54
- package/src/components/feedback/progress.tsx +0 -41
- package/src/components/feedback/skeleton.stories.tsx +0 -36
- package/src/components/feedback/skeleton.tsx +0 -7
- package/src/components/feedback/spinner.stories.tsx +0 -52
- package/src/components/feedback/spinner.tsx +0 -47
- package/src/components/feedback/update-guard.stories.tsx +0 -28
- package/src/components/feedback/update-guard.tsx +0 -57
- package/src/components/filters/active-filters-bar.stories.tsx +0 -114
- package/src/components/filters/active-filters-bar.tsx +0 -61
- package/src/components/filters/filter-chip.tsx +0 -57
- package/src/components/filters/filter-select.stories.tsx +0 -71
- package/src/components/filters/filter-select.tsx +0 -68
- package/src/components/forms/checkbox.stories.tsx +0 -35
- package/src/components/forms/checkbox.tsx +0 -38
- package/src/components/forms/date-month-select.stories.tsx +0 -26
- package/src/components/forms/date-month-select.tsx +0 -79
- package/src/components/forms/date-picker.stories.tsx +0 -188
- package/src/components/forms/date-picker.tsx +0 -303
- package/src/components/forms/date-utils.ts +0 -37
- package/src/components/forms/drop-zone.stories.tsx +0 -140
- package/src/components/forms/drop-zone.tsx +0 -298
- package/src/components/forms/input.stories.tsx +0 -47
- package/src/components/forms/input.tsx +0 -24
- package/src/components/forms/label.stories.tsx +0 -16
- package/src/components/forms/label.tsx +0 -25
- package/src/components/forms/passkey-management.stories.tsx +0 -85
- package/src/components/forms/passkey-management.tsx +0 -168
- package/src/components/forms/radio-group.stories.tsx +0 -46
- package/src/components/forms/radio-group.tsx +0 -44
- package/src/components/forms/select.stories.tsx +0 -207
- package/src/components/forms/select.tsx +0 -182
- package/src/components/forms/slider.stories.tsx +0 -70
- package/src/components/forms/slider.tsx +0 -50
- package/src/components/forms/stepper.stories.tsx +0 -111
- package/src/components/forms/stepper.tsx +0 -66
- package/src/components/forms/switch.stories.tsx +0 -144
- package/src/components/forms/switch.tsx +0 -39
- package/src/components/forms/text-field.stories.tsx +0 -87
- package/src/components/forms/text-field.tsx +0 -75
- package/src/components/forms/text-field.types.ts +0 -9
- package/src/components/forms/textarea.stories.tsx +0 -150
- package/src/components/forms/textarea.tsx +0 -22
- package/src/components/layout/particle-background.stories.tsx +0 -38
- package/src/components/layout/particle-background.tsx +0 -378
- package/src/components/layout/scroll-area.stories.tsx +0 -91
- package/src/components/layout/scroll-area.tsx +0 -79
- package/src/components/layout/section-intro.stories.tsx +0 -29
- package/src/components/layout/section-intro.tsx +0 -31
- package/src/components/layout/surface-panel.stories.tsx +0 -32
- package/src/components/layout/surface-panel.tsx +0 -23
- package/src/components/navigation/app-navigation.stories.tsx +0 -217
- package/src/components/navigation/app-navigation.tsx +0 -234
- package/src/components/navigation/pagination-controls.stories.tsx +0 -41
- package/src/components/navigation/pagination-controls.tsx +0 -46
- package/src/components/navigation/tabs.stories.tsx +0 -48
- package/src/components/navigation/tabs.tsx +0 -52
- package/src/components/overlays/bottom-sheet.stories.tsx +0 -52
- package/src/components/overlays/bottom-sheet.tsx +0 -179
- package/src/components/overlays/command.stories.tsx +0 -65
- package/src/components/overlays/command.tsx +0 -227
- package/src/components/overlays/dialog.stories.tsx +0 -148
- package/src/components/overlays/dialog.tsx +0 -203
- package/src/components/overlays/dropdown-menu.stories.tsx +0 -74
- package/src/components/overlays/dropdown-menu.tsx +0 -236
- package/src/components/overlays/index.ts +0 -56
- package/src/components/overlays/popover.stories.tsx +0 -51
- package/src/components/overlays/popover.tsx +0 -78
- package/src/components/overlays/sheet.stories.tsx +0 -68
- package/src/components/overlays/sheet.tsx +0 -155
- package/src/components/overlays/tooltip.stories.tsx +0 -29
- package/src/components/overlays/tooltip.tsx +0 -41
- package/src/components/primitives/avatar-placeholder.svg +0 -13
- package/src/components/primitives/avatar.stories.tsx +0 -72
- package/src/components/primitives/avatar.tsx +0 -136
- package/src/components/primitives/badge.stories.tsx +0 -43
- package/src/components/primitives/badge.tsx +0 -43
- package/src/components/primitives/button.stories.tsx +0 -113
- package/src/components/primitives/button.tsx +0 -131
- package/src/components/primitives/card.stories.tsx +0 -59
- package/src/components/primitives/card.tsx +0 -66
- package/src/components/primitives/segmented-control.stories.tsx +0 -54
- package/src/components/primitives/segmented-control.tsx +0 -73
- package/src/components/primitives/separator.stories.tsx +0 -34
- package/src/components/primitives/separator.tsx +0 -27
- package/src/constants/chart-colors.ts +0 -39
- package/src/env.d.ts +0 -9
- package/src/hooks/use-api-client.ts +0 -122
- package/src/hooks/use-debounced-value.ts +0 -12
- package/src/hooks/use-derived-filter-state.ts +0 -70
- package/src/hooks/use-filter-state.ts +0 -66
- package/src/hooks/use-media-query.ts +0 -69
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/hooks/use-sort.ts +0 -20
- package/src/lib/auth.ts +0 -5
- package/src/lib/clipboard.ts +0 -8
- package/src/lib/utils.ts +0 -6
- package/src/native/components.tsx +0 -198
- package/src/native/theme.tsx +0 -69
- package/src/storybook/controls.ts +0 -117
- package/src/storybook/options.ts +0 -52
- package/src/styles/build.ts +0 -1
- package/src/styles/index.css +0 -423
- package/src/styles/nokia.css +0 -36
- package/src/styles/package.css +0 -3
- package/src/styles/tokens/chart-colors.stories.tsx +0 -189
- package/src/styles/tokens/color-systems.stories.tsx +0 -190
- package/src/styles/tokens/css-vars.ts +0 -15
- package/src/styles/tokens/generated/dark-class.css +0 -39
- package/src/styles/tokens/generated/dark.colors.generated.ts +0 -39
- package/src/styles/tokens/generated/dark.css +0 -39
- package/src/styles/tokens/generated/foundations.css +0 -149
- package/src/styles/tokens/generated/foundations.generated.ts +0 -454
- package/src/styles/tokens/generated/light.colors.generated.ts +0 -39
- package/src/styles/tokens/generated/light.css +0 -39
- package/src/styles/tokens/index.ts +0 -70
- package/src/styles/tokens/layout.stories.tsx +0 -50
- package/src/styles/tokens/scripts/check-foundations.mjs +0 -126
- package/src/styles/tokens/scripts/check-source.mjs +0 -53
- package/src/styles/tokens/source/dark.tokens.json +0 -138
- package/src/styles/tokens/source/foundations.tokens.json +0 -344
- package/src/styles/tokens/source/light.tokens.json +0 -138
- package/src/styles/tokens/style-dictionary.dark-class.json +0 -16
- package/src/styles/tokens/style-dictionary.dark-storybook.json +0 -16
- package/src/styles/tokens/style-dictionary.dark.json +0 -21
- package/src/styles/tokens/style-dictionary.foundations.json +0 -21
- package/src/styles/tokens/style-dictionary.light-storybook.json +0 -16
- package/src/styles/tokens/style-dictionary.light.json +0 -21
- package/src/styles/tokens/typography.stories.tsx +0 -157
- package/src/translations/en.ts +0 -34
- package/src/translations/index.ts +0 -32
- package/src/types/upload.ts +0 -42
- /package/{src/components/filters/index.ts → dist/components/filters/index.d.ts} +0 -0
- /package/{src/components/layout/index.ts → dist/components/layout/index.d.ts} +0 -0
- /package/{src/hooks/index.ts → dist/hooks/index.d.ts} +0 -0
- /package/{src/lib/index.ts → dist/lib/index.d.ts} +0 -0
- /package/{src/native/index.ts → dist/native/index.d.ts} +0 -0
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
|
|
7
|
-
// Non-modal persistent bottom panel with drag-to-collapse/expand.
|
|
8
|
-
// Positioning and sizing are app-owned via className (the kit only sets
|
|
9
|
-
// structure + the translateY transform; Tailwind translate utilities compose
|
|
10
|
-
// via the independent CSS `translate` property).
|
|
11
|
-
//
|
|
12
|
-
// Distinct from Sheet: Sheet is a modal dialog; BottomSheet is always
|
|
13
|
-
// mounted chrome (maps, players, detail panels).
|
|
14
|
-
|
|
15
|
-
const FLICK_VELOCITY = 0.4;
|
|
16
|
-
const DRAG_THRESHOLD = 0.25;
|
|
17
|
-
|
|
18
|
-
export type BottomSheetProps = {
|
|
19
|
-
children: React.ReactNode;
|
|
20
|
-
/** Controlled expanded state. */
|
|
21
|
-
expanded?: boolean;
|
|
22
|
-
/** Uncontrolled initial state. @default false */
|
|
23
|
-
defaultExpanded?: boolean;
|
|
24
|
-
onExpandedChange?: (expanded: boolean) => void;
|
|
25
|
-
/** Visible stub height when collapsed. @default 48 */
|
|
26
|
-
peek?: number;
|
|
27
|
-
/** Accessible name for the panel region. @default "Details panel" */
|
|
28
|
-
label?: string;
|
|
29
|
-
/** Positioning/sizing (app-owned). */
|
|
30
|
-
className?: string;
|
|
31
|
-
/** Applied to the scrollable content wrapper alongside its defaults. */
|
|
32
|
-
scrollClassName?: string;
|
|
33
|
-
/** Applied to the drag handle button alongside its defaults. */
|
|
34
|
-
handleClassName?: string;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export function BottomSheet({
|
|
38
|
-
children,
|
|
39
|
-
expanded: controlledExpanded,
|
|
40
|
-
defaultExpanded = false,
|
|
41
|
-
onExpandedChange,
|
|
42
|
-
peek = 48,
|
|
43
|
-
label = "Details panel",
|
|
44
|
-
className,
|
|
45
|
-
scrollClassName,
|
|
46
|
-
handleClassName,
|
|
47
|
-
}: BottomSheetProps) {
|
|
48
|
-
const sheetRef = React.useRef<HTMLElement>(null);
|
|
49
|
-
const [translateY, setTranslateY] = React.useState(0);
|
|
50
|
-
const [dragOffset, setDragOffset] = React.useState(0);
|
|
51
|
-
const [internalExpanded, setInternalExpanded] = React.useState(defaultExpanded);
|
|
52
|
-
const isDragging = React.useRef(false);
|
|
53
|
-
const didDrag = React.useRef(false);
|
|
54
|
-
const dragRef = React.useRef<{ startY: number; startTime: number } | null>(null);
|
|
55
|
-
const reduceMotion = React.useRef(
|
|
56
|
-
typeof window !== "undefined" &&
|
|
57
|
-
window.matchMedia("(prefers-reduced-motion: reduce)").matches,
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const expanded = controlledExpanded ?? internalExpanded;
|
|
61
|
-
|
|
62
|
-
const getHeight = React.useCallback(() => sheetRef.current?.offsetHeight ?? 400, []);
|
|
63
|
-
const closedY = React.useCallback(() => Math.max(0, getHeight() - peek), [getHeight, peek]);
|
|
64
|
-
|
|
65
|
-
const setExpanded = React.useCallback(
|
|
66
|
-
(next: boolean) => {
|
|
67
|
-
onExpandedChange?.(next);
|
|
68
|
-
if (controlledExpanded === undefined) setInternalExpanded(next);
|
|
69
|
-
},
|
|
70
|
-
[controlledExpanded, onExpandedChange],
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const snapTo = React.useCallback((targetY: number) => {
|
|
74
|
-
setTranslateY(targetY);
|
|
75
|
-
setDragOffset(0);
|
|
76
|
-
}, []);
|
|
77
|
-
|
|
78
|
-
// Sync visuals with expanded state (and settle closed on mount).
|
|
79
|
-
React.useEffect(() => {
|
|
80
|
-
snapTo(expanded ? 0 : closedY());
|
|
81
|
-
}, [expanded, closedY, snapTo]);
|
|
82
|
-
|
|
83
|
-
const open = React.useCallback(() => setExpanded(true), [setExpanded]);
|
|
84
|
-
const close = React.useCallback(() => setExpanded(false), [setExpanded]);
|
|
85
|
-
|
|
86
|
-
const onPointerDown = React.useCallback((e: React.PointerEvent) => {
|
|
87
|
-
isDragging.current = true;
|
|
88
|
-
didDrag.current = false;
|
|
89
|
-
dragRef.current = { startY: e.clientY, startTime: Date.now() };
|
|
90
|
-
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
91
|
-
}, []);
|
|
92
|
-
|
|
93
|
-
const onPointerMove = React.useCallback(
|
|
94
|
-
(e: React.PointerEvent) => {
|
|
95
|
-
if (!isDragging.current || !dragRef.current) return;
|
|
96
|
-
const delta = e.clientY - dragRef.current.startY;
|
|
97
|
-
if (Math.abs(delta) > 4) didDrag.current = true;
|
|
98
|
-
setDragOffset(Math.max(-translateY, delta));
|
|
99
|
-
},
|
|
100
|
-
[translateY],
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
const endDrag = React.useCallback(
|
|
104
|
-
(e: React.PointerEvent) => {
|
|
105
|
-
if (!isDragging.current || !dragRef.current) return;
|
|
106
|
-
isDragging.current = false;
|
|
107
|
-
|
|
108
|
-
const delta = e.clientY - dragRef.current.startY;
|
|
109
|
-
const elapsed = Date.now() - dragRef.current.startTime;
|
|
110
|
-
const velocity = elapsed > 0 ? delta / elapsed : 0;
|
|
111
|
-
dragRef.current = null;
|
|
112
|
-
setDragOffset(0);
|
|
113
|
-
|
|
114
|
-
if (didDrag.current) {
|
|
115
|
-
const height = getHeight();
|
|
116
|
-
const newY = Math.max(0, translateY + delta);
|
|
117
|
-
const fraction = height > 0 ? newY / height : 0;
|
|
118
|
-
|
|
119
|
-
if (velocity > FLICK_VELOCITY) close();
|
|
120
|
-
else if (velocity < -FLICK_VELOCITY) open();
|
|
121
|
-
else if (fraction > DRAG_THRESHOLD) close();
|
|
122
|
-
else open();
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
[translateY, getHeight, open, close],
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
const onHandleClick = React.useCallback(() => {
|
|
129
|
-
if (didDrag.current) return;
|
|
130
|
-
if (expanded) close();
|
|
131
|
-
else open();
|
|
132
|
-
}, [expanded, open, close]);
|
|
133
|
-
|
|
134
|
-
const currentY = Math.max(0, translateY + dragOffset);
|
|
135
|
-
|
|
136
|
-
return (
|
|
137
|
-
<section
|
|
138
|
-
ref={sheetRef}
|
|
139
|
-
data-slot="bottom-sheet"
|
|
140
|
-
aria-label={label}
|
|
141
|
-
className={cn("flex touch-none flex-col overflow-hidden", className)}
|
|
142
|
-
style={{
|
|
143
|
-
transform: `translateY(${currentY}px)`,
|
|
144
|
-
transition: isDragging.current
|
|
145
|
-
? "none"
|
|
146
|
-
: reduceMotion.current
|
|
147
|
-
? "none"
|
|
148
|
-
: "transform 0.35s cubic-bezier(0.32, 0.72, 0, 1)",
|
|
149
|
-
}}
|
|
150
|
-
>
|
|
151
|
-
<button
|
|
152
|
-
type="button"
|
|
153
|
-
data-slot="bottom-sheet-handle"
|
|
154
|
-
aria-expanded={expanded}
|
|
155
|
-
aria-label={expanded ? "Collapse panel" : "Expand panel"}
|
|
156
|
-
onPointerDown={onPointerDown}
|
|
157
|
-
onPointerMove={onPointerMove}
|
|
158
|
-
onPointerUp={endDrag}
|
|
159
|
-
onPointerCancel={endDrag}
|
|
160
|
-
onClick={onHandleClick}
|
|
161
|
-
onKeyDown={(e) => {
|
|
162
|
-
if (e.key === "Escape") close();
|
|
163
|
-
}}
|
|
164
|
-
className={cn(
|
|
165
|
-
"flex w-full shrink-0 cursor-grab touch-none justify-center py-3.5 active:cursor-grabbing",
|
|
166
|
-
handleClassName,
|
|
167
|
-
)}
|
|
168
|
-
>
|
|
169
|
-
<span aria-hidden="true" className="bg-border h-1 w-9 rounded-full" />
|
|
170
|
-
</button>
|
|
171
|
-
<div
|
|
172
|
-
data-slot="bottom-sheet-scroll"
|
|
173
|
-
className={cn("flex-1 overflow-y-auto", scrollClassName)}
|
|
174
|
-
>
|
|
175
|
-
{children}
|
|
176
|
-
</div>
|
|
177
|
-
</section>
|
|
178
|
-
);
|
|
179
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { Calculator, Calendar, CreditCard, Settings, Smile, User } from "lucide-react";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
Command,
|
|
6
|
-
CommandEmpty,
|
|
7
|
-
CommandGroup,
|
|
8
|
-
CommandInput,
|
|
9
|
-
CommandItem,
|
|
10
|
-
CommandList,
|
|
11
|
-
CommandSeparator,
|
|
12
|
-
CommandShortcut,
|
|
13
|
-
} from "./command";
|
|
14
|
-
|
|
15
|
-
const meta = {
|
|
16
|
-
title: "Overlays/Command",
|
|
17
|
-
component: Command,
|
|
18
|
-
tags: ["autodocs"],
|
|
19
|
-
} satisfies Meta<typeof Command>;
|
|
20
|
-
|
|
21
|
-
export default meta;
|
|
22
|
-
type Story = StoryObj<typeof meta>;
|
|
23
|
-
|
|
24
|
-
export const Default: Story = {
|
|
25
|
-
render: () => (
|
|
26
|
-
<Command className="w-[450px] rounded-md border">
|
|
27
|
-
<CommandInput placeholder="Type a command or search..." />
|
|
28
|
-
<CommandList>
|
|
29
|
-
<CommandEmpty>No results found.</CommandEmpty>
|
|
30
|
-
<CommandGroup heading="Suggestions">
|
|
31
|
-
<CommandItem>
|
|
32
|
-
<Calendar className="mr-2 size-4" />
|
|
33
|
-
<span>Calendar</span>
|
|
34
|
-
</CommandItem>
|
|
35
|
-
<CommandItem>
|
|
36
|
-
<Smile className="mr-2 size-4" />
|
|
37
|
-
<span>Search Emoji</span>
|
|
38
|
-
</CommandItem>
|
|
39
|
-
<CommandItem>
|
|
40
|
-
<Calculator className="mr-2 size-4" />
|
|
41
|
-
<span>Calculator</span>
|
|
42
|
-
</CommandItem>
|
|
43
|
-
</CommandGroup>
|
|
44
|
-
<CommandSeparator />
|
|
45
|
-
<CommandGroup heading="Settings">
|
|
46
|
-
<CommandItem>
|
|
47
|
-
<User className="mr-2 size-4" />
|
|
48
|
-
<span>Profile</span>
|
|
49
|
-
<CommandShortcut>⌘P</CommandShortcut>
|
|
50
|
-
</CommandItem>
|
|
51
|
-
<CommandItem>
|
|
52
|
-
<CreditCard className="mr-2 size-4" />
|
|
53
|
-
<span>Billing</span>
|
|
54
|
-
<CommandShortcut>⌘B</CommandShortcut>
|
|
55
|
-
</CommandItem>
|
|
56
|
-
<CommandItem>
|
|
57
|
-
<Settings className="mr-2 size-4" />
|
|
58
|
-
<span>Settings</span>
|
|
59
|
-
<CommandShortcut>⌘S</CommandShortcut>
|
|
60
|
-
</CommandItem>
|
|
61
|
-
</CommandGroup>
|
|
62
|
-
</CommandList>
|
|
63
|
-
</Command>
|
|
64
|
-
),
|
|
65
|
-
};
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { Combobox as CommandPrimitive } from "@base-ui/react/combobox";
|
|
2
|
-
import { SearchIcon } from "lucide-react";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "./dialog";
|
|
7
|
-
|
|
8
|
-
function Command({
|
|
9
|
-
className,
|
|
10
|
-
children,
|
|
11
|
-
...props
|
|
12
|
-
}: Omit<React.ComponentProps<typeof CommandPrimitive.Root<string>>, "className"> & {
|
|
13
|
-
className?: string;
|
|
14
|
-
}) {
|
|
15
|
-
return (
|
|
16
|
-
<div
|
|
17
|
-
data-slot="command"
|
|
18
|
-
className={cn(
|
|
19
|
-
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
|
|
20
|
-
className,
|
|
21
|
-
)}
|
|
22
|
-
>
|
|
23
|
-
<CommandPrimitive.Root {...props}>{children}</CommandPrimitive.Root>
|
|
24
|
-
</div>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function CommandDialog({
|
|
29
|
-
title = "Command Palette",
|
|
30
|
-
description = "Search for a command to run...",
|
|
31
|
-
children,
|
|
32
|
-
showCloseButton = true,
|
|
33
|
-
...props
|
|
34
|
-
}: Omit<React.ComponentProps<typeof Dialog>, "children"> & {
|
|
35
|
-
title?: string;
|
|
36
|
-
description?: string;
|
|
37
|
-
showCloseButton?: boolean;
|
|
38
|
-
children?: React.ReactNode;
|
|
39
|
-
}) {
|
|
40
|
-
return (
|
|
41
|
-
<Dialog {...props}>
|
|
42
|
-
<DialogHeader className="sr-only">
|
|
43
|
-
<DialogTitle>{title}</DialogTitle>
|
|
44
|
-
<DialogDescription>{description}</DialogDescription>
|
|
45
|
-
</DialogHeader>
|
|
46
|
-
<DialogContent className="overflow-hidden p-0" showCloseButton={showCloseButton}>
|
|
47
|
-
<Command>{children}</Command>
|
|
48
|
-
</DialogContent>
|
|
49
|
-
</Dialog>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
type CommandInputProps = React.ComponentProps<typeof CommandPrimitive.Input> & {
|
|
54
|
-
onValueChange?: (value: string) => void;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
function CommandInput({
|
|
58
|
-
className,
|
|
59
|
-
onValueChange,
|
|
60
|
-
onChange,
|
|
61
|
-
"aria-label": ariaLabel = "Search commands",
|
|
62
|
-
...props
|
|
63
|
-
}: CommandInputProps) {
|
|
64
|
-
return (
|
|
65
|
-
<div data-slot="command-input-wrapper" className="flex h-9 items-center gap-2 border-b px-3">
|
|
66
|
-
<SearchIcon className="size-4 shrink-0 opacity-50" />
|
|
67
|
-
<CommandPrimitive.Input
|
|
68
|
-
data-slot="command-input"
|
|
69
|
-
aria-label={ariaLabel}
|
|
70
|
-
className={cn(
|
|
71
|
-
"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden",
|
|
72
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
73
|
-
className,
|
|
74
|
-
)}
|
|
75
|
-
onChange={(event) => {
|
|
76
|
-
onChange?.(event);
|
|
77
|
-
onValueChange?.(event.currentTarget.value);
|
|
78
|
-
}}
|
|
79
|
-
{...props}
|
|
80
|
-
/>
|
|
81
|
-
</div>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function CommandList({
|
|
86
|
-
children,
|
|
87
|
-
className,
|
|
88
|
-
...props
|
|
89
|
-
}: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
90
|
-
if (typeof children === "function") {
|
|
91
|
-
return (
|
|
92
|
-
<CommandPrimitive.List
|
|
93
|
-
data-slot="command-list"
|
|
94
|
-
aria-label="Command results"
|
|
95
|
-
tabIndex={0}
|
|
96
|
-
className={cn("max-h-75 scroll-py-1 overflow-x-hidden overflow-y-auto", className)}
|
|
97
|
-
{...props}
|
|
98
|
-
>
|
|
99
|
-
{children}
|
|
100
|
-
</CommandPrimitive.List>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const listChildren: React.ReactNode[] = [];
|
|
105
|
-
const emptyChildren: React.ReactNode[] = [];
|
|
106
|
-
|
|
107
|
-
React.Children.forEach(children, (child) => {
|
|
108
|
-
if (React.isValidElement(child) && child.type === CommandEmpty) emptyChildren.push(child);
|
|
109
|
-
else listChildren.push(child);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<div data-slot="command-list-container" className="relative">
|
|
114
|
-
<CommandPrimitive.List
|
|
115
|
-
data-slot="command-list"
|
|
116
|
-
aria-label="Command results"
|
|
117
|
-
tabIndex={0}
|
|
118
|
-
className={cn("max-h-75 scroll-py-1 overflow-x-hidden overflow-y-auto", className)}
|
|
119
|
-
{...props}
|
|
120
|
-
>
|
|
121
|
-
{listChildren}
|
|
122
|
-
</CommandPrimitive.List>
|
|
123
|
-
{emptyChildren}
|
|
124
|
-
</div>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function CommandEmpty({
|
|
129
|
-
className,
|
|
130
|
-
...props
|
|
131
|
-
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
132
|
-
return (
|
|
133
|
-
<CommandPrimitive.Empty
|
|
134
|
-
data-slot="command-empty"
|
|
135
|
-
className={cn("py-6 text-center text-sm", className)}
|
|
136
|
-
{...props}
|
|
137
|
-
/>
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function CommandGroup({
|
|
142
|
-
className,
|
|
143
|
-
heading,
|
|
144
|
-
children,
|
|
145
|
-
...props
|
|
146
|
-
}: React.ComponentProps<typeof CommandPrimitive.Group> & { heading?: React.ReactNode }) {
|
|
147
|
-
return (
|
|
148
|
-
<CommandPrimitive.Group
|
|
149
|
-
data-slot="command-group"
|
|
150
|
-
className={cn("text-foreground overflow-hidden p-1", className)}
|
|
151
|
-
{...props}
|
|
152
|
-
>
|
|
153
|
-
{heading ? (
|
|
154
|
-
<CommandPrimitive.GroupLabel className="text-muted-foreground px-2 py-1.5 text-xs font-medium">
|
|
155
|
-
{heading}
|
|
156
|
-
</CommandPrimitive.GroupLabel>
|
|
157
|
-
) : null}
|
|
158
|
-
{children}
|
|
159
|
-
</CommandPrimitive.Group>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
type CommandItemProps = React.ComponentProps<typeof CommandPrimitive.Item> & {
|
|
164
|
-
onSelect?: () => void;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
function CommandItem({ className, onSelect, onClick, ...props }: CommandItemProps) {
|
|
168
|
-
return (
|
|
169
|
-
<CommandPrimitive.Item
|
|
170
|
-
data-slot="command-item"
|
|
171
|
-
className={cn(
|
|
172
|
-
"data-highlighted:bg-muted data-highlighted:text-muted-foreground relative flex cursor-pointer items-center gap-3 rounded-md px-3 py-2.5 text-sm outline-hidden select-none",
|
|
173
|
-
"data-disabled:pointer-events-none data-disabled:opacity-50",
|
|
174
|
-
className,
|
|
175
|
-
)}
|
|
176
|
-
onClick={(event) => {
|
|
177
|
-
onClick?.(event);
|
|
178
|
-
onSelect?.();
|
|
179
|
-
}}
|
|
180
|
-
{...props}
|
|
181
|
-
/>
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function CommandSeparator({ className, ...props }: React.ComponentProps<"div">) {
|
|
186
|
-
return (
|
|
187
|
-
<div
|
|
188
|
-
data-slot="command-separator"
|
|
189
|
-
aria-hidden="true"
|
|
190
|
-
className={cn("bg-border -mx-1 h-px", className)}
|
|
191
|
-
{...props}
|
|
192
|
-
/>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function CommandShortcut({ className, ...props }: React.ComponentProps<"span">) {
|
|
197
|
-
return (
|
|
198
|
-
<span
|
|
199
|
-
data-slot="command-shortcut"
|
|
200
|
-
className={cn("text-muted-foreground ml-auto text-xs tracking-widest", className)}
|
|
201
|
-
{...props}
|
|
202
|
-
/>
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function CommandListLoading({ className, ...props }: React.ComponentProps<"div">) {
|
|
207
|
-
return (
|
|
208
|
-
<div
|
|
209
|
-
data-slot="command-list-loading"
|
|
210
|
-
className={cn("py-6 text-center text-sm", className)}
|
|
211
|
-
{...props}
|
|
212
|
-
/>
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export {
|
|
217
|
-
Command,
|
|
218
|
-
CommandDialog,
|
|
219
|
-
CommandEmpty,
|
|
220
|
-
CommandGroup,
|
|
221
|
-
CommandInput,
|
|
222
|
-
CommandItem,
|
|
223
|
-
CommandList,
|
|
224
|
-
CommandListLoading,
|
|
225
|
-
CommandSeparator,
|
|
226
|
-
CommandShortcut,
|
|
227
|
-
};
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
|
|
4
|
-
import { booleanControl, hiddenControl } from "../../storybook/controls";
|
|
5
|
-
import { Button } from "../primitives/button";
|
|
6
|
-
import {
|
|
7
|
-
Dialog,
|
|
8
|
-
DialogClose,
|
|
9
|
-
DialogContent,
|
|
10
|
-
DialogDescription,
|
|
11
|
-
DialogFooter,
|
|
12
|
-
DialogHeader,
|
|
13
|
-
DialogTitle,
|
|
14
|
-
DialogTrigger,
|
|
15
|
-
} from "./dialog";
|
|
16
|
-
|
|
17
|
-
const meta = {
|
|
18
|
-
title: "Overlays/Dialog",
|
|
19
|
-
component: Dialog,
|
|
20
|
-
tags: ["autodocs"],
|
|
21
|
-
argTypes: {
|
|
22
|
-
open: booleanControl("Controls whether the dialog is open", true),
|
|
23
|
-
modal: booleanControl("Whether interaction outside the dialog is disabled when open", true),
|
|
24
|
-
defaultOpen: hiddenControl,
|
|
25
|
-
onOpenChange: hiddenControl,
|
|
26
|
-
},
|
|
27
|
-
} satisfies Meta<typeof Dialog>;
|
|
28
|
-
|
|
29
|
-
export default meta;
|
|
30
|
-
type Story = StoryObj<typeof meta>;
|
|
31
|
-
|
|
32
|
-
function DialogPreview({
|
|
33
|
-
open,
|
|
34
|
-
modal,
|
|
35
|
-
children,
|
|
36
|
-
}: {
|
|
37
|
-
open: boolean;
|
|
38
|
-
modal: boolean;
|
|
39
|
-
children: React.ReactNode;
|
|
40
|
-
}) {
|
|
41
|
-
const [isOpen, setIsOpen] = useState(open);
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
setIsOpen(open);
|
|
45
|
-
}, [open]);
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<Dialog open={isOpen} onOpenChange={setIsOpen} modal={modal}>
|
|
49
|
-
{children}
|
|
50
|
-
</Dialog>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const Default: Story = {
|
|
55
|
-
args: {
|
|
56
|
-
open: true,
|
|
57
|
-
modal: true,
|
|
58
|
-
},
|
|
59
|
-
render: (args) => (
|
|
60
|
-
<DialogPreview open={Boolean(args.open ?? true)} modal={Boolean(args.modal ?? true)}>
|
|
61
|
-
<DialogTrigger asChild>
|
|
62
|
-
<Button variant="outline">Open Dialog</Button>
|
|
63
|
-
</DialogTrigger>
|
|
64
|
-
<DialogContent>
|
|
65
|
-
<DialogHeader>
|
|
66
|
-
<DialogTitle>Edit Profile</DialogTitle>
|
|
67
|
-
<DialogDescription>
|
|
68
|
-
Make changes to your profile here. Click save when you're done.
|
|
69
|
-
</DialogDescription>
|
|
70
|
-
</DialogHeader>
|
|
71
|
-
<div className="grid gap-4 py-4">
|
|
72
|
-
<div className="grid grid-cols-4 items-center gap-4">
|
|
73
|
-
<label htmlFor="name" className="text-right text-sm font-medium">
|
|
74
|
-
Name
|
|
75
|
-
</label>
|
|
76
|
-
<input
|
|
77
|
-
id="name"
|
|
78
|
-
defaultValue="Pedro Duarte"
|
|
79
|
-
className="col-span-3 h-9 rounded-md border px-3 text-sm"
|
|
80
|
-
/>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
<DialogFooter>
|
|
84
|
-
<Button type="submit">Save changes</Button>
|
|
85
|
-
</DialogFooter>
|
|
86
|
-
</DialogContent>
|
|
87
|
-
</DialogPreview>
|
|
88
|
-
),
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export const WithCloseButton: Story = {
|
|
92
|
-
args: {
|
|
93
|
-
open: true,
|
|
94
|
-
modal: true,
|
|
95
|
-
},
|
|
96
|
-
render: (args) => (
|
|
97
|
-
<DialogPreview open={Boolean(args.open ?? true)} modal={Boolean(args.modal ?? true)}>
|
|
98
|
-
<DialogTrigger asChild>
|
|
99
|
-
<Button>Open</Button>
|
|
100
|
-
</DialogTrigger>
|
|
101
|
-
<DialogContent showCloseButton>
|
|
102
|
-
<DialogHeader>
|
|
103
|
-
<DialogTitle>Confirmation</DialogTitle>
|
|
104
|
-
<DialogDescription>Are you sure you want to proceed?</DialogDescription>
|
|
105
|
-
</DialogHeader>
|
|
106
|
-
<DialogFooter>
|
|
107
|
-
<DialogClose asChild>
|
|
108
|
-
<Button>Confirm</Button>
|
|
109
|
-
</DialogClose>
|
|
110
|
-
</DialogFooter>
|
|
111
|
-
</DialogContent>
|
|
112
|
-
</DialogPreview>
|
|
113
|
-
),
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* `alert` swaps in Base UI's AlertDialog primitive: `role="alertdialog"`,
|
|
118
|
-
* forced modal, and no dismiss via outside click or Escape. Use it for
|
|
119
|
-
* confirmations that need explicit acknowledgment (destructive actions,
|
|
120
|
-
* unsaved-changes warnings). The close (X) button is off by default in this
|
|
121
|
-
* mode — dismissal should go through an explicit action.
|
|
122
|
-
*/
|
|
123
|
-
export const Alert: Story = {
|
|
124
|
-
render: () => (
|
|
125
|
-
<Dialog alert>
|
|
126
|
-
<DialogTrigger asChild>
|
|
127
|
-
<Button variant="outline">Delete account</Button>
|
|
128
|
-
</DialogTrigger>
|
|
129
|
-
<DialogContent>
|
|
130
|
-
<DialogHeader>
|
|
131
|
-
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
|
132
|
-
<DialogDescription>
|
|
133
|
-
This action cannot be undone. This will permanently delete your account and remove your
|
|
134
|
-
data from our servers.
|
|
135
|
-
</DialogDescription>
|
|
136
|
-
</DialogHeader>
|
|
137
|
-
<DialogFooter>
|
|
138
|
-
<DialogClose asChild>
|
|
139
|
-
<Button variant="outline">Cancel</Button>
|
|
140
|
-
</DialogClose>
|
|
141
|
-
<DialogClose asChild>
|
|
142
|
-
<Button>Continue</Button>
|
|
143
|
-
</DialogClose>
|
|
144
|
-
</DialogFooter>
|
|
145
|
-
</DialogContent>
|
|
146
|
-
</Dialog>
|
|
147
|
-
),
|
|
148
|
-
};
|