@sixthshift/design-system 0.4.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 +134 -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 +50 -4
- package/dist/components/Card/Card.d.ts.map +1 -1
- package/dist/components/Card/Card.js +89 -5
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Card/index.d.ts +1 -1
- package/dist/components/Card/index.d.ts.map +1 -1
- package/dist/components/Card/index.js +1 -1
- package/dist/components/Card/index.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 +34 -10
- 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 +22 -9
- 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 +105 -17
- package/src/{theme/recipes/card.css → components/Card/card.recipe.css} +6 -1
- package/src/components/Card/index.ts +1 -1
- 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 +53 -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/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 { autoUpdate, FloatingPortal, flip, offset, shift, useClick, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
|
|
2
4
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import { cn } from "@sixthshift/design-system/utils";
|
|
@@ -16,8 +18,8 @@ import {
|
|
|
16
18
|
toISOInstant,
|
|
17
19
|
toISOInstantRange,
|
|
18
20
|
} from "../../date-time";
|
|
19
|
-
|
|
20
21
|
import { PickerField } from "../../internal";
|
|
22
|
+
import { useEscapeLayer } from "../../internal/escapeLayers";
|
|
21
23
|
import { Button } from "../Button";
|
|
22
24
|
import { CalendarView } from "../Calendar/CalendarView";
|
|
23
25
|
import { isDateDisabled } from "../Calendar/calendar.hooks";
|
|
@@ -412,6 +414,10 @@ export const DateTimeRangePicker = React.forwardRef<HTMLDivElement, DateTimeRang
|
|
|
412
414
|
|
|
413
415
|
const click = useClick(context);
|
|
414
416
|
const dismiss = useDismiss(context);
|
|
417
|
+
|
|
418
|
+
// While open, an Escape press closes this picker's popover and must not
|
|
419
|
+
// also close a Modal/Sheet it is rendered inside.
|
|
420
|
+
useEscapeLayer(open);
|
|
415
421
|
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss]);
|
|
416
422
|
|
|
417
423
|
// IDs for accessibility
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { Label } from "@sixthshift/design-system/label";
|
|
2
4
|
import { Message } from "@sixthshift/design-system/message";
|
|
3
5
|
import { Muted } from "@sixthshift/design-system/muted";
|
|
@@ -10,61 +12,111 @@ export type FormFieldFeedback = {
|
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
export type FormFieldProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
13
|
-
label:
|
|
14
|
-
description?:
|
|
15
|
+
label: React.ReactNode;
|
|
16
|
+
description?: React.ReactNode;
|
|
15
17
|
feedback?: FormFieldFeedback;
|
|
16
18
|
required?: boolean;
|
|
17
19
|
};
|
|
18
20
|
|
|
21
|
+
/** What FormField knows about the control it wraps — see `useFormField`. */
|
|
22
|
+
export type FormFieldContextValue = {
|
|
23
|
+
/** The id the control should carry, and the label's `htmlFor` target. */
|
|
24
|
+
id: string;
|
|
25
|
+
/** Space-separated ids of the description/feedback texts, for `aria-describedby`. `undefined` when there are none. */
|
|
26
|
+
describedBy: string | undefined;
|
|
27
|
+
/** True when `feedback.intent` is `"danger"` — the control should set `aria-invalid`. */
|
|
28
|
+
invalid: boolean;
|
|
29
|
+
/** Mirrors the `required` prop, for `aria-required`/`required` on the control. */
|
|
30
|
+
required: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const FormFieldContext = React.createContext<FormFieldContextValue | null>(null);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The wiring `FormField` provides to whatever control it wraps: `id`,
|
|
37
|
+
* `describedBy`, `invalid`, `required`. Direct element children get these
|
|
38
|
+
* cloned on automatically; a control nested deeper — inside a wrapper div, a
|
|
39
|
+
* render prop, a custom composite — can call this instead and apply them
|
|
40
|
+
* itself. Returns `null` outside a `FormField`.
|
|
41
|
+
*/
|
|
42
|
+
export const useFormField = () => React.useContext(FormFieldContext);
|
|
43
|
+
|
|
19
44
|
/**
|
|
20
45
|
* Wraps a form control with a label, optional description, and optional
|
|
21
46
|
* validation feedback — the composition point for `Input`, `Textarea`,
|
|
22
47
|
* `Select` and similar controls inside a form.
|
|
23
48
|
*
|
|
24
|
-
* Generates an `id` (or uses the one passed in) and
|
|
25
|
-
* `aria-describedby` (pointing at the description and/or feedback text)
|
|
26
|
-
* `aria-invalid` (when `feedback.intent` is `"danger"`)
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
49
|
+
* Generates an `id` (or uses the one passed in) and wires it, plus
|
|
50
|
+
* `aria-describedby` (pointing at the description and/or feedback text),
|
|
51
|
+
* `aria-invalid` (when `feedback.intent` is `"danger"`) and `aria-required`
|
|
52
|
+
* (when `required`), onto the first element child. A child's own attributes
|
|
53
|
+
* win: an explicit `id` is kept (and becomes the label's `htmlFor` target),
|
|
54
|
+
* an existing `aria-describedby` is merged with FormField's rather than
|
|
55
|
+
* replaced. Controls that aren't the first element child can self-wire via
|
|
56
|
+
* `useFormField`.
|
|
30
57
|
*
|
|
31
58
|
* Distinct from `Field`, which displays a read-only label/value pair rather
|
|
32
59
|
* than wrapping an interactive control.
|
|
33
60
|
*/
|
|
34
|
-
const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>(
|
|
62
|
+
({ className, label, description, feedback, required = false, children, id, ...props }, ref) => {
|
|
63
|
+
const generatedId = React.useId();
|
|
64
|
+
const fieldId = id ?? generatedId;
|
|
65
|
+
|
|
66
|
+
// The label must point at the id the control actually carries: when the
|
|
67
|
+
// (first element) child brings its own id, that id wins over ours.
|
|
68
|
+
const childArray = React.Children.toArray(children);
|
|
69
|
+
const firstElementIndex = childArray.findIndex((child) => React.isValidElement(child));
|
|
70
|
+
const firstElement = firstElementIndex === -1 ? null : (childArray[firstElementIndex] as React.ReactElement<React.HTMLAttributes<HTMLElement>>);
|
|
71
|
+
const controlId = firstElement?.props.id ?? fieldId;
|
|
72
|
+
|
|
73
|
+
const descriptionId = description ? `${fieldId}-description` : undefined;
|
|
74
|
+
const feedbackId = feedback ? `${fieldId}-feedback` : undefined;
|
|
75
|
+
const invalid = feedback?.intent === "danger";
|
|
76
|
+
|
|
77
|
+
const contextValue = React.useMemo<FormFieldContextValue>(
|
|
78
|
+
() => ({
|
|
79
|
+
id: controlId,
|
|
80
|
+
describedBy: cn(descriptionId, feedbackId) || undefined,
|
|
81
|
+
invalid,
|
|
82
|
+
required,
|
|
83
|
+
}),
|
|
84
|
+
[controlId, descriptionId, feedbackId, invalid, required]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const wiredChildren = childArray.map((child, index) => {
|
|
88
|
+
if (index !== firstElementIndex || !React.isValidElement(child)) return child;
|
|
89
|
+
const childProps = child.props as React.HTMLAttributes<HTMLElement>;
|
|
90
|
+
return React.cloneElement(child, {
|
|
91
|
+
id: controlId,
|
|
92
|
+
// The child's own describedby (a tooltip, an external hint) is kept and
|
|
93
|
+
// FormField's ids are appended, rather than overwritten.
|
|
94
|
+
"aria-describedby": cn(childProps["aria-describedby"], descriptionId, feedbackId) || undefined,
|
|
95
|
+
"aria-invalid": childProps["aria-invalid"] ?? (invalid ? true : undefined),
|
|
96
|
+
"aria-required": childProps["aria-required"] ?? (required ? true : undefined),
|
|
97
|
+
} as React.HTMLAttributes<HTMLElement>);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div ref={ref} className={cn("flex flex-col gap-1.5", className)} {...props}>
|
|
102
|
+
<Label htmlFor={controlId}>
|
|
103
|
+
{label}
|
|
104
|
+
{required && <span className="ml-0.5 text-fg-danger">*</span>}
|
|
105
|
+
</Label>
|
|
106
|
+
|
|
107
|
+
{description && <Muted id={descriptionId}>{description}</Muted>}
|
|
108
|
+
|
|
109
|
+
<FormFieldContext.Provider value={contextValue}>{wiredChildren}</FormFieldContext.Provider>
|
|
110
|
+
|
|
111
|
+
{feedback && (
|
|
112
|
+
<Message id={feedbackId} intent={feedback.intent} size="sm">
|
|
113
|
+
{feedback.message}
|
|
114
|
+
</Message>
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
);
|
|
68
120
|
FormField.displayName = "FormField";
|
|
69
121
|
|
|
70
122
|
export { FormField };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { FormFieldFeedback, FormFieldProps } from "./FormField";
|
|
2
|
-
export { FormField } from "./FormField";
|
|
1
|
+
export type { FormFieldContextValue, FormFieldFeedback, FormFieldProps } from "./FormField";
|
|
2
|
+
export { FormField, useFormField } from "./FormField";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { autoUpdate, flip, offset, type Placement, safePolygon, shift, useDismiss, useFloating, useFocus, useHover, useInteractions } from "@floating-ui/react";
|
|
2
4
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import type * as React from "react";
|
|
@@ -10,7 +10,7 @@ import { MessageTitle } from "./components/MessageTitle";
|
|
|
10
10
|
* Geometry only, plus the three `--message-*` component tokens.
|
|
11
11
|
*
|
|
12
12
|
* Every colour reads a `--message-*` component token whose value is decided by
|
|
13
|
-
* src/
|
|
13
|
+
* src/components/Message/message.recipe.css. That file is the mapping from `intent` to a
|
|
14
14
|
* semantic token — the layer that used to be the `intent` entry in `variants`
|
|
15
15
|
* here, compiled into class-name literals and unreachable from outside.
|
|
16
16
|
* `size` stays here: it is pure geometry (padding, gap, font-size), not
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { FloatingFocusManager, FloatingOverlay, FloatingPortal, useDismiss, useFloating, useInteractions, useRole } from "@floating-ui/react";
|
|
2
4
|
import { useMergedFloatingRef, usePresence } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import { cn } from "@sixthshift/design-system/utils";
|
|
4
6
|
import { forwardRef, type HTMLAttributes, type ReactNode, useCallback, useContext, useEffect, useId, useMemo, useState } from "react";
|
|
7
|
+
import { hasOpenEscapeLayer, useEscapeDialog } from "../../internal/escapeLayers";
|
|
5
8
|
import { ModalBody, ModalContext, ModalFooter, ModalHeader } from "./components";
|
|
6
9
|
|
|
7
10
|
// =============================================================================
|
|
@@ -21,9 +24,11 @@ export type ModalProps = Pick<HTMLAttributes<HTMLDivElement>, "className" | "sty
|
|
|
21
24
|
/** Children - use Modal.Header, Modal.Body, Modal.Footer */
|
|
22
25
|
children: ReactNode;
|
|
23
26
|
/**
|
|
24
|
-
* When true (default), clicking outside
|
|
27
|
+
* When true (default), clicking outside — and, for a directly-mounted
|
|
28
|
+
* modal, pressing Escape — closes the modal.
|
|
25
29
|
* When false, the modal can only be closed programmatically.
|
|
26
|
-
* Note:
|
|
30
|
+
* Note: for modals opened via `useModal()`, Escape is handled by
|
|
31
|
+
* OverlayContext for proper stack ordering.
|
|
27
32
|
*/
|
|
28
33
|
dismissable?: boolean;
|
|
29
34
|
/** When true, shows a close (X) button in the modal header */
|
|
@@ -66,6 +71,9 @@ const ModalRoot = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
66
71
|
) => {
|
|
67
72
|
// Prefer explicit prop over context (context is set by useModal's overlay system)
|
|
68
73
|
const contextValue = useContext(ModalContext);
|
|
74
|
+
// A context means useModal's stack owns this modal — and with it, Escape
|
|
75
|
+
// ordering. Without one the modal is mounted directly and handles its own.
|
|
76
|
+
const isStackManaged = contextValue != null;
|
|
69
77
|
// Context provides a parameterless onClose for programmatic modals; adapt to the boolean shape.
|
|
70
78
|
const handleDismiss = useCallback(() => {
|
|
71
79
|
if (onOpenChange) onOpenChange(false);
|
|
@@ -84,8 +92,12 @@ const ModalRoot = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
84
92
|
|
|
85
93
|
const { refs, context } = useFloating({
|
|
86
94
|
open: true,
|
|
87
|
-
onOpenChange: (nextOpen) => {
|
|
88
|
-
if (
|
|
95
|
+
onOpenChange: (nextOpen, _event, reason) => {
|
|
96
|
+
if (nextOpen) return;
|
|
97
|
+
// A transient overlay (Select dropdown, Popover, picker) open above
|
|
98
|
+
// this modal consumes the Escape itself — don't also close the modal.
|
|
99
|
+
if (reason === "escape-key" && hasOpenEscapeLayer()) return;
|
|
100
|
+
handleClose();
|
|
89
101
|
},
|
|
90
102
|
});
|
|
91
103
|
|
|
@@ -93,8 +105,10 @@ const ModalRoot = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
93
105
|
|
|
94
106
|
const dismiss = useDismiss(context, {
|
|
95
107
|
enabled: dismissable,
|
|
96
|
-
//
|
|
97
|
-
|
|
108
|
+
// Stack-managed modals leave Escape to OverlayContext, which closes
|
|
109
|
+
// topmost-first. A directly-mounted modal has no stack above it and
|
|
110
|
+
// handles its own Escape here.
|
|
111
|
+
escapeKey: !isStackManaged,
|
|
98
112
|
outsidePress: true,
|
|
99
113
|
outsidePressEvent: "mousedown",
|
|
100
114
|
});
|
|
@@ -119,52 +133,63 @@ const ModalRoot = forwardRef<HTMLDivElement, ModalProps>(
|
|
|
119
133
|
|
|
120
134
|
const modalContextValue = useMemo(() => ({ onClose: handleClose, closable, titleId, registerTitle }), [closable, handleClose, titleId, registerTitle]);
|
|
121
135
|
|
|
136
|
+
// While mounted (exit animation included), a non-modal Sheet underneath
|
|
137
|
+
// must leave Escape to this dialog.
|
|
138
|
+
useEscapeDialog(isMounted);
|
|
139
|
+
|
|
122
140
|
if (!isMounted) return null;
|
|
123
141
|
|
|
124
142
|
const isEntering = state === "entering";
|
|
125
143
|
const isExiting = state === "exiting";
|
|
126
144
|
|
|
127
145
|
return (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
aria-labelledby={labelledBy}
|
|
139
|
-
aria-describedby={ariaDescribedBy}
|
|
140
|
-
tabIndex={-1}
|
|
141
|
-
data-state={state}
|
|
142
|
-
className={cn(
|
|
143
|
-
"modal fixed flex flex-col overflow-hidden outline-hidden",
|
|
144
|
-
"border-(color:--modal-border) rounded-xl border bg-(--modal-bg)",
|
|
145
|
-
// Size
|
|
146
|
-
sizeClasses[size],
|
|
147
|
-
// Cap height so ModalBody scrolls instead of overflowing the viewport
|
|
148
|
-
"max-h-[95%]",
|
|
149
|
-
// Mobile: slide up from bottom, full width
|
|
150
|
-
"max-sm:inset-x-0 max-sm:bottom-0 max-sm:rounded-b-none",
|
|
151
|
-
isEntering && "max-sm:animate-slide-up-in",
|
|
152
|
-
isExiting && "max-sm:animate-slide-up-out",
|
|
153
|
-
// Desktop: horizontal center + vertical alignment
|
|
154
|
-
"sm:left-1/2 sm:-translate-x-1/2",
|
|
155
|
-
align === "center" && "sm:top-1/2 sm:-translate-y-1/2",
|
|
156
|
-
align === "top" && "sm:top-[15vh]",
|
|
157
|
-
isEntering && "sm:animate-fade-in",
|
|
158
|
-
isExiting && "sm:animate-fade-out",
|
|
159
|
-
className
|
|
160
|
-
)}
|
|
161
|
-
style={style}
|
|
162
|
-
{...getFloatingProps({})}
|
|
146
|
+
// Self-portalled: `position: fixed` resolves against the nearest
|
|
147
|
+
// transformed/filtered ancestor, so a modal rendered in place inside a
|
|
148
|
+
// `transform` container would be positioned (and clipped) by it. Nested
|
|
149
|
+
// FloatingPortals attach to the parent portal's node, so a stack-managed
|
|
150
|
+
// modal stays inside the `OverlayProvider`'s custom `modal` root.
|
|
151
|
+
<FloatingPortal>
|
|
152
|
+
<FloatingFocusManager context={context} modal>
|
|
153
|
+
<FloatingOverlay
|
|
154
|
+
lockScroll
|
|
155
|
+
className={cn("modal-overlay fixed inset-0 z-modal bg-(--modal-overlay-bg)", isEntering && "animate-fade-in", isExiting && "animate-fade-out")}
|
|
163
156
|
>
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
157
|
+
<div
|
|
158
|
+
ref={mergedRef}
|
|
159
|
+
role="dialog"
|
|
160
|
+
aria-modal="true"
|
|
161
|
+
aria-label={ariaLabel}
|
|
162
|
+
aria-labelledby={labelledBy}
|
|
163
|
+
aria-describedby={ariaDescribedBy}
|
|
164
|
+
tabIndex={-1}
|
|
165
|
+
data-state={state}
|
|
166
|
+
className={cn(
|
|
167
|
+
"modal fixed flex flex-col overflow-hidden outline-hidden",
|
|
168
|
+
"border-(color:--modal-border) rounded-xl border bg-(--modal-bg)",
|
|
169
|
+
// Size
|
|
170
|
+
sizeClasses[size],
|
|
171
|
+
// Cap height so ModalBody scrolls instead of overflowing the viewport
|
|
172
|
+
"max-h-[95%]",
|
|
173
|
+
// Mobile: slide up from bottom, full width
|
|
174
|
+
"max-sm:inset-x-0 max-sm:bottom-0 max-sm:rounded-b-none",
|
|
175
|
+
isEntering && "max-sm:animate-slide-up-in",
|
|
176
|
+
isExiting && "max-sm:animate-slide-up-out",
|
|
177
|
+
// Desktop: horizontal center + vertical alignment
|
|
178
|
+
"sm:left-1/2 sm:-translate-x-1/2",
|
|
179
|
+
align === "center" && "sm:top-1/2 sm:-translate-y-1/2",
|
|
180
|
+
align === "top" && "sm:top-[15vh]",
|
|
181
|
+
isEntering && "sm:animate-fade-in",
|
|
182
|
+
isExiting && "sm:animate-fade-out",
|
|
183
|
+
className
|
|
184
|
+
)}
|
|
185
|
+
style={style}
|
|
186
|
+
{...getFloatingProps({})}
|
|
187
|
+
>
|
|
188
|
+
<ModalContext.Provider value={modalContextValue}>{children}</ModalContext.Provider>
|
|
189
|
+
</div>
|
|
190
|
+
</FloatingOverlay>
|
|
191
|
+
</FloatingFocusManager>
|
|
192
|
+
</FloatingPortal>
|
|
168
193
|
);
|
|
169
194
|
}
|
|
170
195
|
);
|
|
@@ -192,11 +217,12 @@ ModalRoot.displayName = "Modal";
|
|
|
192
217
|
* Modal is mount-driven — a parent (or `useModal`'s stack) decides whether it
|
|
193
218
|
* renders at all, so there's no `open` prop. `onOpenChange` still exists,
|
|
194
219
|
* firing only with `false` on dismissal, so every overlay in this library
|
|
195
|
-
* shares one open/close shape. Escape
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* `
|
|
199
|
-
*
|
|
220
|
+
* shares one open/close shape. Escape closes the modal: a directly-mounted
|
|
221
|
+
* Modal handles it itself (via `useDismiss`, so `dismissable={false}` turns
|
|
222
|
+
* it off along with outside-press), while one opened through `useModal()`
|
|
223
|
+
* defers to `OverlayProvider`, which closes a stack of modals topmost-first.
|
|
224
|
+
* Either way, an Escape pressed while a transient overlay (Select dropdown,
|
|
225
|
+
* Popover, picker) is open above the modal closes only that overlay.
|
|
200
226
|
*
|
|
201
227
|
* Focus moves into the modal on mount and is trapped there
|
|
202
228
|
* (`FloatingFocusManager modal`) until it unmounts, then returns to whatever
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { autoUpdate, flip, offset, type Placement, shift, useClick, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
|
|
2
4
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import type * as React from "react";
|
|
4
6
|
import { useId } from "react";
|
|
7
|
+
import { useEscapeLayer } from "../../internal/escapeLayers";
|
|
5
8
|
import { PopoverBody } from "./components/PopoverBody";
|
|
6
9
|
import { PopoverClose } from "./components/PopoverClose";
|
|
7
10
|
import { PopoverContext } from "./components/PopoverContext";
|
|
@@ -42,6 +45,10 @@ const PopoverRoot = ({ open: controlledOpen, onOpenChange, defaultOpen = false,
|
|
|
42
45
|
const dismiss = useDismiss(context);
|
|
43
46
|
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss]);
|
|
44
47
|
|
|
48
|
+
// While open, an Escape press dismisses this popover and must not also
|
|
49
|
+
// close a Modal/Sheet underneath it.
|
|
50
|
+
useEscapeLayer(open);
|
|
51
|
+
|
|
45
52
|
const id = useId();
|
|
46
53
|
const contentId = `popover-content-${id}`;
|
|
47
54
|
// `Popover.Body` is a `role="dialog"`, and a dialog with no accessible name is
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { Input } from "@sixthshift/design-system/input";
|
|
2
4
|
import { cn } from "@sixthshift/design-system/utils";
|
|
3
5
|
import { Search, X } from "lucide-react";
|
|
4
6
|
import * as React from "react";
|
|
5
7
|
|
|
6
|
-
export type SearchInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"
|
|
8
|
+
export type SearchInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"> & {
|
|
7
9
|
value: string;
|
|
8
|
-
|
|
10
|
+
/** Called with the input's string value on every change. The native `onChange(event)` also fires, unchanged. */
|
|
11
|
+
onValueChange: (value: string) => void;
|
|
9
12
|
onClear?: () => void;
|
|
10
13
|
/** Accessible name for the clear button — it is icon-only. */
|
|
11
14
|
clearLabel?: string;
|
|
@@ -17,17 +20,18 @@ export type SearchInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>,
|
|
|
17
20
|
*
|
|
18
21
|
* Wraps `Input`, using its `iconLeft`/`iconRight` slots, rather than
|
|
19
22
|
* reimplementing the field. Always controlled — `value` is required and
|
|
20
|
-
* there is no `defaultValue`/uncontrolled mode. `
|
|
21
|
-
* string value directly
|
|
22
|
-
* provided, otherwise calls
|
|
23
|
+
* there is no `defaultValue`/uncontrolled mode. `onValueChange` receives the
|
|
24
|
+
* string value directly; the native `onChange` keeps its event signature and
|
|
25
|
+
* fires too if passed. Clearing calls `onClear` if provided, otherwise calls
|
|
26
|
+
* `onValueChange("")` — note a programmatic clear dispatches no native event.
|
|
23
27
|
*/
|
|
24
28
|
const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
|
|
25
|
-
({ className, value, onChange, onClear, clearLabel = "Clear search", ...props }, ref) => {
|
|
29
|
+
({ className, value, onValueChange, onChange, onClear, clearLabel = "Clear search", ...props }, ref) => {
|
|
26
30
|
const handleClear = () => {
|
|
27
31
|
if (onClear) {
|
|
28
32
|
onClear();
|
|
29
33
|
} else {
|
|
30
|
-
|
|
34
|
+
onValueChange("");
|
|
31
35
|
}
|
|
32
36
|
};
|
|
33
37
|
|
|
@@ -36,7 +40,10 @@ const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
|
|
|
36
40
|
ref={ref}
|
|
37
41
|
type="text"
|
|
38
42
|
value={value}
|
|
39
|
-
onChange={(e) =>
|
|
43
|
+
onChange={(e) => {
|
|
44
|
+
onValueChange(e.target.value);
|
|
45
|
+
onChange?.(e);
|
|
46
|
+
}}
|
|
40
47
|
iconLeft={<Search />}
|
|
41
48
|
iconRight={
|
|
42
49
|
value ? (
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { autoUpdate, flip, offset, shift, size, useFloating } from "@floating-ui/react";
|
|
2
4
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
3
5
|
import { forwardRef, type HTMLAttributes, type ReactElement, type Ref, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { useEscapeLayer } from "../../internal/escapeLayers";
|
|
4
7
|
import { SelectDropdown, selectOptionId } from "./SelectDropdown";
|
|
5
8
|
import { SelectTriggerButton, SelectTriggerSearch } from "./SelectTrigger";
|
|
6
9
|
import { useSelectKeyboard } from "./useSelectKeyboard";
|
|
@@ -19,6 +22,12 @@ type SelectBaseProps<T extends string = string> = Omit<HTMLAttributes<HTMLElemen
|
|
|
19
22
|
placeholder?: string;
|
|
20
23
|
searchable?: boolean;
|
|
21
24
|
clearable?: boolean;
|
|
25
|
+
/** Input name for native form submission. Selected value(s) are mirrored into hidden `<input>`s, `${name}[]` in multiple mode. */
|
|
26
|
+
name?: string;
|
|
27
|
+
/** The `form` attribute for the hidden input(s), for a Select rendered outside its `<form>`. */
|
|
28
|
+
form?: string;
|
|
29
|
+
/** Marks the combobox `aria-required`. Constraint validation is the caller's job — the mirrored inputs are hidden. */
|
|
30
|
+
required?: boolean;
|
|
22
31
|
};
|
|
23
32
|
|
|
24
33
|
type SelectSingleProps<T extends string = string> = SelectBaseProps<T> & {
|
|
@@ -54,6 +63,9 @@ const SelectRoot = forwardRef(function SelectRoot<T extends string = string>(pro
|
|
|
54
63
|
placeholder = "Select...",
|
|
55
64
|
searchable = false,
|
|
56
65
|
clearable = false,
|
|
66
|
+
name,
|
|
67
|
+
form,
|
|
68
|
+
required = false,
|
|
57
69
|
...restProps
|
|
58
70
|
} = props;
|
|
59
71
|
|
|
@@ -244,6 +256,10 @@ const SelectRoot = forwardRef(function SelectRoot<T extends string = string>(pro
|
|
|
244
256
|
}
|
|
245
257
|
}, [highlightedIndex, open]);
|
|
246
258
|
|
|
259
|
+
// While open, an Escape press closes the dropdown and must not also close
|
|
260
|
+
// a Modal/Sheet this Select is rendered inside.
|
|
261
|
+
useEscapeLayer(open);
|
|
262
|
+
|
|
247
263
|
// Close on outside click
|
|
248
264
|
useEffect(() => {
|
|
249
265
|
if (!open) return;
|
|
@@ -266,7 +282,8 @@ const SelectRoot = forwardRef(function SelectRoot<T extends string = string>(pro
|
|
|
266
282
|
const activeOptionId = open && highlightedIndex >= 0 && highlightedIndex < filteredOptions.length ? selectOptionId(listboxId, highlightedIndex) : undefined;
|
|
267
283
|
|
|
268
284
|
// Strip mode from DOM props
|
|
269
|
-
const { mode: _, value: _v, defaultValue: _dv, onValueChange: _oc, ...
|
|
285
|
+
const { mode: _, value: _v, defaultValue: _dv, onValueChange: _oc, ...strippedProps } = restProps as Record<string, unknown>;
|
|
286
|
+
const htmlProps = required ? { "aria-required": true, ...strippedProps } : strippedProps;
|
|
270
287
|
|
|
271
288
|
// `role="listbox"` requires an accessible name of its own, and the trigger
|
|
272
289
|
// can't supply one: its label is the current *value*, and in searchable mode
|
|
@@ -311,6 +328,12 @@ const SelectRoot = forwardRef(function SelectRoot<T extends string = string>(pro
|
|
|
311
328
|
/>
|
|
312
329
|
)}
|
|
313
330
|
|
|
331
|
+
{/* Hidden inputs mirror the selection for native form submission — same
|
|
332
|
+
contract as DatePicker: rendered inline (not portalled) so they sit
|
|
333
|
+
inside the surrounding <form> unless `form` points elsewhere. */}
|
|
334
|
+
{name && !isMultiple && singleValue && <input type="hidden" name={name} value={singleValue} {...(form ? { form } : {})} />}
|
|
335
|
+
{name && isMultiple && multiValue.map((v) => <input key={v} type="hidden" name={`${name}[]`} value={v} {...(form ? { form } : {})} />)}
|
|
336
|
+
|
|
314
337
|
{open && !collapsed && (
|
|
315
338
|
<SelectDropdown
|
|
316
339
|
setFloating={refs.setFloating}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { cn } from "@sixthshift/design-system/utils";
|
|
2
4
|
import { ChevronDown, X } from "lucide-react";
|
|
3
5
|
import type { HTMLAttributes, Ref } from "react";
|
|
@@ -55,6 +57,9 @@ export const SelectTriggerButton = ({
|
|
|
55
57
|
className
|
|
56
58
|
)}
|
|
57
59
|
title={collapsed ? displayLabel : undefined}
|
|
60
|
+
// The APG select-only combobox: a button-behaving element announced as
|
|
61
|
+
// a combobox, which also admits aria-required — a plain button doesn't.
|
|
62
|
+
role="combobox"
|
|
58
63
|
aria-haspopup="listbox"
|
|
59
64
|
aria-expanded={open}
|
|
60
65
|
// The listbox unmounts when closed, so only reference it while it exists.
|