@sixthshift/design-system 0.5.0 → 0.6.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 +132 -87
- package/dist/components/Badge/Badge.d.ts +2 -2
- package/dist/components/Badge/Badge.js +2 -2
- package/dist/components/Button/Button.d.ts +1 -1
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Calendar/Calendar.d.ts.map +1 -1
- package/dist/components/Calendar/Calendar.js +1 -0
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Calendar/CalendarView.d.ts +0 -11
- package/dist/components/Calendar/CalendarView.d.ts.map +1 -1
- package/dist/components/Calendar/CalendarView.js +1 -0
- package/dist/components/Calendar/CalendarView.js.map +1 -1
- package/dist/components/Calendar/calendar.hooks.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.hooks.js +1 -0
- package/dist/components/Calendar/calendar.hooks.js.map +1 -1
- package/dist/components/Card/Card.d.ts +2 -2
- package/dist/components/Card/Card.d.ts.map +1 -1
- package/dist/components/Card/Card.js +3 -2
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.js +1 -0
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.js +1 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.js.map +1 -1
- package/dist/components/Code/Editor/Editor.d.ts.map +1 -1
- package/dist/components/Code/Editor/Editor.js +1 -0
- package/dist/components/Code/Editor/Editor.js.map +1 -1
- package/dist/components/Code/Workspace/StatusBar.d.ts.map +1 -1
- package/dist/components/Code/Workspace/StatusBar.js +1 -0
- package/dist/components/Code/Workspace/StatusBar.js.map +1 -1
- package/dist/components/Code/Workspace/Toolbar.d.ts.map +1 -1
- package/dist/components/Code/Workspace/Toolbar.js +1 -0
- package/dist/components/Code/Workspace/Toolbar.js.map +1 -1
- package/dist/components/Code/Workspace/Workspace.d.ts.map +1 -1
- package/dist/components/Code/Workspace/Workspace.js +1 -0
- package/dist/components/Code/Workspace/Workspace.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts.map +1 -1
- package/dist/components/DatePicker/DatePicker.js +5 -0
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DatePicker/DateSegments.d.ts.map +1 -1
- package/dist/components/DatePicker/DateSegments.js +1 -0
- package/dist/components/DatePicker/DateSegments.js.map +1 -1
- package/dist/components/DatePicker/datepicker.hooks.d.ts.map +1 -1
- package/dist/components/DatePicker/datepicker.hooks.js +1 -0
- package/dist/components/DatePicker/datepicker.hooks.js.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.d.ts.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.js +1 -0
- package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.js +5 -0
- package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimeSegments.d.ts.map +1 -1
- package/dist/components/DateTimePicker/DateTimeSegments.js +1 -0
- package/dist/components/DateTimePicker/DateTimeSegments.js.map +1 -1
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.d.ts.map +1 -1
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.js +5 -0
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.js.map +1 -1
- package/dist/components/FormField/FormField.d.ts +31 -10
- package/dist/components/FormField/FormField.d.ts.map +1 -1
- package/dist/components/FormField/FormField.js +46 -17
- package/dist/components/FormField/FormField.js.map +1 -1
- package/dist/components/FormField/index.d.ts +2 -2
- package/dist/components/FormField/index.d.ts.map +1 -1
- package/dist/components/FormField/index.js +1 -1
- package/dist/components/FormField/index.js.map +1 -1
- package/dist/components/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/components/HoverCard/HoverCard.js +1 -0
- package/dist/components/HoverCard/HoverCard.js.map +1 -1
- package/dist/components/HoverCard/components/HoverCardContent.d.ts.map +1 -1
- package/dist/components/HoverCard/components/HoverCardContent.js +1 -0
- package/dist/components/HoverCard/components/HoverCardContent.js.map +1 -1
- package/dist/components/HoverCard/components/HoverCardContext.d.ts.map +1 -1
- package/dist/components/HoverCard/components/HoverCardContext.js +1 -0
- package/dist/components/HoverCard/components/HoverCardContext.js.map +1 -1
- package/dist/components/HoverCard/components/HoverCardTrigger.d.ts.map +1 -1
- package/dist/components/HoverCard/components/HoverCardTrigger.js +1 -0
- package/dist/components/HoverCard/components/HoverCardTrigger.js.map +1 -1
- package/dist/components/Message/Message.d.ts +1 -1
- package/dist/components/Message/Message.js +1 -1
- package/dist/components/Modal/Modal.d.ts +14 -9
- package/dist/components/Modal/Modal.d.ts.map +1 -1
- package/dist/components/Modal/Modal.js +42 -20
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/Modal/components/ModalContext.d.ts.map +1 -1
- package/dist/components/Modal/components/ModalContext.js +1 -0
- package/dist/components/Modal/components/ModalContext.js.map +1 -1
- package/dist/components/Modal/components/ModalHeader.d.ts.map +1 -1
- package/dist/components/Modal/components/ModalHeader.js +1 -0
- package/dist/components/Modal/components/ModalHeader.js.map +1 -1
- package/dist/components/Popover/Popover.d.ts.map +1 -1
- package/dist/components/Popover/Popover.js +5 -0
- package/dist/components/Popover/Popover.js.map +1 -1
- package/dist/components/Popover/components/PopoverBody.d.ts.map +1 -1
- package/dist/components/Popover/components/PopoverBody.js +1 -0
- package/dist/components/Popover/components/PopoverBody.js.map +1 -1
- package/dist/components/Popover/components/PopoverClose.d.ts.map +1 -1
- package/dist/components/Popover/components/PopoverClose.js +1 -0
- package/dist/components/Popover/components/PopoverClose.js.map +1 -1
- package/dist/components/Popover/components/PopoverContext.d.ts.map +1 -1
- package/dist/components/Popover/components/PopoverContext.js +1 -0
- package/dist/components/Popover/components/PopoverContext.js.map +1 -1
- package/dist/components/Popover/components/PopoverTrigger.d.ts.map +1 -1
- package/dist/components/Popover/components/PopoverTrigger.js +1 -0
- package/dist/components/Popover/components/PopoverTrigger.js.map +1 -1
- package/dist/components/RadioButton/RadioButton.d.ts.map +1 -1
- package/dist/components/RadioButton/RadioButton.js +1 -0
- package/dist/components/RadioButton/RadioButton.js.map +1 -1
- package/dist/components/RadioButtonGroup/RadioButtonGroup.d.ts.map +1 -1
- package/dist/components/RadioButtonGroup/RadioButtonGroup.js +1 -0
- package/dist/components/RadioButtonGroup/RadioButtonGroup.js.map +1 -1
- package/dist/components/SearchInput/SearchInput.d.ts +10 -7
- package/dist/components/SearchInput/SearchInput.d.ts.map +1 -1
- package/dist/components/SearchInput/SearchInput.js +11 -6
- package/dist/components/SearchInput/SearchInput.js.map +1 -1
- package/dist/components/Select/Select.d.ts +6 -0
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +9 -3
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectDropdown.d.ts.map +1 -1
- package/dist/components/Select/SelectDropdown.js +1 -0
- package/dist/components/Select/SelectDropdown.js.map +1 -1
- package/dist/components/Select/SelectTrigger.d.ts.map +1 -1
- package/dist/components/Select/SelectTrigger.js +5 -1
- package/dist/components/Select/SelectTrigger.js.map +1 -1
- package/dist/components/Select/useSelectKeyboard.d.ts.map +1 -1
- package/dist/components/Select/useSelectKeyboard.js +1 -0
- package/dist/components/Select/useSelectKeyboard.js.map +1 -1
- package/dist/components/Sheet/Sheet.d.ts.map +1 -1
- package/dist/components/Sheet/Sheet.js +23 -9
- package/dist/components/Sheet/Sheet.js.map +1 -1
- package/dist/components/Sheet/components/SheetContext.d.ts.map +1 -1
- package/dist/components/Sheet/components/SheetContext.js +1 -0
- package/dist/components/Sheet/components/SheetContext.js.map +1 -1
- package/dist/components/Sheet/components/SheetHeader.d.ts.map +1 -1
- package/dist/components/Sheet/components/SheetHeader.js +1 -0
- package/dist/components/Sheet/components/SheetHeader.js.map +1 -1
- package/dist/components/Spinner/Spinner.d.ts +2 -2
- package/dist/components/Spinner/Spinner.js +2 -2
- package/dist/components/Switch/Switch.d.ts.map +1 -1
- package/dist/components/Switch/Switch.js +1 -0
- package/dist/components/Switch/Switch.js.map +1 -1
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/Tabs.js +1 -0
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tabs/components/TabsContext.d.ts.map +1 -1
- package/dist/components/Tabs/components/TabsContext.js +1 -0
- package/dist/components/Tabs/components/TabsContext.js.map +1 -1
- package/dist/components/Tabs/components/TabsList.d.ts.map +1 -1
- package/dist/components/Tabs/components/TabsList.js +1 -0
- package/dist/components/Tabs/components/TabsList.js.map +1 -1
- package/dist/components/Tabs/components/TabsPanels.d.ts.map +1 -1
- package/dist/components/Tabs/components/TabsPanels.js +1 -0
- package/dist/components/Tabs/components/TabsPanels.js.map +1 -1
- package/dist/components/Tabs/components/TabsTrigger.d.ts.map +1 -1
- package/dist/components/Tabs/components/TabsTrigger.js +2 -1
- package/dist/components/Tabs/components/TabsTrigger.js.map +1 -1
- package/dist/components/TagChip/TagChip.d.ts.map +1 -1
- package/dist/components/TagChip/TagChip.js +1 -0
- package/dist/components/TagChip/TagChip.js.map +1 -1
- package/dist/components/TagInput/TagInput.d.ts +8 -2
- package/dist/components/TagInput/TagInput.d.ts.map +1 -1
- package/dist/components/TagInput/TagInput.js +8 -5
- package/dist/components/TagInput/TagInput.js.map +1 -1
- package/dist/components/Textarea/Textarea.d.ts +21 -5
- package/dist/components/Textarea/Textarea.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.js +31 -5
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/TimePicker/PeriodSelector.d.ts.map +1 -1
- package/dist/components/TimePicker/PeriodSelector.js +1 -0
- package/dist/components/TimePicker/PeriodSelector.js.map +1 -1
- package/dist/components/TimePicker/TimeColumn.d.ts.map +1 -1
- package/dist/components/TimePicker/TimeColumn.js +1 -0
- package/dist/components/TimePicker/TimeColumn.js.map +1 -1
- package/dist/components/TimePicker/TimePicker.d.ts.map +1 -1
- package/dist/components/TimePicker/TimePicker.js +5 -0
- package/dist/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/TimePicker/TimeSegments.d.ts.map +1 -1
- package/dist/components/TimePicker/TimeSegments.js +1 -0
- package/dist/components/TimePicker/TimeSegments.js.map +1 -1
- package/dist/components/Toast/Toast.d.ts +16 -2
- package/dist/components/Toast/Toast.d.ts.map +1 -1
- package/dist/components/Toast/Toast.js +16 -6
- package/dist/components/Toast/Toast.js.map +1 -1
- package/dist/components/Toggle/Toggle.d.ts +1 -1
- package/dist/components/Toggle/Toggle.d.ts.map +1 -1
- package/dist/components/Toggle/Toggle.js +2 -1
- package/dist/components/Toggle/Toggle.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupMultiple.d.ts +2 -0
- package/dist/components/ToggleGroup/ToggleGroupMultiple.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupMultiple.js +4 -3
- package/dist/components/ToggleGroup/ToggleGroupMultiple.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupSingle.d.ts +2 -0
- package/dist/components/ToggleGroup/ToggleGroupSingle.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupSingle.js +4 -3
- package/dist/components/ToggleGroup/ToggleGroupSingle.js.map +1 -1
- package/dist/components/ToggleGroup/toggleGroup.types.d.ts +7 -0
- package/dist/components/ToggleGroup/toggleGroup.types.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +1 -0
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/Tooltip/components/TooltipBody.d.ts.map +1 -1
- package/dist/components/Tooltip/components/TooltipBody.js +1 -0
- package/dist/components/Tooltip/components/TooltipBody.js.map +1 -1
- package/dist/components/Tooltip/components/TooltipContext.d.ts.map +1 -1
- package/dist/components/Tooltip/components/TooltipContext.js +1 -0
- package/dist/components/Tooltip/components/TooltipContext.js.map +1 -1
- package/dist/components/Tooltip/components/TooltipTrigger.d.ts.map +1 -1
- package/dist/components/Tooltip/components/TooltipTrigger.js +1 -0
- package/dist/components/Tooltip/components/TooltipTrigger.js.map +1 -1
- package/dist/hooks/useCollapsible.d.ts.map +1 -1
- package/dist/hooks/useCollapsible.js +1 -0
- package/dist/hooks/useCollapsible.js.map +1 -1
- package/dist/hooks/useControllableState.d.ts.map +1 -1
- package/dist/hooks/useControllableState.js +1 -0
- package/dist/hooks/useControllableState.js.map +1 -1
- package/dist/hooks/useDebouncedCallback.d.ts.map +1 -1
- package/dist/hooks/useDebouncedCallback.js +1 -0
- package/dist/hooks/useDebouncedCallback.js.map +1 -1
- package/dist/hooks/useDebouncedState.d.ts.map +1 -1
- package/dist/hooks/useDebouncedState.js +1 -0
- package/dist/hooks/useDebouncedState.js.map +1 -1
- package/dist/hooks/useDeviceFormFactor.d.ts.map +1 -1
- package/dist/hooks/useDeviceFormFactor.js +1 -0
- package/dist/hooks/useDeviceFormFactor.js.map +1 -1
- package/dist/hooks/useLocalStorage.d.ts.map +1 -1
- package/dist/hooks/useLocalStorage.js +1 -0
- package/dist/hooks/useLocalStorage.js.map +1 -1
- package/dist/hooks/useMergedFloatingRef.d.ts.map +1 -1
- package/dist/hooks/useMergedFloatingRef.js +1 -0
- package/dist/hooks/useMergedFloatingRef.js.map +1 -1
- package/dist/hooks/usePresence.d.ts.map +1 -1
- package/dist/hooks/usePresence.js +1 -0
- package/dist/hooks/usePresence.js.map +1 -1
- package/dist/hooks/useStack.d.ts.map +1 -1
- package/dist/hooks/useStack.js +34 -10
- package/dist/hooks/useStack.js.map +1 -1
- package/dist/hooks/useTheme.d.ts.map +1 -1
- package/dist/hooks/useTheme.js +1 -0
- package/dist/hooks/useTheme.js.map +1 -1
- package/dist/internal/PickerField.d.ts.map +1 -1
- package/dist/internal/PickerField.js +1 -0
- package/dist/internal/PickerField.js.map +1 -1
- package/dist/internal/SegmentedField.d.ts.map +1 -1
- package/dist/internal/SegmentedField.js +1 -0
- package/dist/internal/SegmentedField.js.map +1 -1
- package/dist/internal/escapeLayers.d.ts +12 -0
- package/dist/internal/escapeLayers.d.ts.map +1 -0
- package/dist/internal/escapeLayers.js +48 -0
- package/dist/internal/escapeLayers.js.map +1 -0
- package/dist/lib/ErrorBoundary.d.ts.map +1 -1
- package/dist/lib/ErrorBoundary.js +1 -0
- package/dist/lib/ErrorBoundary.js.map +1 -1
- package/dist/lib/contexts/ComponentsContext/ComponentsContext.d.ts.map +1 -1
- package/dist/lib/contexts/ComponentsContext/ComponentsContext.js +1 -0
- package/dist/lib/contexts/ComponentsContext/ComponentsContext.js.map +1 -1
- package/dist/lib/contexts/OverlayContext/OverlayContext.d.ts +9 -4
- package/dist/lib/contexts/OverlayContext/OverlayContext.d.ts.map +1 -1
- package/dist/lib/contexts/OverlayContext/OverlayContext.js +25 -12
- package/dist/lib/contexts/OverlayContext/OverlayContext.js.map +1 -1
- package/dist/lib/contexts/OverlayContext/ToastStack.d.ts +20 -0
- package/dist/lib/contexts/OverlayContext/ToastStack.d.ts.map +1 -0
- package/dist/lib/contexts/OverlayContext/ToastStack.js +45 -0
- package/dist/lib/contexts/OverlayContext/ToastStack.js.map +1 -0
- package/dist/lib/contexts/OverlayContext/hooks/useModal.d.ts.map +1 -1
- package/dist/lib/contexts/OverlayContext/hooks/useModal.js +1 -0
- package/dist/lib/contexts/OverlayContext/hooks/useModal.js.map +1 -1
- package/dist/lib/contexts/OverlayContext/hooks/useToast.d.ts +27 -10
- package/dist/lib/contexts/OverlayContext/hooks/useToast.d.ts.map +1 -1
- package/dist/lib/contexts/OverlayContext/hooks/useToast.js +31 -49
- package/dist/lib/contexts/OverlayContext/hooks/useToast.js.map +1 -1
- package/dist/lib/contexts/OverlayContext/index.d.ts +2 -0
- package/dist/lib/contexts/OverlayContext/index.d.ts.map +1 -1
- package/dist/lib/contexts/OverlayContext/index.js +2 -0
- package/dist/lib/contexts/OverlayContext/index.js.map +1 -1
- package/dist/lib/contexts/OverlayContext/toastStore.d.ts +68 -0
- package/dist/lib/contexts/OverlayContext/toastStore.d.ts.map +1 -0
- package/dist/lib/contexts/OverlayContext/toastStore.js +69 -0
- package/dist/lib/contexts/OverlayContext/toastStore.js.map +1 -0
- package/dist/lib/withErrorBoundary.d.ts.map +1 -1
- package/dist/lib/withErrorBoundary.js +1 -0
- package/dist/lib/withErrorBoundary.js.map +1 -1
- package/dist/lib/withSuspenseAndErrorBoundary.d.ts.map +1 -1
- package/dist/lib/withSuspenseAndErrorBoundary.js +1 -0
- package/dist/lib/withSuspenseAndErrorBoundary.js.map +1 -1
- package/dist/{theme/schema.d.ts → theming/vocabulary.d.ts} +4 -4
- package/dist/theming/vocabulary.d.ts.map +1 -0
- package/dist/{theme/schema.js → theming/vocabulary.js} +4 -4
- package/dist/theming/vocabulary.js.map +1 -0
- package/package.json +18 -6
- package/src/components/Badge/Badge.tsx +2 -2
- package/src/components/Button/Button.tsx +1 -1
- package/src/{theme/recipes/button.css → components/Button/button.recipe.css} +2 -2
- package/src/components/Calendar/Calendar.tsx +2 -0
- package/src/components/Calendar/CalendarView.tsx +2 -0
- package/src/components/Calendar/calendar.hooks.ts +2 -0
- package/src/components/Card/Card.tsx +4 -2
- package/src/components/Checkbox/Checkbox.tsx +2 -0
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +2 -0
- package/src/components/Code/Editor/Editor.tsx +2 -0
- package/src/components/Code/Workspace/StatusBar.tsx +2 -0
- package/src/components/Code/Workspace/Toolbar.tsx +2 -0
- package/src/components/Code/Workspace/Workspace.tsx +2 -0
- package/src/components/DatePicker/DatePicker.tsx +7 -0
- package/src/components/DatePicker/DateSegments.tsx +2 -0
- package/src/components/DatePicker/datepicker.hooks.ts +2 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +2 -0
- package/src/components/DateTimePicker/DateTimePicker.tsx +7 -1
- package/src/components/DateTimePicker/DateTimeSegments.tsx +2 -0
- package/src/components/DateTimeRangePicker/DateTimeRangePicker.tsx +7 -1
- package/src/components/FormField/FormField.tsx +94 -42
- package/src/components/FormField/index.ts +2 -2
- package/src/components/HoverCard/HoverCard.tsx +2 -0
- package/src/components/HoverCard/components/HoverCardContent.tsx +2 -0
- package/src/components/HoverCard/components/HoverCardContext.tsx +2 -0
- package/src/components/HoverCard/components/HoverCardTrigger.tsx +2 -0
- package/src/components/Message/Message.tsx +1 -1
- package/src/components/Modal/Modal.tsx +77 -51
- package/src/components/Modal/components/ModalContext.tsx +2 -0
- package/src/components/Modal/components/ModalHeader.tsx +2 -0
- package/src/components/Popover/Popover.tsx +7 -0
- package/src/components/Popover/components/PopoverBody.tsx +2 -0
- package/src/components/Popover/components/PopoverClose.tsx +2 -0
- package/src/components/Popover/components/PopoverContext.tsx +2 -0
- package/src/components/Popover/components/PopoverTrigger.tsx +2 -0
- package/src/components/RadioButton/RadioButton.tsx +2 -0
- package/src/components/RadioButtonGroup/RadioButtonGroup.tsx +2 -0
- package/src/components/SearchInput/SearchInput.tsx +15 -8
- package/src/components/Select/Select.tsx +24 -1
- package/src/components/Select/SelectDropdown.tsx +2 -0
- package/src/components/Select/SelectTrigger.tsx +5 -0
- package/src/components/Select/useSelectKeyboard.ts +2 -0
- package/src/components/Sheet/Sheet.tsx +49 -34
- package/src/components/Sheet/components/SheetContext.tsx +2 -0
- package/src/components/Sheet/components/SheetHeader.tsx +2 -0
- package/src/components/Spinner/Spinner.tsx +2 -2
- package/src/components/Switch/Switch.tsx +2 -0
- package/src/components/Tabs/Tabs.tsx +2 -0
- package/src/components/Tabs/components/TabsContext.tsx +2 -0
- package/src/components/Tabs/components/TabsList.tsx +2 -0
- package/src/components/Tabs/components/TabsPanels.tsx +2 -0
- package/src/components/Tabs/components/TabsTrigger.tsx +3 -1
- package/src/{theme/recipes/tabs.css → components/Tabs/tabs.recipe.css} +1 -1
- package/src/components/TagChip/TagChip.tsx +2 -0
- package/src/components/TagInput/TagInput.tsx +15 -6
- package/src/components/Textarea/Textarea.tsx +42 -6
- package/src/{theme/recipes/textarea.css → components/Textarea/textarea.recipe.css} +1 -1
- package/src/components/TimePicker/PeriodSelector.tsx +2 -0
- package/src/components/TimePicker/TimeColumn.tsx +2 -0
- package/src/components/TimePicker/TimePicker.tsx +7 -0
- package/src/components/TimePicker/TimeSegments.tsx +2 -0
- package/src/components/Toast/Toast.tsx +22 -6
- package/src/components/Toggle/Toggle.tsx +3 -1
- package/src/components/ToggleGroup/ToggleGroupMultiple.tsx +6 -0
- package/src/components/ToggleGroup/ToggleGroupSingle.tsx +6 -0
- package/src/components/ToggleGroup/toggleGroup.types.ts +7 -0
- package/src/components/Tooltip/Tooltip.tsx +2 -0
- package/src/components/Tooltip/components/TooltipBody.tsx +2 -0
- package/src/components/Tooltip/components/TooltipContext.tsx +2 -0
- package/src/components/Tooltip/components/TooltipTrigger.tsx +2 -0
- package/src/hooks/useCollapsible.ts +2 -0
- package/src/hooks/useControllableState.ts +2 -0
- package/src/hooks/useDebouncedCallback.ts +2 -0
- package/src/hooks/useDebouncedState.ts +2 -0
- package/src/hooks/useDeviceFormFactor.ts +2 -0
- package/src/hooks/useLocalStorage.ts +2 -0
- package/src/hooks/useMergedFloatingRef.ts +2 -0
- package/src/hooks/usePresence.ts +2 -0
- package/src/hooks/useStack.ts +35 -12
- package/src/hooks/useTheme.ts +2 -0
- package/src/internal/PickerField.tsx +2 -0
- package/src/internal/SegmentedField.tsx +2 -0
- package/src/internal/escapeLayers.ts +53 -0
- package/src/lib/ErrorBoundary.tsx +2 -0
- package/src/lib/contexts/ComponentsContext/ComponentsContext.tsx +2 -0
- package/src/lib/contexts/OverlayContext/OverlayContext.tsx +42 -26
- package/src/lib/contexts/OverlayContext/ToastStack.tsx +71 -0
- package/src/lib/contexts/OverlayContext/hooks/useModal.tsx +2 -0
- package/src/lib/contexts/OverlayContext/hooks/useToast.ts +30 -73
- package/src/lib/contexts/OverlayContext/index.ts +2 -0
- package/src/lib/contexts/OverlayContext/toastStore.ts +138 -0
- package/src/lib/withErrorBoundary.tsx +2 -0
- package/src/lib/withSuspenseAndErrorBoundary.tsx +2 -0
- package/src/theme/linen/index.css +11 -0
- package/src/theme/linen/palette.css +87 -0
- package/src/theme/linen/theme.css +371 -0
- package/src/theming/tailwind.css +356 -0
- package/src/{theme/schema.ts → theming/vocabulary.ts} +3 -3
- package/dist/theme/index.d.ts +0 -9
- package/dist/theme/index.d.ts.map +0 -1
- package/dist/theme/index.js +0 -8
- package/dist/theme/index.js.map +0 -1
- package/dist/theme/schema.d.ts.map +0 -1
- package/dist/theme/schema.js.map +0 -1
- package/src/theme/index.ts +0 -39
- package/src/theme/recipes/index.css +0 -28
- package/src/theme/tokens.css +0 -824
- /package/src/{theme/recipes/badge.css → components/Badge/badge.recipe.css} +0 -0
- /package/src/{theme/recipes/card.css → components/Card/card.recipe.css} +0 -0
- /package/src/{theme/recipes/checkbox.css → components/Checkbox/checkbox.recipe.css} +0 -0
- /package/src/{theme/recipes/field.css → components/Field/field.recipe.css} +0 -0
- /package/src/{theme/recipes/input.css → components/Input/input.recipe.css} +0 -0
- /package/src/{theme/recipes/message.css → components/Message/message.recipe.css} +0 -0
- /package/src/{theme/recipes/modal.css → components/Modal/modal.recipe.css} +0 -0
- /package/src/{theme/recipes/radio-button.css → components/RadioButton/radio-button.recipe.css} +0 -0
- /package/src/{theme/recipes/search-input.css → components/SearchInput/search-input.recipe.css} +0 -0
- /package/src/{theme/recipes/select.css → components/Select/select.recipe.css} +0 -0
- /package/src/{theme/recipes/sheet.css → components/Sheet/sheet.recipe.css} +0 -0
- /package/src/{theme/recipes/spinner.css → components/Spinner/spinner.recipe.css} +0 -0
- /package/src/{theme/recipes/switch.css → components/Switch/switch.recipe.css} +0 -0
- /package/src/{theme/recipes/tag-chip.css → components/TagChip/tag-chip.recipe.css} +0 -0
- /package/src/{theme/recipes/toggle.css → components/Toggle/toggle.recipe.css} +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { FloatingPortal, type FloatingPortalProps } from "@floating-ui/react";
|
|
2
4
|
import { Button } from "@sixthshift/design-system/button";
|
|
3
5
|
import { usePresence } from "@sixthshift/design-system/hooks";
|
|
@@ -19,6 +21,13 @@ export type ToastProps = Omit<MessageProps, "size"> & {
|
|
|
19
21
|
onAction?: () => void;
|
|
20
22
|
/** Portal root element (default: document.body) */
|
|
21
23
|
root?: FloatingPortalProps["root"];
|
|
24
|
+
/**
|
|
25
|
+
* Set to `false` to play the exit animation and then call `onClose`. This is
|
|
26
|
+
* how a stack dismisses a toast on a timer: the toast stays mounted through
|
|
27
|
+
* its fade-out, and the stack drops it when `onClose` fires.
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
open?: boolean;
|
|
22
31
|
/**
|
|
23
32
|
* Whether Toast should render in a portal and position itself.
|
|
24
33
|
* Set to false when Toast is rendered by a parent that handles positioning (e.g., OverlayContext).
|
|
@@ -50,8 +59,8 @@ export type ToastProps = Omit<MessageProps, "size"> & {
|
|
|
50
59
|
* portals itself (`FloatingPortal`, optionally to a custom `root`) and
|
|
51
60
|
* applies the fixed bottom-center classes itself. Set it to `false` when a
|
|
52
61
|
* parent already handles portalling and position — this is how
|
|
53
|
-
* `
|
|
54
|
-
*
|
|
62
|
+
* `ToastStack` renders it. Toast has no built-in auto-dismiss timer; that's
|
|
63
|
+
* `ToastStack`'s job, one layer up, driven through `open`.
|
|
55
64
|
*
|
|
56
65
|
* Exit animation (`usePresence`) keeps Toast mounted through its fade-out,
|
|
57
66
|
* so `onClose` fires only after the animation completes. Toast has no focus
|
|
@@ -59,13 +68,20 @@ export type ToastProps = Omit<MessageProps, "size"> & {
|
|
|
59
68
|
* a dialog.
|
|
60
69
|
*/
|
|
61
70
|
export const Toast = React.forwardRef<HTMLDivElement, ToastProps>(
|
|
62
|
-
({ className, intent = "neutral", title, icon, action, onAction, onClose, root, standalone = true, children, ...props }, ref) => {
|
|
71
|
+
({ className, intent = "neutral", title, icon, action, onAction, onClose, root, open = true, standalone = true, children, ...props }, ref) => {
|
|
63
72
|
const { ref: presenceRef, state, isMounted, show, hide } = usePresence();
|
|
64
73
|
|
|
65
|
-
//
|
|
74
|
+
// `open` drives presence: enter on mount, exit when it flips false. The
|
|
75
|
+
// close handler is read through a ref so a new identity does not replay
|
|
76
|
+
// the exit.
|
|
77
|
+
const onCloseRef = React.useRef(onClose);
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
onCloseRef.current = onClose;
|
|
80
|
+
});
|
|
66
81
|
React.useEffect(() => {
|
|
67
|
-
show();
|
|
68
|
-
|
|
82
|
+
if (open) show();
|
|
83
|
+
else hide(() => onCloseRef.current?.());
|
|
84
|
+
}, [open, show, hide]);
|
|
69
85
|
|
|
70
86
|
// Handle close with exit animation
|
|
71
87
|
const handleClose = React.useCallback(() => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
2
4
|
import { cn } from "@sixthshift/design-system/utils";
|
|
3
5
|
import type { VariantProps } from "class-variance-authority";
|
|
@@ -32,7 +34,7 @@ export type ToggleProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "o
|
|
|
32
34
|
* Built directly on Button: it calls `buttonRecipe(...)` and takes the same
|
|
33
35
|
* `variant`/`intent`/`size` axes Button does, plus `iconOnly` for a toolbar
|
|
34
36
|
* toggle whose whole content is an icon. The
|
|
35
|
-
* pressed-state colour mapping lives in `src/
|
|
37
|
+
* pressed-state colour mapping lives in `src/components/Toggle/toggle.recipe.css`,
|
|
36
38
|
* keyed off the `data-state="on" | "off"` attribute this component renders
|
|
37
39
|
* alongside `aria-pressed`.
|
|
38
40
|
*
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
2
4
|
import * as React from "react";
|
|
3
5
|
import { ToggleGroupContainer } from "./ToggleGroupContainer";
|
|
@@ -19,6 +21,8 @@ const ToggleGroupMultiple = React.forwardRef<HTMLDivElement, ToggleGroupMultiple
|
|
|
19
21
|
iconOnly = false,
|
|
20
22
|
disabled,
|
|
21
23
|
className,
|
|
24
|
+
name,
|
|
25
|
+
form,
|
|
22
26
|
...props
|
|
23
27
|
},
|
|
24
28
|
ref
|
|
@@ -54,6 +58,8 @@ const ToggleGroupMultiple = React.forwardRef<HTMLDivElement, ToggleGroupMultiple
|
|
|
54
58
|
onClick={() => handleToggle(option.value)}
|
|
55
59
|
/>
|
|
56
60
|
))}
|
|
61
|
+
{/* Mirrors the selection for native form submission, same contract as Checkbox/DatePicker. */}
|
|
62
|
+
{name && value.map((v) => <input key={v} type="hidden" name={`${name}[]`} value={v} {...(form ? { form } : {})} />)}
|
|
57
63
|
</ToggleGroupContainer>
|
|
58
64
|
);
|
|
59
65
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
2
4
|
import * as React from "react";
|
|
3
5
|
import { getRovingTargetIndex } from "../../internal/rovingFocus";
|
|
@@ -21,6 +23,8 @@ const ToggleGroupSingle = React.forwardRef<HTMLDivElement, ToggleGroupSingleProp
|
|
|
21
23
|
iconOnly = false,
|
|
22
24
|
disabled,
|
|
23
25
|
className,
|
|
26
|
+
name,
|
|
27
|
+
form,
|
|
24
28
|
...props
|
|
25
29
|
},
|
|
26
30
|
ref
|
|
@@ -98,6 +102,8 @@ const ToggleGroupSingle = React.forwardRef<HTMLDivElement, ToggleGroupSingleProp
|
|
|
98
102
|
onClick={() => handleSelect(option.value)}
|
|
99
103
|
/>
|
|
100
104
|
))}
|
|
105
|
+
{/* Mirrors the selection for native form submission, same contract as Checkbox/DatePicker. */}
|
|
106
|
+
{name && value && <input type="hidden" name={name} value={value} {...(form ? { form } : {})} />}
|
|
101
107
|
</ToggleGroupContainer>
|
|
102
108
|
);
|
|
103
109
|
}
|
|
@@ -39,6 +39,13 @@ export type ToggleGroupBaseProps = Omit<React.HTMLAttributes<HTMLDivElement>, "o
|
|
|
39
39
|
iconOnly?: boolean;
|
|
40
40
|
/** Disable all options */
|
|
41
41
|
disabled?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Input name for native form submission. The selection is mirrored into
|
|
44
|
+
* hidden `<input>`s — `name` in single mode, `${name}[]` in multiple mode.
|
|
45
|
+
*/
|
|
46
|
+
name?: string;
|
|
47
|
+
/** The `form` attribute for the hidden input(s), for a group rendered outside its `<form>`. */
|
|
48
|
+
form?: string;
|
|
42
49
|
};
|
|
43
50
|
|
|
44
51
|
export type ToggleGroupSingleProps = ToggleGroupBaseProps & {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { autoUpdate, flip, offset, type Placement, shift, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole } from "@floating-ui/react";
|
|
2
4
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import { TooltipBody } from "./components/TooltipBody";
|
package/src/hooks/usePresence.ts
CHANGED
package/src/hooks/useStack.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type Dispatch, type Reducer, startTransition, useCallback, useEffect, useReducer, useRef } from "react";
|
|
2
4
|
|
|
3
5
|
type Id = string | number;
|
|
4
6
|
type Transition = {
|
|
@@ -70,23 +72,44 @@ export function useStack<T extends StackItem>(initialStack: T[] = []): [T[], Sta
|
|
|
70
72
|
|
|
71
73
|
const [state, dispatch] = useReducer(reducer, initialStack);
|
|
72
74
|
|
|
75
|
+
// One removal timer per transitioning item. The effect re-runs on every
|
|
76
|
+
// state change, so timers are tracked in a ref keyed by item id: an item
|
|
77
|
+
// already scheduled is never scheduled again (re-running the effect must not
|
|
78
|
+
// reset or duplicate its countdown), and a timer whose item has left the
|
|
79
|
+
// stack by other means is cancelled rather than left to fire at a reused id.
|
|
80
|
+
const removalTimersRef = useRef(new Map<Id, ReturnType<typeof setTimeout>>());
|
|
81
|
+
|
|
73
82
|
useEffect(() => {
|
|
74
|
-
const
|
|
83
|
+
const timers = removalTimersRef.current;
|
|
84
|
+
const transitioning = new Set(state.filter((item) => item.transition).map((item) => item.id));
|
|
75
85
|
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
for (const [id, timer] of timers) {
|
|
87
|
+
if (!transitioning.has(id)) {
|
|
88
|
+
clearTimeout(timer);
|
|
89
|
+
timers.delete(id);
|
|
90
|
+
}
|
|
78
91
|
}
|
|
79
92
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
);
|
|
87
|
-
}
|
|
93
|
+
for (const item of state) {
|
|
94
|
+
if (!item.transition || timers.has(item.id)) continue;
|
|
95
|
+
const timer = setTimeout(() => {
|
|
96
|
+
timers.delete(item.id);
|
|
97
|
+
dispatch({ type: "remove", id: item.id });
|
|
98
|
+
}, item.transition.duration);
|
|
99
|
+
timers.set(item.id, timer);
|
|
100
|
+
}
|
|
88
101
|
}, [state]);
|
|
89
102
|
|
|
103
|
+
// Unmount only: without this, a stack unmounted mid-transition dispatches
|
|
104
|
+
// into an unmounted reducer.
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
const timers = removalTimersRef.current;
|
|
107
|
+
return () => {
|
|
108
|
+
for (const timer of timers.values()) clearTimeout(timer);
|
|
109
|
+
timers.clear();
|
|
110
|
+
};
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
90
113
|
// Memoize the dispatch wrapper to prevent unnecessary re-renders
|
|
91
114
|
// dispatch from useReducer is stable, so this only creates once
|
|
92
115
|
const wrappedDispatch = useCallback((params: Action<T>) => {
|
package/src/hooks/useTheme.ts
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Registry of open "escape layers" — transient floating overlays (popovers,
|
|
7
|
+
* select dropdowns, picker calendars) that should consume an Escape press
|
|
8
|
+
* before any dialog beneath them reacts to it.
|
|
9
|
+
*
|
|
10
|
+
* The dialogs and these overlays each listen for Escape on `document`
|
|
11
|
+
* independently (floating-ui's `useDismiss` has no tree here), and document
|
|
12
|
+
* listeners fire in registration order — usually the dialog's first, since it
|
|
13
|
+
* opened first. So a dialog cannot rely on `defaultPrevented`; instead it asks
|
|
14
|
+
* this registry whether a layer is open and, if so, leaves the Escape to it.
|
|
15
|
+
* The registry is read synchronously during the event, before React commits
|
|
16
|
+
* the layer's close, so the layer that is handling this Escape still counts.
|
|
17
|
+
*
|
|
18
|
+
* Module-level on purpose: Popover, Select and Modal live in separate subpath
|
|
19
|
+
* entries with no shared context, and a context would also miss overlays
|
|
20
|
+
* rendered outside an `OverlayProvider`.
|
|
21
|
+
*/
|
|
22
|
+
const transientLayers = new Set<symbol>();
|
|
23
|
+
const dialogLayers = new Set<symbol>();
|
|
24
|
+
|
|
25
|
+
/** True while any transient escape-consuming overlay (popover-like) is open. */
|
|
26
|
+
export const hasOpenEscapeLayer = () => transientLayers.size > 0;
|
|
27
|
+
|
|
28
|
+
/** True while any modal dialog is open. A non-modal Sheet under a Modal defers Escape to it. */
|
|
29
|
+
export const hasOpenEscapeDialog = () => dialogLayers.size > 0;
|
|
30
|
+
|
|
31
|
+
function useRegistration(registry: Set<symbol>, active: boolean) {
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (!active) return;
|
|
34
|
+
const token = Symbol("escape-layer");
|
|
35
|
+
registry.add(token);
|
|
36
|
+
return () => {
|
|
37
|
+
registry.delete(token);
|
|
38
|
+
};
|
|
39
|
+
}, [registry, active]);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Marks this component as an open transient escape layer while `active` is
|
|
44
|
+
* true. Call with the overlay's `open` state.
|
|
45
|
+
*/
|
|
46
|
+
export function useEscapeLayer(active: boolean) {
|
|
47
|
+
useRegistration(transientLayers, active);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Marks this component as an open modal dialog while `active` is true. */
|
|
51
|
+
export function useEscapeDialog(active: boolean) {
|
|
52
|
+
useRegistration(dialogLayers, active);
|
|
53
|
+
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { FloatingPortal, type FloatingPortalProps } from "@floating-ui/react";
|
|
2
4
|
import { type StackItem, useStack } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import { createContext, type FunctionComponent, type PropsWithChildren, useContext, useEffect, useMemo } from "react";
|
|
6
|
+
import { hasOpenEscapeLayer } from "../../../internal/escapeLayers";
|
|
7
|
+
import { ToastStack } from "./ToastStack";
|
|
8
|
+
import { toastStore as defaultToastStore, type ToastStore } from "./toastStore";
|
|
4
9
|
|
|
5
10
|
type OverlayContextProps = {
|
|
6
11
|
modal?: FloatingPortalProps["root"];
|
|
7
12
|
toast?: FloatingPortalProps["root"];
|
|
13
|
+
/** The toast stack to render. Default: the app's one, which `toast()` opens onto. Hand in your own for a second bundle or a test. */
|
|
14
|
+
toasts?: ToastStore;
|
|
15
|
+
/** Merged over the toast stack's container classes, so an app can move it (above a bottom bar, into a corner). */
|
|
16
|
+
toastClassName?: string;
|
|
8
17
|
};
|
|
9
18
|
|
|
10
19
|
/** Stack item for overlays - component is a self-contained wrapper */
|
|
@@ -18,10 +27,13 @@ type OverlayStackItem = StackItem & {
|
|
|
18
27
|
};
|
|
19
28
|
|
|
20
29
|
type OverlayContextType = {
|
|
21
|
-
|
|
30
|
+
// `undefined` spelled out rather than an optional `?:` — the context value
|
|
31
|
+
// below always sets the key, and `exactOptionalPropertyTypes` treats "absent"
|
|
32
|
+
// and "present but undefined" as different types.
|
|
33
|
+
modalRoot: FloatingPortalProps["root"] | undefined;
|
|
22
34
|
modalStack: ReturnType<typeof useStack<OverlayStackItem>>;
|
|
23
|
-
toastRoot
|
|
24
|
-
|
|
35
|
+
toastRoot: FloatingPortalProps["root"] | undefined;
|
|
36
|
+
toastStore: ToastStore;
|
|
25
37
|
};
|
|
26
38
|
|
|
27
39
|
/**
|
|
@@ -35,18 +47,28 @@ const rootProp = (root: FloatingPortalProps["root"] | undefined) => (root === un
|
|
|
35
47
|
const OverlayContext = createContext<OverlayContextType>(undefined as unknown as OverlayContextType);
|
|
36
48
|
export const useOverlayContext = () => useContext(OverlayContext);
|
|
37
49
|
|
|
38
|
-
export const OverlayProvider = ({
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
export const OverlayProvider = ({
|
|
51
|
+
modal: modalRoot,
|
|
52
|
+
toast: toastRoot,
|
|
53
|
+
toasts: toastStore = defaultToastStore,
|
|
54
|
+
toastClassName,
|
|
55
|
+
children,
|
|
56
|
+
}: PropsWithChildren<OverlayContextProps>) => {
|
|
57
|
+
// The roots pass through unresolved, deliberately. `"use client"` makes this a
|
|
58
|
+
// Client Component, but a Client Component is still rendered once on the
|
|
59
|
+
// server — defaulting to `document.body` here read the DOM at render scope and
|
|
60
|
+
// threw "document is not defined" on the first App Router request, which
|
|
61
|
+
// src/testing/stories.ssr.test.tsx and src/exports.ssr.test.tsx now catch. It
|
|
62
|
+
// bought nothing either: `FloatingPortal` already falls back to
|
|
63
|
+
// `document.body` when no `root` is given, and does it in an effect, on the
|
|
64
|
+
// client, where a body exists. Both portals below are behind a non-empty
|
|
65
|
+
// stack, and both stacks start empty, so nothing portals on the server anyway.
|
|
66
|
+
//
|
|
67
|
+
// Modals are a `useStack` here; toasts are a store outside React, so that
|
|
68
|
+
// `toast()` works from code that is not a component.
|
|
45
69
|
const modalStack = useStack<OverlayStackItem>([]);
|
|
46
|
-
const toastStack = useStack<OverlayStackItem>([]);
|
|
47
70
|
|
|
48
71
|
const [modals] = modalStack;
|
|
49
|
-
const [toasts] = toastStack;
|
|
50
72
|
|
|
51
73
|
// Global escape key handler - closes topmost modal
|
|
52
74
|
useEffect(() => {
|
|
@@ -54,6 +76,10 @@ export const OverlayProvider = ({ modal: modalRoot, toast: toastRoot, children }
|
|
|
54
76
|
|
|
55
77
|
const handleEscape = (event: KeyboardEvent) => {
|
|
56
78
|
if (event.key === "Escape") {
|
|
79
|
+
// A transient overlay open above the modal (a Select dropdown, a
|
|
80
|
+
// Popover, a picker calendar) consumes this Escape via its own
|
|
81
|
+
// dismiss handling — closing the modal too would double-fire.
|
|
82
|
+
if (hasOpenEscapeLayer()) return;
|
|
57
83
|
const topModal = modals.at(-1);
|
|
58
84
|
topModal?.onClose?.();
|
|
59
85
|
}
|
|
@@ -69,9 +95,9 @@ export const OverlayProvider = ({ modal: modalRoot, toast: toastRoot, children }
|
|
|
69
95
|
modalRoot,
|
|
70
96
|
modalStack,
|
|
71
97
|
toastRoot,
|
|
72
|
-
|
|
98
|
+
toastStore,
|
|
73
99
|
}),
|
|
74
|
-
[modalRoot, modalStack, toastRoot,
|
|
100
|
+
[modalRoot, modalStack, toastRoot, toastStore]
|
|
75
101
|
);
|
|
76
102
|
|
|
77
103
|
return (
|
|
@@ -87,18 +113,8 @@ export const OverlayProvider = ({ modal: modalRoot, toast: toastRoot, children }
|
|
|
87
113
|
</FloatingPortal>
|
|
88
114
|
)}
|
|
89
115
|
|
|
90
|
-
{/* Toast stack -
|
|
91
|
-
{
|
|
92
|
-
<FloatingPortal {...rootProp(toastRoot)}>
|
|
93
|
-
<div className="pointer-events-none fixed bottom-6 left-1/2 z-toast flex -translate-x-1/2 flex-col-reverse items-center gap-3">
|
|
94
|
-
{toasts.map(({ id, component: Component, onClose, ...props }) => (
|
|
95
|
-
<div key={id} className="pointer-events-auto">
|
|
96
|
-
<Component onClose={onClose} {...props} />
|
|
97
|
-
</div>
|
|
98
|
-
))}
|
|
99
|
-
</div>
|
|
100
|
-
</FloatingPortal>
|
|
101
|
-
)}
|
|
116
|
+
{/* Toast stack - portals itself, and only while it holds something */}
|
|
117
|
+
<ToastStack store={toastStore} className={toastClassName} {...rootProp(toastRoot)} />
|
|
102
118
|
</OverlayContext.Provider>
|
|
103
119
|
);
|
|
104
120
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { FloatingPortal, type FloatingPortalProps } from "@floating-ui/react";
|
|
4
|
+
import { Toast } from "@sixthshift/design-system/toast";
|
|
5
|
+
import { cn } from "@sixthshift/design-system/utils";
|
|
6
|
+
import { useCallback, useEffect, useSyncExternalStore } from "react";
|
|
7
|
+
import { toastStore as defaultStore, type ToastRecord, type ToastStore } from "./toastStore";
|
|
8
|
+
|
|
9
|
+
const EMPTY: readonly ToastRecord[] = [];
|
|
10
|
+
|
|
11
|
+
/** The store's stack, re-rendering the caller as it changes. Empty during server rendering. */
|
|
12
|
+
export function useToasts(store: ToastStore = defaultStore): readonly ToastRecord[] {
|
|
13
|
+
return useSyncExternalStore(store.subscribe, store.snapshot, () => EMPTY);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* One toast in the stack: the dismissal timer lives here, not in the store,
|
|
18
|
+
* so the store stays free of the DOM. Expiry and the X button take the same
|
|
19
|
+
* path — `open` flips false, `Toast` plays its exit, and `onClose` drops the
|
|
20
|
+
* record once the animation ends.
|
|
21
|
+
*/
|
|
22
|
+
function ToastItem({ record, store }: { record: ToastRecord; store: ToastStore }) {
|
|
23
|
+
const { id, duration, closing } = record;
|
|
24
|
+
// `duration` is the stack's to act on, not the toast's to render.
|
|
25
|
+
const { component: Component = Toast, duration: _duration, ...props } = record.options;
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (duration <= 0 || closing) return;
|
|
29
|
+
const timer = setTimeout(() => store.close(id), duration);
|
|
30
|
+
return () => clearTimeout(timer);
|
|
31
|
+
}, [id, duration, closing, store]);
|
|
32
|
+
|
|
33
|
+
const onClose = useCallback(() => store.remove(id), [store, id]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className="pointer-events-auto" data-toast-id={id} data-toast-intent={props.intent ?? "neutral"}>
|
|
37
|
+
<Component {...props} standalone={false} open={!closing} onClose={onClose} />
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type ToastStackProps = {
|
|
43
|
+
/** The stack to render. Default: the app's one, which `toast()` opens onto. */
|
|
44
|
+
store?: ToastStore | undefined;
|
|
45
|
+
/** Portal root (default: `document.body`). */
|
|
46
|
+
root?: FloatingPortalProps["root"] | undefined;
|
|
47
|
+
/** Merged over the container's classes, so an app can move the stack (above a bottom bar, to a corner). */
|
|
48
|
+
className?: string | undefined;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** The container's own classes: bottom centre, newest at the bottom, click-through between toasts. */
|
|
52
|
+
export const TOAST_STACK_CLASS = "pointer-events-none fixed bottom-6 left-1/2 z-toast flex -translate-x-1/2 flex-col-reverse items-center gap-3";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The open toasts, portalled and positioned. `OverlayProvider` renders one;
|
|
56
|
+
* render it yourself only when there is no provider to host it.
|
|
57
|
+
*/
|
|
58
|
+
export function ToastStack({ store = defaultStore, root, className }: ToastStackProps) {
|
|
59
|
+
const toasts = useToasts(store);
|
|
60
|
+
if (toasts.length === 0) return null;
|
|
61
|
+
// `root` omitted rather than passed as `undefined`: see OverlayContext's `rootProp`.
|
|
62
|
+
return (
|
|
63
|
+
<FloatingPortal {...(root === undefined ? {} : { root })}>
|
|
64
|
+
<div className={cn(TOAST_STACK_CLASS, className)} data-toast-stack="" data-count={toasts.length}>
|
|
65
|
+
{toasts.map((record) => (
|
|
66
|
+
<ToastItem key={record.id} record={record} store={store} />
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
</FloatingPortal>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { ModalContextProvider, type ModalProps, type OnClose } from "@sixthshift/design-system/modal";
|
|
2
4
|
import { type ComponentType, type ReactNode, Suspense, useCallback, useId, useRef } from "react";
|
|
3
5
|
import { useOverlayContext } from "../OverlayContext";
|