@sixthshift/design-system 0.2.1 → 0.4.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 +242 -33
- package/dist/components/Badge/Badge.d.ts +65 -7
- package/dist/components/Badge/Badge.d.ts.map +1 -1
- package/dist/components/Badge/Badge.js +56 -46
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Badge/index.d.ts +1 -1
- package/dist/components/Badge/index.d.ts.map +1 -1
- package/dist/components/Badge/index.js +1 -1
- package/dist/components/Badge/index.js.map +1 -1
- package/dist/components/BarChart/BarChart.d.ts +20 -2
- package/dist/components/BarChart/BarChart.d.ts.map +1 -1
- package/dist/components/BarChart/BarChart.js +17 -3
- package/dist/components/BarChart/BarChart.js.map +1 -1
- package/dist/components/Button/Button.d.ts +85 -6
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Button/Button.js +97 -106
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Button/index.d.ts +1 -1
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Calendar/Calendar.d.ts +31 -1
- package/dist/components/Calendar/Calendar.d.ts.map +1 -1
- package/dist/components/Calendar/Calendar.js +94 -225
- package/dist/components/Calendar/Calendar.js.map +1 -1
- package/dist/components/Calendar/CalendarView.d.ts +15 -0
- package/dist/components/Calendar/CalendarView.d.ts.map +1 -0
- package/dist/components/Calendar/CalendarView.js +263 -0
- package/dist/components/Calendar/CalendarView.js.map +1 -0
- package/dist/components/Calendar/calendar.types.d.ts +87 -27
- package/dist/components/Calendar/calendar.types.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.types.js +10 -3
- package/dist/components/Calendar/calendar.types.js.map +1 -1
- package/dist/components/Calendar/index.d.ts +16 -2
- package/dist/components/Calendar/index.d.ts.map +1 -1
- package/dist/components/Calendar/index.js +15 -1
- package/dist/components/Calendar/index.js.map +1 -1
- package/dist/components/Card/Card.d.ts +13 -0
- package/dist/components/Card/Card.d.ts.map +1 -1
- package/dist/components/Card/Card.js +15 -2
- package/dist/components/Card/Card.js.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +21 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.js +22 -1
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +22 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.js +22 -0
- package/dist/components/CheckboxGroup/CheckboxGroup.js.map +1 -1
- package/dist/components/Code/Editor/Editor.js +2 -2
- package/dist/components/Code/Editor/Editor.js.map +1 -1
- package/dist/components/Code/Editor/themes.d.ts +2 -2
- package/dist/components/Code/Editor/themes.d.ts.map +1 -1
- package/dist/components/Code/Editor/themes.js +50 -32
- package/dist/components/Code/Editor/themes.js.map +1 -1
- package/dist/components/Code/ValidationStatus/ValidationStatus.d.ts.map +1 -1
- package/dist/components/Code/ValidationStatus/ValidationStatus.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +45 -2
- package/dist/components/DatePicker/DatePicker.d.ts.map +1 -1
- package/dist/components/DatePicker/DatePicker.js +228 -11
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DatePicker/DateSegments.d.ts +60 -0
- package/dist/components/DatePicker/DateSegments.d.ts.map +1 -0
- package/dist/components/DatePicker/DateSegments.js +80 -0
- package/dist/components/DatePicker/DateSegments.js.map +1 -0
- package/dist/components/DatePicker/datepicker.types.d.ts +53 -37
- package/dist/components/DatePicker/datepicker.types.d.ts.map +1 -1
- package/dist/components/DatePicker/datepicker.types.js +5 -3
- package/dist/components/DatePicker/datepicker.types.js.map +1 -1
- package/dist/components/DatePicker/index.d.ts +10 -1
- package/dist/components/DatePicker/index.d.ts.map +1 -1
- package/dist/components/DatePicker/index.js +8 -0
- package/dist/components/DatePicker/index.js.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.d.ts +22 -3
- package/dist/components/DateRangePicker/DateRangePicker.d.ts.map +1 -1
- package/dist/components/DateRangePicker/DateRangePicker.js +38 -24
- package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/DateRangePicker/daterangepicker.types.d.ts +26 -21
- package/dist/components/DateRangePicker/daterangepicker.types.d.ts.map +1 -1
- package/dist/components/DateRangePicker/daterangepicker.types.js +6 -0
- package/dist/components/DateRangePicker/daterangepicker.types.js.map +1 -1
- package/dist/components/DateRangePicker/index.d.ts +8 -1
- package/dist/components/DateRangePicker/index.d.ts.map +1 -1
- package/dist/components/DateRangePicker/index.js +6 -0
- package/dist/components/DateRangePicker/index.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.d.ts +32 -4
- package/dist/components/DateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/components/DateTimePicker/DateTimePicker.js +133 -42
- package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
- package/dist/components/DateTimePicker/DateTimeSegments.d.ts +41 -0
- package/dist/components/DateTimePicker/DateTimeSegments.d.ts.map +1 -0
- package/dist/components/DateTimePicker/DateTimeSegments.js +67 -0
- package/dist/components/DateTimePicker/DateTimeSegments.js.map +1 -0
- package/dist/components/DateTimePicker/datetimepicker.types.d.ts +26 -18
- package/dist/components/DateTimePicker/datetimepicker.types.d.ts.map +1 -1
- package/dist/components/DateTimePicker/datetimepicker.types.js +10 -0
- package/dist/components/DateTimePicker/datetimepicker.types.js.map +1 -1
- package/dist/components/DateTimePicker/index.d.ts +8 -1
- package/dist/components/DateTimePicker/index.d.ts.map +1 -1
- package/dist/components/DateTimePicker/index.js +6 -0
- package/dist/components/DateTimePicker/index.js.map +1 -1
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.d.ts +30 -4
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.d.ts.map +1 -1
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.js +171 -72
- package/dist/components/DateTimeRangePicker/DateTimeRangePicker.js.map +1 -1
- package/dist/components/DateTimeRangePicker/datetimerangepicker.types.d.ts +28 -19
- package/dist/components/DateTimeRangePicker/datetimerangepicker.types.d.ts.map +1 -1
- package/dist/components/DateTimeRangePicker/datetimerangepicker.types.js +8 -0
- package/dist/components/DateTimeRangePicker/datetimerangepicker.types.js.map +1 -1
- package/dist/components/DateTimeRangePicker/index.d.ts +8 -0
- package/dist/components/DateTimeRangePicker/index.d.ts.map +1 -1
- package/dist/components/DateTimeRangePicker/index.js +7 -0
- package/dist/components/DateTimeRangePicker/index.js.map +1 -1
- package/dist/components/Field/Field.d.ts +18 -20
- package/dist/components/Field/Field.d.ts.map +1 -1
- package/dist/components/Field/Field.js +22 -5
- package/dist/components/Field/Field.js.map +1 -1
- package/dist/components/FormField/FormField.d.ts +15 -0
- package/dist/components/FormField/FormField.d.ts.map +1 -1
- package/dist/components/FormField/FormField.js +15 -0
- package/dist/components/FormField/FormField.js.map +1 -1
- package/dist/components/HoverCard/HoverCard.d.ts +6 -0
- package/dist/components/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/components/HoverCard/HoverCard.js +6 -0
- package/dist/components/HoverCard/HoverCard.js.map +1 -1
- package/dist/components/Input/Input.d.ts +15 -0
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/Input/Input.js +18 -3
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/LineChart/LineChart.d.ts +35 -2
- package/dist/components/LineChart/LineChart.d.ts.map +1 -1
- package/dist/components/LineChart/LineChart.js +22 -3
- package/dist/components/LineChart/LineChart.js.map +1 -1
- package/dist/components/Markdown/Markdown.d.ts +19 -4
- package/dist/components/Markdown/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown/Markdown.js +20 -2
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Message/Message.d.ts +49 -4
- package/dist/components/Message/Message.d.ts.map +1 -1
- package/dist/components/Message/Message.js +62 -11
- package/dist/components/Message/Message.js.map +1 -1
- package/dist/components/Message/index.d.ts +1 -1
- package/dist/components/Message/index.d.ts.map +1 -1
- package/dist/components/Modal/Modal.d.ts +60 -5
- package/dist/components/Modal/Modal.d.ts.map +1 -1
- package/dist/components/Modal/Modal.js +52 -6
- package/dist/components/Modal/Modal.js.map +1 -1
- package/dist/components/Modal/components/ModalContext.d.ts +14 -0
- package/dist/components/Modal/components/ModalContext.d.ts.map +1 -1
- 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 +13 -2
- package/dist/components/Modal/components/ModalHeader.js.map +1 -1
- package/dist/components/Popover/Popover.d.ts +29 -0
- package/dist/components/Popover/Popover.d.ts.map +1 -1
- package/dist/components/Popover/Popover.js +36 -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 +5 -2
- package/dist/components/Popover/components/PopoverBody.js.map +1 -1
- package/dist/components/Popover/components/PopoverContext.d.ts +1 -0
- package/dist/components/Popover/components/PopoverContext.d.ts.map +1 -1
- 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 +2 -2
- package/dist/components/Popover/components/PopoverTrigger.js.map +1 -1
- package/dist/components/ProgressBar/ProgressBar.d.ts +16 -1
- package/dist/components/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/components/ProgressBar/ProgressBar.js +19 -3
- package/dist/components/ProgressBar/ProgressBar.js.map +1 -1
- package/dist/components/RadioButton/RadioButton.d.ts +26 -0
- package/dist/components/RadioButton/RadioButton.d.ts.map +1 -1
- package/dist/components/RadioButton/RadioButton.js +35 -1
- package/dist/components/RadioButton/RadioButton.js.map +1 -1
- package/dist/components/RadioButtonGroup/RadioButtonGroup.d.ts +26 -0
- package/dist/components/RadioButtonGroup/RadioButtonGroup.d.ts.map +1 -1
- package/dist/components/RadioButtonGroup/RadioButtonGroup.js +33 -0
- package/dist/components/RadioButtonGroup/RadioButtonGroup.js.map +1 -1
- package/dist/components/SearchInput/SearchInput.d.ts +10 -0
- package/dist/components/SearchInput/SearchInput.d.ts.map +1 -1
- package/dist/components/SearchInput/SearchInput.js +12 -1
- package/dist/components/SearchInput/SearchInput.js.map +1 -1
- package/dist/components/Select/Select.d.ts +10 -2
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +63 -18
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectDropdown.d.ts +14 -2
- package/dist/components/Select/SelectDropdown.d.ts.map +1 -1
- package/dist/components/Select/SelectDropdown.js +20 -4
- package/dist/components/Select/SelectDropdown.js.map +1 -1
- package/dist/components/Select/SelectTrigger.d.ts +10 -3
- package/dist/components/Select/SelectTrigger.d.ts.map +1 -1
- package/dist/components/Select/SelectTrigger.js +12 -3
- package/dist/components/Select/SelectTrigger.js.map +1 -1
- package/dist/components/Select/useSelectKeyboard.d.ts +15 -1
- package/dist/components/Select/useSelectKeyboard.d.ts.map +1 -1
- package/dist/components/Select/useSelectKeyboard.js +73 -65
- package/dist/components/Select/useSelectKeyboard.js.map +1 -1
- package/dist/components/Separator/Separator.d.ts +10 -0
- package/dist/components/Separator/Separator.d.ts.map +1 -1
- package/dist/components/Separator/Separator.js +10 -0
- package/dist/components/Separator/Separator.js.map +1 -1
- package/dist/components/Sheet/Sheet.d.ts +25 -5
- package/dist/components/Sheet/Sheet.d.ts.map +1 -1
- package/dist/components/Sheet/Sheet.js +24 -6
- package/dist/components/Sheet/Sheet.js.map +1 -1
- package/dist/components/Sheet/components/SheetContext.d.ts +10 -0
- package/dist/components/Sheet/components/SheetContext.d.ts.map +1 -1
- package/dist/components/Sheet/components/SheetContext.js.map +1 -1
- package/dist/components/Sheet/components/SheetFooter.js +1 -1
- package/dist/components/Sheet/components/SheetFooter.js.map +1 -1
- package/dist/components/Sheet/components/SheetHeader.d.ts.map +1 -1
- package/dist/components/Sheet/components/SheetHeader.js +11 -2
- package/dist/components/Sheet/components/SheetHeader.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.d.ts +21 -2
- package/dist/components/Sparkline/Sparkline.d.ts.map +1 -1
- package/dist/components/Sparkline/Sparkline.js +16 -3
- package/dist/components/Sparkline/Sparkline.js.map +1 -1
- package/dist/components/Spinner/Spinner.d.ts +27 -2
- package/dist/components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner/Spinner.js +28 -3
- package/dist/components/Spinner/Spinner.js.map +1 -1
- package/dist/components/Switch/Switch.d.ts +18 -0
- package/dist/components/Switch/Switch.d.ts.map +1 -1
- package/dist/components/Switch/Switch.js +19 -1
- package/dist/components/Switch/Switch.js.map +1 -1
- package/dist/components/Tabs/Tabs.d.ts +8 -2
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/Tabs.js +6 -0
- package/dist/components/Tabs/Tabs.js.map +1 -1
- package/dist/components/Tabs/components/TabsList.d.ts +1 -1
- package/dist/components/Tabs/components/TabsList.d.ts.map +1 -1
- package/dist/components/Tabs/components/TabsList.js +5 -4
- package/dist/components/Tabs/components/TabsList.js.map +1 -1
- package/dist/components/Tabs/components/TabsPanels.d.ts +1 -1
- package/dist/components/Tabs/components/TabsPanels.d.ts.map +1 -1
- package/dist/components/Tabs/components/TabsPanels.js +5 -3
- 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 +22 -6
- package/dist/components/Tabs/components/TabsTrigger.js.map +1 -1
- package/dist/components/TagChip/TagChip.d.ts +16 -13
- package/dist/components/TagChip/TagChip.d.ts.map +1 -1
- package/dist/components/TagChip/TagChip.js +18 -3
- package/dist/components/TagChip/TagChip.js.map +1 -1
- package/dist/components/TagInput/TagInput.d.ts +12 -9
- package/dist/components/TagInput/TagInput.d.ts.map +1 -1
- package/dist/components/TagInput/TagInput.js +16 -4
- package/dist/components/TagInput/TagInput.js.map +1 -1
- package/dist/components/Text/Text.d.ts +9 -0
- package/dist/components/Text/Text.d.ts.map +1 -1
- package/dist/components/Text/Text.js +9 -0
- package/dist/components/Text/Text.js.map +1 -1
- package/dist/components/TextInline/TextInline.d.ts +15 -4
- package/dist/components/TextInline/TextInline.d.ts.map +1 -1
- package/dist/components/TextInline/TextInline.js +11 -0
- package/dist/components/TextInline/TextInline.js.map +1 -1
- package/dist/components/Textarea/Textarea.d.ts +12 -0
- package/dist/components/Textarea/Textarea.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.js +13 -1
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/TimePicker/TimeColumn.d.ts +10 -1
- package/dist/components/TimePicker/TimeColumn.d.ts.map +1 -1
- package/dist/components/TimePicker/TimeColumn.js +8 -1
- package/dist/components/TimePicker/TimeColumn.js.map +1 -1
- package/dist/components/TimePicker/TimePicker.d.ts +34 -2
- package/dist/components/TimePicker/TimePicker.d.ts.map +1 -1
- package/dist/components/TimePicker/TimePicker.js +118 -15
- package/dist/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/TimePicker/TimeSegments.d.ts +50 -0
- package/dist/components/TimePicker/TimeSegments.d.ts.map +1 -0
- package/dist/components/TimePicker/TimeSegments.js +93 -0
- package/dist/components/TimePicker/TimeSegments.js.map +1 -0
- package/dist/components/TimePicker/timepicker.hooks.d.ts +0 -4
- package/dist/components/TimePicker/timepicker.hooks.d.ts.map +1 -1
- package/dist/components/TimePicker/timepicker.hooks.js +1 -23
- package/dist/components/TimePicker/timepicker.hooks.js.map +1 -1
- package/dist/components/TimePicker/timepicker.types.d.ts +14 -15
- package/dist/components/TimePicker/timepicker.types.d.ts.map +1 -1
- package/dist/components/TimePicker/timepicker.types.js +4 -3
- package/dist/components/TimePicker/timepicker.types.js.map +1 -1
- package/dist/components/Toast/Toast.d.ts +27 -0
- package/dist/components/Toast/Toast.d.ts.map +1 -1
- package/dist/components/Toast/Toast.js +28 -1
- package/dist/components/Toast/Toast.js.map +1 -1
- package/dist/components/Toggle/Toggle.d.ts +31 -12
- package/dist/components/Toggle/Toggle.d.ts.map +1 -1
- package/dist/components/Toggle/Toggle.js +19 -31
- package/dist/components/Toggle/Toggle.js.map +1 -1
- package/dist/components/Toggle/index.d.ts +1 -1
- package/dist/components/Toggle/index.d.ts.map +1 -1
- package/dist/components/Toggle/index.js +1 -1
- package/dist/components/Toggle/index.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +17 -0
- package/dist/components/ToggleGroup/ToggleGroup.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.js +17 -0
- package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupItem.d.ts +1 -1
- package/dist/components/ToggleGroup/ToggleGroupItem.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupItem.js +7 -6
- package/dist/components/ToggleGroup/ToggleGroupItem.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupMultiple.d.ts +4 -3
- package/dist/components/ToggleGroup/ToggleGroupMultiple.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupMultiple.js +2 -2
- package/dist/components/ToggleGroup/ToggleGroupMultiple.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupSingle.d.ts +4 -3
- package/dist/components/ToggleGroup/ToggleGroupSingle.d.ts.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroupSingle.js +2 -2
- package/dist/components/ToggleGroup/ToggleGroupSingle.js.map +1 -1
- package/dist/components/ToggleGroup/toggleGroup.types.d.ts +12 -3
- package/dist/components/ToggleGroup/toggleGroup.types.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +6 -0
- package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +6 -0
- package/dist/components/Tooltip/Tooltip.js.map +1 -1
- package/dist/date-time/index.d.ts +2 -0
- package/dist/date-time/index.d.ts.map +1 -1
- package/dist/date-time/index.js +9 -1
- package/dist/date-time/index.js.map +1 -1
- package/dist/date-time/iso.d.ts +261 -0
- package/dist/date-time/iso.d.ts.map +1 -0
- package/dist/date-time/iso.js +358 -0
- package/dist/date-time/iso.js.map +1 -0
- package/dist/date-time/now.d.ts +7 -6
- package/dist/date-time/now.d.ts.map +1 -1
- package/dist/date-time/now.js +3 -3
- package/dist/date-time/now.js.map +1 -1
- package/dist/internal/PickerField.d.ts +45 -0
- package/dist/internal/PickerField.d.ts.map +1 -0
- package/dist/internal/PickerField.js +24 -0
- package/dist/internal/PickerField.js.map +1 -0
- package/dist/internal/SegmentedField.d.ts +98 -0
- package/dist/internal/SegmentedField.d.ts.map +1 -0
- package/dist/internal/SegmentedField.js +315 -0
- package/dist/internal/SegmentedField.js.map +1 -0
- package/dist/internal/index.d.ts +2 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +2 -0
- package/dist/internal/index.js.map +1 -1
- package/dist/theme/index.d.ts +4 -3
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +3 -2
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/schema.d.ts +49 -33
- package/dist/theme/schema.d.ts.map +1 -1
- package/dist/theme/schema.js +30 -21
- package/dist/theme/schema.js.map +1 -1
- package/package.json +11 -59
- package/src/components/Badge/Badge.tsx +87 -49
- package/src/components/Badge/index.ts +10 -1
- package/src/components/BarChart/BarChart.tsx +37 -30
- package/src/components/Button/Button.tsx +129 -106
- package/src/components/Button/index.ts +10 -1
- package/src/components/Calendar/Calendar.tsx +104 -401
- package/src/components/Calendar/CalendarView.tsx +454 -0
- package/src/components/Calendar/calendar.types.ts +104 -29
- package/src/components/Calendar/index.ts +16 -17
- package/src/components/Card/Card.tsx +15 -2
- package/src/components/Checkbox/Checkbox.tsx +22 -2
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +22 -0
- package/src/components/Code/Editor/Editor.tsx +2 -2
- package/src/components/Code/Editor/themes.ts +50 -32
- package/src/components/Code/ValidationStatus/ValidationStatus.tsx +6 -3
- package/src/components/DatePicker/DatePicker.tsx +369 -42
- package/src/components/DatePicker/DateSegments.tsx +125 -0
- package/src/components/DatePicker/datepicker.types.ts +58 -39
- package/src/components/DatePicker/index.ts +11 -3
- package/src/components/DateRangePicker/DateRangePicker.tsx +38 -24
- package/src/components/DateRangePicker/daterangepicker.types.ts +29 -23
- package/src/components/DateRangePicker/index.ts +9 -1
- package/src/components/DateTimePicker/DateTimePicker.tsx +189 -88
- package/src/components/DateTimePicker/DateTimeSegments.tsx +113 -0
- package/src/components/DateTimePicker/datetimepicker.types.ts +29 -19
- package/src/components/DateTimePicker/index.ts +9 -1
- package/src/components/DateTimeRangePicker/DateTimeRangePicker.tsx +251 -126
- package/src/components/DateTimeRangePicker/datetimerangepicker.types.ts +31 -20
- package/src/components/DateTimeRangePicker/index.ts +9 -0
- package/src/components/Field/Field.tsx +25 -26
- package/src/components/FormField/FormField.tsx +15 -0
- package/src/components/HoverCard/HoverCard.tsx +6 -0
- package/src/components/Input/Input.tsx +19 -4
- package/src/components/LineChart/LineChart.tsx +164 -141
- package/src/components/Markdown/Markdown.tsx +21 -3
- package/src/components/Message/Message.tsx +83 -17
- package/src/components/Message/index.ts +1 -1
- package/src/components/Modal/Modal.tsx +157 -86
- package/src/components/Modal/components/ModalContext.tsx +14 -0
- package/src/components/Modal/components/ModalHeader.tsx +15 -3
- package/src/components/Popover/Popover.tsx +36 -0
- package/src/components/Popover/components/PopoverBody.tsx +6 -1
- package/src/components/Popover/components/PopoverContext.tsx +1 -0
- package/src/components/Popover/components/PopoverTrigger.tsx +2 -1
- package/src/components/ProgressBar/ProgressBar.tsx +46 -28
- package/src/components/RadioButton/RadioButton.tsx +34 -3
- package/src/components/RadioButtonGroup/RadioButtonGroup.tsx +32 -0
- package/src/components/SearchInput/SearchInput.tsx +13 -2
- package/src/components/Select/Select.tsx +75 -19
- package/src/components/Select/SelectDropdown.tsx +45 -12
- package/src/components/Select/SelectTrigger.tsx +31 -8
- package/src/components/Select/useSelectKeyboard.ts +20 -10
- package/src/components/Separator/Separator.tsx +10 -0
- package/src/components/Sheet/Sheet.tsx +114 -83
- package/src/components/Sheet/components/SheetContext.tsx +10 -0
- package/src/components/Sheet/components/SheetFooter.tsx +1 -1
- package/src/components/Sheet/components/SheetHeader.tsx +18 -3
- package/src/components/Sparkline/Sparkline.tsx +40 -36
- package/src/components/Spinner/Spinner.tsx +28 -3
- package/src/components/Switch/Switch.tsx +27 -4
- package/src/components/Tabs/Tabs.tsx +6 -0
- package/src/components/Tabs/components/TabsList.tsx +5 -3
- package/src/components/Tabs/components/TabsPanels.tsx +5 -3
- package/src/components/Tabs/components/TabsTrigger.tsx +22 -5
- package/src/components/TagChip/TagChip.tsx +27 -18
- package/src/components/TagInput/TagInput.tsx +16 -11
- package/src/components/Text/Text.tsx +9 -0
- package/src/components/TextInline/TextInline.tsx +11 -0
- package/src/components/Textarea/Textarea.tsx +13 -1
- package/src/components/TimePicker/TimeColumn.tsx +24 -1
- package/src/components/TimePicker/TimePicker.tsx +157 -51
- package/src/components/TimePicker/TimeSegments.tsx +131 -0
- package/src/components/TimePicker/timepicker.hooks.ts +1 -24
- package/src/components/TimePicker/timepicker.types.ts +14 -16
- package/src/components/Toast/Toast.tsx +28 -1
- package/src/components/Toggle/Toggle.tsx +34 -32
- package/src/components/Toggle/index.ts +1 -1
- package/src/components/ToggleGroup/ToggleGroup.tsx +17 -0
- package/src/components/ToggleGroup/ToggleGroupItem.tsx +13 -8
- package/src/components/ToggleGroup/ToggleGroupMultiple.tsx +3 -1
- package/src/components/ToggleGroup/ToggleGroupSingle.tsx +3 -1
- package/src/components/ToggleGroup/toggleGroup.types.ts +12 -3
- package/src/components/Tooltip/Tooltip.tsx +6 -0
- package/src/date-time/index.ts +61 -1
- package/src/date-time/iso.ts +511 -0
- package/src/date-time/now.ts +10 -9
- package/src/internal/PickerField.tsx +90 -0
- package/src/internal/SegmentedField.tsx +445 -0
- package/src/internal/index.ts +2 -0
- package/src/theme/index.ts +11 -9
- package/src/theme/recipes/badge.css +140 -0
- package/src/theme/recipes/button.css +167 -0
- package/src/theme/recipes/card.css +26 -0
- package/src/theme/recipes/checkbox.css +44 -0
- package/src/theme/recipes/field.css +14 -0
- package/src/theme/recipes/index.css +28 -0
- package/src/theme/recipes/input.css +29 -0
- package/src/theme/recipes/message.css +47 -0
- package/src/theme/recipes/modal.css +31 -0
- package/src/theme/recipes/radio-button.css +42 -0
- package/src/theme/recipes/search-input.css +16 -0
- package/src/theme/recipes/select.css +105 -0
- package/src/theme/recipes/sheet.css +34 -0
- package/src/theme/recipes/spinner.css +17 -0
- package/src/theme/recipes/switch.css +39 -0
- package/src/theme/recipes/tabs.css +41 -0
- package/src/theme/recipes/tag-chip.css +27 -0
- package/src/theme/recipes/textarea.css +20 -0
- package/src/theme/recipes/toggle.css +92 -0
- package/src/theme/schema.ts +59 -58
- package/src/theme/tokens.css +824 -0
- package/dist/components/Avatar/Avatar.d.ts +0 -6
- package/dist/components/Avatar/Avatar.d.ts.map +0 -1
- package/dist/components/Avatar/Avatar.js +0 -11
- package/dist/components/Avatar/Avatar.js.map +0 -1
- package/dist/components/Avatar/index.d.ts +0 -2
- package/dist/components/Avatar/index.d.ts.map +0 -1
- package/dist/components/Avatar/index.js +0 -2
- package/dist/components/Avatar/index.js.map +0 -1
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +0 -12
- package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +0 -1
- package/dist/components/Breadcrumb/Breadcrumb.js +0 -19
- package/dist/components/Breadcrumb/Breadcrumb.js.map +0 -1
- package/dist/components/Breadcrumb/index.d.ts +0 -2
- package/dist/components/Breadcrumb/index.d.ts.map +0 -1
- package/dist/components/Breadcrumb/index.js +0 -2
- package/dist/components/Breadcrumb/index.js.map +0 -1
- package/dist/components/ColorDot/ColorDot.d.ts +0 -13
- package/dist/components/ColorDot/ColorDot.d.ts.map +0 -1
- package/dist/components/ColorDot/ColorDot.js +0 -34
- package/dist/components/ColorDot/ColorDot.js.map +0 -1
- package/dist/components/ColorDot/index.d.ts +0 -2
- package/dist/components/ColorDot/index.d.ts.map +0 -1
- package/dist/components/ColorDot/index.js +0 -2
- package/dist/components/ColorDot/index.js.map +0 -1
- package/dist/components/EmptyState/EmptyState.d.ts +0 -15
- package/dist/components/EmptyState/EmptyState.d.ts.map +0 -1
- package/dist/components/EmptyState/EmptyState.js +0 -7
- package/dist/components/EmptyState/EmptyState.js.map +0 -1
- package/dist/components/EmptyState/index.d.ts +0 -2
- package/dist/components/EmptyState/index.d.ts.map +0 -1
- package/dist/components/EmptyState/index.js +0 -2
- package/dist/components/EmptyState/index.js.map +0 -1
- package/dist/components/HeatMap/HeatMapCalendar.d.ts +0 -11
- package/dist/components/HeatMap/HeatMapCalendar.d.ts.map +0 -1
- package/dist/components/HeatMap/HeatMapCalendar.js +0 -68
- package/dist/components/HeatMap/HeatMapCalendar.js.map +0 -1
- package/dist/components/HeatMap/HeatMapMatrix.d.ts +0 -12
- package/dist/components/HeatMap/HeatMapMatrix.d.ts.map +0 -1
- package/dist/components/HeatMap/HeatMapMatrix.js +0 -35
- package/dist/components/HeatMap/HeatMapMatrix.js.map +0 -1
- package/dist/components/HeatMap/heat-map.utils.d.ts +0 -10
- package/dist/components/HeatMap/heat-map.utils.d.ts.map +0 -1
- package/dist/components/HeatMap/heat-map.utils.js +0 -10
- package/dist/components/HeatMap/heat-map.utils.js.map +0 -1
- package/dist/components/HeatMap/index.d.ts +0 -4
- package/dist/components/HeatMap/index.d.ts.map +0 -1
- package/dist/components/HeatMap/index.js +0 -3
- package/dist/components/HeatMap/index.js.map +0 -1
- package/dist/components/MetricList/MetricList.d.ts +0 -9
- package/dist/components/MetricList/MetricList.d.ts.map +0 -1
- package/dist/components/MetricList/MetricList.js +0 -6
- package/dist/components/MetricList/MetricList.js.map +0 -1
- package/dist/components/MetricList/MetricRow.d.ts +0 -13
- package/dist/components/MetricList/MetricRow.d.ts.map +0 -1
- package/dist/components/MetricList/MetricRow.js +0 -13
- package/dist/components/MetricList/MetricRow.js.map +0 -1
- package/dist/components/MetricList/index.d.ts +0 -3
- package/dist/components/MetricList/index.d.ts.map +0 -1
- package/dist/components/MetricList/index.js +0 -3
- package/dist/components/MetricList/index.js.map +0 -1
- package/dist/components/NavBottom/NavBottom.d.ts +0 -15
- package/dist/components/NavBottom/NavBottom.d.ts.map +0 -1
- package/dist/components/NavBottom/NavBottom.js +0 -19
- package/dist/components/NavBottom/NavBottom.js.map +0 -1
- package/dist/components/NavBottom/index.d.ts +0 -3
- package/dist/components/NavBottom/index.d.ts.map +0 -1
- package/dist/components/NavBottom/index.js +0 -2
- package/dist/components/NavBottom/index.js.map +0 -1
- package/dist/components/NavSide/NavItem.d.ts +0 -9
- package/dist/components/NavSide/NavItem.d.ts.map +0 -1
- package/dist/components/NavSide/NavItem.js +0 -13
- package/dist/components/NavSide/NavItem.js.map +0 -1
- package/dist/components/NavSide/NavSide.d.ts +0 -15
- package/dist/components/NavSide/NavSide.d.ts.map +0 -1
- package/dist/components/NavSide/NavSide.js +0 -10
- package/dist/components/NavSide/NavSide.js.map +0 -1
- package/dist/components/NavSide/index.d.ts +0 -3
- package/dist/components/NavSide/index.d.ts.map +0 -1
- package/dist/components/NavSide/index.js +0 -2
- package/dist/components/NavSide/index.js.map +0 -1
- package/dist/components/NavSide/types.d.ts +0 -38
- package/dist/components/NavSide/types.d.ts.map +0 -1
- package/dist/components/NavSide/types.js +0 -2
- package/dist/components/NavSide/types.js.map +0 -1
- package/dist/components/Pagination/Pagination.d.ts +0 -35
- package/dist/components/Pagination/Pagination.d.ts.map +0 -1
- package/dist/components/Pagination/Pagination.js +0 -26
- package/dist/components/Pagination/Pagination.js.map +0 -1
- package/dist/components/Pagination/index.d.ts +0 -3
- package/dist/components/Pagination/index.d.ts.map +0 -1
- package/dist/components/Pagination/index.js +0 -2
- package/dist/components/Pagination/index.js.map +0 -1
- package/dist/components/Skeleton/Skeleton.d.ts +0 -3
- package/dist/components/Skeleton/Skeleton.d.ts.map +0 -1
- package/dist/components/Skeleton/Skeleton.js +0 -7
- package/dist/components/Skeleton/Skeleton.js.map +0 -1
- package/dist/components/Skeleton/index.d.ts +0 -2
- package/dist/components/Skeleton/index.d.ts.map +0 -1
- package/dist/components/Skeleton/index.js +0 -2
- package/dist/components/Skeleton/index.js.map +0 -1
- package/dist/components/StatsCard/StatsCard.d.ts +0 -17
- package/dist/components/StatsCard/StatsCard.d.ts.map +0 -1
- package/dist/components/StatsCard/StatsCard.js +0 -13
- package/dist/components/StatsCard/StatsCard.js.map +0 -1
- package/dist/components/StatsCard/index.d.ts +0 -2
- package/dist/components/StatsCard/index.d.ts.map +0 -1
- package/dist/components/StatsCard/index.js +0 -2
- package/dist/components/StatsCard/index.js.map +0 -1
- package/dist/styles.css +0 -2
- package/dist/theme.generated.css +0 -438
- package/src/components/Avatar/Avatar.tsx +0 -19
- package/src/components/Avatar/index.ts +0 -1
- package/src/components/Breadcrumb/Breadcrumb.tsx +0 -47
- package/src/components/Breadcrumb/index.ts +0 -5
- package/src/components/ColorDot/ColorDot.tsx +0 -50
- package/src/components/ColorDot/index.ts +0 -1
- package/src/components/EmptyState/EmptyState.tsx +0 -29
- package/src/components/EmptyState/index.ts +0 -1
- package/src/components/HeatMap/HeatMapCalendar.tsx +0 -127
- package/src/components/HeatMap/HeatMapMatrix.tsx +0 -75
- package/src/components/HeatMap/heat-map.utils.ts +0 -15
- package/src/components/HeatMap/index.ts +0 -3
- package/src/components/MetricList/MetricList.tsx +0 -13
- package/src/components/MetricList/MetricRow.tsx +0 -30
- package/src/components/MetricList/index.ts +0 -2
- package/src/components/NavBottom/NavBottom.tsx +0 -53
- package/src/components/NavBottom/index.ts +0 -3
- package/src/components/NavSide/NavItem.tsx +0 -39
- package/src/components/NavSide/NavSide.tsx +0 -40
- package/src/components/NavSide/index.ts +0 -2
- package/src/components/NavSide/types.ts +0 -36
- package/src/components/Pagination/Pagination.tsx +0 -86
- package/src/components/Pagination/index.ts +0 -2
- package/src/components/Skeleton/Skeleton.tsx +0 -7
- package/src/components/Skeleton/index.ts +0 -1
- package/src/components/StatsCard/StatsCard.tsx +0 -40
- package/src/components/StatsCard/index.ts +0 -1
- package/src/styles/base.css +0 -41
- package/src/theme/palette.json +0 -100
- package/src/theme/palette.schema.json +0 -40
- package/src/theme/theme.json +0 -349
- package/src/theme/theme.schema.json +0 -876
- package/src/theme/typography.json +0 -7
- package/src/theme/typography.schema.json +0 -36
- package/tailwind.config.ts +0 -261
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Caption } from "@sixthshift/design-system/caption";
|
|
2
2
|
import { cn } from "@sixthshift/design-system/utils";
|
|
3
|
+
import * as React from "react";
|
|
3
4
|
|
|
4
5
|
export type ProgressBarProps = {
|
|
5
6
|
completed: number;
|
|
@@ -10,33 +11,50 @@ export type ProgressBarProps = {
|
|
|
10
11
|
className?: string;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Determinate progress meter: a labelled fill bar plus an optional `n/total`
|
|
16
|
+
* fraction (`showFraction`, default `true`).
|
|
17
|
+
*
|
|
18
|
+
* The bar itself is `role="progressbar"` with `aria-valuemin`/`-valuenow`/
|
|
19
|
+
* `-valuemax`/`-valuetext`, and `label` (default `"Progress"`) sets its
|
|
20
|
+
* accessible name — give it something more specific than the default when
|
|
21
|
+
* more than one bar can appear on a page. `completed` is clamped into
|
|
22
|
+
* `[0, total]` before it drives the fill width or `aria-valuenow`, so an
|
|
23
|
+
* out-of-range value (negative, or greater than `total`) can't produce
|
|
24
|
+
* invalid CSS or an impossible reported value — though the fraction text
|
|
25
|
+
* still shows the raw, unclamped numbers. When `total` is not positive the
|
|
26
|
+
* bar renders as indeterminate: no `aria-valuenow`/`aria-valuemax`, 0% fill.
|
|
27
|
+
*/
|
|
28
|
+
export const ProgressBar = React.forwardRef<HTMLDivElement, ProgressBarProps>(
|
|
29
|
+
({ completed, total, showFraction = true, label = "Progress", className }, ref) => {
|
|
30
|
+
// A caller can hand us anything; the bar must not render an out-of-range
|
|
31
|
+
// width (a negative `width` is invalid CSS) or report impossible progress.
|
|
32
|
+
const isMeasurable = total > 0;
|
|
33
|
+
const clamped = isMeasurable ? Math.min(Math.max(completed, 0), total) : 0;
|
|
34
|
+
const percentage = isMeasurable ? (clamped / total) * 100 : 0;
|
|
19
35
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
return (
|
|
37
|
+
<div ref={ref} className={cn("flex items-center gap-3", className)}>
|
|
38
|
+
<div
|
|
39
|
+
role="progressbar"
|
|
40
|
+
aria-label={label}
|
|
41
|
+
aria-valuemin={0}
|
|
42
|
+
aria-valuemax={isMeasurable ? total : undefined}
|
|
43
|
+
// An indeterminate progressbar omits aria-valuenow; with no positive
|
|
44
|
+
// total there is no meaningful progress to report.
|
|
45
|
+
aria-valuenow={isMeasurable ? clamped : undefined}
|
|
46
|
+
aria-valuetext={isMeasurable ? `${clamped} of ${total}` : undefined}
|
|
47
|
+
className="h-2 flex-1 overflow-hidden rounded-full bg-bg-strong"
|
|
48
|
+
>
|
|
49
|
+
<div className="h-full rounded-full bg-fg-success transition-all" style={{ width: `${percentage}%` }} />
|
|
50
|
+
</div>
|
|
51
|
+
{showFraction && (
|
|
52
|
+
<Caption className="shrink-0">
|
|
53
|
+
{completed}/{total}
|
|
54
|
+
</Caption>
|
|
55
|
+
)}
|
|
34
56
|
</div>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)}
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
};
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
ProgressBar.displayName = "ProgressBar";
|
|
@@ -23,6 +23,32 @@ const RadioButtonIcon = () => (
|
|
|
23
23
|
</svg>
|
|
24
24
|
);
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* A single custom radio option — a button with `role="radio"` rather than
|
|
28
|
+
* a native `<input type="radio">`, so it can be styled without fighting
|
|
29
|
+
* native radio rendering.
|
|
30
|
+
*
|
|
31
|
+
* Unlike `Checkbox`, it holds no internal state: `checked` is a plain
|
|
32
|
+
* controlled prop (default `false`, no `defaultChecked`), and clicking an
|
|
33
|
+
* unselected radio calls `onCheckedChange(true)` — the caller owns tracking
|
|
34
|
+
* which option in a group is selected. In practice that means using
|
|
35
|
+
* `RadioButtonGroup` to manage a group's value, or wiring up the shared
|
|
36
|
+
* selection by hand.
|
|
37
|
+
*
|
|
38
|
+
* Clicking an already-selected radio does nothing and reports nothing: a radio
|
|
39
|
+
* is not a toggle, and the way to deselect one is to select a sibling. That
|
|
40
|
+
* makes `onCheckedChange` a one-way signal — it is only ever called with
|
|
41
|
+
* `true`.
|
|
42
|
+
*
|
|
43
|
+
* Only participates in native form submission when `name` is set, via a
|
|
44
|
+
* hidden native `<input type="radio">` rendered alongside the button and
|
|
45
|
+
* kept in sync (`value` defaults to `"on"`); give every radio in a group the
|
|
46
|
+
* same `name` to group them for native submission.
|
|
47
|
+
*
|
|
48
|
+
* Passing `label` wraps the button and a `<Label>` together and wires
|
|
49
|
+
* `htmlFor`/`id` between them; without it, you get just the button and must
|
|
50
|
+
* supply your own accessible name.
|
|
51
|
+
*/
|
|
26
52
|
const RadioButton = React.forwardRef<HTMLButtonElement, RadioButtonProps>(
|
|
27
53
|
({ className, checked = false, onCheckedChange, disabled, name, value = "on", label, labelClassName, id: idProp, ...props }, ref) => {
|
|
28
54
|
const generatedId = React.useId();
|
|
@@ -39,10 +65,15 @@ const RadioButton = React.forwardRef<HTMLButtonElement, RadioButtonProps>(
|
|
|
39
65
|
data-state={checked ? "checked" : "unchecked"}
|
|
40
66
|
disabled={disabled}
|
|
41
67
|
ref={ref}
|
|
42
|
-
|
|
68
|
+
// A radio is not a toggle: activating the selected option leaves it
|
|
69
|
+
// selected, and reports nothing, so a caller holding the selection
|
|
70
|
+
// does not see a spurious change. Deselection happens by selecting a
|
|
71
|
+
// sibling, which is what `RadioButtonGroup` does.
|
|
72
|
+
onClick={() => {
|
|
73
|
+
if (!checked) onCheckedChange?.(true);
|
|
74
|
+
}}
|
|
43
75
|
className={cn(
|
|
44
|
-
"peer h-4 w-4 shrink-0 cursor-pointer rounded-full border
|
|
45
|
-
checked && "bg-bg-brand text-fg-on-brand",
|
|
76
|
+
"radio-button peer border-(color:--radio-button-border) focus-visible:ring-(color:--radio-button-ring) h-4 w-4 shrink-0 cursor-pointer rounded-full border bg-(--radio-button-bg) text-(--radio-button-fg) shadow focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
46
77
|
className
|
|
47
78
|
)}
|
|
48
79
|
{...props}
|
|
@@ -37,6 +37,32 @@ export type RadioButtonGroupProps = Omit<React.HTMLAttributes<HTMLDivElement>, "
|
|
|
37
37
|
onBlur?: () => void;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* A set of mutually exclusive radio options sharing one controlled/
|
|
42
|
+
* uncontrolled `string` selection, via the `value`/`defaultValue`/
|
|
43
|
+
* `onValueChange` triad (`useControllableState`).
|
|
44
|
+
*
|
|
45
|
+
* `variant="default"` (the default) renders one `RadioButton` per option.
|
|
46
|
+
* `variant="button"` is a separate rendering path — not a re-skinned
|
|
47
|
+
* `RadioButton` — a row/column of plain buttons with `role="radio"`;
|
|
48
|
+
* contiguous buttons touch and share borders (`appearance="segmented"`, the
|
|
49
|
+
* default) or sit apart with their own rounded corners
|
|
50
|
+
* (`appearance="separate"`).
|
|
51
|
+
*
|
|
52
|
+
* Implements the WAI-ARIA radiogroup keyboard pattern: the group is one tab
|
|
53
|
+
* stop, landing on the checked option (or the first enabled option if none
|
|
54
|
+
* is checked), and arrow/Home/End keys move focus *and* selection between
|
|
55
|
+
* enabled options, wrapping at the ends.
|
|
56
|
+
*
|
|
57
|
+
* Form submission only happens when `name` is set. In the default variant
|
|
58
|
+
* that means each underlying `RadioButton` gets `name`, so one hidden
|
|
59
|
+
* native radio input is rendered per option; in the button variant the
|
|
60
|
+
* group itself renders a single hidden `<input type="hidden">` carrying the
|
|
61
|
+
* selected value.
|
|
62
|
+
*
|
|
63
|
+
* Renders `role="radiogroup"`; focus leaving the whole group — not just
|
|
64
|
+
* moving between options — fires `onBlur`.
|
|
65
|
+
*/
|
|
40
66
|
const RadioButtonGroup = React.forwardRef<HTMLDivElement, RadioButtonGroupProps>(
|
|
41
67
|
(
|
|
42
68
|
{
|
|
@@ -81,6 +107,12 @@ const RadioButtonGroup = React.forwardRef<HTMLDivElement, RadioButtonGroupProps>
|
|
|
81
107
|
);
|
|
82
108
|
|
|
83
109
|
const handleOptionSelect = (optionValue: string) => {
|
|
110
|
+
// Re-selecting the current option reports nothing, as a native radio does
|
|
111
|
+
// not. The guard lives here as well as in `RadioButton` because the button
|
|
112
|
+
// variant is a separate rendering path that never goes through it — and
|
|
113
|
+
// the two variants must not disagree about this. `ToggleGroup` in
|
|
114
|
+
// `"single"` mode already works this way.
|
|
115
|
+
if (optionValue === value) return;
|
|
84
116
|
setValue(optionValue);
|
|
85
117
|
};
|
|
86
118
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Input } from "@sixthshift/design-system/input";
|
|
2
|
+
import { cn } from "@sixthshift/design-system/utils";
|
|
2
3
|
import { Search, X } from "lucide-react";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
|
|
@@ -10,6 +11,16 @@ export type SearchInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>,
|
|
|
10
11
|
clearLabel?: string;
|
|
11
12
|
};
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Text input specialised for search: a search icon fixed on the left and,
|
|
16
|
+
* once there is a value, a clear button on the right.
|
|
17
|
+
*
|
|
18
|
+
* Wraps `Input`, using its `iconLeft`/`iconRight` slots, rather than
|
|
19
|
+
* reimplementing the field. Always controlled — `value` is required and
|
|
20
|
+
* there is no `defaultValue`/uncontrolled mode. `onChange` receives the
|
|
21
|
+
* string value directly, not the change event. Clearing calls `onClear` if
|
|
22
|
+
* provided, otherwise calls `onChange("")`.
|
|
23
|
+
*/
|
|
13
24
|
const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
|
|
14
25
|
({ className, value, onChange, onClear, clearLabel = "Clear search", ...props }, ref) => {
|
|
15
26
|
const handleClear = () => {
|
|
@@ -29,12 +40,12 @@ const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
|
|
|
29
40
|
iconLeft={<Search />}
|
|
30
41
|
iconRight={
|
|
31
42
|
value ? (
|
|
32
|
-
<button type="button" onClick={handleClear} aria-label={clearLabel} className="rounded hover:bg-bg-
|
|
43
|
+
<button type="button" onClick={handleClear} aria-label={clearLabel} className="rounded hover:bg-(--search-input-clear-bg-hovered)">
|
|
33
44
|
<X />
|
|
34
45
|
</button>
|
|
35
46
|
) : undefined
|
|
36
47
|
}
|
|
37
|
-
className={className}
|
|
48
|
+
className={cn("search-input", className)}
|
|
38
49
|
{...props}
|
|
39
50
|
/>
|
|
40
51
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { autoUpdate, flip, offset, shift, size, useFloating } from "@floating-ui/react";
|
|
2
2
|
import { useControllableState } from "@sixthshift/design-system/hooks";
|
|
3
|
-
import { type HTMLAttributes, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { SelectDropdown } from "./SelectDropdown";
|
|
3
|
+
import { forwardRef, type HTMLAttributes, type ReactElement, type Ref, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { SelectDropdown, selectOptionId } from "./SelectDropdown";
|
|
5
5
|
import { SelectTriggerButton, SelectTriggerSearch } from "./SelectTrigger";
|
|
6
6
|
import { useSelectKeyboard } from "./useSelectKeyboard";
|
|
7
7
|
|
|
@@ -37,7 +37,13 @@ type SelectMultipleProps<T extends string = string> = SelectBaseProps<T> & {
|
|
|
37
37
|
|
|
38
38
|
export type SelectProps<T extends string = string> = SelectSingleProps<T> | SelectMultipleProps<T>;
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
/**
|
|
41
|
+
* `forwardRef` erases the generic, so the implementation takes the ref as an
|
|
42
|
+
* ordinary second argument and the exported `Select` re-declares the generic
|
|
43
|
+
* signature over it. Consumers keep `Select<"a" | "b">` inference *and* get a
|
|
44
|
+
* ref; without the cast they would have to choose.
|
|
45
|
+
*/
|
|
46
|
+
const SelectRoot = forwardRef(function SelectRoot<T extends string = string>(props: SelectProps<T>, rootRef: Ref<HTMLDivElement>) {
|
|
41
47
|
const {
|
|
42
48
|
options,
|
|
43
49
|
onBlur,
|
|
@@ -71,6 +77,11 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
71
77
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
72
78
|
const [searchValue, setSearchValue] = useState("");
|
|
73
79
|
const listboxRef = useRef<HTMLDivElement | null>(null);
|
|
80
|
+
// Also held in state: the listbox is portalled, and FloatingPortal creates its
|
|
81
|
+
// container in an effect, so the node lands a commit after `open` flips. A ref
|
|
82
|
+
// alone is still null when the open effect runs — state re-renders us when the
|
|
83
|
+
// node actually arrives.
|
|
84
|
+
const [listboxNode, setListboxNode] = useState<HTMLDivElement | null>(null);
|
|
74
85
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
75
86
|
const optionRefs = useRef<Map<number, HTMLButtonElement>>(new Map());
|
|
76
87
|
const wasOpenRef = useRef(false);
|
|
@@ -111,6 +122,11 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
111
122
|
whileElementsMounted: autoUpdate,
|
|
112
123
|
});
|
|
113
124
|
|
|
125
|
+
const setListbox = useCallback((node: HTMLDivElement | null) => {
|
|
126
|
+
listboxRef.current = node;
|
|
127
|
+
setListboxNode(node);
|
|
128
|
+
}, []);
|
|
129
|
+
|
|
114
130
|
const focusTrigger = useCallback(() => {
|
|
115
131
|
(refs.reference.current as HTMLElement | null)?.focus();
|
|
116
132
|
}, [refs.reference]);
|
|
@@ -142,18 +158,38 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
142
158
|
[isMultiple, setMultiValue, setSingleValue]
|
|
143
159
|
);
|
|
144
160
|
|
|
161
|
+
const handleListKeyDown = useSelectKeyboard({
|
|
162
|
+
open,
|
|
163
|
+
searchable,
|
|
164
|
+
searchValue,
|
|
165
|
+
highlightedIndex,
|
|
166
|
+
displayOptions: filteredOptions,
|
|
167
|
+
setOpen,
|
|
168
|
+
setHighlightedIndex,
|
|
169
|
+
setSearchValue,
|
|
170
|
+
handleSelect,
|
|
171
|
+
focusTrigger,
|
|
172
|
+
});
|
|
173
|
+
|
|
145
174
|
const handleTriggerKeyDown = useCallback(
|
|
146
175
|
(event: React.KeyboardEvent<HTMLButtonElement>) => {
|
|
147
176
|
if (disabled || collapsed) return;
|
|
148
177
|
if (!open && (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter" || event.key === " ")) {
|
|
149
178
|
event.preventDefault();
|
|
150
179
|
setOpen(true);
|
|
180
|
+
return;
|
|
151
181
|
}
|
|
152
182
|
if (searchable && !open && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
153
183
|
setOpen(true);
|
|
184
|
+
return;
|
|
154
185
|
}
|
|
186
|
+
// Focus normally moves into the listbox as it opens, but it can still be
|
|
187
|
+
// on the trigger — the frame the dropdown mounts in, or after the user
|
|
188
|
+
// shift-tabs back to it. Handle navigation here too rather than dropping
|
|
189
|
+
// the keystroke.
|
|
190
|
+
handleListKeyDown(event);
|
|
155
191
|
},
|
|
156
|
-
[disabled, collapsed, open, setOpen, searchable]
|
|
192
|
+
[disabled, collapsed, open, setOpen, searchable, handleListKeyDown]
|
|
157
193
|
);
|
|
158
194
|
|
|
159
195
|
const handleSearchChange = useCallback((val: string) => {
|
|
@@ -186,6 +222,14 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
186
222
|
wasOpenRef.current = open;
|
|
187
223
|
}, [open, filteredOptions, searchable, selectedValues]);
|
|
188
224
|
|
|
225
|
+
// Non-searchable: focus the listbox itself, so arrow keys reach the scoped
|
|
226
|
+
// keydown handler and a screen reader follows aria-activedescendant. The
|
|
227
|
+
// searchable variant keeps focus in its input instead.
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
if (!open || searchable) return;
|
|
230
|
+
listboxNode?.focus();
|
|
231
|
+
}, [open, searchable, listboxNode]);
|
|
232
|
+
|
|
189
233
|
// Scroll highlighted option into view
|
|
190
234
|
useEffect(() => {
|
|
191
235
|
if (open && highlightedIndex >= 0) {
|
|
@@ -215,32 +259,28 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
215
259
|
return () => document.removeEventListener("mousedown", handler);
|
|
216
260
|
}, [open, setOpen, refs]);
|
|
217
261
|
|
|
218
|
-
useSelectKeyboard({
|
|
219
|
-
open,
|
|
220
|
-
searchable,
|
|
221
|
-
searchValue,
|
|
222
|
-
highlightedIndex,
|
|
223
|
-
displayOptions: filteredOptions,
|
|
224
|
-
setOpen,
|
|
225
|
-
setHighlightedIndex,
|
|
226
|
-
setSearchValue,
|
|
227
|
-
handleSelect,
|
|
228
|
-
focusTrigger,
|
|
229
|
-
});
|
|
230
|
-
|
|
231
262
|
// The listbox id must be unique per instance: it is referenced by
|
|
232
263
|
// aria-controls, and a hardcoded value meant two Selects on one page
|
|
233
264
|
// produced duplicate ids and cross-wired ARIA.
|
|
234
265
|
const listboxId = useId();
|
|
266
|
+
const activeOptionId = open && highlightedIndex >= 0 && highlightedIndex < filteredOptions.length ? selectOptionId(listboxId, highlightedIndex) : undefined;
|
|
235
267
|
|
|
236
268
|
// Strip mode from DOM props
|
|
237
269
|
const { mode: _, value: _v, defaultValue: _dv, onValueChange: _oc, ...htmlProps } = restProps as Record<string, unknown>;
|
|
238
270
|
|
|
271
|
+
// `role="listbox"` requires an accessible name of its own, and the trigger
|
|
272
|
+
// can't supply one: its label is the current *value*, and in searchable mode
|
|
273
|
+
// it is an input whose name would resolve to whatever has been typed. Use the
|
|
274
|
+
// caller's `aria-label` when there is one, else the placeholder — the closest
|
|
275
|
+
// thing this component has to a field label.
|
|
276
|
+
const listboxLabel = typeof htmlProps["aria-label"] === "string" ? (htmlProps["aria-label"] as string) : placeholder;
|
|
277
|
+
|
|
239
278
|
return (
|
|
240
279
|
<>
|
|
241
280
|
{searchable && open && !collapsed ? (
|
|
242
281
|
<SelectTriggerSearch
|
|
243
282
|
setReference={refs.setReference}
|
|
283
|
+
rootRef={rootRef}
|
|
244
284
|
inputRef={inputRef}
|
|
245
285
|
searchValue={searchValue}
|
|
246
286
|
disabled={disabled}
|
|
@@ -248,12 +288,15 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
248
288
|
open={open}
|
|
249
289
|
className={className}
|
|
250
290
|
onSearchChange={handleSearchChange}
|
|
291
|
+
onKeyDown={handleListKeyDown}
|
|
251
292
|
listboxId={listboxId}
|
|
293
|
+
activeOptionId={activeOptionId}
|
|
252
294
|
props={htmlProps as React.InputHTMLAttributes<HTMLInputElement>}
|
|
253
295
|
/>
|
|
254
296
|
) : (
|
|
255
297
|
<SelectTriggerButton
|
|
256
298
|
setReference={refs.setReference}
|
|
299
|
+
rootRef={rootRef}
|
|
257
300
|
open={open}
|
|
258
301
|
disabled={disabled}
|
|
259
302
|
collapsed={collapsed}
|
|
@@ -272,7 +315,9 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
272
315
|
<SelectDropdown
|
|
273
316
|
setFloating={refs.setFloating}
|
|
274
317
|
listboxId={listboxId}
|
|
275
|
-
|
|
318
|
+
setListbox={setListbox}
|
|
319
|
+
label={listboxLabel}
|
|
320
|
+
activeOptionId={activeOptionId}
|
|
276
321
|
floatingStyles={floatingStyles}
|
|
277
322
|
displayOptions={filteredOptions}
|
|
278
323
|
highlightedIndex={highlightedIndex}
|
|
@@ -282,8 +327,19 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
|
|
|
282
327
|
multiple={isMultiple}
|
|
283
328
|
onSelect={handleSelect}
|
|
284
329
|
onHighlight={setHighlightedIndex}
|
|
330
|
+
onKeyDown={handleListKeyDown}
|
|
285
331
|
/>
|
|
286
332
|
)}
|
|
287
333
|
</>
|
|
288
334
|
);
|
|
289
|
-
};
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
SelectRoot.displayName = "Select";
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* NOTE: Storybook shows the copy in Select.stories.tsx
|
|
341
|
+
* (`parameters.docs.description.component`), not this comment. react-docgen
|
|
342
|
+
* cannot extract a description from this declaration shape, so keeping a
|
|
343
|
+
* second copy here would only drift. Edit the stories file.
|
|
344
|
+
*/
|
|
345
|
+
export const Select = SelectRoot as <T extends string = string>(props: SelectProps<T> & { ref?: Ref<HTMLDivElement> }) => ReactElement;
|
|
@@ -4,10 +4,22 @@ import { Check } from "lucide-react";
|
|
|
4
4
|
import type React from "react";
|
|
5
5
|
import type { WritableRefObject } from "../../internal/types";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Options are addressed by id, not by focus: the listbox (or the search input)
|
|
9
|
+
* keeps focus and points `aria-activedescendant` at the highlighted option, so
|
|
10
|
+
* both sides need to agree on the id.
|
|
11
|
+
*/
|
|
12
|
+
export const selectOptionId = (listboxId: string, index: number) => `${listboxId}-option-${index}`;
|
|
13
|
+
|
|
7
14
|
interface SelectDropdownProps<T extends string> {
|
|
8
15
|
setFloating: (node: HTMLElement | null) => void;
|
|
9
16
|
listboxId: string;
|
|
10
|
-
|
|
17
|
+
/** Publishes the listbox node upward — Select focuses it and scrolls it. */
|
|
18
|
+
setListbox: (node: HTMLDivElement | null) => void;
|
|
19
|
+
/** Names the listbox — a bare `role="listbox"` has no accessible name. */
|
|
20
|
+
label: string;
|
|
21
|
+
/** The highlighted option's id, or undefined when nothing is highlighted. */
|
|
22
|
+
activeOptionId: string | undefined;
|
|
11
23
|
floatingStyles: React.CSSProperties;
|
|
12
24
|
displayOptions: readonly { value: T; label: string }[];
|
|
13
25
|
highlightedIndex: number;
|
|
@@ -17,12 +29,15 @@ interface SelectDropdownProps<T extends string> {
|
|
|
17
29
|
multiple: boolean;
|
|
18
30
|
onSelect: (value: T) => void;
|
|
19
31
|
onHighlight: (index: number) => void;
|
|
32
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLElement>) => void;
|
|
20
33
|
}
|
|
21
34
|
|
|
22
35
|
export const SelectDropdown = <T extends string>({
|
|
23
36
|
setFloating,
|
|
24
37
|
listboxId,
|
|
25
|
-
|
|
38
|
+
setListbox,
|
|
39
|
+
label,
|
|
40
|
+
activeOptionId,
|
|
26
41
|
floatingStyles,
|
|
27
42
|
displayOptions,
|
|
28
43
|
highlightedIndex,
|
|
@@ -32,25 +47,35 @@ export const SelectDropdown = <T extends string>({
|
|
|
32
47
|
multiple,
|
|
33
48
|
onSelect,
|
|
34
49
|
onHighlight,
|
|
50
|
+
onKeyDown,
|
|
35
51
|
}: SelectDropdownProps<T>) => (
|
|
36
52
|
<FloatingPortal>
|
|
37
53
|
<div
|
|
38
54
|
ref={(node) => {
|
|
39
55
|
setFloating(node);
|
|
40
|
-
|
|
56
|
+
setListbox(node);
|
|
41
57
|
}}
|
|
42
58
|
id={listboxId}
|
|
43
59
|
role="listbox"
|
|
60
|
+
aria-label={label}
|
|
44
61
|
aria-multiselectable={multiple || undefined}
|
|
62
|
+
aria-activedescendant={activeOptionId}
|
|
63
|
+
// Focus lands here when the dropdown opens (the searchable variant keeps
|
|
64
|
+
// it in the input instead), which is what makes `aria-activedescendant`
|
|
65
|
+
// and the scoped keydown handler work.
|
|
45
66
|
tabIndex={-1}
|
|
67
|
+
onKeyDown={onKeyDown}
|
|
46
68
|
style={floatingStyles}
|
|
47
|
-
className="z-popover max-h-60 overflow-y-auto rounded-md border
|
|
69
|
+
className="select-dropdown border-(color:--select-dropdown-border) z-popover max-h-60 overflow-y-auto rounded-md border bg-(--select-dropdown-bg) shadow-lg"
|
|
48
70
|
>
|
|
49
71
|
{displayOptions.length === 0 ? (
|
|
50
|
-
<div className="px-3 py-2 text-center text-fg
|
|
72
|
+
<div className="px-3 py-2 text-center text-(--select-dropdown-empty-fg) text-sm">
|
|
73
|
+
{searchValue ? `No results for "${searchValue}"` : "No options available"}
|
|
74
|
+
</div>
|
|
51
75
|
) : (
|
|
52
76
|
displayOptions.map((option, index) => {
|
|
53
77
|
const isSelected = selectedValues.has(option.value);
|
|
78
|
+
const isHighlighted = highlightedIndex === index;
|
|
54
79
|
return (
|
|
55
80
|
<button
|
|
56
81
|
key={option.value}
|
|
@@ -59,23 +84,31 @@ export const SelectDropdown = <T extends string>({
|
|
|
59
84
|
else optionRefs.current.delete(index);
|
|
60
85
|
}}
|
|
61
86
|
type="button"
|
|
87
|
+
id={selectOptionId(listboxId, index)}
|
|
62
88
|
role="option"
|
|
63
89
|
aria-selected={isSelected}
|
|
90
|
+
// Surfaces the keyboard/mouse "current" option as an attribute
|
|
91
|
+
// the select.css recipe selects on, rather than compiling it
|
|
92
|
+
// straight into a class name — see select.css's header.
|
|
93
|
+
data-highlighted={isHighlighted ? "true" : undefined}
|
|
94
|
+
// The options are not tab stops and must not steal focus: the
|
|
95
|
+
// listbox holds it and delegates via aria-activedescendant, so a
|
|
96
|
+
// click that moved focus onto the option would strand the keyboard
|
|
97
|
+
// handler with nothing listening.
|
|
98
|
+
tabIndex={-1}
|
|
99
|
+
onMouseDown={(event) => event.preventDefault()}
|
|
64
100
|
onClick={() => onSelect(option.value)}
|
|
65
101
|
onMouseEnter={() => onHighlight(index)}
|
|
66
102
|
className={cn(
|
|
67
|
-
`flex w-full cursor-pointer items-center px-3 py-2 text-fg
|
|
103
|
+
`select-option flex w-full cursor-pointer items-center bg-(--select-option-bg) px-3 py-2 text-(--select-option-fg) text-sm transition-colors`,
|
|
68
104
|
multiple && "gap-2",
|
|
69
|
-
|
|
70
|
-
isSelected ? "font-medium text-fg-normal" : "text-fg-subtle"
|
|
105
|
+
isSelected && "font-medium"
|
|
71
106
|
)}
|
|
72
107
|
>
|
|
73
108
|
{multiple && (
|
|
74
109
|
<span
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
isSelected ? "border-border-brand bg-bg-brand text-fg-on-brand" : "border-border-normal"
|
|
78
|
-
)}
|
|
110
|
+
data-selected={isSelected ? "true" : undefined}
|
|
111
|
+
className="select-option-indicator border-(color:--select-option-indicator-border) flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border bg-(--select-option-indicator-bg) text-(--select-option-indicator-fg)"
|
|
79
112
|
>
|
|
80
113
|
{isSelected && <Check className="h-3 w-3" />}
|
|
81
114
|
</span>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { cn } from "@sixthshift/design-system/utils";
|
|
2
2
|
import { ChevronDown, X } from "lucide-react";
|
|
3
|
-
import type { HTMLAttributes } from "react";
|
|
3
|
+
import type { HTMLAttributes, Ref } from "react";
|
|
4
|
+
import type { WritableRefObject } from "../../internal/types";
|
|
4
5
|
|
|
5
6
|
interface SelectTriggerButtonProps {
|
|
6
7
|
setReference: (node: HTMLElement | null) => void;
|
|
8
|
+
/** Consumer ref from Select, attached to this trigger's root element. */
|
|
9
|
+
rootRef?: Ref<HTMLDivElement>;
|
|
7
10
|
listboxId: string;
|
|
8
11
|
open: boolean;
|
|
9
12
|
disabled: boolean;
|
|
@@ -19,6 +22,7 @@ interface SelectTriggerButtonProps {
|
|
|
19
22
|
|
|
20
23
|
export const SelectTriggerButton = ({
|
|
21
24
|
setReference,
|
|
25
|
+
rootRef,
|
|
22
26
|
listboxId,
|
|
23
27
|
open,
|
|
24
28
|
disabled,
|
|
@@ -37,7 +41,7 @@ export const SelectTriggerButton = ({
|
|
|
37
41
|
const showClear = showClearButton && !collapsed;
|
|
38
42
|
|
|
39
43
|
return (
|
|
40
|
-
<div className="relative w-full">
|
|
44
|
+
<div ref={rootRef} className="select-trigger relative w-full">
|
|
41
45
|
<button
|
|
42
46
|
ref={setReference}
|
|
43
47
|
type="button"
|
|
@@ -45,7 +49,7 @@ export const SelectTriggerButton = ({
|
|
|
45
49
|
onKeyDown={onKeyDown}
|
|
46
50
|
disabled={disabled}
|
|
47
51
|
className={cn(
|
|
48
|
-
`flex w-full cursor-pointer items-center gap-2 rounded-md border
|
|
52
|
+
`border-(color:--select-trigger-border) focus-visible:ring-(color:--select-trigger-ring) flex w-full cursor-pointer items-center gap-2 rounded-md border bg-(--select-trigger-bg) px-3 py-2 font-medium text-(--select-trigger-fg) text-sm transition-colors hover:bg-(--select-trigger-bg-hovered) focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50`,
|
|
49
53
|
collapsed ? "justify-center" : "justify-between",
|
|
50
54
|
showClear && "pr-9",
|
|
51
55
|
className
|
|
@@ -63,7 +67,7 @@ export const SelectTriggerButton = ({
|
|
|
63
67
|
<>
|
|
64
68
|
<span className="truncate">{displayLabel}</span>
|
|
65
69
|
<span className="flex shrink-0 items-center gap-1">
|
|
66
|
-
<ChevronDown className={cn("h-4 w-4 text-fg
|
|
70
|
+
<ChevronDown className={cn("h-4 w-4 text-(--select-trigger-icon-fg) transition-transform", open && "rotate-180")} />
|
|
67
71
|
</span>
|
|
68
72
|
</>
|
|
69
73
|
)}
|
|
@@ -73,7 +77,7 @@ export const SelectTriggerButton = ({
|
|
|
73
77
|
type="button"
|
|
74
78
|
onClick={onClear}
|
|
75
79
|
disabled={disabled}
|
|
76
|
-
className="absolute top-1/2 right-8 -translate-y-1/2 rounded-sm p-0.5 text-fg
|
|
80
|
+
className="select-trigger-clear focus-visible:ring-(color:--select-trigger-ring) absolute top-1/2 right-8 -translate-y-1/2 rounded-sm p-0.5 text-(--select-trigger-clear-fg) hover:bg-(--select-trigger-clear-bg-hovered) hover:text-(--select-trigger-clear-fg-hovered) focus-visible:outline-none focus-visible:ring-2"
|
|
77
81
|
aria-label="Clear selection"
|
|
78
82
|
>
|
|
79
83
|
<X className="h-3.5 w-3.5" />
|
|
@@ -85,7 +89,11 @@ export const SelectTriggerButton = ({
|
|
|
85
89
|
|
|
86
90
|
interface SelectTriggerSearchProps {
|
|
87
91
|
setReference: (node: HTMLElement | null) => void;
|
|
92
|
+
/** Consumer ref from Select, attached to this trigger's root element. */
|
|
93
|
+
rootRef?: Ref<HTMLDivElement>;
|
|
88
94
|
listboxId: string;
|
|
95
|
+
/** Id of the highlighted option — the input keeps focus and delegates to it. */
|
|
96
|
+
activeOptionId: string | undefined;
|
|
89
97
|
inputRef: React.RefObject<HTMLInputElement | null>;
|
|
90
98
|
searchValue: string;
|
|
91
99
|
disabled: boolean;
|
|
@@ -93,12 +101,15 @@ interface SelectTriggerSearchProps {
|
|
|
93
101
|
open: boolean;
|
|
94
102
|
className: string | undefined;
|
|
95
103
|
onSearchChange: (value: string) => void;
|
|
104
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLElement>) => void;
|
|
96
105
|
props: React.InputHTMLAttributes<HTMLInputElement>;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
export const SelectTriggerSearch = ({
|
|
100
109
|
setReference,
|
|
110
|
+
rootRef,
|
|
101
111
|
listboxId,
|
|
112
|
+
activeOptionId,
|
|
102
113
|
inputRef,
|
|
103
114
|
searchValue,
|
|
104
115
|
disabled,
|
|
@@ -106,25 +117,37 @@ export const SelectTriggerSearch = ({
|
|
|
106
117
|
open,
|
|
107
118
|
className,
|
|
108
119
|
onSearchChange,
|
|
120
|
+
onKeyDown,
|
|
109
121
|
props,
|
|
110
122
|
}: SelectTriggerSearchProps) => (
|
|
111
|
-
|
|
123
|
+
// floating-ui anchors to this element and the consumer may also want it, so
|
|
124
|
+
// both refs run off one callback rather than one silently winning.
|
|
125
|
+
<div
|
|
126
|
+
ref={(node) => {
|
|
127
|
+
setReference(node);
|
|
128
|
+
if (typeof rootRef === "function") rootRef(node);
|
|
129
|
+
else if (rootRef) (rootRef as WritableRefObject<HTMLDivElement | null>).current = node;
|
|
130
|
+
}}
|
|
131
|
+
className={cn("select-trigger relative flex w-full items-center", className)}
|
|
132
|
+
>
|
|
112
133
|
<input
|
|
113
134
|
ref={inputRef as React.RefObject<HTMLInputElement>}
|
|
114
135
|
type="text"
|
|
115
136
|
value={searchValue}
|
|
116
137
|
onChange={(e) => onSearchChange(e.target.value)}
|
|
138
|
+
onKeyDown={onKeyDown}
|
|
117
139
|
placeholder={displayLabel}
|
|
118
140
|
disabled={disabled}
|
|
119
141
|
className={cn(
|
|
120
|
-
`flex-1 rounded-md border
|
|
142
|
+
`border-(color:--select-trigger-border) focus-visible:ring-(color:--select-trigger-ring) flex-1 rounded-md border bg-(--select-trigger-bg) px-3 py-2 font-medium text-(--select-trigger-fg) text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50`
|
|
121
143
|
)}
|
|
122
144
|
role="combobox"
|
|
123
145
|
aria-expanded={open}
|
|
124
146
|
aria-controls={listboxId}
|
|
147
|
+
aria-activedescendant={activeOptionId}
|
|
125
148
|
aria-autocomplete="list"
|
|
126
149
|
{...props}
|
|
127
150
|
/>
|
|
128
|
-
<ChevronDown className="pointer-events-none absolute right-3 h-4 w-4 text-fg
|
|
151
|
+
<ChevronDown className="pointer-events-none absolute right-3 h-4 w-4 text-(--select-trigger-icon-fg)" />
|
|
129
152
|
</div>
|
|
130
153
|
);
|