@qijenchen/design-system 0.1.0-beta.10
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 +163 -0
- package/dist/components/Accordion/accordion.d.ts +37 -0
- package/dist/components/Accordion/accordion.d.ts.map +1 -0
- package/dist/components/Accordion/accordion.js +78 -0
- package/dist/components/Accordion/accordion.js.map +1 -0
- package/dist/components/Alert/alert.d.ts +47 -0
- package/dist/components/Alert/alert.d.ts.map +1 -0
- package/dist/components/Alert/alert.js +132 -0
- package/dist/components/Alert/alert.js.map +1 -0
- package/dist/components/AppShell/_demo-helpers.d.ts +49 -0
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -0
- package/dist/components/AppShell/app-shell.d.ts +76 -0
- package/dist/components/AppShell/app-shell.d.ts.map +1 -0
- package/dist/components/AppShell/app-shell.js +214 -0
- package/dist/components/AppShell/app-shell.js.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts +40 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.js +23 -0
- package/dist/components/AspectRatio/aspect-ratio.js.map +1 -0
- package/dist/components/Avatar/avatar.d.ts +85 -0
- package/dist/components/Avatar/avatar.d.ts.map +1 -0
- package/dist/components/Avatar/avatar.js +195 -0
- package/dist/components/Avatar/avatar.js.map +1 -0
- package/dist/components/Badge/badge.d.ts +43 -0
- package/dist/components/Badge/badge.d.ts.map +1 -0
- package/dist/components/Badge/badge.js +69 -0
- package/dist/components/Badge/badge.js.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts +163 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.js +300 -0
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +46 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.js +78 -0
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -0
- package/dist/components/Button/button-group.d.ts +49 -0
- package/dist/components/Button/button-group.d.ts.map +1 -0
- package/dist/components/Button/button-group.js +46 -0
- package/dist/components/Button/button-group.js.map +1 -0
- package/dist/components/Button/button.d.ts +203 -0
- package/dist/components/Button/button.d.ts.map +1 -0
- package/dist/components/Button/button.js +309 -0
- package/dist/components/Button/button.js.map +1 -0
- package/dist/components/Calendar/calendar.d.ts +81 -0
- package/dist/components/Calendar/calendar.d.ts.map +1 -0
- package/dist/components/Calendar/calendar.js +282 -0
- package/dist/components/Calendar/calendar.js.map +1 -0
- package/dist/components/Carousel/carousel.d.ts +61 -0
- package/dist/components/Carousel/carousel.d.ts.map +1 -0
- package/dist/components/Carousel/carousel.js +276 -0
- package/dist/components/Carousel/carousel.js.map +1 -0
- package/dist/components/Chart/chart.d.ts +94 -0
- package/dist/components/Chart/chart.d.ts.map +1 -0
- package/dist/components/Chart/chart.js +233 -0
- package/dist/components/Chart/chart.js.map +1 -0
- package/dist/components/Checkbox/checkbox-group.d.ts +58 -0
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -0
- package/dist/components/Checkbox/checkbox-group.js +28 -0
- package/dist/components/Checkbox/checkbox-group.js.map +1 -0
- package/dist/components/Checkbox/checkbox.d.ts +73 -0
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/checkbox.js +125 -0
- package/dist/components/Checkbox/checkbox.js.map +1 -0
- package/dist/components/Chip/chip.d.ts +54 -0
- package/dist/components/Chip/chip.d.ts.map +1 -0
- package/dist/components/Chip/chip.js +224 -0
- package/dist/components/Chip/chip.js.map +1 -0
- package/dist/components/CircularProgress/circular-progress.d.ts +40 -0
- package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -0
- package/dist/components/CircularProgress/circular-progress.js +118 -0
- package/dist/components/CircularProgress/circular-progress.js.map +1 -0
- package/dist/components/Coachmark/coachmark.d.ts +100 -0
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -0
- package/dist/components/Coachmark/coachmark.js +107 -0
- package/dist/components/Coachmark/coachmark.js.map +1 -0
- package/dist/components/Combobox/combobox.d.ts +150 -0
- package/dist/components/Combobox/combobox.d.ts.map +1 -0
- package/dist/components/Combobox/combobox.js +595 -0
- package/dist/components/Combobox/combobox.js.map +1 -0
- package/dist/components/Command/command.d.ts +106 -0
- package/dist/components/Command/command.d.ts.map +1 -0
- package/dist/components/Command/command.js +123 -0
- package/dist/components/Command/command.js.map +1 -0
- package/dist/components/DataTable/active-editor-controller.d.ts +66 -0
- package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -0
- package/dist/components/DataTable/cell-registry.d.ts +37 -0
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -0
- package/dist/components/DataTable/cell-registry.js +377 -0
- package/dist/components/DataTable/cell-registry.js.map +1 -0
- package/dist/components/DataTable/column-types.d.ts +145 -0
- package/dist/components/DataTable/column-types.d.ts.map +1 -0
- package/dist/components/DataTable/column-types.js +17 -0
- package/dist/components/DataTable/column-types.js.map +1 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +49 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts +30 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +78 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.js +220 -0
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -0
- package/dist/components/DataTable/data-table-sort-manager.d.ts +19 -0
- package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +181 -0
- package/dist/components/DataTable/data-table.d.ts.map +1 -0
- package/dist/components/DataTable/data-table.js +1851 -0
- package/dist/components/DataTable/data-table.js.map +1 -0
- package/dist/components/DataTable/filter-operators.d.ts +116 -0
- package/dist/components/DataTable/filter-operators.d.ts.map +1 -0
- package/dist/components/DataTable/filter-tree.d.ts +66 -0
- package/dist/components/DataTable/filter-tree.d.ts.map +1 -0
- package/dist/components/DataTable/lib/column-meta.d.ts +49 -0
- package/dist/components/DataTable/lib/column-meta.d.ts.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts +61 -0
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -0
- package/dist/components/DateGrid/date-grid.js +168 -0
- package/dist/components/DateGrid/date-grid.js.map +1 -0
- package/dist/components/DatePicker/date-picker.d.ts +119 -0
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -0
- package/dist/components/DatePicker/date-picker.js +743 -0
- package/dist/components/DatePicker/date-picker.js.map +1 -0
- package/dist/components/DescriptionList/description-list.d.ts +60 -0
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -0
- package/dist/components/DescriptionList/description-list.js +77 -0
- package/dist/components/DescriptionList/description-list.js.map +1 -0
- package/dist/components/Dialog/dialog.d.ts +54 -0
- package/dist/components/Dialog/dialog.d.ts.map +1 -0
- package/dist/components/Dialog/dialog.js +151 -0
- package/dist/components/Dialog/dialog.js.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +111 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.js +288 -0
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -0
- package/dist/components/Empty/empty.d.ts +40 -0
- package/dist/components/Empty/empty.d.ts.map +1 -0
- package/dist/components/Empty/empty.js +66 -0
- package/dist/components/Empty/empty.js.map +1 -0
- package/dist/components/Field/field-context.d.ts +77 -0
- package/dist/components/Field/field-context.d.ts.map +1 -0
- package/dist/components/Field/field-context.js +37 -0
- package/dist/components/Field/field-context.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +5 -0
- package/dist/components/Field/field-types.d.ts.map +1 -0
- package/dist/components/Field/field-types.js +13 -0
- package/dist/components/Field/field-types.js.map +1 -0
- package/dist/components/Field/field-wrapper.d.ts +17 -0
- package/dist/components/Field/field-wrapper.d.ts.map +1 -0
- package/dist/components/Field/field-wrapper.js +252 -0
- package/dist/components/Field/field-wrapper.js.map +1 -0
- package/dist/components/Field/field.d.ts +127 -0
- package/dist/components/Field/field.d.ts.map +1 -0
- package/dist/components/Field/field.js +295 -0
- package/dist/components/Field/field.js.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts +74 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.js +62 -0
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -0
- package/dist/components/FileItem/file-item.d.ts +44 -0
- package/dist/components/FileItem/file-item.d.ts.map +1 -0
- package/dist/components/FileItem/file-item.js +202 -0
- package/dist/components/FileItem/file-item.js.map +1 -0
- package/dist/components/FileUpload/file-upload.d.ts +97 -0
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -0
- package/dist/components/FileUpload/file-upload.js +231 -0
- package/dist/components/FileUpload/file-upload.js.map +1 -0
- package/dist/components/FileViewer/file-viewer-types.d.ts +73 -0
- package/dist/components/FileViewer/file-viewer-types.d.ts.map +1 -0
- package/dist/components/FileViewer/file-viewer.d.ts +82 -0
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -0
- package/dist/components/FileViewer/file-viewer.js +752 -0
- package/dist/components/FileViewer/file-viewer.js.map +1 -0
- package/dist/components/FileViewer/image-renderer.d.ts +9 -0
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -0
- package/dist/components/FileViewer/image-renderer.js +165 -0
- package/dist/components/FileViewer/image-renderer.js.map +1 -0
- package/dist/components/HoverCard/hover-card.d.ts +30 -0
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -0
- package/dist/components/HoverCard/hover-card.js +61 -0
- package/dist/components/HoverCard/hover-card.js.map +1 -0
- package/dist/components/Input/input.d.ts +72 -0
- package/dist/components/Input/input.d.ts.map +1 -0
- package/dist/components/Input/input.js +148 -0
- package/dist/components/Input/input.js.map +1 -0
- package/dist/components/LinkInput/link-input.d.ts +46 -0
- package/dist/components/LinkInput/link-input.d.ts.map +1 -0
- package/dist/components/LinkInput/link-input.js +215 -0
- package/dist/components/LinkInput/link-input.js.map +1 -0
- package/dist/components/Menu/menu-item.d.ts +83 -0
- package/dist/components/Menu/menu-item.d.ts.map +1 -0
- package/dist/components/Menu/menu-item.js +209 -0
- package/dist/components/Menu/menu-item.js.map +1 -0
- package/dist/components/NameCard/name-card.d.ts +85 -0
- package/dist/components/NameCard/name-card.d.ts.map +1 -0
- package/dist/components/NameCard/name-card.js +153 -0
- package/dist/components/NameCard/name-card.js.map +1 -0
- package/dist/components/Notice/notice.d.ts +69 -0
- package/dist/components/Notice/notice.d.ts.map +1 -0
- package/dist/components/Notice/notice.js +121 -0
- package/dist/components/Notice/notice.js.map +1 -0
- package/dist/components/NumberInput/number-input.d.ts +57 -0
- package/dist/components/NumberInput/number-input.d.ts.map +1 -0
- package/dist/components/NumberInput/number-input.js +131 -0
- package/dist/components/NumberInput/number-input.js.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +23 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.js +111 -0
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +57 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.js +35 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts +7 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.js +25 -0
- package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker.d.ts +77 -0
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -0
- package/dist/components/PeoplePicker/people-picker.js +263 -0
- package/dist/components/PeoplePicker/people-picker.js.map +1 -0
- package/dist/components/PeoplePicker/person-display.d.ts +66 -0
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -0
- package/dist/components/PeoplePicker/person-display.js +203 -0
- package/dist/components/PeoplePicker/person-display.js.map +1 -0
- package/dist/components/Popover/popover.d.ts +50 -0
- package/dist/components/Popover/popover.d.ts.map +1 -0
- package/dist/components/Popover/popover.js +113 -0
- package/dist/components/Popover/popover.js.map +1 -0
- package/dist/components/ProgressBar/progress-bar.d.ts +37 -0
- package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -0
- package/dist/components/ProgressBar/progress-bar.js +86 -0
- package/dist/components/ProgressBar/progress-bar.js.map +1 -0
- package/dist/components/RadioGroup/radio-group.d.ts +78 -0
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -0
- package/dist/components/RadioGroup/radio-group.js +153 -0
- package/dist/components/RadioGroup/radio-group.js.map +1 -0
- package/dist/components/Rating/rating.d.ts +46 -0
- package/dist/components/Rating/rating.d.ts.map +1 -0
- package/dist/components/Rating/rating.js +179 -0
- package/dist/components/Rating/rating.js.map +1 -0
- package/dist/components/ScrollArea/scroll-area.d.ts +45 -0
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -0
- package/dist/components/ScrollArea/scroll-area.js +65 -0
- package/dist/components/ScrollArea/scroll-area.js.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts +102 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.js +171 -0
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -0
- package/dist/components/Select/select.d.ts +102 -0
- package/dist/components/Select/select.d.ts.map +1 -0
- package/dist/components/Select/select.js +435 -0
- package/dist/components/Select/select.js.map +1 -0
- package/dist/components/SelectMenu/select-menu.d.ts +103 -0
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -0
- package/dist/components/SelectMenu/select-menu.js +239 -0
- package/dist/components/SelectMenu/select-menu.js.map +1 -0
- package/dist/components/SelectionControl/selection-item.d.ts +69 -0
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -0
- package/dist/components/SelectionControl/selection-item.js +142 -0
- package/dist/components/SelectionControl/selection-item.js.map +1 -0
- package/dist/components/Separator/separator.d.ts +17 -0
- package/dist/components/Separator/separator.d.ts.map +1 -0
- package/dist/components/Separator/separator.js +39 -0
- package/dist/components/Separator/separator.js.map +1 -0
- package/dist/components/Sheet/sheet.d.ts +56 -0
- package/dist/components/Sheet/sheet.d.ts.map +1 -0
- package/dist/components/Sheet/sheet.js +145 -0
- package/dist/components/Sheet/sheet.js.map +1 -0
- package/dist/components/Sidebar/sidebar.d.ts +195 -0
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -0
- package/dist/components/Sidebar/sidebar.js +826 -0
- package/dist/components/Sidebar/sidebar.js.map +1 -0
- package/dist/components/Skeleton/skeleton.d.ts +16 -0
- package/dist/components/Skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/Skeleton/skeleton.js +30 -0
- package/dist/components/Skeleton/skeleton.js.map +1 -0
- package/dist/components/Slider/slider.d.ts +48 -0
- package/dist/components/Slider/slider.d.ts.map +1 -0
- package/dist/components/Slider/slider.js +108 -0
- package/dist/components/Slider/slider.js.map +1 -0
- package/dist/components/Steps/steps.d.ts +71 -0
- package/dist/components/Steps/steps.d.ts.map +1 -0
- package/dist/components/Steps/steps.js +583 -0
- package/dist/components/Steps/steps.js.map +1 -0
- package/dist/components/Switch/switch.d.ts +112 -0
- package/dist/components/Switch/switch.d.ts.map +1 -0
- package/dist/components/Switch/switch.js +179 -0
- package/dist/components/Switch/switch.js.map +1 -0
- package/dist/components/Tabs/tabs.d.ts +104 -0
- package/dist/components/Tabs/tabs.d.ts.map +1 -0
- package/dist/components/Tabs/tabs.js +316 -0
- package/dist/components/Tabs/tabs.js.map +1 -0
- package/dist/components/Tag/tag.d.ts +86 -0
- package/dist/components/Tag/tag.d.ts.map +1 -0
- package/dist/components/Tag/tag.js +172 -0
- package/dist/components/Tag/tag.js.map +1 -0
- package/dist/components/Textarea/textarea.d.ts +74 -0
- package/dist/components/Textarea/textarea.d.ts.map +1 -0
- package/dist/components/Textarea/textarea.js +224 -0
- package/dist/components/Textarea/textarea.js.map +1 -0
- package/dist/components/TimePicker/time-columns.d.ts +46 -0
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -0
- package/dist/components/TimePicker/time-columns.js +173 -0
- package/dist/components/TimePicker/time-columns.js.map +1 -0
- package/dist/components/TimePicker/time-picker.d.ts +94 -0
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -0
- package/dist/components/TimePicker/time-picker.js +253 -0
- package/dist/components/TimePicker/time-picker.js.map +1 -0
- package/dist/components/Toast/toast.d.ts +61 -0
- package/dist/components/Toast/toast.d.ts.map +1 -0
- package/dist/components/Toast/toast.js +76 -0
- package/dist/components/Toast/toast.js.map +1 -0
- package/dist/components/Tooltip/tooltip.d.ts +20 -0
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip/tooltip.js +53 -0
- package/dist/components/Tooltip/tooltip.js.map +1 -0
- package/dist/components/TreeView/tree-view.d.ts +166 -0
- package/dist/components/TreeView/tree-view.d.ts.map +1 -0
- package/dist/components/TreeView/tree-view.js +617 -0
- package/dist/components/TreeView/tree-view.js.map +1 -0
- package/dist/hooks/use-controllable.d.ts +16 -0
- package/dist/hooks/use-controllable.d.ts.map +1 -0
- package/dist/hooks/use-controllable.js +26 -0
- package/dist/hooks/use-controllable.js.map +1 -0
- package/dist/hooks/use-is-narrow-viewport.d.ts +2 -0
- package/dist/hooks/use-is-narrow-viewport.d.ts.map +1 -0
- package/dist/hooks/use-is-narrow-viewport.js +19 -0
- package/dist/hooks/use-is-narrow-viewport.js.map +1 -0
- package/dist/hooks/use-is-touch-device.d.ts +8 -0
- package/dist/hooks/use-is-touch-device.d.ts.map +1 -0
- package/dist/hooks/use-is-touch-device.js +16 -0
- package/dist/hooks/use-is-touch-device.js.map +1 -0
- package/dist/hooks/use-overflow-items.d.ts +124 -0
- package/dist/hooks/use-overflow-items.d.ts.map +1 -0
- package/dist/hooks/use-overflow-items.js +97 -0
- package/dist/hooks/use-overflow-items.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/drag-visual.d.ts +158 -0
- package/dist/lib/drag-visual.d.ts.map +1 -0
- package/dist/lib/drag-visual.js +96 -0
- package/dist/lib/drag-visual.js.map +1 -0
- package/dist/lib/i18n/i18n-context.d.ts +105 -0
- package/dist/lib/i18n/i18n-context.d.ts.map +1 -0
- package/dist/lib/multi-select-ordering.d.ts +54 -0
- package/dist/lib/multi-select-ordering.d.ts.map +1 -0
- package/dist/lib/multi-select-ordering.js +13 -0
- package/dist/lib/multi-select-ordering.js.map +1 -0
- package/dist/lib/utils.d.ts +12 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +79 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +370 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.js +272 -0
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts +80 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.js +75 -0
- package/dist/patterns/header-canonical/chrome-header.js.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +101 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js +105 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts +28 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.js +85 -0
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts +102 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.js +74 -0
- package/dist/patterns/resize-handle/resize-handle.js.map +1 -0
- package/dist/react-day-picker.css +457 -0
- package/dist/stories-helpers/anatomy/anatomy-utils.d.ts +40 -0
- package/dist/stories-helpers/anatomy/anatomy-utils.d.ts.map +1 -0
- package/dist/tokens/elevation/overlay-geometry.d.ts +12 -0
- package/dist/tokens/elevation/overlay-geometry.d.ts.map +1 -0
- package/dist/tokens/elevation/overlay-geometry.js +7 -0
- package/dist/tokens/elevation/overlay-geometry.js.map +1 -0
- package/dist/tokens/motion/motion.d.ts +15 -0
- package/dist/tokens/motion/motion.d.ts.map +1 -0
- package/dist/tokens/motion/motion.js +9 -0
- package/dist/tokens/motion/motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.d.ts +53 -0
- package/dist/tokens/uiSize/icon-size.d.ts.map +1 -0
- package/package.json +92 -0
- package/src/README.md +32 -0
- package/src/components/Accordion/accordion.tsx +104 -0
- package/src/components/Alert/alert.tsx +188 -0
- package/src/components/AppShell/_demo-helpers.tsx +198 -0
- package/src/components/AppShell/app-shell.tsx +364 -0
- package/src/components/AspectRatio/aspect-ratio.tsx +58 -0
- package/src/components/Avatar/avatar.tsx +368 -0
- package/src/components/Badge/badge.tsx +104 -0
- package/src/components/Breadcrumb/breadcrumb.tsx +619 -0
- package/src/components/BulkActionBar/bulk-action-bar.tsx +156 -0
- package/src/components/Button/button-group.tsx +96 -0
- package/src/components/Button/button.tsx +539 -0
- package/src/components/Calendar/calendar.tsx +411 -0
- package/src/components/Carousel/carousel.tsx +371 -0
- package/src/components/Chart/chart.tsx +376 -0
- package/src/components/Checkbox/checkbox-group.tsx +94 -0
- package/src/components/Checkbox/checkbox.tsx +237 -0
- package/src/components/Chip/chip.tsx +359 -0
- package/src/components/CircularProgress/circular-progress.tsx +204 -0
- package/src/components/Coachmark/coachmark.tsx +255 -0
- package/src/components/Combobox/combobox.tsx +826 -0
- package/src/components/Command/command.tsx +187 -0
- package/src/components/DataTable/active-editor-controller.ts +72 -0
- package/src/components/DataTable/cell-registry.tsx +520 -0
- package/src/components/DataTable/column-types.ts +180 -0
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +261 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +813 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +483 -0
- package/src/components/DataTable/data-table-sort-manager.tsx +210 -0
- package/src/components/DataTable/data-table.css +165 -0
- package/src/components/DataTable/data-table.tsx +2924 -0
- package/src/components/DataTable/filter-operators.ts +225 -0
- package/src/components/DataTable/filter-tree.ts +313 -0
- package/src/components/DataTable/lib/column-meta.ts +79 -0
- package/src/components/DateGrid/date-grid.tsx +209 -0
- package/src/components/DatePicker/date-picker.tsx +1114 -0
- package/src/components/DescriptionList/description-list.tsx +141 -0
- package/src/components/Dialog/dialog.tsx +267 -0
- package/src/components/DropdownMenu/dropdown-menu.tsx +475 -0
- package/src/components/Empty/empty.tsx +108 -0
- package/src/components/Field/field-context.ts +136 -0
- package/src/components/Field/field-types.ts +52 -0
- package/src/components/Field/field-wrapper.tsx +348 -0
- package/src/components/Field/field.tsx +535 -0
- package/src/components/FieldControlGroup/field-control-group.tsx +136 -0
- package/src/components/FileItem/file-item.tsx +322 -0
- package/src/components/FileUpload/file-upload.tsx +326 -0
- package/src/components/FileViewer/file-viewer-types.ts +76 -0
- package/src/components/FileViewer/file-viewer.tsx +1065 -0
- package/src/components/FileViewer/image-renderer.tsx +256 -0
- package/src/components/HoverCard/hover-card.tsx +79 -0
- package/src/components/Input/input.tsx +233 -0
- package/src/components/LinkInput/link-input.tsx +304 -0
- package/src/components/Menu/menu-item.tsx +334 -0
- package/src/components/NameCard/name-card.tsx +319 -0
- package/src/components/Notice/notice.tsx +196 -0
- package/src/components/NumberInput/number-input.tsx +203 -0
- package/src/components/OverflowIndicator/overflow-indicator.tsx +156 -0
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +100 -0
- package/src/components/PeoplePicker/people-picker-helpers.ts +76 -0
- package/src/components/PeoplePicker/people-picker.tsx +455 -0
- package/src/components/PeoplePicker/person-display.tsx +358 -0
- package/src/components/Popover/popover.tsx +183 -0
- package/src/components/ProgressBar/progress-bar.tsx +157 -0
- package/src/components/README.md +58 -0
- package/src/components/RadioGroup/radio-group.tsx +261 -0
- package/src/components/Rating/rating.tsx +295 -0
- package/src/components/ScrollArea/scroll-area.tsx +110 -0
- package/src/components/SegmentedControl/segmented-control.tsx +304 -0
- package/src/components/Select/select.tsx +658 -0
- package/src/components/SelectMenu/select-menu.tsx +430 -0
- package/src/components/SelectionControl/selection-item.tsx +261 -0
- package/src/components/Separator/separator.tsx +48 -0
- package/src/components/Sheet/sheet.tsx +240 -0
- package/src/components/Sidebar/sidebar.tsx +1280 -0
- package/src/components/Skeleton/skeleton.tsx +35 -0
- package/src/components/Slider/slider.tsx +158 -0
- package/src/components/Steps/steps.tsx +850 -0
- package/src/components/Switch/switch.tsx +285 -0
- package/src/components/Tabs/tabs.tsx +515 -0
- package/src/components/Tag/tag.tsx +246 -0
- package/src/components/Textarea/textarea.tsx +280 -0
- package/src/components/TimePicker/time-columns.tsx +260 -0
- package/src/components/TimePicker/time-picker.tsx +419 -0
- package/src/components/Toast/toast.tsx +129 -0
- package/src/components/Tooltip/tooltip.tsx +68 -0
- package/src/components/TreeView/tree-view.tsx +1031 -0
- package/src/hooks/use-controllable.ts +40 -0
- package/src/hooks/use-is-narrow-viewport.ts +19 -0
- package/src/hooks/use-is-touch-device.ts +21 -0
- package/src/hooks/use-overflow-items.ts +256 -0
- package/src/index.ts +85 -0
- package/src/lib/README.md +82 -0
- package/src/lib/drag-visual.ts +272 -0
- package/src/lib/i18n/README.md +60 -0
- package/src/lib/i18n/i18n-context.tsx +129 -0
- package/src/lib/multi-select-ordering.ts +61 -0
- package/src/lib/utils.ts +93 -0
- package/src/patterns/README.md +67 -0
- package/src/patterns/element-anatomy/item-anatomy.tsx +744 -0
- package/src/patterns/header-canonical/chrome-header.tsx +175 -0
- package/src/patterns/header-canonical/header-canonical.css +27 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +217 -0
- package/src/patterns/overlay-surface/overlay-surface.tsx +191 -0
- package/src/patterns/resize-handle/resize-handle.tsx +188 -0
- package/src/stories-helpers/anatomy/anatomy-utils.tsx +64 -0
- package/src/styles/preset.css +31 -0
- package/src/styles/tokens.css +35 -0
- package/src/tokens/README.md +53 -0
- package/src/tokens/color/primitives.css +429 -0
- package/src/tokens/color/semantic.css +539 -0
- package/src/tokens/elevation/overlay-geometry.ts +13 -0
- package/src/tokens/layoutSpace/layoutSpace.css +36 -0
- package/src/tokens/motion/motion.css +30 -0
- package/src/tokens/motion/motion.ts +17 -0
- package/src/tokens/opacity/opacity.css +23 -0
- package/src/tokens/radius/radius.css +19 -0
- package/src/tokens/typography/typography.css +118 -0
- package/src/tokens/uiSize/icon-size.ts +52 -0
- package/src/tokens/uiSize/uiSize.css +125 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
|
+
/**
|
|
3
|
+
* TimeColumns — H/M/S scroll selector primitive(M17 Rule-of-3 SSOT)。
|
|
4
|
+
*
|
|
5
|
+
* 共用消費者:
|
|
6
|
+
* - `TimePicker`(本元件家)
|
|
7
|
+
* - `DatePicker showTime`(date + time)
|
|
8
|
+
* - `DatePickerRange showTime`(range with time)
|
|
9
|
+
*
|
|
10
|
+
* 抽出原因:三個 picker 共用 H/M/S column scroll-pick 行為,公式重覆 = M17 違反。
|
|
11
|
+
* 抽到 TimePicker/(time scroll selector 的 canonical 家)。
|
|
12
|
+
*
|
|
13
|
+
* ── 設計 ──
|
|
14
|
+
* - Value:`TimeParts { hours, minutes, seconds }`(對齊 date-fns / Date getHours()...)
|
|
15
|
+
* - Step:每欄獨立 `minuteStep` / `secondStep`(會議常用 15)
|
|
16
|
+
* - Disabled:`disabledHours / disabledMinutes / disabledSeconds`(動態根據已選其他欄位)
|
|
17
|
+
* - Visual:對齊 ref/timepicker.png — 多欄並排 + border-r 分隔
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import * as React from 'react'
|
|
21
|
+
import { ScrollArea } from '@/design-system/components/ScrollArea/scroll-area'
|
|
22
|
+
import { cn } from '@/lib/utils'
|
|
23
|
+
|
|
24
|
+
// ── Types ───────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export interface TimeParts {
|
|
27
|
+
hours: number
|
|
28
|
+
minutes: number
|
|
29
|
+
seconds: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type TimeStep = 1 | 5 | 10 | 15 | 30
|
|
33
|
+
|
|
34
|
+
export interface TimeColumnsDisabled {
|
|
35
|
+
hours?: number[]
|
|
36
|
+
minutes?: number[]
|
|
37
|
+
seconds?: number[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ── ISO time parsing ────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
/** Parse "HH:MM:SS" / "HH:MM" / full ISO datetime — returns time parts only */
|
|
43
|
+
export function isoToTimeParts(iso: string | null | undefined): TimeParts | undefined {
|
|
44
|
+
if (!iso) return undefined
|
|
45
|
+
const timeMatch = iso.match(/(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?/)
|
|
46
|
+
if (!timeMatch) return undefined
|
|
47
|
+
const h = Number(timeMatch[1])
|
|
48
|
+
const m = Number(timeMatch[2])
|
|
49
|
+
const s = timeMatch[3] !== undefined ? Number(timeMatch[3]) : 0
|
|
50
|
+
if (
|
|
51
|
+
Number.isNaN(h) || h < 0 || h > 23 ||
|
|
52
|
+
Number.isNaN(m) || m < 0 || m > 59 ||
|
|
53
|
+
Number.isNaN(s) || s < 0 || s > 59
|
|
54
|
+
) return undefined
|
|
55
|
+
return { hours: h, minutes: m, seconds: s }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Format time parts → "HH:MM" or "HH:MM:SS" depending on showSeconds */
|
|
59
|
+
export function timePartsToString(parts: TimeParts, showSeconds = false): string {
|
|
60
|
+
const hh = String(parts.hours).padStart(2, '0')
|
|
61
|
+
const mm = String(parts.minutes).padStart(2, '0')
|
|
62
|
+
if (!showSeconds) return `${hh}:${mm}`
|
|
63
|
+
const ss = String(parts.seconds).padStart(2, '0')
|
|
64
|
+
return `${hh}:${mm}:${ss}`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Range builder ───────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
function buildRange(max: number, step: number): number[] {
|
|
70
|
+
const arr: number[] = []
|
|
71
|
+
for (let v = 0; v < max; v += step) arr.push(v)
|
|
72
|
+
return arr
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Single column ───────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
interface TimeColumnProps {
|
|
78
|
+
values: number[]
|
|
79
|
+
selected: number
|
|
80
|
+
/** disabled value set(動態根據其他欄位推) */
|
|
81
|
+
disabledSet?: Set<number>
|
|
82
|
+
label: string
|
|
83
|
+
onSelect: (value: number) => void
|
|
84
|
+
/** 右側分隔線(對齊 ref 多欄樣式) */
|
|
85
|
+
withDivider?: boolean
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// code-quality-allow: long-function — column 含 scroll-into-view useEffect / WAI-ARIA listbox 鍵盤 handler / 視覺 state 計算,拆 sub-fn 會切散 listbox accessibility 邏輯
|
|
89
|
+
function TimeColumn({ values, selected, disabledSet, label, onSelect, withDivider }: TimeColumnProps) {
|
|
90
|
+
const listRef = React.useRef<HTMLDivElement>(null)
|
|
91
|
+
|
|
92
|
+
// 開啟時跳到 selected 位置(置中);後續變更走 smooth(對齊 iOS / Material / Ant timepicker idiom)。
|
|
93
|
+
// 用 scrollIntoView({ block: 'center' }) 自動找最近的 scrollable ancestor —
|
|
94
|
+
// 比 manual scrollTop + parentElement 強健(Radix ScrollArea 結構為 Viewport > inner-div > content,
|
|
95
|
+
// listRef.parentElement 不是真正 scrollable 元素)。
|
|
96
|
+
// mount 用 'auto' 避免開啟瞬間出現飄移,後續 user 操作走 'smooth'(同 Tabs/Chip/FileViewer canonical)。
|
|
97
|
+
const isFirstRunRef = React.useRef(true)
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
const list = listRef.current
|
|
100
|
+
if (!list) return
|
|
101
|
+
const idx = values.indexOf(selected)
|
|
102
|
+
if (idx < 0) return
|
|
103
|
+
const item = list.children[idx] as HTMLElement | undefined
|
|
104
|
+
if (!item) return
|
|
105
|
+
item.scrollIntoView({ block: 'center', behavior: isFirstRunRef.current ? 'auto' : 'smooth' })
|
|
106
|
+
isFirstRunRef.current = false
|
|
107
|
+
}, [values, selected])
|
|
108
|
+
|
|
109
|
+
// WAI-ARIA listbox keyboard pattern:ArrowUp/Down 切 option / Home / End 跳邊界。
|
|
110
|
+
// 對標 Ant TimePicker / Material TimePicker。Tab 跳離 listbox(走預設行為,不 stopPropagation)。
|
|
111
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
112
|
+
const idx = values.indexOf(selected)
|
|
113
|
+
if (e.key === 'ArrowDown') {
|
|
114
|
+
e.preventDefault()
|
|
115
|
+
const next = values.find((_, i) => i > idx && !disabledSet?.has(values[i])) ?? values[idx]
|
|
116
|
+
onSelect(next)
|
|
117
|
+
} else if (e.key === 'ArrowUp') {
|
|
118
|
+
e.preventDefault()
|
|
119
|
+
// 反向找第一個 enabled
|
|
120
|
+
let i = idx - 1
|
|
121
|
+
while (i >= 0 && disabledSet?.has(values[i])) i--
|
|
122
|
+
if (i >= 0) onSelect(values[i])
|
|
123
|
+
} else if (e.key === 'Home') {
|
|
124
|
+
e.preventDefault()
|
|
125
|
+
const first = values.find((v) => !disabledSet?.has(v))
|
|
126
|
+
if (first !== undefined) onSelect(first)
|
|
127
|
+
} else if (e.key === 'End') {
|
|
128
|
+
e.preventDefault()
|
|
129
|
+
for (let i = values.length - 1; i >= 0; i--) {
|
|
130
|
+
if (!disabledSet?.has(values[i])) {
|
|
131
|
+
onSelect(values[i])
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// WAI-ARIA listbox pattern:role=listbox 直接包 role=option(button),不另用 li 包
|
|
139
|
+
// (li role=option + 內含 button 會被 axe 抓 nested-interactive)
|
|
140
|
+
// 高度策略:本 primitive 不鎖死 height(對齊 ScrollArea / Combobox 同 idiom)。
|
|
141
|
+
// ScrollArea 用 h-full,parent flex container 控高 — 讓 consumer:
|
|
142
|
+
// - TimePicker:wrap in h-[216px] container(預設 ~7 items)
|
|
143
|
+
// - DatePicker showTime / Range:flex-row items-stretch + calendar 一起決定高度(自動同高)
|
|
144
|
+
return (
|
|
145
|
+
<ScrollArea className={cn('flex-1 h-full', withDivider && 'border-r border-divider')}>
|
|
146
|
+
<div
|
|
147
|
+
ref={listRef}
|
|
148
|
+
role="listbox"
|
|
149
|
+
aria-label={label}
|
|
150
|
+
tabIndex={0}
|
|
151
|
+
onKeyDown={handleKeyDown}
|
|
152
|
+
className="flex flex-col py-2 focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-[-2px]"
|
|
153
|
+
>
|
|
154
|
+
{values.map((v) => {
|
|
155
|
+
const isSelected = v === selected
|
|
156
|
+
const isDisabled = disabledSet?.has(v) ?? false
|
|
157
|
+
return (
|
|
158
|
+
<button
|
|
159
|
+
key={v}
|
|
160
|
+
type="button"
|
|
161
|
+
role="option"
|
|
162
|
+
aria-selected={isSelected}
|
|
163
|
+
disabled={isDisabled}
|
|
164
|
+
// tabIndex=-1:listbox 自身 tabbable + 用 ArrowUp/Down 切 option(WAI-ARIA roving),
|
|
165
|
+
// 不讓每個 option 都進 Tab order(會 Tab 84 次過完 hours+minutes)
|
|
166
|
+
tabIndex={-1}
|
|
167
|
+
onClick={() => onSelect(v)}
|
|
168
|
+
className={cn(
|
|
169
|
+
'w-full h-field-sm text-body tabular-nums',
|
|
170
|
+
'flex items-center justify-center',
|
|
171
|
+
'cursor-pointer transition-colors',
|
|
172
|
+
'hover:bg-neutral-hover',
|
|
173
|
+
isSelected && 'bg-neutral-selected text-foreground hover:bg-neutral-selected',
|
|
174
|
+
isDisabled && 'text-fg-disabled cursor-not-allowed hover:bg-transparent',
|
|
175
|
+
)}
|
|
176
|
+
>
|
|
177
|
+
{String(v).padStart(2, '0')}
|
|
178
|
+
</button>
|
|
179
|
+
)
|
|
180
|
+
})}
|
|
181
|
+
</div>
|
|
182
|
+
</ScrollArea>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ── Composite — H/M/S columns ──────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
export interface TimeColumnsProps {
|
|
189
|
+
value?: TimeParts
|
|
190
|
+
onChange: (next: TimeParts) => void
|
|
191
|
+
showSeconds?: boolean
|
|
192
|
+
minuteStep?: TimeStep
|
|
193
|
+
secondStep?: TimeStep
|
|
194
|
+
/** 動態 disabled 各欄位 value 子集 */
|
|
195
|
+
disabled?: TimeColumnsDisabled
|
|
196
|
+
className?: string
|
|
197
|
+
/** 是否在最左側加 border-l(配 DatePicker showTime / Range date+time 拼接時用) */
|
|
198
|
+
leadingDivider?: boolean
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function TimeColumns({
|
|
202
|
+
value,
|
|
203
|
+
onChange,
|
|
204
|
+
showSeconds = false,
|
|
205
|
+
minuteStep = 1,
|
|
206
|
+
secondStep = 1,
|
|
207
|
+
disabled,
|
|
208
|
+
className,
|
|
209
|
+
leadingDivider = false,
|
|
210
|
+
}: TimeColumnsProps) {
|
|
211
|
+
const safeValue: TimeParts = value ?? { hours: 0, minutes: 0, seconds: 0 }
|
|
212
|
+
const hourValues = React.useMemo(() => buildRange(24, 1), [])
|
|
213
|
+
const minuteValues = React.useMemo(() => buildRange(60, minuteStep), [minuteStep])
|
|
214
|
+
const secondValues = React.useMemo(() => buildRange(60, secondStep), [secondStep])
|
|
215
|
+
|
|
216
|
+
const disabledSets = React.useMemo(() => ({
|
|
217
|
+
hours: disabled?.hours ? new Set(disabled.hours) : undefined,
|
|
218
|
+
minutes: disabled?.minutes ? new Set(disabled.minutes) : undefined,
|
|
219
|
+
seconds: disabled?.seconds ? new Set(disabled.seconds) : undefined,
|
|
220
|
+
}), [disabled?.hours, disabled?.minutes, disabled?.seconds])
|
|
221
|
+
|
|
222
|
+
const widthClass = showSeconds ? 'w-60' : 'w-40'
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<div
|
|
226
|
+
className={cn(
|
|
227
|
+
'flex flex-row',
|
|
228
|
+
widthClass,
|
|
229
|
+
leadingDivider && 'border-l border-divider',
|
|
230
|
+
className,
|
|
231
|
+
)}
|
|
232
|
+
>
|
|
233
|
+
<TimeColumn
|
|
234
|
+
values={hourValues}
|
|
235
|
+
selected={safeValue.hours}
|
|
236
|
+
disabledSet={disabledSets.hours}
|
|
237
|
+
label="hours"
|
|
238
|
+
onSelect={(h) => onChange({ ...safeValue, hours: h })}
|
|
239
|
+
withDivider
|
|
240
|
+
/>
|
|
241
|
+
<TimeColumn
|
|
242
|
+
values={minuteValues}
|
|
243
|
+
selected={safeValue.minutes}
|
|
244
|
+
disabledSet={disabledSets.minutes}
|
|
245
|
+
label="minutes"
|
|
246
|
+
onSelect={(m) => onChange({ ...safeValue, minutes: m })}
|
|
247
|
+
withDivider={showSeconds}
|
|
248
|
+
/>
|
|
249
|
+
{showSeconds && (
|
|
250
|
+
<TimeColumn
|
|
251
|
+
values={secondValues}
|
|
252
|
+
selected={safeValue.seconds}
|
|
253
|
+
disabledSet={disabledSets.seconds}
|
|
254
|
+
label="seconds"
|
|
255
|
+
onSelect={(s) => onChange({ ...safeValue, seconds: s })}
|
|
256
|
+
/>
|
|
257
|
+
)}
|
|
258
|
+
</div>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { X, Clock } from 'lucide-react'
|
|
4
|
+
import type { LucideIcon } from 'lucide-react'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
import type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'
|
|
7
|
+
import {
|
|
8
|
+
fieldWrapperStyles,
|
|
9
|
+
bareInputStyles,
|
|
10
|
+
EMPTY_DISPLAY,
|
|
11
|
+
fieldDisplayTextClass,
|
|
12
|
+
} from '@/design-system/components/Field/field-wrapper'
|
|
13
|
+
import { ItemInlineAction, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
14
|
+
import { Popover, PopoverTrigger, PopoverContent } from '@/design-system/components/Popover/popover'
|
|
15
|
+
import { useFieldContext } from '@/design-system/components/Field/field-context'
|
|
16
|
+
import { Button } from '@/design-system/components/Button/button'
|
|
17
|
+
import {
|
|
18
|
+
TimeColumns,
|
|
19
|
+
isoToTimeParts,
|
|
20
|
+
timePartsToString,
|
|
21
|
+
type TimeParts,
|
|
22
|
+
type TimeStep,
|
|
23
|
+
type TimeColumnsDisabled,
|
|
24
|
+
} from '@/design-system/components/TimePicker/time-columns'
|
|
25
|
+
import { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* TimePicker — 單一時間(時/分/秒)輸入與顯示元件
|
|
29
|
+
*
|
|
30
|
+
* ── 定位(同 DatePicker 家族)──
|
|
31
|
+
* Value 以 ISO time string 儲存("HH:mm" 或 "HH:mm:ss"),local-time 語義(不帶時區)。
|
|
32
|
+
* Edit 用本 DS 自建 time column panel + Popover 呈現,視覺與 DatePicker 一致。
|
|
33
|
+
* Display 用 Intl.DateTimeFormat 格式化(跨 locale / 12h-24h 統一經過此 API)。
|
|
34
|
+
*
|
|
35
|
+
* ── Layout Family ──
|
|
36
|
+
* CLAUDE.md 4-Family Model Family 4(Field control layout)消費者。結構繼承
|
|
37
|
+
* `fieldWrapperStyles + [<editable>] [endIcon=Clock]`,視覺對齊 DatePicker(同
|
|
38
|
+
* 「點擊觸發浮層」role:indicator 在 suffix slot,對齊 Material `endAdornment` /
|
|
39
|
+
* Ant DatePicker / Polaris Picker 共識)。
|
|
40
|
+
*
|
|
41
|
+
* ── 實作基礎 ──
|
|
42
|
+
* Trigger:`<button>` + `fieldWrapperStyles`(視覺仍是 Input wrapper,改為可點擊觸發浮層)
|
|
43
|
+
* Popup:`Popover`(消費 overlay-surface pattern)
|
|
44
|
+
* Panel 主體:自建 column picker(三欄 scrollable list),不引入第三方 time library
|
|
45
|
+
*
|
|
46
|
+
* ── 共用規則 ──
|
|
47
|
+
* Mode / size / disabled / error 等詳見 `../Field/field-controls.spec.md`。
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
// ── Time ISO <-> parts conversion ───────────────────────────────────────────
|
|
51
|
+
// Value 用 ISO time string(HH:mm 或 HH:mm:ss),local-time 語義(不帶時區/日期)。
|
|
52
|
+
// 跟 DatePicker 的 ISO date string 策略一致。
|
|
53
|
+
// `isoToTimeParts` / `timePartsToString` 改 import from time-columns(M17 SSOT)。
|
|
54
|
+
|
|
55
|
+
// ── Display formatting ──────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
export interface TimeFormatOptions {
|
|
58
|
+
/** Intl.DateTimeFormat options(預設 { hour: '2-digit', minute: '2-digit', hour12: false }) */
|
|
59
|
+
formatOptions?: Intl.DateTimeFormatOptions
|
|
60
|
+
/** locale(預設 'en-US') */
|
|
61
|
+
locale?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function formatTime(
|
|
65
|
+
iso: string,
|
|
66
|
+
options: TimeFormatOptions = {},
|
|
67
|
+
): string {
|
|
68
|
+
const parts = isoToTimeParts(iso)
|
|
69
|
+
if (!parts) return iso
|
|
70
|
+
const {
|
|
71
|
+
formatOptions = { hour: '2-digit', minute: '2-digit', hour12: false },
|
|
72
|
+
locale = 'en-US',
|
|
73
|
+
} = options
|
|
74
|
+
// 借用 Date 讓 Intl.DateTimeFormat 處理 locale / 12h-24h
|
|
75
|
+
const d = new Date()
|
|
76
|
+
d.setHours(parts.hours, parts.minutes, parts.seconds, 0)
|
|
77
|
+
return new Intl.DateTimeFormat(locale, formatOptions).format(d)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Disabled time callback ──────────────────────────────────────────────────
|
|
81
|
+
// `Step` / `buildRange` / `TimeColumn`(內部欄位實作)拔掉,改 import `TimeColumns` primitive。
|
|
82
|
+
|
|
83
|
+
// code-quality-allow: dead-export — public API surface — consumer-exposed for future use
|
|
84
|
+
export interface DisabledTimeResult {
|
|
85
|
+
disabledHours?: number[]
|
|
86
|
+
disabledMinutes?: number[]
|
|
87
|
+
disabledSeconds?: number[]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── Component props ─────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
export interface TimePickerProps
|
|
93
|
+
extends TimeFormatOptions,
|
|
94
|
+
Omit<
|
|
95
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
96
|
+
'onChange' | 'placeholder'
|
|
97
|
+
> {
|
|
98
|
+
mode?: FieldMode
|
|
99
|
+
/** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */
|
|
100
|
+
variant?: FieldVariant
|
|
101
|
+
error?: boolean
|
|
102
|
+
size?: 'sm' | 'md' | 'lg'
|
|
103
|
+
/** ISO time string("HH:mm" 或 "HH:mm:ss") */
|
|
104
|
+
value?: string | null
|
|
105
|
+
onChange?: (value: string) => void
|
|
106
|
+
placeholder?: string
|
|
107
|
+
className?: string
|
|
108
|
+
disabled?: boolean
|
|
109
|
+
/** 允許清空已選值 */
|
|
110
|
+
clearable?: boolean
|
|
111
|
+
/**
|
|
112
|
+
* 是否顯示秒欄(三欄 picker)。預設 false(兩欄:時/分)。
|
|
113
|
+
* format 自動對應:false → "HH:mm",true → "HH:mm:ss"。
|
|
114
|
+
*/
|
|
115
|
+
showSeconds?: boolean
|
|
116
|
+
/** 分鐘步進(會議常用 15)。預設 1 */
|
|
117
|
+
minuteStep?: TimeStep
|
|
118
|
+
/** 秒步進。預設 1。僅 showSeconds=true 有效 */
|
|
119
|
+
secondStep?: TimeStep
|
|
120
|
+
/** 動態 disabled 某些時/分/秒(基於已選其他欄位)。 */
|
|
121
|
+
disabledTime?: (parts: TimeParts) => DisabledTimeResult
|
|
122
|
+
/**
|
|
123
|
+
* Suffix indicator(2026-05-05 v9 canonical fix):「點擊觸發浮層」indicator 一律 suffix
|
|
124
|
+
* (對齊 DatePicker calendar / Material endAdornment)。預設 Clock,傳 null 可關閉。
|
|
125
|
+
*/
|
|
126
|
+
endIcon?: LucideIcon | null
|
|
127
|
+
/**
|
|
128
|
+
* Display 是否渲 endIcon + Field naked wrapper(D-path opt-in,2026-05-08)
|
|
129
|
+
* — DataTable cell display↔edit 像素級對齊用。預設 false(裸 span,backward compat)。
|
|
130
|
+
* 設 true 時 display 也走 fieldWrapperStyles(naked variant)+ ItemSuffix Clock,
|
|
131
|
+
* 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。
|
|
132
|
+
*/
|
|
133
|
+
showDisplayEndIcon?: boolean
|
|
134
|
+
/** Initial open state(uncontrolled)— DataTable cell-as-input 1-step open canonical */
|
|
135
|
+
defaultOpen?: boolean
|
|
136
|
+
/** open state 變更 callback。DataTable cell-as-input 用:open=false → cell exit edit */
|
|
137
|
+
onOpenChange?: (open: boolean) => void
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding
|
|
141
|
+
const TimePicker = React.forwardRef<HTMLDivElement, TimePickerProps>(
|
|
142
|
+
(
|
|
143
|
+
{
|
|
144
|
+
mode = 'edit',
|
|
145
|
+
variant: variantProp,
|
|
146
|
+
error: errorProp = false,
|
|
147
|
+
size = 'md',
|
|
148
|
+
value,
|
|
149
|
+
onChange,
|
|
150
|
+
placeholder,
|
|
151
|
+
className,
|
|
152
|
+
disabled: disabledProp,
|
|
153
|
+
clearable = false,
|
|
154
|
+
showSeconds = false,
|
|
155
|
+
minuteStep = 1,
|
|
156
|
+
secondStep = 1,
|
|
157
|
+
disabledTime,
|
|
158
|
+
endIcon,
|
|
159
|
+
showDisplayEndIcon = false,
|
|
160
|
+
formatOptions,
|
|
161
|
+
locale,
|
|
162
|
+
defaultOpen = false,
|
|
163
|
+
onOpenChange,
|
|
164
|
+
id: idProp,
|
|
165
|
+
'aria-describedby': ariaDescribedByProp,
|
|
166
|
+
'aria-errormessage': ariaErrorMessageProp,
|
|
167
|
+
...props
|
|
168
|
+
},
|
|
169
|
+
ref,
|
|
170
|
+
) => {
|
|
171
|
+
const fieldCtx = useFieldContext()
|
|
172
|
+
const error = errorProp || (fieldCtx?.invalid ?? false)
|
|
173
|
+
const disabled = disabledProp ?? fieldCtx?.disabled
|
|
174
|
+
const resolvedMode = disabled ? 'disabled' : mode
|
|
175
|
+
const variant: FieldVariant = variantProp ?? fieldCtx?.variant ?? 'default'
|
|
176
|
+
const isEditable = resolvedMode === 'edit'
|
|
177
|
+
// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)
|
|
178
|
+
const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
|
|
179
|
+
const EndIconCmp: LucideIcon | null =
|
|
180
|
+
endIcon === null ? null : (endIcon ?? Clock)
|
|
181
|
+
const defaultPlaceholder = showSeconds ? 'HH:MM:SS' : 'HH:MM'
|
|
182
|
+
const resolvedPlaceholder = placeholder ?? defaultPlaceholder
|
|
183
|
+
const showClear = clearable && !!value && isEditable
|
|
184
|
+
const [open, setOpenState] = React.useState(defaultOpen)
|
|
185
|
+
const setOpen = React.useCallback((next: boolean) => { setOpenState(next); onOpenChange?.(next) }, [onOpenChange])
|
|
186
|
+
|
|
187
|
+
const currentParts = React.useMemo(() => isoToTimeParts(value), [value])
|
|
188
|
+
// draft 僅在 panel 開啟時用來處理 commit(OK button)的暫存
|
|
189
|
+
const [draft, setDraft] = React.useState<TimeParts>(
|
|
190
|
+
() => currentParts ?? { hours: 0, minutes: 0, seconds: 0 },
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// 每次 popover 開啟時以當前 value 初始化 draft
|
|
194
|
+
React.useEffect(() => {
|
|
195
|
+
if (open) {
|
|
196
|
+
setDraft(currentParts ?? { hours: 0, minutes: 0, seconds: 0 })
|
|
197
|
+
}
|
|
198
|
+
}, [open, currentParts])
|
|
199
|
+
|
|
200
|
+
const disabledForColumns: TimeColumnsDisabled | undefined = React.useMemo(() => {
|
|
201
|
+
if (!disabledTime) return undefined
|
|
202
|
+
const res = disabledTime(draft)
|
|
203
|
+
return {
|
|
204
|
+
hours: res.disabledHours,
|
|
205
|
+
minutes: res.disabledMinutes,
|
|
206
|
+
seconds: res.disabledSeconds,
|
|
207
|
+
}
|
|
208
|
+
}, [disabledTime, draft])
|
|
209
|
+
|
|
210
|
+
const commitDraft = (next: TimeParts) => {
|
|
211
|
+
setDraft(next)
|
|
212
|
+
onChange?.(timePartsToString(next, showSeconds))
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const handleNow = () => {
|
|
216
|
+
const now = new Date()
|
|
217
|
+
// 按照 minuteStep / secondStep 對齊
|
|
218
|
+
const m = Math.round(now.getMinutes() / minuteStep) * minuteStep
|
|
219
|
+
const s = showSeconds
|
|
220
|
+
? Math.round(now.getSeconds() / secondStep) * secondStep
|
|
221
|
+
: 0
|
|
222
|
+
const next: TimeParts = {
|
|
223
|
+
hours: now.getHours(),
|
|
224
|
+
minutes: Math.min(m, 59),
|
|
225
|
+
seconds: Math.min(s, 59),
|
|
226
|
+
}
|
|
227
|
+
commitDraft(next)
|
|
228
|
+
setOpen(false)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// mode='display'(Phase B2 2026-05-05):純內容輸出 — 對齊原 TimePickerDisplay sub-component(retired)。
|
|
232
|
+
// Default(showDisplayEndIcon=false):無 Field wrapper / 無 Clock icon — backward compat 裸 span。
|
|
233
|
+
// Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix Clock,
|
|
234
|
+
// 與 edit 同結構消除 cell display↔edit 像素偏移(Layer-B padding mismatch)。
|
|
235
|
+
if (resolvedMode === 'display') {
|
|
236
|
+
if (!showDisplayEndIcon) {
|
|
237
|
+
// 2026-05-14 I2 fix(spec contract (e) display typography canonical):bare span 套
|
|
238
|
+
// `fieldDisplayTextClass(size)`(sm/md→text-body,lg→text-body-lg)— 對齊 Field family 統一。
|
|
239
|
+
if (!value) return <span className={cn(fieldDisplayTextClass(size), 'text-fg-muted', className)}>{EMPTY_DISPLAY}</span>
|
|
240
|
+
return <span className={cn(fieldDisplayTextClass(size), 'truncate', className)}>{formatTime(value, { formatOptions, locale })}</span>
|
|
241
|
+
}
|
|
242
|
+
return (
|
|
243
|
+
<div
|
|
244
|
+
className={cn(fieldWrapperStyles({ mode: 'display', variant, size }), className)}
|
|
245
|
+
data-field-mode="display"
|
|
246
|
+
>
|
|
247
|
+
<span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && 'text-fg-muted')}>
|
|
248
|
+
{value ? formatTime(value, { formatOptions, locale }) : EMPTY_DISPLAY}
|
|
249
|
+
</span>
|
|
250
|
+
{EndIconCmp && (
|
|
251
|
+
<ItemSuffix className="pointer-events-none">
|
|
252
|
+
<EndIconCmp size={iconSize} className="text-fg-muted" aria-hidden />
|
|
253
|
+
</ItemSuffix>
|
|
254
|
+
)}
|
|
255
|
+
</div>
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// readonly / disabled
|
|
260
|
+
if (!isEditable) {
|
|
261
|
+
return (
|
|
262
|
+
<div
|
|
263
|
+
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}
|
|
264
|
+
data-field-mode={resolvedMode}
|
|
265
|
+
{...(props as React.HTMLAttributes<HTMLDivElement>)}
|
|
266
|
+
>
|
|
267
|
+
<span
|
|
268
|
+
className={cn(
|
|
269
|
+
'flex-1 min-w-0',
|
|
270
|
+
resolvedMode === 'disabled' && 'text-fg-disabled',
|
|
271
|
+
)}
|
|
272
|
+
>
|
|
273
|
+
{value
|
|
274
|
+
? formatTime(value, { formatOptions, locale })
|
|
275
|
+
: <span className="text-fg-muted">{EMPTY_DISPLAY}</span>
|
|
276
|
+
}
|
|
277
|
+
</span>
|
|
278
|
+
{EndIconCmp && (
|
|
279
|
+
<ItemSuffix className="pointer-events-none">
|
|
280
|
+
<EndIconCmp
|
|
281
|
+
size={iconSize}
|
|
282
|
+
className={resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted'}
|
|
283
|
+
aria-hidden
|
|
284
|
+
/>
|
|
285
|
+
</ItemSuffix>
|
|
286
|
+
)}
|
|
287
|
+
</div>
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const displayText = value
|
|
292
|
+
? formatTime(value, { formatOptions, locale })
|
|
293
|
+
: <span className="text-fg-muted">{resolvedPlaceholder}</span>
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
297
|
+
{/* a11y(2026-04-25 nested-interactive fix):trigger 改 <div role='combobox'>
|
|
298
|
+
(對齊 Select / Combobox 同 pattern),原 <button> 會與內層 ItemInlineAction
|
|
299
|
+
清除 button 構成 nested-interactive。Radix Popover 在 trigger asChild 下會
|
|
300
|
+
自動 inject keyboard handler(Enter / Space 開啟)+ 正確 aria attributes。 */}
|
|
301
|
+
<PopoverTrigger asChild>
|
|
302
|
+
<div
|
|
303
|
+
ref={ref}
|
|
304
|
+
id={idProp ?? fieldCtx?.id}
|
|
305
|
+
role="combobox"
|
|
306
|
+
tabIndex={disabled ? -1 : 0}
|
|
307
|
+
aria-disabled={disabled || undefined}
|
|
308
|
+
aria-labelledby={fieldCtx?.labelId}
|
|
309
|
+
aria-invalid={error || undefined}
|
|
310
|
+
aria-required={fieldCtx?.required || undefined}
|
|
311
|
+
aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}
|
|
312
|
+
aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}
|
|
313
|
+
aria-haspopup="dialog"
|
|
314
|
+
aria-expanded={open}
|
|
315
|
+
data-field-mode="edit"
|
|
316
|
+
data-error={error ? '' : undefined}
|
|
317
|
+
className={cn(
|
|
318
|
+
fieldWrapperStyles({ mode: 'edit', variant: variant, size }),
|
|
319
|
+
'text-left cursor-pointer',
|
|
320
|
+
'focus-visible:outline-none',
|
|
321
|
+
error && [
|
|
322
|
+
'border-error hover:border-error-hover',
|
|
323
|
+
'focus-within:border-error focus-within:hover:border-error',
|
|
324
|
+
],
|
|
325
|
+
className,
|
|
326
|
+
)}
|
|
327
|
+
{...props}
|
|
328
|
+
>
|
|
329
|
+
<span className={cn(bareInputStyles, 'truncate', !value && 'text-fg-muted')}>
|
|
330
|
+
{displayText}
|
|
331
|
+
</span>
|
|
332
|
+
{showClear && (
|
|
333
|
+
<ItemInlineAction
|
|
334
|
+
size={size ?? 'md'}
|
|
335
|
+
action={{
|
|
336
|
+
icon: X,
|
|
337
|
+
label: '清除時間', // i18n-allow: DS default inline-action label
|
|
338
|
+
onClick: (e) => {
|
|
339
|
+
e?.stopPropagation()
|
|
340
|
+
onChange?.('')
|
|
341
|
+
},
|
|
342
|
+
}}
|
|
343
|
+
/>
|
|
344
|
+
)}
|
|
345
|
+
{EndIconCmp && (
|
|
346
|
+
<ItemSuffix className="pointer-events-none">
|
|
347
|
+
<EndIconCmp size={iconSize} className="text-fg-muted" aria-hidden />
|
|
348
|
+
</ItemSuffix>
|
|
349
|
+
)}
|
|
350
|
+
</div>
|
|
351
|
+
</PopoverTrigger>
|
|
352
|
+
<PopoverContent className="w-auto p-0" align="start">
|
|
353
|
+
{/* Panel 對齊 ref/timepicker.png:2-3 個 SelectMenu 式欄位並排,分隔線分開。
|
|
354
|
+
Width 依欄數由 TimeColumns 決定:2 欄 w-40 / 3 欄 w-60。
|
|
355
|
+
Height 由 wrapper 控:216px 預設(~7 items)。
|
|
356
|
+
TimeColumns 本身 h-full,parent 控 height — 讓 DatePicker showTime / Range 可
|
|
357
|
+
用 flex-row items-stretch 自動同 calendar 高。 */}
|
|
358
|
+
<div className="flex flex-col h-[216px]">
|
|
359
|
+
<TimeColumns
|
|
360
|
+
value={draft}
|
|
361
|
+
onChange={commitDraft}
|
|
362
|
+
showSeconds={showSeconds}
|
|
363
|
+
minuteStep={minuteStep}
|
|
364
|
+
secondStep={secondStep}
|
|
365
|
+
disabled={disabledForColumns}
|
|
366
|
+
// 2026-05-06 v9.1 M25 chain fix:TimeColumns 自然高 = 24 buttons × ~28.7px = 688px
|
|
367
|
+
// 會撐破 parent h-[216px]。flex-1 + min-h-0 讓 TimeColumns 取 parent 剩餘空間
|
|
368
|
+
// (216 - footer 40 = 176px)→ ScrollArea h-full 才能正確收斂 →
|
|
369
|
+
// listbox scrollIntoView 找對 nearest scrollable ancestor(內部 viewport),
|
|
370
|
+
// 不會走到 document body 把 popover 內容推出畫面(user 報「hours 欄空白」根因)。
|
|
371
|
+
className="flex-1 min-h-0"
|
|
372
|
+
/>
|
|
373
|
+
{/* Footer:Now + OK */}
|
|
374
|
+
<div
|
|
375
|
+
className={cn(
|
|
376
|
+
'flex items-center justify-between gap-2',
|
|
377
|
+
'border-t border-divider',
|
|
378
|
+
'px-[var(--layout-space-tight)] py-[var(--layout-space-tight)]',
|
|
379
|
+
)}
|
|
380
|
+
>
|
|
381
|
+
<Button variant="text" size="sm" onClick={handleNow}>
|
|
382
|
+
此刻
|
|
383
|
+
</Button>
|
|
384
|
+
<Button
|
|
385
|
+
variant="primary"
|
|
386
|
+
size="sm"
|
|
387
|
+
onClick={() => setOpen(false)}
|
|
388
|
+
>
|
|
389
|
+
確定
|
|
390
|
+
</Button>
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
</PopoverContent>
|
|
394
|
+
</Popover>
|
|
395
|
+
)
|
|
396
|
+
},
|
|
397
|
+
)
|
|
398
|
+
TimePicker.displayName = 'TimePicker'
|
|
399
|
+
|
|
400
|
+
// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)
|
|
401
|
+
// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs
|
|
402
|
+
export const timePickerMeta = {
|
|
403
|
+
component: 'TimePicker',
|
|
404
|
+
family: 4,
|
|
405
|
+
variants: {
|
|
406
|
+
|
|
407
|
+
},
|
|
408
|
+
sizes: {
|
|
409
|
+
|
|
410
|
+
},
|
|
411
|
+
states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],
|
|
412
|
+
tokens: {
|
|
413
|
+
bg: ['bg-neutral-hover', 'bg-primary', 'bg-transparent'],
|
|
414
|
+
fg: ['text-fg-disabled', 'text-fg-muted', 'text-foreground'],
|
|
415
|
+
ring: [],
|
|
416
|
+
},
|
|
417
|
+
} as const
|
|
418
|
+
|
|
419
|
+
export { TimePicker }
|