@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,121 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { XCircle, TriangleAlert, CircleCheck, Info, X } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { Button } from "../Button/button.js";
|
|
6
|
+
import { ItemPrefix, ItemContent } from "../../patterns/element-anatomy/item-anatomy.js";
|
|
7
|
+
const VARIANT_ICON = {
|
|
8
|
+
neutral: null,
|
|
9
|
+
info: Info,
|
|
10
|
+
success: CircleCheck,
|
|
11
|
+
warning: TriangleAlert,
|
|
12
|
+
error: XCircle
|
|
13
|
+
};
|
|
14
|
+
const SUBTLE_ICON_COLOR = {
|
|
15
|
+
neutral: "text-fg-muted",
|
|
16
|
+
info: "text-info-text",
|
|
17
|
+
success: "text-success-text",
|
|
18
|
+
warning: "text-warning-text",
|
|
19
|
+
error: "text-error-text"
|
|
20
|
+
};
|
|
21
|
+
const NOTICE_LAYOUT = [
|
|
22
|
+
"flex items-start gap-2 w-full",
|
|
23
|
+
"text-body leading-compact",
|
|
24
|
+
"px-4 py-3"
|
|
25
|
+
].join(" ");
|
|
26
|
+
const Notice = React.forwardRef(
|
|
27
|
+
({
|
|
28
|
+
variant = "neutral",
|
|
29
|
+
title,
|
|
30
|
+
description,
|
|
31
|
+
endContent,
|
|
32
|
+
dismissible = true,
|
|
33
|
+
onDismiss,
|
|
34
|
+
dismissAriaLabel = "關閉通知",
|
|
35
|
+
// i18n-allow: DS default; consumer override via dismissAriaLabel prop
|
|
36
|
+
iconClassName,
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
39
|
+
}, ref) => {
|
|
40
|
+
const StatusIcon = VARIANT_ICON[variant];
|
|
41
|
+
return /* @__PURE__ */ jsxs(
|
|
42
|
+
"div",
|
|
43
|
+
{
|
|
44
|
+
ref,
|
|
45
|
+
className: cn(NOTICE_LAYOUT, className),
|
|
46
|
+
...props,
|
|
47
|
+
children: [
|
|
48
|
+
StatusIcon && /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(StatusIcon, { size: 16, className: cn("shrink-0", iconClassName), "aria-hidden": true }) }),
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
ItemContent,
|
|
51
|
+
{
|
|
52
|
+
label: title,
|
|
53
|
+
description,
|
|
54
|
+
labelClassName: description ? "font-medium" : void 0
|
|
55
|
+
}
|
|
56
|
+
),
|
|
57
|
+
(endContent || dismissible) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0 h-[1lh]", children: [
|
|
58
|
+
endContent,
|
|
59
|
+
dismissible && /* @__PURE__ */ jsx(
|
|
60
|
+
Button,
|
|
61
|
+
{
|
|
62
|
+
"data-dismiss": true,
|
|
63
|
+
iconOnly: true,
|
|
64
|
+
dismiss: true,
|
|
65
|
+
size: "xs",
|
|
66
|
+
startIcon: X,
|
|
67
|
+
"aria-label": dismissAriaLabel,
|
|
68
|
+
onClick: onDismiss
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
] })
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
Notice.displayName = "Notice";
|
|
78
|
+
let themeObserverStarted = false;
|
|
79
|
+
const themeSubscribers = /* @__PURE__ */ new Set();
|
|
80
|
+
function getInverseTheme() {
|
|
81
|
+
if (typeof document === "undefined") return "dark";
|
|
82
|
+
const current = document.documentElement.getAttribute("data-theme") ?? "light";
|
|
83
|
+
return current === "dark" ? "light" : "dark";
|
|
84
|
+
}
|
|
85
|
+
function startThemeObserver() {
|
|
86
|
+
if (themeObserverStarted || typeof document === "undefined") return;
|
|
87
|
+
themeObserverStarted = true;
|
|
88
|
+
const root = document.documentElement;
|
|
89
|
+
const observer = new MutationObserver(() => {
|
|
90
|
+
themeSubscribers.forEach((cb) => cb());
|
|
91
|
+
});
|
|
92
|
+
observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] });
|
|
93
|
+
}
|
|
94
|
+
function subscribe(cb) {
|
|
95
|
+
startThemeObserver();
|
|
96
|
+
themeSubscribers.add(cb);
|
|
97
|
+
return () => themeSubscribers.delete(cb);
|
|
98
|
+
}
|
|
99
|
+
function useInverseTheme() {
|
|
100
|
+
return React.useSyncExternalStore(subscribe, getInverseTheme, getInverseTheme);
|
|
101
|
+
}
|
|
102
|
+
const noticeMeta = {
|
|
103
|
+
component: "Notice",
|
|
104
|
+
family: null,
|
|
105
|
+
// non-family composite / overlay / layout
|
|
106
|
+
variants: {},
|
|
107
|
+
sizes: {},
|
|
108
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
109
|
+
tokens: {
|
|
110
|
+
bg: [],
|
|
111
|
+
fg: ["text-error-text", "text-fg-muted", "text-fg-secondary", "text-info-text", "text-success-text", "text-warning-text"],
|
|
112
|
+
ring: []
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
export {
|
|
116
|
+
Notice,
|
|
117
|
+
SUBTLE_ICON_COLOR,
|
|
118
|
+
noticeMeta,
|
|
119
|
+
useInverseTheme
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=notice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notice.js","sources":["../../../src/components/Notice/notice.tsx"],"sourcesContent":["import * as React from 'react'\nimport { X as XIcon, Info, CircleCheck, TriangleAlert, XCircle, type LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/design-system/components/Button/button'\nimport { ItemContent, ItemPrefix } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n/**\n * Notice — Toast / Alert 共用的視覺佈局層\n *\n * ── Typography: md tier ──\n * title: text-body (14px) leading-compact — 有 description 時加 font-medium\n * description: text-body (14px) leading-compact + text-fg-secondary (neutral-8)\n * 14px 配 14px — 視覺層級靠 font-weight + color 區分,不靠 font-size。\n *\n * ── Padding(固定,不隨 density 變) ──\n * px = px-4(16px)\n * py = py-3(12px)\n * gap = gap-2(8px)\n * Toast/Alert 是浮動通知,不是工作區域元件——density 控制表單/選單的緊湊度,\n * 通知的尺寸應該固定,不隨 density 縮放。\n *\n * ── Icon: md tier ──\n * icon size: 16px(ICON_SIZE.md)\n *\n * ── Dismiss X(chrome corner close,Cat 3 Action group region)──\n * 用 Button iconOnly dismiss **size=\"xs\"** — 非 Inline Action、非自刻 button。\n * Rationale(Notification banner family canonical):\n * - Notice / Alert / Toast 屬 **notification banner family**(ephemeral、px-4 py-3 固定不隨 density),\n * dismiss 是邊角小 affordance,xs 視覺不搶眼不跟 content 競爭。見 `overlay-surface.spec.md`\n * 「Chrome dismiss size canonical」三家族分類(Modal sm / Non-modal xs / Notification xs)\n * - Close 左側可加 refresh / share(action group region),皆統一 xs\n * - `dismiss` prop 自動套 variant=\"text\" + fg-muted override\n * SSOT:patterns/element-anatomy/inline-action.spec.md「Dismiss canonical — X close only」\n * + components/Alert/alert.spec.md「Chrome corner close X canonical」。\n */\n\nexport type NoticeVariant = 'neutral' | 'info' | 'success' | 'warning' | 'error'\n\nconst VARIANT_ICON: Record<NoticeVariant, LucideIcon | null> = {\n neutral: null,\n info: Info,\n success: CircleCheck,\n warning: TriangleAlert,\n error: XCircle,\n}\n\nexport const SUBTLE_ICON_COLOR: Record<NoticeVariant, string> = {\n neutral: 'text-fg-muted',\n info: 'text-info-text',\n success: 'text-success-text',\n warning: 'text-warning-text',\n error: 'text-error-text',\n}\n\nconst NOTICE_LAYOUT = [\n 'flex items-start gap-2 w-full',\n 'text-body leading-compact',\n 'px-4 py-3',\n].join(' ')\n\nexport interface NoticeProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n variant?: NoticeVariant\n title: React.ReactNode\n description?: React.ReactNode\n endContent?: React.ReactNode\n dismissible?: boolean\n onDismiss?: () => void\n /** ARIA label for the dismiss button. Override for i18n. Default: \"關閉通知\" */\n dismissAriaLabel?: string\n iconClassName?: string\n /**\n * ARIA role 由 wrapping consumer 決定(Alert / Toast / 自管 host),Notice 預設不帶 role。\n * Notice 是 layout primitive,Alert / Toast 是 live region 擁有者——避免 nested live region\n * 造成 screen reader 重複朗讀。明文傳遞才覆寫。\n */\n role?: 'status' | 'alert'\n /**\n * 對應 role 的 aria-live 策略,wrapping consumer 決定;Notice 預設 undefined 不帶 live region。\n */\n 'aria-live'?: 'polite' | 'assertive' | 'off'\n}\n\nconst Notice = React.forwardRef<HTMLDivElement, NoticeProps>(\n (\n {\n variant = 'neutral',\n title,\n description,\n endContent,\n dismissible = true,\n onDismiss,\n dismissAriaLabel = '關閉通知', // i18n-allow: DS default; consumer override via dismissAriaLabel prop\n iconClassName,\n className,\n ...props\n },\n ref,\n ) => {\n const StatusIcon = VARIANT_ICON[variant]\n\n return (\n <div\n ref={ref}\n className={cn(NOTICE_LAYOUT, className)}\n {...props}\n >\n {StatusIcon && (\n <ItemPrefix>\n <StatusIcon size={16} className={cn('shrink-0', iconClassName)} aria-hidden />\n </ItemPrefix>\n )}\n\n {/* Title + description 消費 ItemContent primitive(SSOT)。\n Label 有 desc 時 font-medium(Notice idiom:title 跟 desc 對照時 title 要更重)。 */}\n <ItemContent\n label={title}\n description={description}\n labelClassName={description ? 'font-medium' : undefined}\n />\n\n {(endContent || dismissible) && (\n <div className=\"flex items-center gap-2 shrink-0 h-[1lh]\">\n {endContent}\n {dismissible && (\n <Button\n data-dismiss\n iconOnly\n dismiss\n size=\"xs\"\n startIcon={XIcon}\n aria-label={dismissAriaLabel}\n onClick={onDismiss}\n />\n )}\n </div>\n )}\n </div>\n )\n },\n)\nNotice.displayName = 'Notice'\n\n// Singleton MutationObserver + subscription fan-out(2026-04-22 D3 perf audit):\n// 先前每個 useInverseTheme consumer(Alert / Toast / Notice instance 等)各建一個 MO,\n// N 個 Notice = N 個 observers。singleton 共用一個 MO + pub/sub 讓 theme swap 只做一次 DOM read。\nlet themeObserverStarted = false\nconst themeSubscribers = new Set<() => void>()\n\nfunction getInverseTheme(): 'dark' | 'light' {\n if (typeof document === 'undefined') return 'dark'\n const current = document.documentElement.getAttribute('data-theme') ?? 'light'\n return current === 'dark' ? 'light' : 'dark'\n}\n\nfunction startThemeObserver() {\n if (themeObserverStarted || typeof document === 'undefined') return\n themeObserverStarted = true\n const root = document.documentElement\n const observer = new MutationObserver(() => {\n themeSubscribers.forEach((cb) => cb())\n })\n observer.observe(root, { attributes: true, attributeFilter: ['data-theme'] })\n}\n\nfunction subscribe(cb: () => void): () => void {\n startThemeObserver()\n themeSubscribers.add(cb)\n return () => themeSubscribers.delete(cb)\n}\n\nexport function useInverseTheme(): 'dark' | 'light' {\n // useSyncExternalStore canonical (React 18+):單一 external source 被 N consumers 訂閱\n return React.useSyncExternalStore(subscribe, getInverseTheme, getInverseTheme)\n}\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const noticeMeta = {\n component: 'Notice',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: [],\n fg: ['text-error-text', 'text-fg-muted', 'text-fg-secondary', 'text-info-text', 'text-success-text', 'text-warning-text'],\n ring: [],\n },\n} as const\n\nexport { Notice }\n"],"names":["XIcon"],"mappings":";;;;;;AAsCA,MAAM,eAAyD;AAAA,EAC7D,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEO,MAAM,oBAAmD;AAAA,EAC9D,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAyBV,MAAM,SAAS,MAAM;AAAA,EACnB,CACE;AAAA,IACE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,mBAAmB;AAAA;AAAA,IACnB;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,aAAa,aAAa,OAAO;AAEvC,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW,GAAG,eAAe,SAAS;AAAA,QACrC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,cACC,oBAAC,YAAA,EACC,UAAA,oBAAC,YAAA,EAAW,MAAM,IAAI,WAAW,GAAG,YAAY,aAAa,GAAG,eAAW,MAAC,GAC9E;AAAA,UAKF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,cACP;AAAA,cACA,gBAAgB,cAAc,gBAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,WAG9C,cAAc,gBACd,qBAAC,OAAA,EAAI,WAAU,4CACZ,UAAA;AAAA,YAAA;AAAA,YACA,eACC;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,gBAAY;AAAA,gBACZ,UAAQ;AAAA,gBACR,SAAO;AAAA,gBACP,MAAK;AAAA,gBACL,WAAWA;AAAAA,gBACX,cAAY;AAAA,gBACZ,SAAS;AAAA,cAAA;AAAA,YAAA;AAAA,UACX,EAAA,CAEJ;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AACA,OAAO,cAAc;AAKrB,IAAI,uBAAuB;AAC3B,MAAM,uCAAuB,IAAA;AAE7B,SAAS,kBAAoC;AAC3C,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAM,UAAU,SAAS,gBAAgB,aAAa,YAAY,KAAK;AACvE,SAAO,YAAY,SAAS,UAAU;AACxC;AAEA,SAAS,qBAAqB;AAC5B,MAAI,wBAAwB,OAAO,aAAa,YAAa;AAC7D,yBAAuB;AACvB,QAAM,OAAO,SAAS;AACtB,QAAM,WAAW,IAAI,iBAAiB,MAAM;AAC1C,qBAAiB,QAAQ,CAAC,OAAO,GAAA,CAAI;AAAA,EACvC,CAAC;AACD,WAAS,QAAQ,MAAM,EAAE,YAAY,MAAM,iBAAiB,CAAC,YAAY,GAAG;AAC9E;AAEA,SAAS,UAAU,IAA4B;AAC7C,qBAAA;AACA,mBAAiB,IAAI,EAAE;AACvB,SAAO,MAAM,iBAAiB,OAAO,EAAE;AACzC;AAEO,SAAS,kBAAoC;AAElD,SAAO,MAAM,qBAAqB,WAAW,iBAAiB,eAAe;AAC/E;AAIO,MAAM,aAAa;AAAA,EACxB,WAAW;AAAA,EACX,QAAQ;AAAA;AAAA,EACR,UAAU,CAAA;AAAA,EAGV,OAAO,CAAA;AAAA,EAGP,QAAQ,CAAC,WAAW,SAAS,UAAU,iBAAiB,UAAU;AAAA,EAClE,QAAQ;AAAA,IACN,IAAI,CAAA;AAAA,IACJ,IAAI,CAAC,mBAAmB,iBAAiB,qBAAqB,kBAAkB,qBAAqB,mBAAmB;AAAA,IACxH,MAAM,CAAA;AAAA,EAAC;AAEX;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
|
|
4
|
+
import type { InlineActionConfig } from '../../patterns/element-anatomy/item-anatomy';
|
|
5
|
+
import { fieldWrapperStyles } from '../../components/Field/field-wrapper';
|
|
6
|
+
export interface NumberFormatOptions {
|
|
7
|
+
/** 小數位數 */
|
|
8
|
+
precision?: number;
|
|
9
|
+
/** 前綴(如 '$'、'NT$') */
|
|
10
|
+
prefix?: string;
|
|
11
|
+
/** 後綴(如 '%'、'元') */
|
|
12
|
+
suffix?: string;
|
|
13
|
+
/** locale(預設 'en-US') */
|
|
14
|
+
locale?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function formatNumber(value: number | null | undefined, options?: NumberFormatOptions): string;
|
|
17
|
+
export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'value' | 'onChange' | 'type'>, Omit<VariantProps<typeof fieldWrapperStyles>, 'mode' | 'variant'>, NumberFormatOptions {
|
|
18
|
+
/** Field display mode */
|
|
19
|
+
mode?: FieldMode;
|
|
20
|
+
/**
|
|
21
|
+
* Visual chrome(正交於 mode);Phase B1(2026-05-05)新增。
|
|
22
|
+
* - `'default'`(預設)— 完整 Field wrapper chrome。
|
|
23
|
+
* - `'bare'` — 透明 variant,hover/focus 才 reveal(Toolbar inline / DataTable cell)。
|
|
24
|
+
*
|
|
25
|
+
* 透傳:在 `<Field variant="bare">` 內自動繼承 context.variant;per-prop override context。
|
|
26
|
+
*/
|
|
27
|
+
variant?: FieldVariant;
|
|
28
|
+
/** Error 狀態(正交於 mode)。 */
|
|
29
|
+
error?: boolean;
|
|
30
|
+
/** 數值 */
|
|
31
|
+
value?: number | null;
|
|
32
|
+
/** 數值變更 */
|
|
33
|
+
onChange?: (value: number | null) => void;
|
|
34
|
+
/** 右側 inline action — 宣告式 API,Field 根據 size 自動渲染。 */
|
|
35
|
+
endAction?: InlineActionConfig;
|
|
36
|
+
/**
|
|
37
|
+
* 右側 slot(ReactNode)— escape hatch 供 consumer 放自訂元素(如 stepper button group / 自訂 popover trigger)。
|
|
38
|
+
* 跟 `endAction` 互斥(同時傳 endSlot 會優先,endAction 被忽略)。
|
|
39
|
+
* 規則對齊 Input.endSlot:90% case 用 endAction 宣告式 API,10% config 表達不出時走 endSlot。
|
|
40
|
+
*/
|
|
41
|
+
endSlot?: React.ReactNode;
|
|
42
|
+
}
|
|
43
|
+
declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
44
|
+
export declare const numberInputMeta: {
|
|
45
|
+
readonly component: "NumberInput";
|
|
46
|
+
readonly family: 4;
|
|
47
|
+
readonly variants: {};
|
|
48
|
+
readonly sizes: {};
|
|
49
|
+
readonly states: readonly ["default", "hover", "active", "focus-visible", "disabled"];
|
|
50
|
+
readonly tokens: {
|
|
51
|
+
readonly bg: readonly [];
|
|
52
|
+
readonly fg: readonly ["text-fg-disabled", "text-fg-muted"];
|
|
53
|
+
readonly ring: readonly [];
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
export { NumberInput, formatNumber };
|
|
57
|
+
//# sourceMappingURL=number-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../../src/components/NumberInput/number-input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAC3F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uDAAuD,CAAA;AAC/F,OAAO,EAAE,kBAAkB,EAAkC,MAAM,gDAAgD,CAAA;AAMnH,MAAM,WAAW,mBAAmB;IAClC,WAAW;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,iBAAS,YAAY,CACnB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAOR;AAOD,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC,EAC/F,IAAI,CAAC,YAAY,CAAC,OAAO,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,EACjE,mBAAmB;IACrB,yBAAyB;IACzB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS;IACT,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,WAAW;IACX,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACzC,qDAAqD;IACrD,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAKD,QAAA,MAAM,WAAW,2FA0GhB,CAAA;AAMD,eAAO,MAAM,eAAe;;;;;;;;;;;CAelB,CAAA;AAGV,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { EMPTY_DISPLAY, fieldWrapperStyles, bareInputStyles } from "../Field/field-wrapper.js";
|
|
5
|
+
import { useFieldContext } from "../Field/field-context.js";
|
|
6
|
+
import { ItemInlineAction } from "../../patterns/element-anatomy/item-anatomy.js";
|
|
7
|
+
function formatNumber(value, options = {}) {
|
|
8
|
+
if (value == null) return "";
|
|
9
|
+
const { precision, prefix = "", suffix = "", locale = "en-US" } = options;
|
|
10
|
+
const formatted = precision != null ? value.toLocaleString(locale, { minimumFractionDigits: precision, maximumFractionDigits: precision }) : value.toLocaleString(locale);
|
|
11
|
+
return `${prefix}${formatted}${suffix}`;
|
|
12
|
+
}
|
|
13
|
+
const NumberInput = React.forwardRef(
|
|
14
|
+
({
|
|
15
|
+
mode: modeProp,
|
|
16
|
+
variant: variantProp,
|
|
17
|
+
error: errorProp = false,
|
|
18
|
+
size: sizeProp,
|
|
19
|
+
value,
|
|
20
|
+
onChange,
|
|
21
|
+
precision,
|
|
22
|
+
prefix,
|
|
23
|
+
suffix,
|
|
24
|
+
locale,
|
|
25
|
+
endAction,
|
|
26
|
+
endSlot,
|
|
27
|
+
className,
|
|
28
|
+
disabled: disabledProp,
|
|
29
|
+
readOnly,
|
|
30
|
+
id: idProp,
|
|
31
|
+
"aria-describedby": ariaDescribedByProp,
|
|
32
|
+
"aria-errormessage": ariaErrorMessageProp,
|
|
33
|
+
...props
|
|
34
|
+
}, ref) => {
|
|
35
|
+
const fieldCtx = useFieldContext();
|
|
36
|
+
const error = errorProp || ((fieldCtx == null ? void 0 : fieldCtx.invalid) ?? false);
|
|
37
|
+
const size = sizeProp ?? (fieldCtx == null ? void 0 : fieldCtx.size) ?? "md";
|
|
38
|
+
const disabled = disabledProp ?? (fieldCtx == null ? void 0 : fieldCtx.disabled);
|
|
39
|
+
const variant = variantProp ?? (fieldCtx == null ? void 0 : fieldCtx.variant) ?? "default";
|
|
40
|
+
const resolvedMode = modeProp ?? (fieldCtx == null ? void 0 : fieldCtx.mode) ?? (readOnly ? "readonly" : disabled ? "disabled" : "edit");
|
|
41
|
+
if (resolvedMode !== "edit") {
|
|
42
|
+
return /* @__PURE__ */ jsx(
|
|
43
|
+
"div",
|
|
44
|
+
{
|
|
45
|
+
className: cn(fieldWrapperStyles({ mode: resolvedMode, variant, size }), className),
|
|
46
|
+
"data-field-mode": resolvedMode,
|
|
47
|
+
children: /* @__PURE__ */ jsx(
|
|
48
|
+
"span",
|
|
49
|
+
{
|
|
50
|
+
className: cn(
|
|
51
|
+
"flex-1 min-w-0",
|
|
52
|
+
resolvedMode === "disabled" && "text-fg-disabled cursor-not-allowed",
|
|
53
|
+
value == null && "text-fg-muted"
|
|
54
|
+
),
|
|
55
|
+
children: value == null ? EMPTY_DISPLAY : formatNumber(value, { precision, prefix, suffix, locale })
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const handleChange = (e) => {
|
|
62
|
+
if (!onChange) return;
|
|
63
|
+
const raw = e.target.value;
|
|
64
|
+
if (raw === "" || raw === "-") {
|
|
65
|
+
onChange(null);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const parsed = Number(raw);
|
|
69
|
+
if (!Number.isNaN(parsed)) {
|
|
70
|
+
onChange(parsed);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return /* @__PURE__ */ jsxs(
|
|
74
|
+
"div",
|
|
75
|
+
{
|
|
76
|
+
className: cn(
|
|
77
|
+
fieldWrapperStyles({ mode: "edit", variant, size }),
|
|
78
|
+
error && [
|
|
79
|
+
"border-error hover:border-error-hover",
|
|
80
|
+
"focus-within:border-error focus-within:hover:border-error"
|
|
81
|
+
],
|
|
82
|
+
className
|
|
83
|
+
),
|
|
84
|
+
"data-field-mode": "edit",
|
|
85
|
+
"data-error": error ? "" : void 0,
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
"input",
|
|
89
|
+
{
|
|
90
|
+
ref,
|
|
91
|
+
type: "text",
|
|
92
|
+
inputMode: "decimal",
|
|
93
|
+
id: idProp ?? (fieldCtx == null ? void 0 : fieldCtx.id),
|
|
94
|
+
value: value ?? "",
|
|
95
|
+
onChange: handleChange,
|
|
96
|
+
"aria-invalid": error || void 0,
|
|
97
|
+
"aria-required": (fieldCtx == null ? void 0 : fieldCtx.required) || void 0,
|
|
98
|
+
"aria-describedby": ariaDescribedByProp ?? (fieldCtx == null ? void 0 : fieldCtx.descriptionId),
|
|
99
|
+
"aria-errormessage": ariaErrorMessageProp ?? (error ? fieldCtx == null ? void 0 : fieldCtx.errorId : void 0),
|
|
100
|
+
className: bareInputStyles,
|
|
101
|
+
...props
|
|
102
|
+
}
|
|
103
|
+
),
|
|
104
|
+
endSlot ? (
|
|
105
|
+
// endSlot escape hatch:consumer 自控右側 slot(對齊 Input.endSlot canonical)
|
|
106
|
+
endSlot
|
|
107
|
+
) : endAction ? /* @__PURE__ */ jsx(ItemInlineAction, { action: endAction, size: size ?? "md" }) : null
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
NumberInput.displayName = "NumberInput";
|
|
114
|
+
const numberInputMeta = {
|
|
115
|
+
component: "NumberInput",
|
|
116
|
+
family: 4,
|
|
117
|
+
variants: {},
|
|
118
|
+
sizes: {},
|
|
119
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
120
|
+
tokens: {
|
|
121
|
+
bg: [],
|
|
122
|
+
fg: ["text-fg-disabled", "text-fg-muted"],
|
|
123
|
+
ring: []
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
export {
|
|
127
|
+
NumberInput,
|
|
128
|
+
formatNumber,
|
|
129
|
+
numberInputMeta
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=number-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-input.js","sources":["../../../src/components/NumberInput/number-input.tsx"],"sourcesContent":["import * as React from 'react'\nimport { type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'\nimport type { InlineActionConfig } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { fieldWrapperStyles, bareInputStyles, EMPTY_DISPLAY } from '@/design-system/components/Field/field-wrapper'\nimport { useFieldContext } from '@/design-system/components/Field/field-context'\nimport { ItemInlineAction } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n// ── Format ──────────────────────────────────────────────────────────────────\n\nexport interface NumberFormatOptions {\n /** 小數位數 */\n precision?: number\n /** 前綴(如 '$'、'NT$') */\n prefix?: string\n /** 後綴(如 '%'、'元') */\n suffix?: string\n /** locale(預設 'en-US') */\n locale?: string\n}\n\nfunction formatNumber(\n value: number | null | undefined,\n options: NumberFormatOptions = {},\n): string {\n if (value == null) return ''\n const { precision, prefix = '', suffix = '', locale = 'en-US' } = options\n const formatted = precision != null\n ? value.toLocaleString(locale, { minimumFractionDigits: precision, maximumFractionDigits: precision })\n : value.toLocaleString(locale)\n return `${prefix}${formatted}${suffix}`\n}\n\n// Phase B1(2026-05-05):NumberInputDisplay 退場。\n// 改用 `<NumberInput mode=\"display\" value={...} prefix={...} ... />`,format 邏輯在 mode='display' 分支重用。\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface NumberInputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'value' | 'onChange' | 'type'>,\n Omit<VariantProps<typeof fieldWrapperStyles>, 'mode' | 'variant'>,\n NumberFormatOptions {\n /** Field display mode */\n mode?: FieldMode\n /**\n * Visual chrome(正交於 mode);Phase B1(2026-05-05)新增。\n * - `'default'`(預設)— 完整 Field wrapper chrome。\n * - `'bare'` — 透明 variant,hover/focus 才 reveal(Toolbar inline / DataTable cell)。\n *\n * 透傳:在 `<Field variant=\"bare\">` 內自動繼承 context.variant;per-prop override context。\n */\n variant?: FieldVariant\n /** Error 狀態(正交於 mode)。 */\n error?: boolean\n /** 數值 */\n value?: number | null\n /** 數值變更 */\n onChange?: (value: number | null) => void\n /** 右側 inline action — 宣告式 API,Field 根據 size 自動渲染。 */\n endAction?: InlineActionConfig\n /**\n * 右側 slot(ReactNode)— escape hatch 供 consumer 放自訂元素(如 stepper button group / 自訂 popover trigger)。\n * 跟 `endAction` 互斥(同時傳 endSlot 會優先,endAction 被忽略)。\n * 規則對齊 Input.endSlot:90% case 用 endAction 宣告式 API,10% config 表達不出時走 endSlot。\n */\n endSlot?: React.ReactNode\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(\n (\n {\n mode: modeProp,\n variant: variantProp,\n error: errorProp = false,\n size: sizeProp,\n value,\n onChange,\n precision,\n prefix,\n suffix,\n locale,\n endAction,\n endSlot,\n className,\n disabled: disabledProp,\n readOnly,\n id: idProp,\n 'aria-describedby': ariaDescribedByProp,\n 'aria-errormessage': ariaErrorMessageProp,\n ...props\n },\n ref\n ) => {\n const fieldCtx = useFieldContext()\n const error = errorProp || (fieldCtx?.invalid ?? false)\n const size = sizeProp ?? fieldCtx?.size ?? 'md'\n const disabled = disabledProp ?? fieldCtx?.disabled\n // chrome 透傳:per-prop override context;context 沒值則 'default'\n const variant: FieldVariant = variantProp ?? fieldCtx?.variant ?? 'default'\n // mode resolve order(Phase B1 2026-05-05):prop > fieldCtx > readOnly/disabled fallback\n const resolvedMode: FieldMode = modeProp\n ?? fieldCtx?.mode\n ?? (readOnly ? 'readonly' : disabled ? 'disabled' : 'edit')\n\n // display / readonly / disabled 都顯示格式化值(span 取代 input)\n if (resolvedMode !== 'edit') {\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}\n data-field-mode={resolvedMode}\n >\n <span\n className={cn(\n 'flex-1 min-w-0',\n resolvedMode === 'disabled' && 'text-fg-disabled cursor-not-allowed',\n value == null && 'text-fg-muted',\n )}\n >\n {value == null ? EMPTY_DISPLAY : formatNumber(value, { precision, prefix, suffix, locale })}\n </span>\n </div>\n )\n }\n\n // edit 模式:raw 數值輸入\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (!onChange) return\n const raw = e.target.value\n if (raw === '' || raw === '-') {\n onChange(null)\n return\n }\n const parsed = Number(raw)\n if (!Number.isNaN(parsed)) {\n onChange(parsed)\n }\n }\n\n return (\n <div\n className={cn(\n fieldWrapperStyles({ mode: 'edit', variant: variant, size }),\n error && [\n 'border-error hover:border-error-hover',\n 'focus-within:border-error focus-within:hover:border-error',\n ],\n className,\n )}\n data-field-mode=\"edit\"\n data-error={error ? '' : undefined}\n >\n <input\n ref={ref}\n type=\"text\"\n inputMode=\"decimal\"\n id={idProp ?? fieldCtx?.id}\n value={value ?? ''}\n onChange={handleChange}\n aria-invalid={error || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n className={bareInputStyles}\n {...props}\n />\n {endSlot ? (\n // endSlot escape hatch:consumer 自控右側 slot(對齊 Input.endSlot canonical)\n endSlot\n ) : endAction ? (\n <ItemInlineAction action={endAction} size={size ?? 'md'} />\n ) : null}\n </div>\n )\n }\n)\nNumberInput.displayName = 'NumberInput'\n\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const numberInputMeta = {\n component: 'NumberInput',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: [],\n fg: ['text-fg-disabled', 'text-fg-muted'],\n ring: [],\n },\n} as const\n\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport { NumberInput, formatNumber }\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface OverflowIndicatorProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {
|
|
3
|
+
count: number;
|
|
4
|
+
shape?: 'circle' | 'tag';
|
|
5
|
+
size?: 'sm' | 'md' | 'lg';
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const OverflowIndicator: React.ForwardRefExoticComponent<OverflowIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
|
|
10
|
+
export declare const overflowIndicatorMeta: {
|
|
11
|
+
readonly component: "OverflowIndicator";
|
|
12
|
+
readonly family: null;
|
|
13
|
+
readonly variants: {};
|
|
14
|
+
readonly sizes: {};
|
|
15
|
+
readonly states: readonly ["default", "hover", "active", "focus-visible", "disabled"];
|
|
16
|
+
readonly tokens: {
|
|
17
|
+
readonly bg: readonly ["bg-muted"];
|
|
18
|
+
readonly fg: readonly ["text-foreground"];
|
|
19
|
+
readonly ring: readonly [];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export { OverflowIndicator };
|
|
23
|
+
//# sourceMappingURL=overflow-indicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overflow-indicator.d.ts","sourceRoot":"","sources":["../../../src/components/OverflowIndicator/overflow-indicator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA6B9B,MAAM,WAAW,sBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,UAAU,CAAC;IAC/D,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IACxB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAmDD,QAAA,MAAM,iBAAiB,gGA8CtB,CAAA;AAKD,eAAO,MAAM,qBAAqB;;;;;;;;;;;CAexB,CAAA;AAEV,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { HoverCard, HoverCardTrigger, HoverCardContent } from "../HoverCard/hover-card.js";
|
|
5
|
+
import { tagVariants } from "../Tag/tag.js";
|
|
6
|
+
import { HOVER_DELAY_CLOSE_MS, HOVER_DELAY_RICH_MS } from "../../tokens/motion/motion.js";
|
|
7
|
+
const triggerSize = {
|
|
8
|
+
sm: "h-5 min-w-5",
|
|
9
|
+
md: "h-6 min-w-6",
|
|
10
|
+
lg: "h-6 min-w-6"
|
|
11
|
+
};
|
|
12
|
+
const triggerText = {
|
|
13
|
+
sm: "text-[10px]",
|
|
14
|
+
md: "text-caption",
|
|
15
|
+
lg: "text-caption"
|
|
16
|
+
};
|
|
17
|
+
function ShrinkWrapList({ children }) {
|
|
18
|
+
const containerRef = React.useRef(null);
|
|
19
|
+
React.useLayoutEffect(() => {
|
|
20
|
+
const container = containerRef.current;
|
|
21
|
+
if (!container) return;
|
|
22
|
+
let rafId = 0;
|
|
23
|
+
rafId = requestAnimationFrame(() => {
|
|
24
|
+
rafId = 0;
|
|
25
|
+
const cs = getComputedStyle(container);
|
|
26
|
+
const padL = parseFloat(cs.paddingLeft) || 0;
|
|
27
|
+
const padR = parseFloat(cs.paddingRight) || 0;
|
|
28
|
+
const gap = parseFloat(cs.gap) || parseFloat(cs.columnGap) || 0;
|
|
29
|
+
const available = container.offsetWidth - padL - padR;
|
|
30
|
+
const items = Array.from(container.children);
|
|
31
|
+
if (items.length === 0) return;
|
|
32
|
+
let currentRow = 0;
|
|
33
|
+
let maxRow = 0;
|
|
34
|
+
items.forEach((item) => {
|
|
35
|
+
const w = item.offsetWidth;
|
|
36
|
+
const needed = currentRow > 0 ? currentRow + gap + w : w;
|
|
37
|
+
if (needed > available && currentRow > 0) {
|
|
38
|
+
maxRow = Math.max(maxRow, currentRow);
|
|
39
|
+
currentRow = w;
|
|
40
|
+
} else {
|
|
41
|
+
currentRow = needed;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
maxRow = Math.max(maxRow, currentRow);
|
|
45
|
+
container.style.maxWidth = `${Math.ceil(maxRow) + padL + padR + 1}px`;
|
|
46
|
+
});
|
|
47
|
+
return () => {
|
|
48
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
49
|
+
};
|
|
50
|
+
}, [children]);
|
|
51
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "flex flex-wrap gap-1 p-2 max-w-[280px]", children });
|
|
52
|
+
}
|
|
53
|
+
const OverflowIndicator = React.forwardRef(
|
|
54
|
+
function OverflowIndicator2({ count, shape = "circle", size = "md", children, className, ...props }, ref) {
|
|
55
|
+
if (count <= 0) return null;
|
|
56
|
+
const trigger = shape === "tag" ? /* @__PURE__ */ jsx(
|
|
57
|
+
"span",
|
|
58
|
+
{
|
|
59
|
+
ref,
|
|
60
|
+
"data-overflow-indicator": "",
|
|
61
|
+
className: cn(tagVariants({ color: "neutral", size }), "cursor-default", className),
|
|
62
|
+
...props,
|
|
63
|
+
children: /* @__PURE__ */ jsxs("span", { className: "px-1", children: [
|
|
64
|
+
"+",
|
|
65
|
+
count
|
|
66
|
+
] })
|
|
67
|
+
}
|
|
68
|
+
) : /* @__PURE__ */ jsxs(
|
|
69
|
+
"span",
|
|
70
|
+
{
|
|
71
|
+
ref,
|
|
72
|
+
"data-overflow-indicator": "",
|
|
73
|
+
className: cn(
|
|
74
|
+
"shrink-0 rounded-full inline-grid place-content-center",
|
|
75
|
+
"bg-muted text-foreground font-medium leading-none cursor-default",
|
|
76
|
+
triggerSize[size],
|
|
77
|
+
triggerText[size],
|
|
78
|
+
className
|
|
79
|
+
),
|
|
80
|
+
...props,
|
|
81
|
+
children: [
|
|
82
|
+
"+",
|
|
83
|
+
count
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
return /* @__PURE__ */ jsxs(HoverCard, { openDelay: HOVER_DELAY_RICH_MS, closeDelay: HOVER_DELAY_CLOSE_MS, children: [
|
|
88
|
+
/* @__PURE__ */ jsx(HoverCardTrigger, { asChild: true, children: trigger }),
|
|
89
|
+
/* @__PURE__ */ jsx(HoverCardContent, { className: "bg-tooltip rounded-lg", "data-theme": "dark", children: /* @__PURE__ */ jsx(ShrinkWrapList, { children }) })
|
|
90
|
+
] });
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
OverflowIndicator.displayName = "OverflowIndicator";
|
|
94
|
+
const overflowIndicatorMeta = {
|
|
95
|
+
component: "OverflowIndicator",
|
|
96
|
+
family: null,
|
|
97
|
+
// non-family composite / overlay / layout
|
|
98
|
+
variants: {},
|
|
99
|
+
sizes: {},
|
|
100
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
101
|
+
tokens: {
|
|
102
|
+
bg: ["bg-muted"],
|
|
103
|
+
fg: ["text-foreground"],
|
|
104
|
+
ring: []
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
export {
|
|
108
|
+
OverflowIndicator,
|
|
109
|
+
overflowIndicatorMeta
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=overflow-indicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overflow-indicator.js","sources":["../../../src/components/OverflowIndicator/overflow-indicator.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { HoverCard, HoverCardTrigger, HoverCardContent } from '@/design-system/components/HoverCard/hover-card'\nimport { tagVariants } from '@/design-system/components/Tag/tag'\nimport { HOVER_DELAY_RICH_MS, HOVER_DELAY_CLOSE_MS } from '@/design-system/tokens/motion/motion'\n\n/**\n * OverflowIndicator — +N 觸發器 + HoverCard 顯示溢出內容\n *\n * 統一用 HoverCard(不用 Tooltip)——溢出內容可能需要互動:\n * - 人員 +N:tag dismiss + hover name card\n * - 一般 +N:穩定顯示溢出項目\n *\n * trigger 不用 Tag 元件(Tag 有內建 truncation Tooltip 會跟 HoverCard 衝突),\n * 改用 tagVariants 直接套樣式。\n */\n\nconst triggerSize: Record<string, string> = {\n sm: 'h-5 min-w-5',\n md: 'h-6 min-w-6',\n lg: 'h-6 min-w-6',\n}\n\nconst triggerText: Record<string, string> = {\n sm: 'text-[10px]',\n md: 'text-caption',\n lg: 'text-caption',\n}\n\nexport interface OverflowIndicatorProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {\n count: number\n shape?: 'circle' | 'tag'\n size?: 'sm' | 'md' | 'lg'\n children: React.ReactNode\n className?: string\n}\n\nfunction ShrinkWrapList({ children }: { children: React.ReactNode }) {\n const containerRef = React.useRef<HTMLDivElement | null>(null)\n\n // 2026-05-16 audit codex Round 6:rAF capture + cancel on unmount/re-run(defensive hygiene)。\n // 原 callback ref `requestAnimationFrame(() => ...)` 沒 cancel,unmount-during-rAF 可能 fire 後\n // mutate detached element.style — no-op but pattern hygiene 應對齊 DS-wide rAF cancel canonical。\n React.useLayoutEffect(() => {\n const container = containerRef.current\n if (!container) return\n let rafId = 0\n rafId = requestAnimationFrame(() => {\n rafId = 0\n const cs = getComputedStyle(container)\n const padL = parseFloat(cs.paddingLeft) || 0\n const padR = parseFloat(cs.paddingRight) || 0\n const gap = parseFloat(cs.gap) || parseFloat(cs.columnGap) || 0\n const available = container.offsetWidth - padL - padR\n\n const items = Array.from(container.children) as HTMLElement[]\n if (items.length === 0) return\n\n let currentRow = 0\n let maxRow = 0\n\n items.forEach(item => {\n const w = item.offsetWidth\n const needed = currentRow > 0 ? currentRow + gap + w : w\n\n if (needed > available && currentRow > 0) {\n maxRow = Math.max(maxRow, currentRow)\n currentRow = w\n } else {\n currentRow = needed\n }\n })\n maxRow = Math.max(maxRow, currentRow)\n\n container.style.maxWidth = `${Math.ceil(maxRow) + padL + padR + 1}px`\n })\n return () => { if (rafId) cancelAnimationFrame(rafId) }\n }, [children])\n\n return (\n <div ref={containerRef} className=\"flex flex-wrap gap-1 p-2 max-w-[280px]\">\n {children}\n </div>\n )\n}\n\nconst OverflowIndicator = React.forwardRef<HTMLSpanElement, OverflowIndicatorProps>(\n function OverflowIndicator(\n { count, shape = 'circle', size = 'md', children, className, ...props },\n ref,\n ) {\n if (count <= 0) return null\n\n const trigger = shape === 'tag' ? (\n <span\n ref={ref}\n data-overflow-indicator=\"\"\n className={cn(tagVariants({ color: 'neutral', size }), 'cursor-default', className)}\n {...props}\n >\n <span className=\"px-1\">+{count}</span>\n </span>\n ) : (\n <span\n ref={ref}\n data-overflow-indicator=\"\"\n className={cn(\n 'shrink-0 rounded-full inline-grid place-content-center',\n 'bg-muted text-foreground font-medium leading-none cursor-default',\n triggerSize[size],\n triggerText[size],\n className,\n )}\n {...props}\n >\n +{count}\n </span>\n )\n\n // 2026-05-18 fix(per user audit「所有 hovercard 應消費 hover delay token」+ motion.spec.md SSOT):\n // rich tier(可互動 popup,user 可移浮層上操作)= HOVER_DELAY_RICH_MS;close = HOVER_DELAY_CLOSE_MS。\n return (\n <HoverCard openDelay={HOVER_DELAY_RICH_MS} closeDelay={HOVER_DELAY_CLOSE_MS}>\n <HoverCardTrigger asChild>\n {trigger}\n </HoverCardTrigger>\n <HoverCardContent className=\"bg-tooltip rounded-lg\" data-theme=\"dark\">\n <ShrinkWrapList>{children}</ShrinkWrapList>\n </HoverCardContent>\n </HoverCard>\n )\n },\n)\nOverflowIndicator.displayName = 'OverflowIndicator'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const overflowIndicatorMeta = {\n component: 'OverflowIndicator',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-muted'],\n fg: ['text-foreground'],\n ring: [],\n },\n} as const\n\nexport { OverflowIndicator }\n"],"names":["OverflowIndicator"],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* avatar-stack-overflow — Deterministic SSOT primitive for avatar stack overflow math
|
|
3
|
+
*
|
|
4
|
+
* **2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus,user verbatim「就 A」)**:
|
|
5
|
+
*
|
|
6
|
+
* Real root cause of Bug 3「same cell width but different overflow timing per total count」:
|
|
7
|
+
* 1. `useOverflowCount` 在 Combobox 用 DOM `offsetWidth` 量測 + `overflowW = 60` fallback(實際 24px)
|
|
8
|
+
* 2. `overflowEl` 不被 ResizeObserver observe,first calc 用 fallback 後不會 recalc
|
|
9
|
+
* 3. `offsetWidth` 不減 `-ml-0.5` overlap → measurement 偏保守
|
|
10
|
+
* 4. **架構違反**:`MultiPersonDisplay` display path 用 canvas-based 算 / Combobox edit path 用 DOM offsetWidth
|
|
11
|
+
* → 同 cell width 兩 path 不同結果 → user verbatim「同寬 cell overflow 時間不一樣」SSOT 根本被違反
|
|
12
|
+
*
|
|
13
|
+
* **Fix**(per codex Q3 consensus):抽 pure formula + React hook,display + edit 兩 path **共用**。
|
|
14
|
+
*
|
|
15
|
+
* **Deterministic formula**:
|
|
16
|
+
* ```
|
|
17
|
+
* firstAvatar + (visible - 1) * (avatar - overlap) + overflowChip <= available
|
|
18
|
+
* ```
|
|
19
|
+
* - `firstAvatar`:第一個 avatar 全寬 = `avatarPx`
|
|
20
|
+
* - subsequent items:`avatar - overlap`(stack `-ml-0.5` 視覺等同 measurement subtract)
|
|
21
|
+
* - `overflowChip`:若有 hidden,留 +N chip 空間;最後一個 visible item 不需留(`remaining === 0`)
|
|
22
|
+
*
|
|
23
|
+
* **Why centralize**:M14 mechanical guard against future drift。`MultiPersonDisplay` +
|
|
24
|
+
* PeoplePicker stack edit + future avatar consumers 都 import 此 helper,不可 copy formula。
|
|
25
|
+
* 對齊 codex「one avatar-stack primitive owns avatarPx, overlapPx, overflowChipPx」directive。
|
|
26
|
+
*
|
|
27
|
+
* **Benchmark cite**(per codex external baseline):MDN flex truncation / MUI Autocomplete
|
|
28
|
+
* limitTags / Ant Select maxTagCount="responsive"(explicit overflow contract,非 incidental clip)/
|
|
29
|
+
* Primer Truncate(parent-constrained max width)。
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Pure deterministic visible-count formula for avatar stack with overlap + overflow chip.
|
|
33
|
+
*
|
|
34
|
+
* @param availablePx — Container width available for the entire stack(含 +N chip 預留空間)
|
|
35
|
+
* @param total — Total avatars in selection
|
|
36
|
+
* @param avatarPx — Per-avatar pixel width(包含 ring border)
|
|
37
|
+
* @param overlapPx — Negative margin overlap between siblings(default 2px = `-ml-0.5`)
|
|
38
|
+
* @param overflowChipPx — Width reserved for +N indicator when overflow needed(default 24px = circle h-6 min-w-6)
|
|
39
|
+
* @returns visible count(0 ≤ visible ≤ total)。若全部 fit 則 visible = total(無 +N chip);否則 visible 為 max fit。
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAvatarStackVisibleCount({ availablePx, total, avatarPx, overlapPx, overflowChipPx: _overflowChipPx, }: {
|
|
42
|
+
availablePx: number;
|
|
43
|
+
total: number;
|
|
44
|
+
avatarPx: number;
|
|
45
|
+
overlapPx?: number;
|
|
46
|
+
overflowChipPx?: number;
|
|
47
|
+
}): number;
|
|
48
|
+
/**
|
|
49
|
+
* Map size token to avatar pixel(對齊 person-display.tsx:80 AVATAR_PX SSOT)。
|
|
50
|
+
*/
|
|
51
|
+
export declare const AVATAR_STACK_AVATAR_PX: Record<'sm' | 'md' | 'lg', number>;
|
|
52
|
+
/**
|
|
53
|
+
* Default overflow chip width per size(對齊 overflow-indicator.tsx:17 triggerSize SSOT)。
|
|
54
|
+
* shape='circle' → h-{5|6} min-w-{5|6} ≈ 20-24px
|
|
55
|
+
*/
|
|
56
|
+
export declare const AVATAR_STACK_OVERFLOW_CHIP_PX: Record<'sm' | 'md' | 'lg', number>;
|
|
57
|
+
//# sourceMappingURL=avatar-stack-overflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-stack-overflow.d.ts","sourceRoot":"","sources":["../../../src/components/PeoplePicker/avatar-stack-overflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,WAAW,EACX,KAAK,EACL,QAAQ,EACR,SAAa,EAKb,cAAc,EAAE,eAAoB,GACrC,EAAE;IACD,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,GAAG,MAAM,CAuBT;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,MAAM,CAIrE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,MAAM,CAI5E,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
function getAvatarStackVisibleCount({
|
|
2
|
+
availablePx,
|
|
3
|
+
total,
|
|
4
|
+
avatarPx,
|
|
5
|
+
overlapPx = 2,
|
|
6
|
+
// NOTE: overflowChipPx is kept for backward-compat API but the slot-based
|
|
7
|
+
// formula below treats chip = avatar physical size(both circles same shape
|
|
8
|
+
// + same -ml-0.5 overlap when stacked)。Consumer 必 ensure 視覺 chip wrapper
|
|
9
|
+
// 也套同 `-ml-0.5` overlap class(Combobox `overflowWrapperClassName`)。
|
|
10
|
+
overflowChipPx: _overflowChipPx = 24
|
|
11
|
+
}) {
|
|
12
|
+
if (total <= 0 || availablePx <= 0) return 0;
|
|
13
|
+
const step = avatarPx - overlapPx;
|
|
14
|
+
if (step <= 0) return Math.min(total, 1);
|
|
15
|
+
const slots = 1 + Math.floor((availablePx - avatarPx) / step);
|
|
16
|
+
if (slots <= 0) return 0;
|
|
17
|
+
if (total <= slots) return total;
|
|
18
|
+
return Math.max(0, slots - 1);
|
|
19
|
+
}
|
|
20
|
+
const AVATAR_STACK_AVATAR_PX = {
|
|
21
|
+
sm: 20,
|
|
22
|
+
md: 24,
|
|
23
|
+
lg: 24
|
|
24
|
+
};
|
|
25
|
+
const AVATAR_STACK_OVERFLOW_CHIP_PX = {
|
|
26
|
+
sm: 20,
|
|
27
|
+
md: 24,
|
|
28
|
+
lg: 24
|
|
29
|
+
};
|
|
30
|
+
export {
|
|
31
|
+
AVATAR_STACK_AVATAR_PX,
|
|
32
|
+
AVATAR_STACK_OVERFLOW_CHIP_PX,
|
|
33
|
+
getAvatarStackVisibleCount
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=avatar-stack-overflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-stack-overflow.js","sources":["../../../src/components/PeoplePicker/avatar-stack-overflow.ts"],"sourcesContent":["/**\n * avatar-stack-overflow — Deterministic SSOT primitive for avatar stack overflow math\n *\n * **2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus,user verbatim「就 A」)**:\n *\n * Real root cause of Bug 3「same cell width but different overflow timing per total count」:\n * 1. `useOverflowCount` 在 Combobox 用 DOM `offsetWidth` 量測 + `overflowW = 60` fallback(實際 24px)\n * 2. `overflowEl` 不被 ResizeObserver observe,first calc 用 fallback 後不會 recalc\n * 3. `offsetWidth` 不減 `-ml-0.5` overlap → measurement 偏保守\n * 4. **架構違反**:`MultiPersonDisplay` display path 用 canvas-based 算 / Combobox edit path 用 DOM offsetWidth\n * → 同 cell width 兩 path 不同結果 → user verbatim「同寬 cell overflow 時間不一樣」SSOT 根本被違反\n *\n * **Fix**(per codex Q3 consensus):抽 pure formula + React hook,display + edit 兩 path **共用**。\n *\n * **Deterministic formula**:\n * ```\n * firstAvatar + (visible - 1) * (avatar - overlap) + overflowChip <= available\n * ```\n * - `firstAvatar`:第一個 avatar 全寬 = `avatarPx`\n * - subsequent items:`avatar - overlap`(stack `-ml-0.5` 視覺等同 measurement subtract)\n * - `overflowChip`:若有 hidden,留 +N chip 空間;最後一個 visible item 不需留(`remaining === 0`)\n *\n * **Why centralize**:M14 mechanical guard against future drift。`MultiPersonDisplay` +\n * PeoplePicker stack edit + future avatar consumers 都 import 此 helper,不可 copy formula。\n * 對齊 codex「one avatar-stack primitive owns avatarPx, overlapPx, overflowChipPx」directive。\n *\n * **Benchmark cite**(per codex external baseline):MDN flex truncation / MUI Autocomplete\n * limitTags / Ant Select maxTagCount=\"responsive\"(explicit overflow contract,非 incidental clip)/\n * Primer Truncate(parent-constrained max width)。\n */\n\n/**\n * Pure deterministic visible-count formula for avatar stack with overlap + overflow chip.\n *\n * @param availablePx — Container width available for the entire stack(含 +N chip 預留空間)\n * @param total — Total avatars in selection\n * @param avatarPx — Per-avatar pixel width(包含 ring border)\n * @param overlapPx — Negative margin overlap between siblings(default 2px = `-ml-0.5`)\n * @param overflowChipPx — Width reserved for +N indicator when overflow needed(default 24px = circle h-6 min-w-6)\n * @returns visible count(0 ≤ visible ≤ total)。若全部 fit 則 visible = total(無 +N chip);否則 visible 為 max fit。\n */\nexport function getAvatarStackVisibleCount({\n availablePx,\n total,\n avatarPx,\n overlapPx = 2,\n // NOTE: overflowChipPx is kept for backward-compat API but the slot-based\n // formula below treats chip = avatar physical size(both circles same shape\n // + same -ml-0.5 overlap when stacked)。Consumer 必 ensure 視覺 chip wrapper\n // 也套同 `-ml-0.5` overlap class(Combobox `overflowWrapperClassName`)。\n overflowChipPx: _overflowChipPx = 24,\n}: {\n availablePx: number\n total: number\n avatarPx: number\n overlapPx?: number\n overflowChipPx?: number\n}): number {\n if (total <= 0 || availablePx <= 0) return 0\n // 2026-05-16 真 root cause fix(Claude+Codex Round 2 + user 物理模型 directive):\n //\n // 原 formula 雙態 bug:\n // 1. full-fit 路徑算 fullStack(無 chip space)\n // 2. overflow 路徑重算 remainder(chip 當 24px 額外空間)\n // 兩 path 切換時 visible 跳 2(saw)— 因 chip 不被當「stack 內 1 個圓」,\n // 被當「stack 外額外 chunk」。User 抓 length=4→4、length=5→2+3 = 物理錯。\n //\n // **User 物理模型(對齊 MUI AvatarGroup / Primer AvatarStack / Material idiom)**:\n // avatar 跟 +N 都是同尺寸圓形 + 同 -ml-0.5 overlap → 同 step。空間 W 容\n // `slots = 1 + floor((W - avatar) / step)` 個圓。total ≤ slots → 全 avatar 無 chip;\n // total > slots → (slots-1) avatar + 1 chip(共 slots 個圓)。\n //\n // 物理 saw 性質:length 從 slots 跳到 slots+1 時 visible 從 slots 跳到 slots-1\n // = delta 1 avatar(同 slots 個圓,只 swap 最後一個 avatar 變 chip)。對齊 user 直覺。\n const step = avatarPx - overlapPx\n if (step <= 0) return Math.min(total, 1)\n const slots = 1 + Math.floor((availablePx - avatarPx) / step)\n if (slots <= 0) return 0\n if (total <= slots) return total // 全 fit:每 slot 一個 avatar\n return Math.max(0, slots - 1) // 超過 slots:slots-1 個 avatar + 1 個 chip(last slot)\n}\n\n/**\n * Map size token to avatar pixel(對齊 person-display.tsx:80 AVATAR_PX SSOT)。\n */\nexport const AVATAR_STACK_AVATAR_PX: Record<'sm' | 'md' | 'lg', number> = {\n sm: 20,\n md: 24,\n lg: 24,\n}\n\n/**\n * Default overflow chip width per size(對齊 overflow-indicator.tsx:17 triggerSize SSOT)。\n * shape='circle' → h-{5|6} min-w-{5|6} ≈ 20-24px\n */\nexport const AVATAR_STACK_OVERFLOW_CHIP_PX: Record<'sm' | 'md' | 'lg', number> = {\n sm: 20,\n md: 24,\n lg: 24,\n}\n"],"names":[],"mappings":"AAyCO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,EAKZ,gBAAgB,kBAAkB;AACpC,GAMW;AACT,MAAI,SAAS,KAAK,eAAe,EAAG,QAAO;AAgB3C,QAAM,OAAO,WAAW;AACxB,MAAI,QAAQ,EAAG,QAAO,KAAK,IAAI,OAAO,CAAC;AACvC,QAAM,QAAQ,IAAI,KAAK,OAAO,cAAc,YAAY,IAAI;AAC5D,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,MAAO,QAAO;AAC3B,SAAO,KAAK,IAAI,GAAG,QAAQ,CAAC;AAC9B;AAKO,MAAM,yBAA6D;AAAA,EACxE,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAMO,MAAM,gCAAoE;AAAA,EAC/E,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SelectOption } from '../../components/Select/select';
|
|
2
|
+
import { type PersonValue } from './person-display';
|
|
3
|
+
export declare const PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS = "flex-1 min-w-0 inline-flex items-center group-data-[row-mode=auto]/cell:items-start";
|
|
4
|
+
export declare function getPeoplePickerTagWrapperClass(selectedCount: number): string;
|
|
5
|
+
export declare function personToSelectOption(person: PersonValue): SelectOption;
|
|
6
|
+
export declare function findPerson(people: PersonValue[], name: string): PersonValue;
|
|
7
|
+
//# sourceMappingURL=people-picker-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"people-picker-helpers.d.ts","sourceRoot":"","sources":["../../../src/components/PeoplePicker/people-picker-helpers.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAsC,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAA;AA8BvF,eAAO,MAAM,mCAAmC,wFAAqE,CAAA;AAGrH,wBAAgB,8BAA8B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAK5E;AAYD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAQtE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAE3E"}
|