flikkui 0.2.0-beta.2 → 0.2.0-beta.5
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 +92 -0
- package/dist/components/ai/PromptInput/PromptInput.js +23 -15
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.d.ts +27 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.js +62 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.d.ts +10 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +12 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.types.d.ts +53 -0
- package/dist/components/ai/PromptSuggestions/index.d.ts +4 -2
- package/dist/components/ai/index.d.ts +2 -12
- package/dist/components/charts/ActivityRings/ActivityRings.js +70 -58
- package/dist/components/charts/ActivityRings/ActivityRings.theme.js +0 -1
- package/dist/components/charts/ActivityRings/ActivityRings.types.d.ts +17 -0
- package/dist/components/charts/BarChart/BarChart.js +8 -4
- package/dist/components/charts/BarChart/BarChart.types.d.ts +14 -0
- package/dist/components/charts/DonutChart/DonutChart.js +11 -8
- package/dist/components/charts/DonutChart/DonutChart.theme.d.ts +3 -0
- package/dist/components/charts/DonutChart/DonutChart.theme.js +5 -4
- package/dist/components/charts/DonutChart/donut-utils.d.ts +5 -0
- package/dist/components/charts/DonutChart/donut-utils.js +26 -1
- package/dist/components/charts/Heatmap/Heatmap.theme.js +2 -2
- package/dist/components/charts/shared/ChartAxis/XAxis.d.ts +2 -2
- package/dist/components/charts/shared/ChartAxis/XAxis.js +4 -4
- package/dist/components/charts/shared/ChartAxis/YAxis.d.ts +2 -2
- package/dist/components/charts/shared/ChartAxis/YAxis.js +8 -7
- package/dist/components/charts/shared/ChartGrid/HorizontalGrid.d.ts +1 -1
- package/dist/components/charts/shared/ChartGrid/HorizontalGrid.js +2 -2
- package/dist/components/charts/theme/chart.theme.d.ts +1 -1
- package/dist/components/charts/theme/chart.theme.js +39 -39
- package/dist/components/core/Accordion/Accordion.d.ts +1 -1
- package/dist/components/core/Accordion/Accordion.js +2 -2
- package/dist/components/core/Accordion/Accordion.types.d.ts +8 -0
- package/dist/components/core/Badge/Badge.js +11 -15
- package/dist/components/core/Badge/Badge.theme.js +7 -21
- package/dist/components/core/Badge/Badge.types.d.ts +9 -1
- package/dist/components/core/Button/Button.js +2 -2
- package/dist/components/core/Button/Button.theme.js +1 -1
- package/dist/components/core/Button/Button.types.d.ts +8 -0
- package/dist/components/core/Card/Card.js +8 -2
- package/dist/components/core/Card/Card.theme.js +1 -1
- package/dist/components/core/Card/Card.types.d.ts +24 -1
- package/dist/components/core/Drawer/Drawer.d.ts +1 -1
- package/dist/components/core/Drawer/Drawer.js +10 -40
- package/dist/components/core/Drawer/Drawer.theme.js +2 -1
- package/dist/components/core/Drawer/Drawer.types.d.ts +8 -0
- package/dist/components/core/Dropdown/Dropdown.d.ts +1 -1
- package/dist/components/core/Dropdown/Dropdown.js +2 -2
- package/dist/components/core/Dropdown/Dropdown.types.d.ts +8 -0
- package/dist/components/core/Metric/Metric.d.ts +1 -1
- package/dist/components/core/Metric/Metric.js +9 -5
- package/dist/components/core/Metric/Metric.theme.d.ts +1 -1
- package/dist/components/core/Metric/Metric.theme.js +38 -28
- package/dist/components/core/Metric/Metric.types.d.ts +27 -8
- package/dist/components/core/Modal/Modal.d.ts +1 -1
- package/dist/components/core/Modal/Modal.js +17 -40
- package/dist/components/core/Modal/Modal.theme.js +8 -3
- package/dist/components/core/Modal/Modal.types.d.ts +18 -0
- package/dist/components/core/Modal/index.d.ts +1 -1
- package/dist/components/core/Notification/Notification.js +2 -0
- package/dist/components/core/Pill/Pill.d.ts +6 -11
- package/dist/components/core/Pill/Pill.theme.d.ts +2 -2
- package/dist/components/core/Pill/Pill.types.d.ts +9 -22
- package/dist/components/core/Pill/index.d.ts +1 -1
- package/dist/components/core/Popover/Popover.d.ts +1 -1
- package/dist/components/core/Popover/Popover.js +2 -2
- package/dist/components/core/Popover/Popover.types.d.ts +8 -0
- package/dist/components/core/Progress/Progress.d.ts +28 -0
- package/dist/components/core/Progress/Progress.js +114 -0
- package/dist/components/core/Progress/Progress.theme.d.ts +5 -0
- package/dist/components/core/Progress/Progress.theme.js +33 -0
- package/dist/components/core/Progress/Progress.types.d.ts +92 -0
- package/dist/components/core/Progress/index.d.ts +2 -0
- package/dist/components/core/Table/Table.animations.d.ts +5 -16
- package/dist/components/core/Table/Table.animations.js +46 -0
- package/dist/components/core/Table/Table.d.ts +0 -27
- package/dist/components/core/Table/Table.js +58 -156
- package/dist/components/core/Table/Table.theme.js +28 -19
- package/dist/components/core/Table/Table.types.d.ts +95 -8
- package/dist/components/core/Table/Table.utils.d.ts +7 -0
- package/dist/components/core/Table/Table.utils.js +11 -1
- package/dist/components/core/Table/{components/TableActions/TableActions.d.ts → TableActions.d.ts} +3 -3
- package/dist/components/core/Table/{components/TableActions/TableActions.js → TableActions.js} +14 -24
- package/dist/components/core/Table/{components/TableActions/TableActionsMenu.d.ts → TableActionsMenu.d.ts} +1 -1
- package/dist/components/core/Table/{components/TableActions/TableActionsMenu.js → TableActionsMenu.js} +4 -4
- package/dist/components/core/Table/{components/core/TableBody.d.ts → TableBody.d.ts} +1 -1
- package/dist/components/core/Table/{components/core/TableBody.js → TableBody.js} +14 -20
- package/dist/components/core/Table/{components/core/TableCell.d.ts → TableCell.d.ts} +1 -9
- package/dist/components/core/Table/{components/core/TableCell.js → TableCell.js} +5 -13
- package/dist/components/core/Table/TableColumnManager.d.ts +3 -0
- package/dist/components/core/Table/TableColumnManager.js +34 -0
- package/dist/components/core/Table/{components/DeclarativeComponents.d.ts → TableDeclarative.d.ts} +1 -1
- package/dist/components/core/Table/{components/DeclarativeComponents.js → TableDeclarative.js} +6 -56
- package/dist/components/core/Table/TableFilter.d.ts +3 -0
- package/dist/components/core/Table/TableFilter.js +122 -0
- package/dist/components/core/Table/{components/core/TableHeader.d.ts → TableHeader.d.ts} +1 -1
- package/dist/components/core/Table/{components/core/TableHeader.js → TableHeader.js} +15 -29
- package/dist/components/core/Table/TablePagination.d.ts +7 -0
- package/dist/components/core/Table/{components/TablePagination/TablePagination.js → TablePagination.js} +5 -16
- package/dist/components/core/Table/TableRow.d.ts +8 -0
- package/dist/components/core/Table/TableRow.js +45 -0
- package/dist/components/core/Table/TableSelectionHeader.d.ts +7 -0
- package/dist/components/core/Table/{components/TableSelectionHeader/TableSelectionHeader.js → TableSelectionHeader.js} +4 -5
- package/dist/components/core/Table/hooks/index.d.ts +10 -0
- package/dist/components/core/Table/hooks/useTableColumns.d.ts +16 -0
- package/dist/components/core/Table/hooks/useTableColumns.js +67 -0
- package/dist/components/core/Table/hooks/useTableExpansion.d.ts +8 -0
- package/dist/components/core/Table/hooks/useTableExpansion.js +15 -0
- package/dist/components/core/Table/hooks/useTableFilter.d.ts +12 -0
- package/dist/components/core/Table/hooks/useTableFilter.js +37 -0
- package/dist/components/core/Table/hooks/useTablePagination.d.ts +12 -0
- package/dist/components/core/Table/hooks/useTablePagination.js +13 -0
- package/dist/components/core/Table/hooks/useTableSelection.d.ts +17 -0
- package/dist/components/core/Table/hooks/useTableSelection.js +40 -0
- package/dist/components/core/Table/index.d.ts +9 -8
- package/dist/components/core/Table/index.js +7 -5
- package/dist/components/core/Tabs/Tabs.js +2 -2
- package/dist/components/core/Tabs/Tabs.types.d.ts +8 -0
- package/dist/components/core/Tag/Tag.animations.d.ts +3 -0
- package/dist/components/core/Tag/Tag.animations.js +31 -0
- package/dist/components/core/Tag/Tag.d.ts +14 -0
- package/dist/components/core/Tag/Tag.js +45 -0
- package/dist/components/core/Tag/Tag.theme.d.ts +2 -0
- package/dist/components/core/Tag/Tag.theme.js +21 -0
- package/dist/components/core/Tag/Tag.types.d.ts +40 -0
- package/dist/components/core/Tag/index.d.ts +3 -0
- package/dist/components/core/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/core/Tooltip/Tooltip.js +3 -3
- package/dist/components/core/Tooltip/Tooltip.theme.js +1 -1
- package/dist/components/core/Tooltip/Tooltip.types.d.ts +17 -0
- package/dist/components/core/index.d.ts +2 -1
- package/dist/components/core/index.js +12 -5
- package/dist/components/effects/CustomCursor/CustomCursor.d.ts +0 -13
- package/dist/components/effects/CustomCursor/CustomCursor.js +26 -2
- package/dist/components/effects/CustomCursor/CustomCursor.theme.js +12 -1
- package/dist/components/effects/CustomCursor/CustomCursor.types.d.ts +14 -1
- package/dist/components/forms/Combobox/Combobox.d.ts +25 -0
- package/dist/components/forms/Combobox/Combobox.js +412 -0
- package/dist/components/forms/Combobox/Combobox.theme.d.ts +6 -0
- package/dist/components/forms/Combobox/Combobox.theme.js +60 -0
- package/dist/components/forms/Combobox/Combobox.types.d.ts +111 -0
- package/dist/components/forms/Combobox/index.d.ts +3 -0
- package/dist/components/forms/FileUpload/FileUpload.js +2 -0
- package/dist/components/forms/Input/Input.js +25 -28
- package/dist/components/forms/Input/inputMasks.d.ts +15 -0
- package/dist/components/forms/Input/inputMasks.js +72 -1
- package/dist/components/forms/InputTag/InputTag.d.ts +40 -0
- package/dist/components/forms/InputTag/InputTag.js +491 -0
- package/dist/components/forms/InputTag/InputTag.theme.d.ts +2 -0
- package/dist/components/forms/InputTag/InputTag.theme.js +16 -0
- package/dist/components/forms/InputTag/InputTag.types.d.ts +107 -0
- package/dist/components/forms/InputTag/index.d.ts +3 -0
- package/dist/components/forms/Select/Select.d.ts +101 -2
- package/dist/components/forms/Select/Select.js +128 -132
- package/dist/components/forms/Select/Select.theme.js +10 -14
- package/dist/components/forms/Select/Select.types.d.ts +6 -2
- package/dist/components/forms/Select/index.d.ts +7 -4
- package/dist/components/forms/Select/useSelectState.d.ts +66 -0
- package/dist/components/forms/Select/useSelectState.js +134 -0
- package/dist/components/forms/SelectExpand/SelectExpand.animations.d.ts +20 -0
- package/dist/components/forms/SelectExpand/SelectExpand.animations.js +74 -0
- package/dist/components/forms/SelectExpand/SelectExpand.d.ts +9 -0
- package/dist/components/forms/SelectExpand/SelectExpand.js +223 -0
- package/dist/components/forms/SelectExpand/SelectExpand.theme.d.ts +5 -0
- package/dist/components/forms/SelectExpand/SelectExpand.theme.js +74 -0
- package/dist/components/forms/SelectExpand/SelectExpand.types.d.ts +126 -0
- package/dist/components/forms/SelectExpand/index.d.ts +4 -0
- package/dist/components/forms/Switch/Switch.js +3 -3
- package/dist/components/forms/Switch/Switch.theme.d.ts +1 -1
- package/dist/components/forms/Switch/Switch.theme.js +2 -2
- package/dist/components/forms/TimePicker/TimePicker.animations.d.ts +0 -46
- package/dist/components/forms/TimePicker/TimePicker.d.ts +15 -6
- package/dist/components/forms/TimePicker/TimePicker.js +285 -124
- package/dist/components/forms/TimePicker/TimePicker.theme.d.ts +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +39 -22
- package/dist/components/forms/TimePicker/TimePicker.types.d.ts +88 -34
- package/dist/components/forms/TimePicker/TimePickerContent.d.ts +7 -10
- package/dist/components/forms/TimePicker/TimePickerContent.js +149 -16
- package/dist/components/forms/TimePicker/TimePickerTrigger.d.ts +3 -3
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +22 -19
- package/dist/components/forms/TimePicker/WheelColumn.d.ts +14 -0
- package/dist/components/forms/TimePicker/WheelColumn.js +90 -0
- package/dist/components/forms/TimePicker/index.d.ts +4 -1
- package/dist/components/forms/TimePicker/useWheelPicker.d.ts +37 -0
- package/dist/components/forms/TimePicker/useWheelPicker.js +138 -0
- package/dist/components/forms/forms.theme.d.ts +14 -0
- package/dist/components/forms/forms.theme.js +31 -0
- package/dist/components/forms/index.d.ts +9 -3
- package/dist/components/forms/index.js +73 -2
- package/dist/hooks/index.d.ts +0 -4
- package/dist/icons/Icon.d.ts +7 -0
- package/dist/icons/Icon.js +6 -2
- package/dist/index.js +21 -19
- package/dist/styles.css +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/optimisticErrors.js +1 -70
- package/package.json +1 -1
- package/dist/components/ai/EditingIndicator/EditingIndicator.animations.d.ts +0 -31
- package/dist/components/ai/EditingIndicator/EditingIndicator.animations.js +0 -115
- package/dist/components/ai/EditingIndicator/EditingIndicator.d.ts +0 -35
- package/dist/components/ai/EditingIndicator/EditingIndicator.js +0 -94
- package/dist/components/ai/EditingIndicator/EditingIndicator.theme.d.ts +0 -2
- package/dist/components/ai/EditingIndicator/EditingIndicator.theme.js +0 -13
- package/dist/components/ai/EditingIndicator/EditingIndicator.types.d.ts +0 -54
- package/dist/components/ai/EditingIndicator/index.d.ts +0 -9
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.d.ts +0 -3
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.js +0 -126
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.theme.d.ts +0 -2
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.theme.js +0 -8
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.types.d.ts +0 -45
- package/dist/components/ai/GenerativeRenderer/index.d.ts +0 -3
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.animations.d.ts +0 -17
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.animations.js +0 -56
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.d.ts +0 -38
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.js +0 -110
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.theme.d.ts +0 -2
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.theme.js +0 -13
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.types.d.ts +0 -53
- package/dist/components/ai/PresenceIndicator/index.d.ts +0 -8
- package/dist/components/ai/PresenceProvider/PresenceContext.d.ts +0 -24
- package/dist/components/ai/PresenceProvider/PresenceContext.js +0 -34
- package/dist/components/ai/PresenceProvider/PresenceProvider.d.ts +0 -32
- package/dist/components/ai/PresenceProvider/PresenceProvider.js +0 -321
- package/dist/components/ai/PresenceProvider/PresenceProvider.types.d.ts +0 -140
- package/dist/components/ai/PresenceProvider/adapters/MockAdapter.d.ts +0 -102
- package/dist/components/ai/PresenceProvider/adapters/MockAdapter.js +0 -331
- package/dist/components/ai/PresenceProvider/adapters/PresenceAdapter.d.ts +0 -93
- package/dist/components/ai/PresenceProvider/adapters/SupabaseAdapter.d.ts +0 -134
- package/dist/components/ai/PresenceProvider/adapters/WebSocketAdapter.d.ts +0 -149
- package/dist/components/ai/PresenceProvider/adapters/index.d.ts +0 -11
- package/dist/components/ai/PresenceProvider/index.d.ts +0 -10
- package/dist/components/ai/PromptSuggestions/PromptSuggestions.d.ts +0 -27
- package/dist/components/ai/PromptSuggestions/PromptSuggestions.js +0 -61
- package/dist/components/ai/PromptSuggestions/PromptSuggestions.types.d.ts +0 -65
- package/dist/components/ai/VersionSlider/VersionSlider.d.ts +0 -3
- package/dist/components/ai/VersionSlider/VersionSlider.js +0 -97
- package/dist/components/ai/VersionSlider/VersionSlider.theme.d.ts +0 -2
- package/dist/components/ai/VersionSlider/VersionSlider.theme.js +0 -18
- package/dist/components/ai/VersionSlider/VersionSlider.types.d.ts +0 -77
- package/dist/components/ai/VersionSlider/index.d.ts +0 -3
- package/dist/components/core/Pill/Pill.animations.js +0 -25
- package/dist/components/core/Pill/Pill.js +0 -145
- package/dist/components/core/Pill/Pill.theme.js +0 -65
- package/dist/components/core/RetryBoundary/RetryBoundary.d.ts +0 -35
- package/dist/components/core/RetryBoundary/RetryBoundary.js +0 -154
- package/dist/components/core/RetryBoundary/RetryBoundary.theme.d.ts +0 -2
- package/dist/components/core/RetryBoundary/RetryBoundary.theme.js +0 -7
- package/dist/components/core/RetryBoundary/RetryBoundary.types.d.ts +0 -51
- package/dist/components/core/RetryBoundary/index.d.ts +0 -3
- package/dist/components/core/Table/components/TableActions/TableActions.types.d.ts +0 -40
- package/dist/components/core/Table/components/TableActions/index.d.ts +0 -3
- package/dist/components/core/Table/components/TableActionsMenu.d.ts +0 -6
- package/dist/components/core/Table/components/TablePagination/TablePagination.d.ts +0 -17
- package/dist/components/core/Table/components/TablePagination/TablePagination.types.d.ts +0 -21
- package/dist/components/core/Table/components/TablePagination/index.d.ts +0 -2
- package/dist/components/core/Table/components/TableSelectionHeader/TableSelectionHeader.d.ts +0 -15
- package/dist/components/core/Table/components/TableSelectionHeader/index.d.ts +0 -3
- package/dist/components/core/Table/components/core/TableRow.d.ts +0 -3
- package/dist/components/core/Table/components/core/TableRow.js +0 -44
- package/dist/components/core/Table/components/core/index.d.ts +0 -4
- package/dist/components/forms/OptimisticForm/OptimisticForm.d.ts +0 -33
- package/dist/components/forms/OptimisticForm/OptimisticForm.js +0 -87
- package/dist/components/forms/OptimisticForm/OptimisticForm.theme.d.ts +0 -2
- package/dist/components/forms/OptimisticForm/OptimisticForm.theme.js +0 -8
- package/dist/components/forms/OptimisticForm/OptimisticForm.types.d.ts +0 -74
- package/dist/components/forms/OptimisticForm/index.d.ts +0 -3
- package/dist/hooks/useOptimisticMutation.d.ts +0 -109
- package/dist/hooks/useOptimisticMutation.js +0 -171
- package/dist/hooks/usePresence.d.ts +0 -88
- package/dist/utils/presenceUtils.d.ts +0 -66
- package/dist/utils/presenceUtils.js +0 -107
|
@@ -1,18 +1,117 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { SelectProps, SelectButtonProps, SelectOptionsProps, SelectOptionProps } from "./Select.types";
|
|
2
|
+
import type { SelectProps, SelectButtonProps, SelectOptionsProps, SelectOptionProps, SelectState, SelectSize, SelectThemeOverrides } from "./Select.types";
|
|
3
|
+
import { useSelectState, type UseSelectStateReturn, type UseSelectStateProps } from "./useSelectState";
|
|
4
|
+
/**
|
|
5
|
+
* Context value type for Select components
|
|
6
|
+
* Extends UseSelectStateReturn with additional component-specific properties
|
|
7
|
+
*/
|
|
8
|
+
export interface SelectContextValue<T = any> extends UseSelectStateReturn<T> {
|
|
9
|
+
/** Size variant */
|
|
10
|
+
size: SelectSize;
|
|
11
|
+
/** Component state (default, disabled) */
|
|
12
|
+
state: SelectState;
|
|
13
|
+
/** Theme configuration */
|
|
14
|
+
theme: SelectThemeOverrides;
|
|
15
|
+
/** Whether search is enabled */
|
|
16
|
+
searchable: boolean;
|
|
17
|
+
/** Whether typeahead is enabled */
|
|
18
|
+
enableTypeahead: boolean;
|
|
19
|
+
/** Button ref (alias for triggerRef for backward compatibility) */
|
|
20
|
+
buttonRef: React.MutableRefObject<HTMLButtonElement | null>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* SelectContext - exported for external consumption
|
|
24
|
+
*/
|
|
25
|
+
export declare const SelectContext: React.Context<SelectContextValue<any> | undefined>;
|
|
26
|
+
/**
|
|
27
|
+
* useSelectContext - Hook to consume SelectContext
|
|
28
|
+
* Throws if used outside of SelectProvider
|
|
29
|
+
*/
|
|
30
|
+
export declare const useSelectContext: <T = any>() => SelectContextValue<T>;
|
|
31
|
+
/**
|
|
32
|
+
* Props for the SelectProvider component
|
|
33
|
+
*/
|
|
34
|
+
export interface SelectProviderProps<T = any> {
|
|
35
|
+
/** Child components */
|
|
36
|
+
children: React.ReactNode;
|
|
37
|
+
/** State from useSelectState hook */
|
|
38
|
+
selectState: UseSelectStateReturn<T>;
|
|
39
|
+
/** Size variant */
|
|
40
|
+
size?: SelectSize;
|
|
41
|
+
/** Component state */
|
|
42
|
+
componentState?: SelectState;
|
|
43
|
+
/** Theme overrides */
|
|
44
|
+
theme?: SelectThemeOverrides;
|
|
45
|
+
/** Whether search is enabled */
|
|
46
|
+
searchable?: boolean;
|
|
47
|
+
/** Whether typeahead is enabled */
|
|
48
|
+
enableTypeahead?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* SelectProvider - Provides select context to children
|
|
52
|
+
*
|
|
53
|
+
* This component allows building custom dropdown components using Select primitives.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* const selectState = useSelectState({ options, value, onChange });
|
|
58
|
+
*
|
|
59
|
+
* <SelectProvider selectState={selectState} size="md">
|
|
60
|
+
* <MyCustomTrigger />
|
|
61
|
+
* <SelectOptions isOpen={selectState.isOpen}>
|
|
62
|
+
* {selectState.filteredOptions.map(option => (
|
|
63
|
+
* <SelectOption key={option.id} value={option.value}>
|
|
64
|
+
* {option.label}
|
|
65
|
+
* </SelectOption>
|
|
66
|
+
* ))}
|
|
67
|
+
* </SelectOptions>
|
|
68
|
+
* </SelectProvider>
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function SelectProvider<T = any>({ children, selectState, size, componentState, theme: themeOverrides, searchable, enableTypeahead, }: SelectProviderProps<T>): React.JSX.Element;
|
|
3
72
|
/**
|
|
4
73
|
* Select Button Component
|
|
5
74
|
*/
|
|
6
75
|
export declare const SelectButton: React.FC<SelectButtonProps>;
|
|
76
|
+
/**
|
|
77
|
+
* Extended props for SelectOptions to support custom triggers
|
|
78
|
+
*/
|
|
79
|
+
export interface SelectOptionsExtendedProps extends SelectOptionsProps {
|
|
80
|
+
/** Custom trigger ref - if provided, uses this instead of buttonRef from context */
|
|
81
|
+
triggerRef?: React.RefObject<HTMLElement>;
|
|
82
|
+
}
|
|
7
83
|
/**
|
|
8
84
|
* Select Options Component
|
|
9
85
|
*/
|
|
10
|
-
export declare const SelectOptions: React.FC<
|
|
86
|
+
export declare const SelectOptions: React.FC<SelectOptionsExtendedProps>;
|
|
11
87
|
/**
|
|
12
88
|
* Select Option Component
|
|
13
89
|
*/
|
|
14
90
|
export declare const SelectOption: <T extends any>({ value, isSelected, disabled, className, onSelect, children, }: SelectOptionProps<T>) => React.JSX.Element;
|
|
15
91
|
/**
|
|
16
92
|
* Main Select Component
|
|
93
|
+
*
|
|
94
|
+
* A fully-featured select/dropdown component with support for:
|
|
95
|
+
* - Keyboard navigation
|
|
96
|
+
* - Search/filtering
|
|
97
|
+
* - Typeahead
|
|
98
|
+
* - Creatable options
|
|
99
|
+
* - Portal rendering
|
|
100
|
+
* - Custom theming
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```tsx
|
|
104
|
+
* <Select
|
|
105
|
+
* options={[
|
|
106
|
+
* { id: "1", label: "Option 1", value: "option1" },
|
|
107
|
+
* { id: "2", label: "Option 2", value: "option2" },
|
|
108
|
+
* ]}
|
|
109
|
+
* value={selected}
|
|
110
|
+
* onChange={setSelected}
|
|
111
|
+
* placeholder="Select an option"
|
|
112
|
+
* />
|
|
113
|
+
* ```
|
|
17
114
|
*/
|
|
18
115
|
export declare const Select: <T extends any>({ id, name, size, state, value, displayValue, placeholder, disabled, required, options, label, helperText, onChange, onFocus, onBlur, iconStart, iconEnd, theme: themeOverrides, className, wrapperClassName, searchable, searchPlaceholder, portal, placement, offset, enableTypeahead, creatable, onCreateOption, createLabel, children, }: SelectProps<T>) => React.JSX.Element;
|
|
116
|
+
export { useSelectState };
|
|
117
|
+
export type { UseSelectStateProps, UseSelectStateReturn };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React__default, { createContext,
|
|
1
|
+
import React__default, { createContext, useRef, useCallback, useEffect, useContext } from 'react';
|
|
2
2
|
import { AnimatePresence, motion } from 'motion/react';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
4
|
import { selectTheme } from './Select.theme.js';
|
|
@@ -10,13 +10,17 @@ import { ChevronUpDownIcon } from '../../../icons/core/ChevronUpDown.js';
|
|
|
10
10
|
import { useSelectPortal } from '../../../hooks/useSelectPortal.js';
|
|
11
11
|
import { cn } from '../../../utils/cn.js';
|
|
12
12
|
import { isValidTypeaheadChar, findNextMatchingOption, TYPEAHEAD_TIMEOUT_MS } from '../../../utils/typeaheadUtils.js';
|
|
13
|
-
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
|
|
13
|
+
import { PlusIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline';
|
|
14
|
+
import { useSelectState } from './useSelectState.js';
|
|
14
15
|
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Dark Mode Hook
|
|
18
|
+
// ============================================================================
|
|
15
19
|
/**
|
|
16
20
|
* Hook to detect dark mode state from document
|
|
17
21
|
*/
|
|
18
22
|
const useDarkMode = () => {
|
|
19
|
-
const [isDark, setIsDark] = useState(false);
|
|
23
|
+
const [isDark, setIsDark] = React__default.useState(false);
|
|
20
24
|
useEffect(() => {
|
|
21
25
|
if (typeof document === "undefined")
|
|
22
26
|
return;
|
|
@@ -41,14 +45,60 @@ const useDarkMode = () => {
|
|
|
41
45
|
}, []);
|
|
42
46
|
return isDark;
|
|
43
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* SelectContext - exported for external consumption
|
|
50
|
+
*/
|
|
44
51
|
const SelectContext = createContext(undefined);
|
|
52
|
+
/**
|
|
53
|
+
* useSelectContext - Hook to consume SelectContext
|
|
54
|
+
* Throws if used outside of SelectProvider
|
|
55
|
+
*/
|
|
45
56
|
const useSelectContext = () => {
|
|
46
57
|
const context = useContext(SelectContext);
|
|
47
58
|
if (!context) {
|
|
48
|
-
throw new Error("Select components must be used within a
|
|
59
|
+
throw new Error("Select components must be used within a SelectProvider");
|
|
49
60
|
}
|
|
50
61
|
return context;
|
|
51
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* SelectProvider - Provides select context to children
|
|
65
|
+
*
|
|
66
|
+
* This component allows building custom dropdown components using Select primitives.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* const selectState = useSelectState({ options, value, onChange });
|
|
71
|
+
*
|
|
72
|
+
* <SelectProvider selectState={selectState} size="md">
|
|
73
|
+
* <MyCustomTrigger />
|
|
74
|
+
* <SelectOptions isOpen={selectState.isOpen}>
|
|
75
|
+
* {selectState.filteredOptions.map(option => (
|
|
76
|
+
* <SelectOption key={option.id} value={option.value}>
|
|
77
|
+
* {option.label}
|
|
78
|
+
* </SelectOption>
|
|
79
|
+
* ))}
|
|
80
|
+
* </SelectOptions>
|
|
81
|
+
* </SelectProvider>
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
function SelectProvider({ children, selectState, size = "md", componentState = "default", theme: themeOverrides, searchable = false, enableTypeahead = true, }) {
|
|
85
|
+
const theme = { ...selectTheme, ...(themeOverrides || {}) };
|
|
86
|
+
// Cast triggerRef to buttonRef for backward compatibility
|
|
87
|
+
const buttonRef = selectState.triggerRef;
|
|
88
|
+
const contextValue = {
|
|
89
|
+
...selectState,
|
|
90
|
+
size,
|
|
91
|
+
state: componentState,
|
|
92
|
+
theme,
|
|
93
|
+
searchable,
|
|
94
|
+
enableTypeahead,
|
|
95
|
+
buttonRef,
|
|
96
|
+
};
|
|
97
|
+
return (React__default.createElement(SelectContext.Provider, { value: contextValue }, children));
|
|
98
|
+
}
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// SelectButton Component
|
|
101
|
+
// ============================================================================
|
|
52
102
|
/**
|
|
53
103
|
* Select Button Component
|
|
54
104
|
*/
|
|
@@ -72,7 +122,8 @@ const SelectButton = ({ id, disabled, isOpen, state = "default", size = "md", ic
|
|
|
72
122
|
"outline-2 outline-[var(--color-primary)] -outline-offset-1 ring-4 ring-[var(--color-primary)]/10"
|
|
73
123
|
: "";
|
|
74
124
|
return (React__default.createElement("div", { className: cn(buttonWrapperStyle) },
|
|
75
|
-
React__default.createElement("button", { ref: buttonRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconStartPadding, iconEndPadding, buttonStyle, className
|
|
125
|
+
React__default.createElement("button", { ref: buttonRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconStartPadding, iconEndPadding, buttonStyle, className // User overrides take highest precedence
|
|
126
|
+
), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "listbox" },
|
|
76
127
|
iconStart && React__default.createElement("span", { className: iconStartStyle }, iconStart),
|
|
77
128
|
children,
|
|
78
129
|
iconEnd && React__default.createElement("span", { className: iconEndStyle }, iconEnd))));
|
|
@@ -80,17 +131,19 @@ const SelectButton = ({ id, disabled, isOpen, state = "default", size = "md", ic
|
|
|
80
131
|
/**
|
|
81
132
|
* Select Options Component
|
|
82
133
|
*/
|
|
83
|
-
const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, children, portal = true, placement = "bottom-start", offset = 4, }) => {
|
|
134
|
+
const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, children, portal = true, placement = "bottom-start", offset = 4, triggerRef: customTriggerRef, }) => {
|
|
84
135
|
var _a;
|
|
85
|
-
const
|
|
136
|
+
const context = useSelectContext();
|
|
137
|
+
const { optionsRef, buttonRef, highlightedIndex, setHighlightedIndex, filteredOptions, searchable, searchValue, setSearchValue, enableTypeahead, typeaheadValue, setTypeaheadValue, typeaheadTimeoutRef, theme, selectOption, } = context;
|
|
138
|
+
// Use custom triggerRef if provided, otherwise fall back to buttonRef
|
|
139
|
+
const effectiveTriggerRef = customTriggerRef || buttonRef;
|
|
86
140
|
// Detect dark mode for portal content
|
|
87
141
|
const isDarkMode = useDarkMode();
|
|
88
142
|
const searchInputRef = useRef(null);
|
|
89
143
|
// Use enhanced dropdown positioning hook with direction-aware animations
|
|
90
|
-
|
|
91
|
-
const triggerWidth = ((_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) || 0;
|
|
144
|
+
const triggerWidth = ((_a = effectiveTriggerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) || 0;
|
|
92
145
|
const { position, cssVariables, contentRef, isFlipped } = useSelectPortal({
|
|
93
|
-
triggerRef:
|
|
146
|
+
triggerRef: effectiveTriggerRef,
|
|
94
147
|
isOpen: isOpen || false,
|
|
95
148
|
placement,
|
|
96
149
|
offset,
|
|
@@ -103,7 +156,7 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
103
156
|
// Convert maxHeight to a valid CSS value
|
|
104
157
|
const maxHeightValue = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
|
|
105
158
|
// Combine refs for portal and legacy usage
|
|
106
|
-
const combinedRef =
|
|
159
|
+
const combinedRef = useCallback((el) => {
|
|
107
160
|
if (optionsRef &&
|
|
108
161
|
typeof optionsRef === "object" &&
|
|
109
162
|
"current" in optionsRef) {
|
|
@@ -126,8 +179,8 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
126
179
|
: optionsRef.current;
|
|
127
180
|
if (currentContentRef &&
|
|
128
181
|
!currentContentRef.contains(event.target) &&
|
|
129
|
-
|
|
130
|
-
!
|
|
182
|
+
effectiveTriggerRef.current &&
|
|
183
|
+
!effectiveTriggerRef.current.contains(event.target)) {
|
|
131
184
|
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
132
185
|
}
|
|
133
186
|
};
|
|
@@ -135,7 +188,7 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
135
188
|
return () => {
|
|
136
189
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
137
190
|
};
|
|
138
|
-
}, [isOpen, onClose, optionsRef,
|
|
191
|
+
}, [isOpen, onClose, optionsRef, effectiveTriggerRef, contentRef, portal]);
|
|
139
192
|
// Handle keyboard navigation
|
|
140
193
|
useEffect(() => {
|
|
141
194
|
if (!isOpen)
|
|
@@ -203,9 +256,8 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
203
256
|
highlightedIndex < filteredOptions.length) {
|
|
204
257
|
const highlightedOption = filteredOptions[highlightedIndex];
|
|
205
258
|
if (!highlightedOption.disabled) {
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
context.selectOption(value);
|
|
259
|
+
const isCreateAction = highlightedOption.id === "__create__";
|
|
260
|
+
selectOption(highlightedOption.value, isCreateAction);
|
|
209
261
|
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
210
262
|
}
|
|
211
263
|
}
|
|
@@ -226,25 +278,7 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
226
278
|
setTypeaheadValue,
|
|
227
279
|
typeaheadTimeoutRef,
|
|
228
280
|
optionsRef,
|
|
229
|
-
|
|
230
|
-
// Reset search and highlighted index when closing
|
|
231
|
-
useEffect(() => {
|
|
232
|
-
if (!isOpen) {
|
|
233
|
-
setSearchValue("");
|
|
234
|
-
setHighlightedIndex(-1);
|
|
235
|
-
setTypeaheadValue("");
|
|
236
|
-
// Clear any pending typeahead timeout
|
|
237
|
-
if (typeaheadTimeoutRef.current) {
|
|
238
|
-
clearTimeout(typeaheadTimeoutRef.current);
|
|
239
|
-
typeaheadTimeoutRef.current = null;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}, [
|
|
243
|
-
isOpen,
|
|
244
|
-
setSearchValue,
|
|
245
|
-
setHighlightedIndex,
|
|
246
|
-
setTypeaheadValue,
|
|
247
|
-
typeaheadTimeoutRef,
|
|
281
|
+
selectOption,
|
|
248
282
|
]);
|
|
249
283
|
// Autofocus search input on open for searchable selects
|
|
250
284
|
useEffect(() => {
|
|
@@ -282,10 +316,10 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
282
316
|
maxHeight: searchable ? "none" : maxHeightValue,
|
|
283
317
|
}),
|
|
284
318
|
}, role: "listbox", tabIndex: -1, variants: animations, initial: "initial", animate: "visible", exit: "exit" },
|
|
285
|
-
searchable && (React__default.createElement("div", { className: `sticky top-0 py-1 bg-white z-[10000] border-b border-[var(--color-border)] ${searchInputStyle}`, style: {
|
|
319
|
+
searchable && (React__default.createElement("div", { className: `sticky top-0 py-1 bg-white dark:bg-[var(--color-background-secondary)] z-[10000] border-b border-[var(--color-border)] ${searchInputStyle}`, style: {
|
|
286
320
|
"--form-rounded": "0",
|
|
287
321
|
} },
|
|
288
|
-
React__default.createElement(Input, { placeholder: "Search...", value: searchValue, onChange: handleSearchChange, type: "search", ref: searchInputRef, className: "w-full block bg-white border-none outline-none !min-h-8 py-2 ring-0 shadow-none [&:focus]:outline-none [&:focus]:ring-0 [&:focus]:border-none [&:focus-visible]:outline-none [&:focus-visible]:ring-0 [&:focus-visible]:border-none", iconStart: React__default.createElement(MagnifyingGlassIcon, { strokeWidth: 2, className: "size-4 text-[var(--color-text-muted)] group-focus-within:text-[var(--color-primary)]" }), wrapperClassName: "!border-none !outline-none !ring-0 !shadow-none", inputGroupClassName: "!border-none !outline-none !ring-0 !shadow-none flex items-center", style: {
|
|
322
|
+
React__default.createElement(Input, { placeholder: "Search...", value: searchValue, onChange: handleSearchChange, type: "search", ref: searchInputRef, className: "w-full block bg-white dark:bg-[var(--color-background-secondary)] border-none outline-none !min-h-8 py-2 ring-0 shadow-none [&:focus]:outline-none [&:focus]:ring-0 [&:focus]:border-none [&:focus-visible]:outline-none [&:focus-visible]:ring-0 [&:focus-visible]:border-none", iconStart: React__default.createElement(MagnifyingGlassIcon, { strokeWidth: 2, className: "size-4 text-[var(--color-text-muted)] group-focus-within:text-[var(--color-primary)] dark:group-focus-within:text-white" }), wrapperClassName: "!border-none !outline-none !ring-0 !shadow-none", inputGroupClassName: "!border-none !outline-none !ring-0 !shadow-none flex items-center", style: {
|
|
289
323
|
border: "none",
|
|
290
324
|
outline: "none",
|
|
291
325
|
boxShadow: "none",
|
|
@@ -297,15 +331,20 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
|
|
|
297
331
|
}
|
|
298
332
|
return optionsContent;
|
|
299
333
|
};
|
|
334
|
+
// ============================================================================
|
|
335
|
+
// SelectOption Component
|
|
336
|
+
// ============================================================================
|
|
300
337
|
/**
|
|
301
338
|
* Select Option Component
|
|
302
339
|
*/
|
|
303
340
|
const SelectOption = ({ value, isSelected, disabled, className = "", onSelect, children, }) => {
|
|
304
341
|
var _a;
|
|
305
|
-
const { highlightedIndex, setHighlightedIndex,
|
|
342
|
+
const { highlightedIndex, setHighlightedIndex, filteredOptions, theme, selectOption, } = useSelectContext();
|
|
306
343
|
const optionStyle = theme.optionStyle || "";
|
|
307
344
|
const selectedOptionStyle = theme.selectedOptionStyle || "";
|
|
308
345
|
const disabledOptionStyle = theme.disabledOptionStyle || "";
|
|
346
|
+
const highlightedOptionStyle = theme.highlightedOptionStyle || "";
|
|
347
|
+
const createOptionStyleTheme = theme.createOptionStyle || "";
|
|
309
348
|
// Find index of this option in filteredOptions (not options, to support create option)
|
|
310
349
|
const optionIndex = filteredOptions.findIndex((option) => option.value === value);
|
|
311
350
|
const isHighlighted = optionIndex === highlightedIndex;
|
|
@@ -320,78 +359,58 @@ const SelectOption = ({ value, isSelected, disabled, className = "", onSelect, c
|
|
|
320
359
|
}
|
|
321
360
|
};
|
|
322
361
|
// Apply the hover style directly when keyboard navigating
|
|
323
|
-
const keyboardHighlightStyle = isHighlighted
|
|
324
|
-
? "text-[var(--color-primary)] bg-[var(--color-primary-50)]/50"
|
|
325
|
-
: "";
|
|
362
|
+
const keyboardHighlightStyle = isHighlighted ? highlightedOptionStyle : "";
|
|
326
363
|
// Style create option differently
|
|
327
|
-
const createOptionStyle = isCreateOption
|
|
328
|
-
|
|
329
|
-
: "";
|
|
330
|
-
return (React__default.createElement("div", { className: cn(optionStyle, isSelected && selectedOptionStyle, disabled && disabledOptionStyle, keyboardHighlightStyle, createOptionStyle, className), role: "option", "aria-selected": isSelected, "aria-disabled": disabled, "data-option-index": optionIndex, onMouseEnter: () => !disabled && setHighlightedIndex(optionIndex), onClick: handleClick }, children));
|
|
364
|
+
const createOptionStyle = isCreateOption ? createOptionStyleTheme : "";
|
|
365
|
+
return (React__default.createElement("div", { className: cn(optionStyle, isSelected && selectedOptionStyle, disabled && disabledOptionStyle, keyboardHighlightStyle, createOptionStyle, className // User overrides take highest precedence
|
|
366
|
+
), role: "option", "aria-selected": isSelected, "aria-disabled": disabled, "data-option-index": optionIndex, onMouseEnter: () => !disabled && setHighlightedIndex(optionIndex), onClick: handleClick }, children));
|
|
331
367
|
};
|
|
368
|
+
// ============================================================================
|
|
369
|
+
// Main Select Component
|
|
370
|
+
// ============================================================================
|
|
332
371
|
/**
|
|
333
372
|
* Main Select Component
|
|
373
|
+
*
|
|
374
|
+
* A fully-featured select/dropdown component with support for:
|
|
375
|
+
* - Keyboard navigation
|
|
376
|
+
* - Search/filtering
|
|
377
|
+
* - Typeahead
|
|
378
|
+
* - Creatable options
|
|
379
|
+
* - Portal rendering
|
|
380
|
+
* - Custom theming
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```tsx
|
|
384
|
+
* <Select
|
|
385
|
+
* options={[
|
|
386
|
+
* { id: "1", label: "Option 1", value: "option1" },
|
|
387
|
+
* { id: "2", label: "Option 2", value: "option2" },
|
|
388
|
+
* ]}
|
|
389
|
+
* value={selected}
|
|
390
|
+
* onChange={setSelected}
|
|
391
|
+
* placeholder="Select an option"
|
|
392
|
+
* />
|
|
393
|
+
* ```
|
|
334
394
|
*/
|
|
335
395
|
const Select = ({ id, name, size = "md", state = "default", value, displayValue, placeholder = "Select an option", disabled = false, required = false, options = [], label, helperText, onChange, onFocus, onBlur, iconStart, iconEnd, theme: themeOverrides, className = "", wrapperClassName = "", searchable = false, searchPlaceholder = "Search options...", portal = true, placement = "bottom-start", offset = 8, enableTypeahead = true, creatable = false, onCreateOption, createLabel, children, }) => {
|
|
336
396
|
var _a;
|
|
337
397
|
// Merge theme with overrides
|
|
338
398
|
const theme = { ...selectTheme, ...(themeOverrides || {}) };
|
|
339
|
-
//
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}, [value]);
|
|
354
|
-
// Get display value for the selected option
|
|
355
|
-
const getOptionByValue = (searchValue) => {
|
|
356
|
-
return options.find((option) => option.value === searchValue);
|
|
357
|
-
};
|
|
358
|
-
// Filter options based on search query
|
|
359
|
-
const baseFilteredOptions = searchValue
|
|
360
|
-
? options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()))
|
|
361
|
-
: options;
|
|
362
|
-
// Check if we should show the create option
|
|
363
|
-
const shouldShowCreateOption = creatable &&
|
|
364
|
-
searchable &&
|
|
365
|
-
searchValue.trim() !== "" &&
|
|
366
|
-
!baseFilteredOptions.some((option) => option.label.toLowerCase() === searchValue.toLowerCase());
|
|
367
|
-
// Add create option if needed
|
|
368
|
-
const filteredOptions = shouldShowCreateOption
|
|
369
|
-
? [
|
|
370
|
-
{
|
|
371
|
-
id: "__create__",
|
|
372
|
-
label: typeof createLabel === "function"
|
|
373
|
-
? createLabel(searchValue)
|
|
374
|
-
: createLabel || `Create "${searchValue}"`,
|
|
375
|
-
value: searchValue,
|
|
376
|
-
},
|
|
377
|
-
...baseFilteredOptions,
|
|
378
|
-
]
|
|
379
|
-
: baseFilteredOptions;
|
|
380
|
-
const selectedOption = getOptionByValue(selectedValue);
|
|
399
|
+
// Use the extracted state hook
|
|
400
|
+
const selectState = useSelectState({
|
|
401
|
+
options,
|
|
402
|
+
value,
|
|
403
|
+
onChange,
|
|
404
|
+
searchable,
|
|
405
|
+
creatable,
|
|
406
|
+
onCreateOption,
|
|
407
|
+
createLabel,
|
|
408
|
+
enableTypeahead,
|
|
409
|
+
});
|
|
410
|
+
const { isOpen, setIsOpen, selectedValue, filteredOptions, selectedOption, } = selectState;
|
|
411
|
+
// Cast triggerRef to buttonRef type
|
|
412
|
+
selectState.triggerRef;
|
|
381
413
|
const computedDisplayValue = displayValue || (selectedOption ? selectedOption.label : placeholder);
|
|
382
|
-
// Function to select an option
|
|
383
|
-
const selectOption = (newValue, isCreateAction = false) => {
|
|
384
|
-
if (isCreateAction && onCreateOption) {
|
|
385
|
-
// Call onCreateOption callback if provided
|
|
386
|
-
onCreateOption(String(newValue));
|
|
387
|
-
}
|
|
388
|
-
if (newValue !== selectedValue) {
|
|
389
|
-
setSelectedValue(newValue);
|
|
390
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(newValue);
|
|
391
|
-
}
|
|
392
|
-
setIsOpen(false);
|
|
393
|
-
setSearchValue(""); // Clear search value after selection
|
|
394
|
-
};
|
|
395
414
|
// Button click handler
|
|
396
415
|
const handleButtonClick = () => {
|
|
397
416
|
if (!disabled) {
|
|
@@ -407,34 +426,7 @@ const Select = ({ id, name, size = "md", state = "default", value, displayValue,
|
|
|
407
426
|
const defaultChevronIcon = React__default.createElement(ChevronUpDownIcon, { size: 16, className: "" });
|
|
408
427
|
// Generate a unique ID if not provided
|
|
409
428
|
const selectId = id || `select-${Math.random().toString(36).substring(2, 9)}`;
|
|
410
|
-
return (React__default.createElement(
|
|
411
|
-
isOpen,
|
|
412
|
-
setIsOpen,
|
|
413
|
-
selectedValue,
|
|
414
|
-
setSelectedValue,
|
|
415
|
-
highlightedIndex,
|
|
416
|
-
setHighlightedIndex,
|
|
417
|
-
options,
|
|
418
|
-
filteredOptions,
|
|
419
|
-
searchValue,
|
|
420
|
-
setSearchValue,
|
|
421
|
-
getOptionByValue,
|
|
422
|
-
selectOption,
|
|
423
|
-
size,
|
|
424
|
-
state,
|
|
425
|
-
theme,
|
|
426
|
-
searchable,
|
|
427
|
-
enableTypeahead,
|
|
428
|
-
typeaheadValue,
|
|
429
|
-
setTypeaheadValue,
|
|
430
|
-
typeaheadTimeoutRef,
|
|
431
|
-
buttonRef,
|
|
432
|
-
optionsRef,
|
|
433
|
-
creatable,
|
|
434
|
-
createLabel,
|
|
435
|
-
onCreateOption,
|
|
436
|
-
hasCreateOption: shouldShowCreateOption,
|
|
437
|
-
} },
|
|
429
|
+
return (React__default.createElement(SelectProvider, { selectState: selectState, size: size, componentState: state, theme: themeOverrides, searchable: searchable, enableTypeahead: enableTypeahead },
|
|
438
430
|
React__default.createElement("div", { className: cn("relative", containerStyle, wrapperClassName) },
|
|
439
431
|
label && (React__default.createElement(FormLabel, { htmlFor: selectId, required: required }, label)),
|
|
440
432
|
React__default.createElement(SelectButton, { id: selectId, disabled: disabled, isOpen: isOpen, state: state, size: size, iconStart: iconStart, iconEnd: iconEnd || defaultChevronIcon, onClick: handleButtonClick, onFocus: onFocus, onBlur: onBlur, className: className },
|
|
@@ -442,10 +434,14 @@ const Select = ({ id, name, size = "md", state = "default", value, displayValue,
|
|
|
442
434
|
? theme.valueTextStyle
|
|
443
435
|
: theme.placeholderTextStyle) }, computedDisplayValue)),
|
|
444
436
|
React__default.createElement(SelectOptions, { isOpen: isOpen, onClose: () => setIsOpen(false), portal: portal, placement: placement, offset: offset }, children ||
|
|
445
|
-
filteredOptions.map((option) =>
|
|
446
|
-
|
|
437
|
+
filteredOptions.map((option) => {
|
|
438
|
+
const isCreateOption = option.id === "__create__";
|
|
439
|
+
return (React__default.createElement(SelectOption, { key: option.id, value: option.value, isSelected: option.value === selectedValue, disabled: option.disabled || false }, isCreateOption ? (React__default.createElement("span", { className: "flex items-center gap-2" },
|
|
440
|
+
React__default.createElement(PlusIcon, { className: "size-4 shrink-0" }),
|
|
441
|
+
React__default.createElement("span", { className: "block truncate" }, option.label))) : (React__default.createElement("span", { className: "block truncate" }, option.label))));
|
|
442
|
+
})),
|
|
447
443
|
helperText && (React__default.createElement("p", { className: cn(helperTextStyle, helperTextStateStyle) }, helperText)),
|
|
448
444
|
name && (React__default.createElement("input", { type: "hidden", name: name, value: selectedValue !== undefined ? String(selectedValue) : "" })))));
|
|
449
445
|
};
|
|
450
446
|
|
|
451
|
-
export { Select, SelectButton, SelectOption, SelectOptions };
|
|
447
|
+
export { Select, SelectButton, SelectContext, SelectOption, SelectOptions, SelectProvider, useSelectContext, useSelectState };
|
|
@@ -14,7 +14,7 @@ const selectTheme = {
|
|
|
14
14
|
// Button style - bg-white for light mode only; dark mode bg comes from baseStyle (inputGroupBaseStyle)
|
|
15
15
|
buttonStyle: "w-full cursor-pointer bg-white dark:bg-[var(--color-neutral-900)]",
|
|
16
16
|
// Placeholder text style - matches Input placeholder styling
|
|
17
|
-
placeholderTextStyle:
|
|
17
|
+
placeholderTextStyle: formsBaseTheme.placeholderStyle,
|
|
18
18
|
// Selected value text style
|
|
19
19
|
valueTextStyle: "text-[var(--color-text-primary)] dark:text-[var(--color-neutral-200)]",
|
|
20
20
|
// Size variants - composed from atomic tokens
|
|
@@ -31,27 +31,23 @@ const selectTheme = {
|
|
|
31
31
|
hoverStates: formsBaseTheme.hoverStates,
|
|
32
32
|
// Options container style - Uses position: fixed for proper scroll behavior with standardized z-index
|
|
33
33
|
// Width is controlled by trigger size via estimatedWidth parameter
|
|
34
|
-
optionsContainerStyle: "
|
|
35
|
-
"rounded-[var(--form-rounded)] bg-[var(--color-background)]/90 backdrop-blur-md py-0 text-sm " +
|
|
36
|
-
"shadow-real-lg ring-1 ring-slate-200 focus:outline-none " +
|
|
37
|
-
"dark:bg-[var(--color-neutral-900)]/90 dark:ring-[var(--color-neutral-700)]",
|
|
34
|
+
optionsContainerStyle: formsBaseTheme.dropdownStyles.container + " py-0 border border-[var(--color-border)]",
|
|
38
35
|
// Search input style
|
|
39
36
|
searchInputStyle: "group",
|
|
40
37
|
// Individual option style
|
|
41
|
-
optionStyle:
|
|
42
|
-
"hover:text-[var(--color-primary)] hover:bg-[var(--color-primary-50)]/50 " +
|
|
43
|
-
"dark:text-[var(--color-neutral-200)] dark:hover:text-[var(--color-primary-400)] dark:hover:bg-[var(--color-primary-900)]/50",
|
|
38
|
+
optionStyle: formsBaseTheme.dropdownStyles.option,
|
|
44
39
|
// Selected option style
|
|
45
|
-
selectedOptionStyle:
|
|
40
|
+
selectedOptionStyle: formsBaseTheme.dropdownStyles.optionSelected,
|
|
41
|
+
// Highlighted option style (keyboard navigation)
|
|
42
|
+
highlightedOptionStyle: formsBaseTheme.dropdownStyles.optionHighlighted,
|
|
46
43
|
// Disabled option style
|
|
47
|
-
disabledOptionStyle:
|
|
44
|
+
disabledOptionStyle: formsBaseTheme.dropdownStyles.optionDisabled,
|
|
45
|
+
// Create option style
|
|
46
|
+
createOptionStyle: formsBaseTheme.dropdownStyles.optionCreate,
|
|
48
47
|
// Helper text style - inherited from common form theme
|
|
49
48
|
helperTextStyle: formsBaseTheme.helperText,
|
|
50
49
|
// Helper text state variants
|
|
51
|
-
helperTextStates:
|
|
52
|
-
default: "text-[var(--color-text-muted)] dark:text-[var(--color-neutral-400)]",
|
|
53
|
-
disabled: "text-[var(--color-text-disabled)] dark:text-[var(--color-neutral-600)]",
|
|
54
|
-
},
|
|
50
|
+
helperTextStates: formsBaseTheme.helperTextStates,
|
|
55
51
|
// Left icon style - inherited from common form theme
|
|
56
52
|
iconStartStyle: formsBaseTheme.iconStyles.left,
|
|
57
53
|
// Right icon style - inherited from common form theme
|
|
@@ -37,7 +37,7 @@ export interface SelectProps<T = any> extends SelectBaseProps {
|
|
|
37
37
|
/** Currently selected option */
|
|
38
38
|
value?: T;
|
|
39
39
|
/** Custom display value to show in trigger (overrides selected option label) */
|
|
40
|
-
displayValue?:
|
|
40
|
+
displayValue?: React.ReactNode;
|
|
41
41
|
/** Placeholder text when no option is selected */
|
|
42
42
|
placeholder?: string;
|
|
43
43
|
/** Whether the select is disabled */
|
|
@@ -147,7 +147,7 @@ export interface SelectOptionProps<T = any> extends SelectBaseProps {
|
|
|
147
147
|
children?: React.ReactNode;
|
|
148
148
|
}
|
|
149
149
|
export type SelectSize = "sm" | "md" | "lg";
|
|
150
|
-
export type SelectState = "default" | "disabled";
|
|
150
|
+
export type SelectState = "default" | "disabled" | "invalid";
|
|
151
151
|
/**
|
|
152
152
|
* Theme overrides for the Select component
|
|
153
153
|
*/
|
|
@@ -180,8 +180,12 @@ export interface SelectThemeOverrides {
|
|
|
180
180
|
optionStyle?: string;
|
|
181
181
|
/** Style for selected options */
|
|
182
182
|
selectedOptionStyle?: string;
|
|
183
|
+
/** Style for highlighted options (keyboard navigation) */
|
|
184
|
+
highlightedOptionStyle?: string;
|
|
183
185
|
/** Style for disabled options */
|
|
184
186
|
disabledOptionStyle?: string;
|
|
187
|
+
/** Style for create option */
|
|
188
|
+
createOptionStyle?: string;
|
|
185
189
|
/** Style for the helper text */
|
|
186
190
|
helperTextStyle?: string;
|
|
187
191
|
/** State styles for the helper text */
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
export
|
|
4
|
-
export { selectTheme } from
|
|
1
|
+
export { Select, SelectButton, SelectOptions, SelectOption, } from "./Select";
|
|
2
|
+
export { SelectProvider, SelectContext, useSelectContext, } from "./Select";
|
|
3
|
+
export { useSelectState, } from "./Select";
|
|
4
|
+
export { selectTheme } from "./Select.theme";
|
|
5
|
+
export type { SelectProps, SelectOption as SelectOptionType, SelectSize, SelectState, SelectThemeOverrides, SelectButtonProps, SelectOptionsProps, SelectOptionProps, } from "./Select.types";
|
|
6
|
+
export type { UseSelectStateProps, UseSelectStateReturn, } from "./useSelectState";
|
|
7
|
+
export type { SelectContextValue, SelectProviderProps, SelectOptionsExtendedProps, } from "./Select";
|