@simplysm/solid 13.0.28 → 13.0.30
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 +15 -9
- package/dist/components/data/Pagination.d.ts +4 -5
- package/dist/components/data/Pagination.d.ts.map +1 -1
- package/dist/components/data/Pagination.js +14 -14
- package/dist/components/data/Pagination.js.map +2 -2
- package/dist/components/data/Table.js +1 -1
- package/dist/components/data/calendar/Calendar.d.ts.map +1 -1
- package/dist/components/data/calendar/Calendar.js +1 -1
- package/dist/components/data/calendar/Calendar.js.map +1 -1
- package/dist/components/data/kanban/Kanban.d.ts +9 -9
- package/dist/components/data/kanban/Kanban.d.ts.map +1 -1
- package/dist/components/data/kanban/Kanban.js +6 -6
- package/dist/components/data/kanban/Kanban.js.map +2 -2
- package/dist/components/data/list/List.d.ts.map +1 -1
- package/dist/components/data/list/List.js.map +1 -1
- package/dist/components/data/list/ListItem.d.ts.map +1 -1
- package/dist/components/data/list/ListItem.js.map +1 -1
- package/dist/components/data/permission-table/PermissionTable.d.ts.map +1 -1
- package/dist/components/data/permission-table/PermissionTable.js.map +1 -1
- package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.js +102 -107
- package/dist/components/data/sheet/DataSheet.js.map +2 -2
- package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.styles.js +24 -6
- package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
- package/dist/components/data/sheet/DataSheetColumn.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheetColumn.js.map +1 -1
- package/dist/components/data/sheet/DataSheetConfigDialog.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheetConfigDialog.js.map +1 -1
- package/dist/components/data/sheet/sheetUtils.d.ts.map +1 -1
- package/dist/components/data/sheet/sheetUtils.js.map +1 -1
- package/dist/components/data/sheet/types.d.ts +2 -2
- package/dist/components/data/sheet/types.d.ts.map +1 -1
- package/dist/components/disclosure/Collapse.d.ts.map +1 -1
- package/dist/components/disclosure/Collapse.js +0 -3
- package/dist/components/disclosure/Collapse.js.map +1 -1
- package/dist/components/disclosure/Dialog.d.ts +8 -8
- package/dist/components/disclosure/Dialog.d.ts.map +1 -1
- package/dist/components/disclosure/Dialog.js +64 -69
- package/dist/components/disclosure/Dialog.js.map +2 -2
- package/dist/components/disclosure/DialogContext.d.ts +4 -4
- package/dist/components/disclosure/DialogContext.d.ts.map +1 -1
- package/dist/components/disclosure/DialogContext.js.map +1 -1
- package/dist/components/disclosure/DialogProvider.d.ts.map +1 -1
- package/dist/components/disclosure/DialogProvider.js +8 -8
- package/dist/components/disclosure/DialogProvider.js.map +2 -2
- package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
- package/dist/components/disclosure/Dropdown.js.map +1 -1
- package/dist/components/disclosure/Tabs.d.ts.map +1 -1
- package/dist/components/disclosure/Tabs.js.map +1 -1
- package/dist/components/display/Alert.d.ts.map +1 -1
- package/dist/components/display/Alert.js.map +1 -1
- package/dist/components/display/Card.d.ts +0 -1
- package/dist/components/display/Card.d.ts.map +1 -1
- package/dist/components/display/Card.js +1 -2
- package/dist/components/display/Card.js.map +1 -1
- package/dist/components/display/Echarts.d.ts +1 -1
- package/dist/components/display/Echarts.d.ts.map +1 -1
- package/dist/components/display/Echarts.js +2 -2
- package/dist/components/display/Echarts.js.map +2 -2
- package/dist/components/display/Link.d.ts +5 -0
- package/dist/components/display/Link.d.ts.map +1 -0
- package/dist/components/display/Link.js +26 -0
- package/dist/components/display/Link.js.map +6 -0
- package/dist/components/feedback/Progress.d.ts +3 -3
- package/dist/components/feedback/Progress.d.ts.map +1 -1
- package/dist/components/feedback/Progress.js +1 -1
- package/dist/components/feedback/Progress.js.map +2 -2
- package/dist/components/feedback/busy/BusyContainer.d.ts +13 -0
- package/dist/components/feedback/busy/BusyContainer.d.ts.map +1 -0
- package/dist/components/feedback/{loading/LoadingContainer.js → busy/BusyContainer.js} +20 -13
- package/dist/components/feedback/busy/BusyContainer.js.map +6 -0
- package/dist/components/feedback/busy/BusyContext.d.ts +11 -0
- package/dist/components/feedback/busy/BusyContext.d.ts.map +1 -0
- package/dist/components/feedback/busy/BusyContext.js +14 -0
- package/dist/components/feedback/busy/BusyContext.js.map +6 -0
- package/dist/components/feedback/busy/BusyProvider.d.ts +7 -0
- package/dist/components/feedback/busy/BusyProvider.d.ts.map +1 -0
- package/dist/components/feedback/{loading/LoadingProvider.js → busy/BusyProvider.js} +7 -7
- package/dist/components/feedback/busy/BusyProvider.js.map +6 -0
- package/dist/components/feedback/notification/NotificationBanner.d.ts.map +1 -1
- package/dist/components/feedback/notification/NotificationBanner.js +1 -1
- package/dist/components/feedback/notification/NotificationBanner.js.map +1 -1
- package/dist/components/feedback/notification/NotificationBell.d.ts.map +1 -1
- package/dist/components/feedback/notification/NotificationBell.js +4 -2
- package/dist/components/feedback/notification/NotificationBell.js.map +2 -2
- package/dist/components/feedback/notification/NotificationContext.d.ts.map +1 -1
- package/dist/components/feedback/notification/NotificationContext.js.map +1 -1
- package/dist/components/feedback/notification/NotificationProvider.d.ts.map +1 -1
- package/dist/components/feedback/notification/NotificationProvider.js +1 -0
- package/dist/components/feedback/notification/NotificationProvider.js.map +1 -1
- package/dist/components/form-control/Button.d.ts.map +1 -1
- package/dist/components/form-control/Button.js +2 -2
- package/dist/components/form-control/Button.js.map +1 -1
- package/dist/components/form-control/DropdownTrigger.styles.d.ts.map +1 -1
- package/dist/components/form-control/DropdownTrigger.styles.js +6 -1
- package/dist/components/form-control/DropdownTrigger.styles.js.map +1 -1
- package/dist/components/form-control/Invalid.d.ts +4 -2
- package/dist/components/form-control/Invalid.d.ts.map +1 -1
- package/dist/components/form-control/Invalid.js +81 -41
- package/dist/components/form-control/Invalid.js.map +2 -2
- package/dist/components/form-control/ThemeToggle.d.ts.map +1 -1
- package/dist/components/form-control/ThemeToggle.js +4 -5
- package/dist/components/form-control/ThemeToggle.js.map +2 -2
- package/dist/components/form-control/checkbox/Checkbox.d.ts +4 -2
- package/dist/components/form-control/checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Checkbox.js +65 -52
- package/dist/components/form-control/checkbox/Checkbox.js.map +2 -2
- package/dist/components/form-control/checkbox/Checkbox.styles.d.ts +1 -2
- package/dist/components/form-control/checkbox/Checkbox.styles.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Checkbox.styles.js +8 -10
- package/dist/components/form-control/checkbox/Checkbox.styles.js.map +1 -1
- package/dist/components/form-control/checkbox/CheckboxGroup.d.ts +9 -9
- package/dist/components/form-control/checkbox/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/CheckboxGroup.js +10 -82
- package/dist/components/form-control/checkbox/CheckboxGroup.js.map +2 -2
- package/dist/components/form-control/checkbox/Radio.d.ts +4 -2
- package/dist/components/form-control/checkbox/Radio.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/Radio.js +64 -51
- package/dist/components/form-control/checkbox/Radio.js.map +2 -2
- package/dist/components/form-control/checkbox/RadioGroup.d.ts +9 -9
- package/dist/components/form-control/checkbox/RadioGroup.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/RadioGroup.js +10 -77
- package/dist/components/form-control/checkbox/RadioGroup.js.map +2 -2
- package/dist/components/form-control/color-picker/ColorPicker.d.ts +8 -3
- package/dist/components/form-control/color-picker/ColorPicker.d.ts.map +1 -1
- package/dist/components/form-control/color-picker/ColorPicker.js +43 -26
- package/dist/components/form-control/color-picker/ColorPicker.js.map +2 -2
- package/dist/components/form-control/combobox/Combobox.d.ts +8 -8
- package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
- package/dist/components/form-control/combobox/Combobox.js +72 -59
- package/dist/components/form-control/combobox/Combobox.js.map +2 -2
- package/dist/components/form-control/editor/EditorToolbar.d.ts.map +1 -1
- package/dist/components/form-control/editor/EditorToolbar.js +3 -2
- package/dist/components/form-control/editor/EditorToolbar.js.map +2 -2
- package/dist/components/form-control/editor/RichTextEditor.d.ts.map +1 -1
- package/dist/components/form-control/editor/RichTextEditor.js.map +1 -1
- package/dist/components/form-control/field/DatePicker.d.ts +6 -0
- package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/DatePicker.js +138 -117
- package/dist/components/form-control/field/DatePicker.js.map +2 -2
- package/dist/components/form-control/field/DateTimePicker.d.ts +6 -0
- package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/DateTimePicker.js +138 -115
- package/dist/components/form-control/field/DateTimePicker.js.map +2 -2
- package/dist/components/form-control/field/Field.styles.d.ts +14 -0
- package/dist/components/form-control/field/Field.styles.d.ts.map +1 -1
- package/dist/components/form-control/field/Field.styles.js +47 -3
- package/dist/components/form-control/field/Field.styles.js.map +1 -1
- package/dist/components/form-control/field/FieldPlaceholder.d.ts +7 -0
- package/dist/components/form-control/field/FieldPlaceholder.d.ts.map +1 -0
- package/dist/components/form-control/field/FieldPlaceholder.js +34 -0
- package/dist/components/form-control/field/FieldPlaceholder.js.map +6 -0
- package/dist/components/form-control/field/NumberInput.d.ts +13 -0
- package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
- package/dist/components/form-control/field/NumberInput.js +163 -111
- package/dist/components/form-control/field/NumberInput.js.map +2 -2
- package/dist/components/form-control/field/TextInput.d.ts +16 -1
- package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
- package/dist/components/form-control/field/TextInput.js +177 -114
- package/dist/components/form-control/field/TextInput.js.map +2 -2
- package/dist/components/form-control/field/Textarea.d.ts +10 -0
- package/dist/components/form-control/field/Textarea.d.ts.map +1 -1
- package/dist/components/form-control/field/Textarea.js +156 -121
- package/dist/components/form-control/field/Textarea.js.map +2 -2
- package/dist/components/form-control/field/TimePicker.d.ts +10 -0
- package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/TimePicker.js +126 -94
- package/dist/components/form-control/field/TimePicker.js.map +2 -2
- package/dist/components/form-control/select/Select.d.ts +7 -9
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +71 -60
- package/dist/components/form-control/select/Select.js.map +2 -2
- package/dist/components/form-control/select/SelectItem.d.ts.map +1 -1
- package/dist/components/form-control/select/SelectItem.js.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.js +2 -1
- package/dist/components/form-control/state-preset/StatePreset.js.map +2 -2
- package/dist/components/layout/FormGroup.d.ts.map +1 -1
- package/dist/components/layout/FormGroup.js.map +1 -1
- package/dist/components/layout/sidebar/Sidebar.d.ts.map +1 -1
- package/dist/components/layout/sidebar/Sidebar.js +1 -1
- package/dist/components/layout/sidebar/Sidebar.js.map +1 -1
- package/dist/components/layout/sidebar/SidebarContainer.d.ts.map +1 -1
- package/dist/components/layout/sidebar/SidebarContainer.js.map +1 -1
- package/dist/components/layout/sidebar/SidebarMenu.js +1 -1
- package/dist/components/layout/sidebar/SidebarMenu.js.map +1 -1
- package/dist/components/layout/sidebar/SidebarUser.d.ts.map +1 -1
- package/dist/components/layout/sidebar/SidebarUser.js +4 -4
- package/dist/components/layout/sidebar/SidebarUser.js.map +1 -1
- package/dist/components/layout/topbar/Topbar.js +1 -1
- package/dist/components/layout/topbar/TopbarMenu.d.ts.map +1 -1
- package/dist/components/layout/topbar/TopbarMenu.js.map +1 -1
- package/dist/components/layout/topbar/TopbarUser.d.ts.map +1 -1
- package/dist/components/layout/topbar/TopbarUser.js.map +1 -1
- package/dist/helpers/createAppStructure.d.ts.map +1 -1
- package/dist/helpers/createAppStructure.js +17 -12
- package/dist/helpers/createAppStructure.js.map +1 -1
- package/dist/helpers/mergeStyles.d.ts.map +1 -1
- package/dist/helpers/mergeStyles.js +4 -1
- package/dist/helpers/mergeStyles.js.map +1 -1
- package/dist/helpers/splitSlots.d.ts.map +1 -1
- package/dist/helpers/splitSlots.js.map +1 -1
- package/dist/hooks/createControllableSignal.d.ts.map +1 -1
- package/dist/hooks/createControllableSignal.js.map +1 -1
- package/dist/hooks/createItemTemplate.d.ts +17 -0
- package/dist/hooks/createItemTemplate.d.ts.map +1 -0
- package/dist/hooks/createItemTemplate.js +40 -0
- package/dist/hooks/createItemTemplate.js.map +6 -0
- package/dist/hooks/createPointerDrag.d.ts +13 -0
- package/dist/hooks/createPointerDrag.d.ts.map +1 -0
- package/dist/hooks/createPointerDrag.js +15 -0
- package/dist/hooks/createPointerDrag.js.map +6 -0
- package/dist/hooks/createSelectionGroup.d.ts +70 -0
- package/dist/hooks/createSelectionGroup.d.ts.map +1 -0
- package/dist/hooks/createSelectionGroup.js +141 -0
- package/dist/hooks/createSelectionGroup.js.map +6 -0
- package/dist/hooks/useClipboardValueCopy.js +3 -1
- package/dist/hooks/useClipboardValueCopy.js.map +1 -1
- package/dist/hooks/useLocalStorage.d.ts +5 -3
- package/dist/hooks/useLocalStorage.d.ts.map +1 -1
- package/dist/hooks/useLocalStorage.js.map +1 -1
- package/dist/hooks/usePrint.d.ts.map +1 -1
- package/dist/hooks/usePrint.js +5 -3
- package/dist/hooks/usePrint.js.map +1 -1
- package/dist/hooks/{createPwaUpdate.d.ts → usePwaUpdate.d.ts} +2 -2
- package/dist/hooks/usePwaUpdate.d.ts.map +1 -0
- package/dist/hooks/{createPwaUpdate.js → usePwaUpdate.js} +3 -3
- package/dist/hooks/usePwaUpdate.js.map +6 -0
- package/dist/hooks/useRouterLink.d.ts.map +1 -1
- package/dist/hooks/useRouterLink.js.map +1 -1
- package/dist/hooks/useSyncConfig.d.ts +3 -3
- package/dist/hooks/useSyncConfig.d.ts.map +1 -1
- package/dist/hooks/useSyncConfig.js +6 -7
- package/dist/hooks/useSyncConfig.js.map +1 -1
- package/dist/index.d.ts +5 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/providers/ConfigContext.d.ts +2 -2
- package/dist/providers/ConfigContext.d.ts.map +1 -1
- package/dist/providers/InitializeProvider.js +5 -5
- package/dist/providers/InitializeProvider.js.map +2 -2
- package/dist/providers/ServiceClientProvider.d.ts.map +1 -1
- package/dist/providers/ServiceClientProvider.js.map +1 -1
- package/dist/providers/ThemeContext.d.ts.map +1 -1
- package/dist/providers/ThemeContext.js +2 -1
- package/dist/providers/ThemeContext.js.map +2 -2
- package/dist/providers/shared-data/SharedDataChangeEvent.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataChangeEvent.js +1 -3
- package/dist/providers/shared-data/SharedDataChangeEvent.js.map +1 -1
- package/dist/providers/shared-data/SharedDataContext.d.ts +1 -1
- package/dist/providers/shared-data/SharedDataContext.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.js +6 -6
- package/dist/providers/shared-data/SharedDataProvider.js.map +2 -2
- package/dist/styles/patterns.styles.d.ts +1 -0
- package/dist/styles/patterns.styles.d.ts.map +1 -1
- package/dist/styles/patterns.styles.js +12 -1
- package/dist/styles/patterns.styles.js.map +1 -1
- package/dist/styles/tokens.styles.d.ts +2 -1
- package/dist/styles/tokens.styles.d.ts.map +1 -1
- package/dist/styles/tokens.styles.js +1 -1
- package/dist/styles/tokens.styles.js.map +1 -1
- package/docs/data-components.md +34 -5
- package/docs/disclosure.md +28 -8
- package/docs/display.md +19 -2
- package/docs/feedback.md +35 -12
- package/docs/form-controls.md +289 -33
- package/docs/hooks.md +21 -9
- package/docs/layout.md +15 -3
- package/docs/providers.md +120 -8
- package/docs/styling.md +90 -0
- package/package.json +3 -3
- package/src/components/data/Pagination.tsx +26 -22
- package/src/components/data/Table.tsx +1 -1
- package/src/components/data/calendar/Calendar.tsx +19 -5
- package/src/components/data/kanban/Kanban.tsx +72 -35
- package/src/components/data/list/List.tsx +11 -4
- package/src/components/data/list/ListItem.tsx +12 -2
- package/src/components/data/permission-table/PermissionTable.tsx +32 -5
- package/src/components/data/sheet/DataSheet.styles.ts +24 -6
- package/src/components/data/sheet/DataSheet.tsx +215 -149
- package/src/components/data/sheet/DataSheetColumn.tsx +5 -1
- package/src/components/data/sheet/DataSheetConfigDialog.tsx +27 -5
- package/src/components/data/sheet/sheetUtils.ts +12 -3
- package/src/components/data/sheet/types.ts +2 -2
- package/src/components/disclosure/Collapse.tsx +14 -3
- package/src/components/disclosure/Dialog.tsx +122 -106
- package/src/components/disclosure/DialogContext.ts +8 -5
- package/src/components/disclosure/DialogProvider.tsx +19 -7
- package/src/components/disclosure/Dropdown.tsx +12 -2
- package/src/components/disclosure/Tabs.tsx +29 -5
- package/src/components/display/Alert.tsx +3 -4
- package/src/components/display/Card.tsx +1 -2
- package/src/components/display/Echarts.tsx +12 -5
- package/src/components/display/Link.tsx +22 -0
- package/src/components/feedback/Progress.tsx +9 -5
- package/src/components/feedback/{loading/LoadingContainer.tsx → busy/BusyContainer.tsx} +52 -19
- package/src/components/feedback/busy/BusyContext.ts +20 -0
- package/src/components/feedback/{loading/LoadingProvider.tsx → busy/BusyProvider.tsx} +10 -10
- package/src/components/feedback/notification/NotificationBanner.tsx +14 -3
- package/src/components/feedback/notification/NotificationBell.tsx +21 -15
- package/src/components/feedback/notification/NotificationContext.ts +4 -1
- package/src/components/feedback/notification/NotificationProvider.tsx +4 -1
- package/src/components/form-control/Button.tsx +8 -3
- package/src/components/form-control/DropdownTrigger.styles.ts +7 -1
- package/src/components/form-control/Invalid.tsx +114 -48
- package/src/components/form-control/ThemeToggle.tsx +9 -18
- package/src/components/form-control/checkbox/Checkbox.styles.ts +7 -10
- package/src/components/form-control/checkbox/Checkbox.tsx +39 -28
- package/src/components/form-control/checkbox/CheckboxGroup.tsx +18 -97
- package/src/components/form-control/checkbox/Radio.tsx +39 -28
- package/src/components/form-control/checkbox/RadioGroup.tsx +18 -92
- package/src/components/form-control/color-picker/ColorPicker.tsx +51 -18
- package/src/components/form-control/combobox/Combobox.tsx +53 -35
- package/src/components/form-control/editor/EditorToolbar.tsx +19 -19
- package/src/components/form-control/editor/RichTextEditor.tsx +22 -4
- package/src/components/form-control/field/DatePicker.tsx +99 -93
- package/src/components/form-control/field/DateTimePicker.tsx +115 -96
- package/src/components/form-control/field/Field.styles.ts +62 -3
- package/src/components/form-control/field/FieldPlaceholder.tsx +18 -0
- package/src/components/form-control/field/NumberInput.tsx +136 -84
- package/src/components/form-control/field/TextInput.tsx +135 -88
- package/src/components/form-control/field/Textarea.tsx +126 -99
- package/src/components/form-control/field/TimePicker.tsx +101 -71
- package/src/components/form-control/select/Select.tsx +75 -42
- package/src/components/form-control/select/SelectItem.tsx +3 -1
- package/src/components/form-control/state-preset/StatePreset.tsx +41 -22
- package/src/components/layout/FormGroup.tsx +11 -2
- package/src/components/layout/sidebar/Sidebar.tsx +3 -2
- package/src/components/layout/sidebar/SidebarContainer.tsx +8 -1
- package/src/components/layout/sidebar/SidebarMenu.tsx +8 -2
- package/src/components/layout/sidebar/SidebarUser.tsx +12 -7
- package/src/components/layout/topbar/Topbar.tsx +1 -1
- package/src/components/layout/topbar/TopbarMenu.tsx +27 -5
- package/src/components/layout/topbar/TopbarUser.tsx +5 -1
- package/src/helpers/createAppStructure.ts +29 -15
- package/src/helpers/mergeStyles.ts +6 -2
- package/src/helpers/splitSlots.ts +4 -1
- package/src/hooks/createControllableSignal.ts +2 -1
- package/src/hooks/createItemTemplate.tsx +42 -0
- package/src/hooks/createPointerDrag.ts +28 -0
- package/src/hooks/createSelectionGroup.tsx +235 -0
- package/src/hooks/useClipboardValueCopy.ts +5 -2
- package/src/hooks/useLocalStorage.ts +11 -5
- package/src/hooks/usePrint.ts +9 -4
- package/src/hooks/{createPwaUpdate.ts → usePwaUpdate.ts} +1 -1
- package/src/hooks/useRouterLink.ts +3 -1
- package/src/hooks/useSyncConfig.ts +9 -13
- package/src/index.ts +6 -7
- package/src/providers/ConfigContext.ts +2 -2
- package/src/providers/InitializeProvider.tsx +4 -4
- package/src/providers/ServiceClientProvider.tsx +14 -3
- package/src/providers/ThemeContext.tsx +12 -3
- package/src/providers/shared-data/SharedDataChangeEvent.ts +4 -3
- package/src/providers/shared-data/SharedDataContext.ts +1 -1
- package/src/providers/shared-data/SharedDataProvider.tsx +13 -8
- package/src/styles/patterns.styles.ts +13 -1
- package/src/styles/tokens.styles.ts +2 -1
- package/tailwind.config.ts +9 -0
- package/tailwind.css +1 -1
- package/dist/components/display/Card.css +0 -15
- package/dist/components/feedback/loading/LoadingContainer.d.ts +0 -12
- package/dist/components/feedback/loading/LoadingContainer.d.ts.map +0 -1
- package/dist/components/feedback/loading/LoadingContainer.js.map +0 -6
- package/dist/components/feedback/loading/LoadingContext.d.ts +0 -11
- package/dist/components/feedback/loading/LoadingContext.d.ts.map +0 -1
- package/dist/components/feedback/loading/LoadingContext.js +0 -14
- package/dist/components/feedback/loading/LoadingContext.js.map +0 -6
- package/dist/components/feedback/loading/LoadingProvider.d.ts +0 -7
- package/dist/components/feedback/loading/LoadingProvider.d.ts.map +0 -1
- package/dist/components/feedback/loading/LoadingProvider.js.map +0 -6
- package/dist/hooks/createPwaUpdate.d.ts.map +0 -1
- package/dist/hooks/createPwaUpdate.js.map +0 -6
- package/src/components/display/Card.css +0 -15
- package/src/components/feedback/loading/LoadingContext.ts +0 -20
- /package/dist/components/feedback/{loading/LoadingContainer.css → busy/BusyContainer.css} +0 -0
- /package/src/components/feedback/{loading/LoadingContainer.css → busy/BusyContainer.css} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type JSX, type ParentComponent, splitProps } from "solid-js";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
|
|
5
|
+
export interface LinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {}
|
|
6
|
+
|
|
7
|
+
const baseClass = clsx(
|
|
8
|
+
"text-primary-600",
|
|
9
|
+
"dark:text-primary-400",
|
|
10
|
+
"hover:underline",
|
|
11
|
+
"cursor-pointer",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export const Link: ParentComponent<LinkProps> = (props) => {
|
|
15
|
+
const [local, rest] = splitProps(props, ["children", "class"]);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<a class={twMerge(baseClass, local.class)} {...rest}>
|
|
19
|
+
{local.children}
|
|
20
|
+
</a>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { type JSX, type ParentComponent, Show, splitProps } from "solid-js";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { twMerge } from "tailwind-merge";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type ComponentSizeCompact,
|
|
6
|
+
type SemanticTheme,
|
|
7
|
+
themeTokens,
|
|
8
|
+
} from "../../styles/tokens.styles";
|
|
5
9
|
|
|
6
10
|
export type ProgressTheme = SemanticTheme;
|
|
7
|
-
export type ProgressSize = "sm" | "lg";
|
|
8
11
|
|
|
9
12
|
export interface ProgressProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
13
|
+
/** 진행률 (0~1 범위, 0 = 0%, 1 = 100%) */
|
|
10
14
|
value: number;
|
|
11
15
|
theme?: ProgressTheme;
|
|
12
|
-
size?:
|
|
16
|
+
size?: ComponentSizeCompact;
|
|
13
17
|
inset?: boolean;
|
|
14
18
|
}
|
|
15
19
|
|
|
@@ -21,7 +25,7 @@ const baseClass = clsx(
|
|
|
21
25
|
"border border-base-200 dark:border-base-700",
|
|
22
26
|
);
|
|
23
27
|
|
|
24
|
-
const sizeClasses: Record<"default" |
|
|
28
|
+
const sizeClasses: Record<"default" | ComponentSizeCompact, string> = {
|
|
25
29
|
default: "py-1 px-2",
|
|
26
30
|
sm: "py-0.5 px-2",
|
|
27
31
|
lg: "py-2 px-3",
|
|
@@ -46,7 +50,7 @@ export const Progress: ParentComponent<ProgressProps> = (props) => {
|
|
|
46
50
|
return clsx("absolute left-0 top-0 h-full", "z-[1]", "transition-all", barThemeClasses[theme]);
|
|
47
51
|
};
|
|
48
52
|
|
|
49
|
-
const getPercentText = () => (local.value * 100).toFixed(2) + "%";
|
|
53
|
+
const getPercentText = () => (Math.max(0, Math.min(1, local.value)) * 100).toFixed(2) + "%";
|
|
50
54
|
|
|
51
55
|
return (
|
|
52
56
|
<div data-progress class={getClassName()} {...rest}>
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ParentComponent,
|
|
3
|
+
type JSX,
|
|
4
|
+
splitProps,
|
|
5
|
+
createEffect,
|
|
6
|
+
onCleanup,
|
|
7
|
+
Show,
|
|
8
|
+
useContext,
|
|
9
|
+
} from "solid-js";
|
|
2
10
|
import clsx from "clsx";
|
|
3
11
|
import { twMerge } from "tailwind-merge";
|
|
4
|
-
import {
|
|
12
|
+
import { BusyContext, type BusyVariant } from "./BusyContext";
|
|
5
13
|
import { createMountTransition } from "../../../hooks/createMountTransition";
|
|
6
|
-
import "./
|
|
14
|
+
import "./BusyContainer.css";
|
|
7
15
|
|
|
8
|
-
export interface
|
|
16
|
+
export interface BusyContainerProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
9
17
|
busy?: boolean;
|
|
10
|
-
|
|
18
|
+
ready?: boolean;
|
|
19
|
+
variant?: BusyVariant;
|
|
11
20
|
message?: string;
|
|
12
21
|
progressPercent?: number;
|
|
13
22
|
children?: JSX.Element;
|
|
@@ -46,18 +55,28 @@ const progressBarClass = clsx(
|
|
|
46
55
|
|
|
47
56
|
const barIndicatorClass = clsx("absolute left-0 top-0", "h-1 w-full", "bg-white dark:bg-base-800");
|
|
48
57
|
|
|
49
|
-
export const
|
|
50
|
-
const [local, rest] = splitProps(props, [
|
|
58
|
+
export const BusyContainer: ParentComponent<BusyContainerProps> = (props) => {
|
|
59
|
+
const [local, rest] = splitProps(props, [
|
|
60
|
+
"busy",
|
|
61
|
+
"ready",
|
|
62
|
+
"variant",
|
|
63
|
+
"message",
|
|
64
|
+
"progressPercent",
|
|
65
|
+
"class",
|
|
66
|
+
"children",
|
|
67
|
+
]);
|
|
51
68
|
|
|
52
|
-
const
|
|
53
|
-
const currVariant = ():
|
|
69
|
+
const busyCtx = useContext(BusyContext);
|
|
70
|
+
const currVariant = (): BusyVariant => local.variant ?? busyCtx?.variant() ?? "spinner";
|
|
54
71
|
|
|
55
72
|
// 애니메이션 상태 (mount transition)
|
|
56
|
-
const { mounted, animating, unmount } = createMountTransition(
|
|
73
|
+
const { mounted, animating, unmount } = createMountTransition(
|
|
74
|
+
() => local.ready === false || !!local.busy,
|
|
75
|
+
);
|
|
57
76
|
|
|
58
77
|
const handleTransitionEnd = (e: TransitionEvent) => {
|
|
59
78
|
if (e.propertyName !== "opacity") return;
|
|
60
|
-
if (!local.busy) {
|
|
79
|
+
if (local.ready !== false && !local.busy) {
|
|
61
80
|
unmount();
|
|
62
81
|
}
|
|
63
82
|
};
|
|
@@ -67,18 +86,23 @@ export const LoadingContainer: ParentComponent<LoadingContainerProps> = (props)
|
|
|
67
86
|
|
|
68
87
|
createEffect(() => {
|
|
69
88
|
const handleKeyDownCapture = (e: KeyboardEvent) => {
|
|
70
|
-
if (local.busy) {
|
|
89
|
+
if (local.ready === false || local.busy) {
|
|
71
90
|
e.preventDefault();
|
|
72
91
|
e.stopPropagation();
|
|
73
92
|
}
|
|
74
93
|
};
|
|
75
94
|
|
|
76
95
|
containerRef.addEventListener("keydown", handleKeyDownCapture, { capture: true });
|
|
77
|
-
onCleanup(() =>
|
|
96
|
+
onCleanup(() =>
|
|
97
|
+
containerRef.removeEventListener("keydown", handleKeyDownCapture, { capture: true }),
|
|
98
|
+
);
|
|
78
99
|
});
|
|
79
100
|
|
|
80
101
|
const screenClass = () =>
|
|
81
|
-
clsx(
|
|
102
|
+
clsx(
|
|
103
|
+
screenBaseClass,
|
|
104
|
+
animating() ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0",
|
|
105
|
+
);
|
|
82
106
|
|
|
83
107
|
// spinner: 슬라이드 다운 애니메이션
|
|
84
108
|
const rectClass = () => {
|
|
@@ -97,16 +121,22 @@ export const LoadingContainer: ParentComponent<LoadingContainerProps> = (props)
|
|
|
97
121
|
<Show when={currVariant() === "spinner"}>
|
|
98
122
|
<div class={spinnerClass} />
|
|
99
123
|
</Show>
|
|
100
|
-
<Show when={currVariant() === "bar" && local.busy}>
|
|
124
|
+
<Show when={currVariant() === "bar" && (local.ready === false || local.busy)}>
|
|
101
125
|
<div class={barIndicatorClass}>
|
|
102
126
|
<div
|
|
103
|
-
class={clsx(
|
|
127
|
+
class={clsx(
|
|
128
|
+
"absolute left-0 top-0 h-1 w-full origin-left",
|
|
129
|
+
"bg-primary-500 dark:bg-primary-400",
|
|
130
|
+
)}
|
|
104
131
|
style={{
|
|
105
132
|
animation: "sd-busy-bar-before 2s infinite ease-in",
|
|
106
133
|
}}
|
|
107
134
|
/>
|
|
108
135
|
<div
|
|
109
|
-
class={clsx(
|
|
136
|
+
class={clsx(
|
|
137
|
+
"absolute left-0 top-0 h-1 w-full origin-left",
|
|
138
|
+
"bg-white dark:bg-base-800",
|
|
139
|
+
)}
|
|
110
140
|
style={{
|
|
111
141
|
animation: "sd-busy-bar-after 2s infinite ease-out",
|
|
112
142
|
}}
|
|
@@ -121,12 +151,15 @@ export const LoadingContainer: ParentComponent<LoadingContainerProps> = (props)
|
|
|
121
151
|
</div>
|
|
122
152
|
<Show when={local.progressPercent != null}>
|
|
123
153
|
<div class={progressTrackClass}>
|
|
124
|
-
<div
|
|
154
|
+
<div
|
|
155
|
+
class={progressBarClass}
|
|
156
|
+
style={{ transform: `scaleX(${(local.progressPercent ?? 0) / 100})` }}
|
|
157
|
+
/>
|
|
125
158
|
</div>
|
|
126
159
|
</Show>
|
|
127
160
|
</div>
|
|
128
161
|
</Show>
|
|
129
|
-
{local.children}
|
|
162
|
+
<Show when={local.ready !== false}>{local.children}</Show>
|
|
130
163
|
</div>
|
|
131
164
|
);
|
|
132
165
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createContext, useContext, type Accessor } from "solid-js";
|
|
2
|
+
|
|
3
|
+
export type BusyVariant = "spinner" | "bar";
|
|
4
|
+
|
|
5
|
+
export interface BusyContextValue {
|
|
6
|
+
variant: Accessor<BusyVariant>;
|
|
7
|
+
show: (message?: string) => void;
|
|
8
|
+
hide: () => void;
|
|
9
|
+
setProgress: (percent: number | undefined) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const BusyContext = createContext<BusyContextValue>();
|
|
13
|
+
|
|
14
|
+
export function useBusy(): BusyContextValue {
|
|
15
|
+
const context = useContext(BusyContext);
|
|
16
|
+
if (!context) {
|
|
17
|
+
throw new Error("useBusy는 BusyProvider 내부에서만 사용할 수 있습니다");
|
|
18
|
+
}
|
|
19
|
+
return context;
|
|
20
|
+
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { type ParentComponent, createSignal } from "solid-js";
|
|
2
2
|
import { Portal } from "solid-js/web";
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { BusyContext, type BusyContextValue, type BusyVariant } from "./BusyContext";
|
|
5
|
+
import { BusyContainer } from "./BusyContainer";
|
|
6
6
|
|
|
7
7
|
const overlayClass = clsx("fixed left-0 top-0", "h-screen w-screen", "overflow-hidden");
|
|
8
8
|
|
|
9
|
-
export interface
|
|
10
|
-
variant?:
|
|
9
|
+
export interface BusyProviderProps {
|
|
10
|
+
variant?: BusyVariant;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const
|
|
13
|
+
export const BusyProvider: ParentComponent<BusyProviderProps> = (props) => {
|
|
14
14
|
const [busyCount, setBusyCount] = createSignal(0);
|
|
15
15
|
const [message, setMessage] = createSignal<string | undefined>();
|
|
16
16
|
const [progress, setProgress] = createSignal<number | undefined>();
|
|
17
17
|
|
|
18
|
-
const variant = ():
|
|
18
|
+
const variant = (): BusyVariant => props.variant ?? "spinner";
|
|
19
19
|
|
|
20
20
|
const show = (msg?: string): void => {
|
|
21
21
|
setBusyCount((c) => c + 1);
|
|
@@ -33,7 +33,7 @@ export const LoadingProvider: ParentComponent<LoadingProviderProps> = (props) =>
|
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
const contextValue:
|
|
36
|
+
const contextValue: BusyContextValue = {
|
|
37
37
|
variant,
|
|
38
38
|
show,
|
|
39
39
|
hide,
|
|
@@ -41,10 +41,10 @@ export const LoadingProvider: ParentComponent<LoadingProviderProps> = (props) =>
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
return (
|
|
44
|
-
<
|
|
44
|
+
<BusyContext.Provider value={contextValue}>
|
|
45
45
|
{props.children}
|
|
46
46
|
<Portal>
|
|
47
|
-
<
|
|
47
|
+
<BusyContainer
|
|
48
48
|
busy={busyCount() > 0}
|
|
49
49
|
variant={variant()}
|
|
50
50
|
message={message()}
|
|
@@ -53,6 +53,6 @@ export const LoadingProvider: ParentComponent<LoadingProviderProps> = (props) =>
|
|
|
53
53
|
style={{ "pointer-events": busyCount() > 0 ? "auto" : "none" }}
|
|
54
54
|
/>
|
|
55
55
|
</Portal>
|
|
56
|
-
</
|
|
56
|
+
</BusyContext.Provider>
|
|
57
57
|
);
|
|
58
58
|
};
|
|
@@ -33,7 +33,13 @@ const themeClasses: Record<string, string> = {
|
|
|
33
33
|
const contentClass = clsx("flex flex-col", "gap-0.5", "min-w-0");
|
|
34
34
|
const messageClass = clsx("text-sm", "opacity-90", "overflow-auto");
|
|
35
35
|
const actionsClass = clsx("flex items-center", "gap-2", "shrink-0");
|
|
36
|
-
const actionButtonClass = clsx(
|
|
36
|
+
const actionButtonClass = clsx(
|
|
37
|
+
"rounded",
|
|
38
|
+
"bg-white/20",
|
|
39
|
+
"px-3 py-1",
|
|
40
|
+
"text-sm",
|
|
41
|
+
"hover:bg-white/30",
|
|
42
|
+
);
|
|
37
43
|
const dismissButtonClass = clsx("rounded", "p-1", "hover:bg-white/20");
|
|
38
44
|
|
|
39
45
|
export const NotificationBanner: Component = () => {
|
|
@@ -59,7 +65,7 @@ export const NotificationBanner: Component = () => {
|
|
|
59
65
|
class={clsx(baseClass, themeClasses[item().theme])}
|
|
60
66
|
>
|
|
61
67
|
<div class={contentClass}>
|
|
62
|
-
<span class="font-
|
|
68
|
+
<span class="font-bold">{item().title}</span>
|
|
63
69
|
<Show when={item().message}>
|
|
64
70
|
<pre class={messageClass}>{item().message}</pre>
|
|
65
71
|
</Show>
|
|
@@ -70,7 +76,12 @@ export const NotificationBanner: Component = () => {
|
|
|
70
76
|
{item().action!.label}
|
|
71
77
|
</button>
|
|
72
78
|
</Show>
|
|
73
|
-
<button
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
aria-label="알림 닫기"
|
|
82
|
+
class={dismissButtonClass}
|
|
83
|
+
onClick={handleDismiss}
|
|
84
|
+
>
|
|
74
85
|
<Icon icon={IconX} size="1.25em" />
|
|
75
86
|
</button>
|
|
76
87
|
</div>
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
import { type Component, createSignal, For, Show } from "solid-js";
|
|
2
2
|
import { IconBell } from "@tabler/icons-solidjs";
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
+
import { twMerge } from "tailwind-merge";
|
|
4
5
|
import { useNotification } from "./NotificationContext";
|
|
5
6
|
import { Dropdown } from "../../disclosure/Dropdown";
|
|
6
7
|
import { Icon } from "../../display/Icon";
|
|
7
8
|
import { NotificationBanner } from "./NotificationBanner";
|
|
9
|
+
import { iconButtonBase } from "../../../styles/patterns.styles";
|
|
8
10
|
|
|
9
11
|
export interface NotificationBellProps {
|
|
10
12
|
showBanner?: boolean;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
const buttonClass =
|
|
14
|
-
"relative",
|
|
15
|
-
"p-2",
|
|
16
|
-
"rounded-full",
|
|
17
|
-
"hover:bg-base-100",
|
|
18
|
-
"dark:hover:bg-base-700",
|
|
19
|
-
"transition-colors",
|
|
20
|
-
"focus:outline-none",
|
|
21
|
-
"focus-visible:ring-2",
|
|
22
|
-
"focus-visible:ring-primary-500",
|
|
23
|
-
);
|
|
15
|
+
const buttonClass = twMerge(iconButtonBase, "relative", "p-2", "rounded-full");
|
|
24
16
|
|
|
25
17
|
const badgeClass = clsx(
|
|
26
18
|
"absolute",
|
|
@@ -99,18 +91,32 @@ export const NotificationBell: Component<NotificationBellProps> = (props) => {
|
|
|
99
91
|
</Show>
|
|
100
92
|
</button>
|
|
101
93
|
|
|
102
|
-
<Dropdown
|
|
94
|
+
<Dropdown
|
|
95
|
+
triggerRef={() => buttonRef}
|
|
96
|
+
open={open()}
|
|
97
|
+
onOpenChange={handleOpenChange}
|
|
98
|
+
maxHeight={400}
|
|
99
|
+
class="w-80"
|
|
100
|
+
>
|
|
103
101
|
<div class="p-2">
|
|
104
102
|
<div class={dropdownHeaderClass}>
|
|
105
|
-
<span class="font-
|
|
103
|
+
<span class="font-bold">알림</span>
|
|
106
104
|
<Show when={notification.items().length > 0}>
|
|
107
|
-
<button
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
data-notification-clear
|
|
108
|
+
class={clearButtonClass}
|
|
109
|
+
onClick={handleClear}
|
|
110
|
+
>
|
|
108
111
|
전체 삭제
|
|
109
112
|
</button>
|
|
110
113
|
</Show>
|
|
111
114
|
</div>
|
|
112
115
|
|
|
113
|
-
<Show
|
|
116
|
+
<Show
|
|
117
|
+
when={notification.items().length > 0}
|
|
118
|
+
fallback={<div class={emptyClass}>알림이 없습니다</div>}
|
|
119
|
+
>
|
|
114
120
|
<div class={listClass}>
|
|
115
121
|
<For each={[...notification.items()].reverse()}>
|
|
116
122
|
{(item) => (
|
|
@@ -38,7 +38,10 @@ export interface NotificationContextValue {
|
|
|
38
38
|
danger: (title: string, message?: string, options?: NotificationOptions) => string;
|
|
39
39
|
|
|
40
40
|
// 에러 처리 (danger 알림 + 로깅)
|
|
41
|
-
try: <TResult>(
|
|
41
|
+
try: <TResult>(
|
|
42
|
+
fn: () => Promise<TResult> | TResult,
|
|
43
|
+
header?: string,
|
|
44
|
+
) => Promise<TResult | undefined>;
|
|
42
45
|
|
|
43
46
|
// 알림 수정
|
|
44
47
|
update: (
|
|
@@ -125,6 +125,7 @@ export const NotificationProvider: ParentComponent = (props) => {
|
|
|
125
125
|
const latest = latestUnread();
|
|
126
126
|
if (latest) {
|
|
127
127
|
setDismissedBannerId(latest.id);
|
|
128
|
+
markAsRead(latest.id);
|
|
128
129
|
}
|
|
129
130
|
};
|
|
130
131
|
|
|
@@ -154,7 +155,9 @@ export const NotificationProvider: ParentComponent = (props) => {
|
|
|
154
155
|
<NotificationContext.Provider value={contextValue}>
|
|
155
156
|
{/* 스크린 리더용 Live Region */}
|
|
156
157
|
<div role="status" aria-live="polite" aria-atomic="true" class="sr-only">
|
|
157
|
-
<Show when={latestUnread()}>
|
|
158
|
+
<Show when={latestUnread()}>
|
|
159
|
+
{(item) => `알림: ${item().title} ${item().message ?? ""}`}
|
|
160
|
+
</Show>
|
|
158
161
|
</div>
|
|
159
162
|
{props.children}
|
|
160
163
|
</NotificationContext.Provider>
|
|
@@ -2,7 +2,12 @@ import { type JSX, type ParentComponent, splitProps } from "solid-js";
|
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { twMerge } from "tailwind-merge";
|
|
4
4
|
import { ripple } from "../../directives/ripple";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
themeTokens,
|
|
7
|
+
type SemanticTheme,
|
|
8
|
+
type ComponentSize,
|
|
9
|
+
disabledOpacity,
|
|
10
|
+
} from "../../styles/tokens.styles";
|
|
6
11
|
|
|
7
12
|
// Directive 사용 선언 (TypeScript용)
|
|
8
13
|
void ripple;
|
|
@@ -18,7 +23,7 @@ const baseClass = clsx(
|
|
|
18
23
|
"justify-center",
|
|
19
24
|
"text-center",
|
|
20
25
|
"cursor-pointer",
|
|
21
|
-
"transition
|
|
26
|
+
"transition",
|
|
22
27
|
"rounded",
|
|
23
28
|
"focus:outline-none",
|
|
24
29
|
"focus-visible:ring-2",
|
|
@@ -30,7 +35,7 @@ const themeClasses = Object.fromEntries(
|
|
|
30
35
|
Object.entries(themeTokens).map(([theme, t]) => [
|
|
31
36
|
theme,
|
|
32
37
|
{
|
|
33
|
-
solid: clsx(t.solid, t.solidHover),
|
|
38
|
+
solid: clsx(t.solid, t.solidHover, "shadow-md hover:shadow-lg"),
|
|
34
39
|
outline: clsx("bg-transparent", t.hoverBg, t.text, t.border),
|
|
35
40
|
ghost: clsx("bg-transparent", t.hoverBg, t.text),
|
|
36
41
|
},
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import clsx from "clsx";
|
|
2
2
|
import { twMerge } from "tailwind-merge";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
borderDefault,
|
|
5
|
+
type ComponentSize,
|
|
6
|
+
paddingLg,
|
|
7
|
+
paddingSm,
|
|
8
|
+
paddingXl,
|
|
9
|
+
} from "../../styles/tokens.styles";
|
|
4
10
|
import { insetBase, insetFocusOutlineSelf } from "../../styles/patterns.styles";
|
|
5
11
|
|
|
6
12
|
export const triggerBaseClass = clsx(
|
|
@@ -1,65 +1,131 @@
|
|
|
1
|
-
import { type ParentComponent, createEffect,
|
|
2
|
-
import clsx from "clsx";
|
|
3
|
-
import { twMerge } from "tailwind-merge";
|
|
1
|
+
import { type ParentComponent, children, createEffect, createSignal, onCleanup } from "solid-js";
|
|
4
2
|
import "@simplysm/core-browser";
|
|
5
3
|
|
|
6
4
|
export interface InvalidProps {
|
|
7
5
|
/** Validation error message. Non-empty = invalid. */
|
|
8
6
|
message?: string;
|
|
9
|
-
/**
|
|
10
|
-
|
|
7
|
+
/** Visual indicator variant */
|
|
8
|
+
variant?: "border" | "dot";
|
|
9
|
+
/** When true, visual display only appears after target loses focus */
|
|
10
|
+
touchMode?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
export const Invalid: ParentComponent<InvalidProps> = (props) => {
|
|
14
|
+
const hiddenInputEl = document.createElement("input");
|
|
15
|
+
hiddenInputEl.type = "text";
|
|
16
|
+
hiddenInputEl.style.cssText =
|
|
17
|
+
"position:absolute; bottom:0; left:50%; width:1px; height:1px; opacity:0; pointer-events:none; z-index:-10;";
|
|
18
|
+
hiddenInputEl.autocomplete = "off";
|
|
19
|
+
hiddenInputEl.tabIndex = -1;
|
|
20
|
+
hiddenInputEl.setAttribute("aria-hidden", "true");
|
|
19
21
|
|
|
20
|
-
const
|
|
22
|
+
const [touched, setTouched] = createSignal(false);
|
|
21
23
|
|
|
22
|
-
const
|
|
23
|
-
"absolute bottom-0 left-0.5",
|
|
24
|
-
"size-px opacity-0",
|
|
25
|
-
"pointer-events-none -z-10",
|
|
26
|
-
"select-none",
|
|
27
|
-
);
|
|
24
|
+
const resolved = children(() => props.children);
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
// message 변경 시 setCustomValidity 반응형 업데이트 (touchMode 무관하게 항상)
|
|
27
|
+
createEffect(() => {
|
|
28
|
+
const msg = props.message ?? "";
|
|
29
|
+
hiddenInputEl.setCustomValidity(msg);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// target에 relative 설정 + hidden input을 target 내부에 삽입
|
|
33
|
+
createEffect(() => {
|
|
34
|
+
const targetEl = resolved.toArray().find((el): el is HTMLElement => el instanceof HTMLElement);
|
|
35
|
+
if (!targetEl) return;
|
|
36
|
+
|
|
37
|
+
const computedPosition = getComputedStyle(targetEl).position;
|
|
38
|
+
if (computedPosition === "static") {
|
|
39
|
+
targetEl.style.position = "relative";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
targetEl.appendChild(hiddenInputEl);
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
onCleanup(() => {
|
|
45
|
+
if (hiddenInputEl.parentElement === targetEl) {
|
|
46
|
+
targetEl.removeChild(hiddenInputEl);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
33
50
|
|
|
34
|
-
//
|
|
51
|
+
// 시각적 표시 처리
|
|
35
52
|
createEffect(() => {
|
|
36
|
-
const
|
|
37
|
-
|
|
53
|
+
const variant = props.variant ?? "dot";
|
|
54
|
+
const message = props.message ?? "";
|
|
55
|
+
const touchMode = props.touchMode ?? false;
|
|
56
|
+
const isTouched = touched();
|
|
57
|
+
|
|
58
|
+
const targetEl = resolved.toArray().find((el): el is HTMLElement => el instanceof HTMLElement);
|
|
59
|
+
|
|
60
|
+
if (!targetEl) return;
|
|
61
|
+
|
|
62
|
+
const shouldShow = message !== "" && (!touchMode || isTouched);
|
|
63
|
+
|
|
64
|
+
if (variant === "border") {
|
|
65
|
+
if (shouldShow) {
|
|
66
|
+
targetEl.classList.add("border-danger-500");
|
|
67
|
+
} else {
|
|
68
|
+
targetEl.classList.remove("border-danger-500");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
onCleanup(() => {
|
|
72
|
+
targetEl.classList.remove("border-danger-500");
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
// variant === "dot"
|
|
76
|
+
const existingDot = targetEl.querySelector("[data-invalid-dot]");
|
|
77
|
+
if (existingDot) {
|
|
78
|
+
existingDot.remove();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (shouldShow) {
|
|
82
|
+
const dot = document.createElement("span");
|
|
83
|
+
dot.setAttribute("data-invalid-dot", "");
|
|
84
|
+
dot.style.cssText =
|
|
85
|
+
"position:absolute; top:2px; right:2px; width:6px; height:6px; border-radius:50%; background:red; pointer-events:none;";
|
|
86
|
+
targetEl.appendChild(dot);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
onCleanup(() => {
|
|
90
|
+
const dot = targetEl.querySelector("[data-invalid-dot]");
|
|
91
|
+
if (dot) {
|
|
92
|
+
dot.remove();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
38
96
|
});
|
|
39
97
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (!
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
98
|
+
// touchMode: target에 focusout 이벤트 등록하여 touched 상태 추적
|
|
99
|
+
createEffect(() => {
|
|
100
|
+
if (!(props.touchMode ?? false)) return;
|
|
101
|
+
|
|
102
|
+
const targetEl = resolved.toArray().find((el): el is HTMLElement => el instanceof HTMLElement);
|
|
103
|
+
|
|
104
|
+
if (!targetEl) return;
|
|
105
|
+
|
|
106
|
+
const handleFocusOut = () => {
|
|
107
|
+
setTouched(true);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
targetEl.addEventListener("focusout", handleFocusOut);
|
|
111
|
+
|
|
112
|
+
onCleanup(() => {
|
|
113
|
+
targetEl.removeEventListener("focusout", handleFocusOut);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// hidden input 포커스 시 target의 focusable child로 리디렉션
|
|
118
|
+
hiddenInputEl.addEventListener("focus", () => {
|
|
119
|
+
const targetEl = resolved.toArray().find((el): el is HTMLElement => el instanceof HTMLElement);
|
|
120
|
+
|
|
121
|
+
if (targetEl) {
|
|
122
|
+
const focusable =
|
|
123
|
+
targetEl.findFirstFocusableChild() ?? (targetEl.tabIndex >= 0 ? targetEl : undefined);
|
|
124
|
+
if (focusable && focusable !== hiddenInputEl) {
|
|
125
|
+
focusable.focus();
|
|
126
|
+
}
|
|
46
127
|
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<div {...rest} class={twMerge("inline", local.class)}>
|
|
51
|
-
<span class={anchorClass}>
|
|
52
|
-
<span class={indicatorClass} style={{ display: (local.message ?? "") !== "" ? "block" : "none" }} />
|
|
53
|
-
</span>
|
|
54
|
-
{local.children}
|
|
55
|
-
<input
|
|
56
|
-
ref={hiddenInputEl}
|
|
57
|
-
type="text"
|
|
58
|
-
class={hiddenInputClass}
|
|
59
|
-
tabIndex={-1}
|
|
60
|
-
aria-hidden="true"
|
|
61
|
-
onFocus={handleHiddenInputFocus}
|
|
62
|
-
/>
|
|
63
|
-
</div>
|
|
64
|
-
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return <>{resolved()}</>;
|
|
65
131
|
};
|