@qijenchen/design-system 0.1.0-beta.85 → 0.1.0-beta.86
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/AGENTS.md +210 -0
- package/CLAUDE.md +17 -191
- package/cli-init.mjs +30 -2
- package/dist/components/Accordion/accordion.d.ts +2 -2
- package/dist/components/Accordion/accordion.d.ts.map +1 -1
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Avatar/avatar.js +1 -1
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button-group.d.ts +2 -2
- package/dist/components/Button/button-group.d.ts.map +1 -1
- package/dist/components/Button/button-group.js +2 -2
- package/dist/components/Button/button-group.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -1
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +1 -1
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts +14 -8
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +64 -37
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox-group.js +21 -14
- package/dist/components/Checkbox/checkbox-group.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +2 -2
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +49 -10
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +15 -6
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +13 -7
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +11 -2
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts +5 -5
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +41 -38
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +1 -17
- package/dist/components/DataTable/column-types.d.ts.map +1 -1
- package/dist/components/DataTable/column-types.js.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +3 -4
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +2 -2
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +44 -32
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +3 -3
- package/dist/components/DatePicker/date-picker.js +4 -4
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.d.ts +3 -3
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
- package/dist/components/DescriptionList/description-list.js +6 -6
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +2 -2
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +16 -10
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-types.d.ts +2 -2
- package/dist/components/Field/field-types.d.ts.map +1 -1
- package/dist/components/Field/field-types.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +20 -4
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +30 -31
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +25 -3
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/use-form-validation.d.ts +1 -1
- package/dist/components/Field/use-form-validation.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +2 -5
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +5 -1
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +2 -1
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts +2 -2
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +4 -2
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
- package/dist/components/InlineEdit/inline-edit.js +104 -62
- package/dist/components/InlineEdit/inline-edit.js.map +1 -1
- package/dist/components/Input/input.d.ts +1 -1
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +6 -6
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +5 -5
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +3 -3
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +17 -1
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +7 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +1 -1
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +12 -1
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +7 -5
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +1 -1
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +3 -3
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +1 -1
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/rating.d.ts.map +1 -1
- package/dist/components/Rating/rating.js +4 -0
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/select.d.ts +16 -6
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +17 -5
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +17 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +17 -3
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
- package/dist/components/SelectionControl/boolean-value.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +2 -2
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +1 -1
- package/dist/components/Sidebar/sidebar.js +2 -2
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +6 -3
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts +6 -4
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +19 -5
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +4 -4
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -1
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +73 -23
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/tag.d.ts +3 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +2 -2
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +4 -4
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +15 -15
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +4 -4
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +8 -5
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/tooltip.js +27 -23
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +16 -0
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/drag-visual.d.ts +2 -2
- package/dist/lib/drag-visual.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +21 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.d.ts +3 -3
- package/dist/tokens/categorical-color.d.ts.map +1 -1
- package/dist/tokens/categorical-color.js +2 -2
- package/dist/tokens/categorical-color.js.map +1 -1
- package/ds-canonical/fork/AGENTS.md +213 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
- package/ds-canonical/fork/codex/hooks.json +16 -0
- package/ds-canonical/fork/governance.lock +22 -7
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/fork/manifest.json +10 -1
- package/ds-canonical/fork/preamble.md +3 -2
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
- package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
- package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
- package/ds-canonical/references/certified-surfaces.md +20 -0
- package/ds-canonical/references/preflight-gate-baseline.json +5 -0
- package/ds-canonical/references/principle-dim-map.json +20 -2
- package/ds-canonical/references/props-naming.md +2 -1
- package/ds-canonical/references/ssot-index.md +2 -2
- package/ds-canonical/references/story-baseline-registry.json +2 -2
- package/ds-canonical/rules/story-rules.md +1 -1
- package/ds-canonical/rules/ui-development.md +2 -1
- package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
- package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
- package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
- package/ds-story-manifest.json +21 -21
- package/llms-full.txt +3 -3
- package/llms.txt +1 -1
- package/package.json +2 -1
- package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
- package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
- package/src/components/Accordion/accordion.spec.md +10 -1
- package/src/components/Accordion/accordion.stories.tsx +10 -5
- package/src/components/Accordion/accordion.tsx +7 -2
- package/src/components/Alert/alert.principles.stories.tsx +2 -8
- package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
- package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
- package/src/components/AppShell/app-shell.spec.md +4 -0
- package/src/components/AppShell/app-shell.stories.tsx +4 -5
- package/src/components/Avatar/avatar.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -2
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
- package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
- package/src/components/Button/button-group.tsx +4 -4
- package/src/components/Button/button.anatomy.stories.tsx +26 -7
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.stories.tsx +22 -28
- package/src/components/Button/button.tsx +2 -1
- package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
- package/src/components/Calendar/calendar.spec.md +1 -1
- package/src/components/Carousel/carousel.spec.md +17 -1
- package/src/components/Carousel/carousel.tsx +93 -42
- package/src/components/Checkbox/checkbox-group.tsx +26 -15
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
- package/src/components/Checkbox/checkbox.spec.md +12 -3
- package/src/components/Checkbox/checkbox.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.tsx +79 -19
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
- package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
- package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
- package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
- package/src/components/Combobox/combobox.spec.md +6 -2
- package/src/components/Combobox/combobox.stories.tsx +9 -36
- package/src/components/Combobox/combobox.tsx +42 -27
- package/src/components/Command/command.spec.md +3 -3
- package/src/components/Command/command.tsx +9 -2
- package/src/components/DataTable/cell-registry.tsx +75 -76
- package/src/components/DataTable/column-types.ts +4 -17
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
- package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
- package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
- package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
- package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
- package/src/components/DataTable/data-table.css +2 -3
- package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
- package/src/components/DataTable/data-table.spec.md +7 -7
- package/src/components/DataTable/data-table.stories.tsx +39 -29
- package/src/components/DataTable/data-table.tsx +90 -67
- package/src/components/DataTable/filter-operators.spec.md +2 -0
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
- package/src/components/DatePicker/date-picker.spec.md +9 -9
- package/src/components/DatePicker/date-picker.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.tsx +13 -13
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +12 -12
- package/src/components/DescriptionList/description-list.stories.tsx +3 -3
- package/src/components/DescriptionList/description-list.tsx +10 -10
- package/src/components/Dialog/dialog.tsx +4 -1
- package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
- package/src/components/Field/field-context.ts +17 -11
- package/src/components/Field/field-controls.spec.md +44 -37
- package/src/components/Field/field-types.ts +14 -12
- package/src/components/Field/field-wrapper.tsx +59 -43
- package/src/components/Field/field.anatomy.stories.tsx +6 -6
- package/src/components/Field/field.principles.stories.tsx +5 -28
- package/src/components/Field/field.spec.md +4 -4
- package/src/components/Field/field.stories.tsx +103 -72
- package/src/components/Field/field.tsx +36 -4
- package/src/components/Field/form-validation.spec.md +2 -0
- package/src/components/Field/use-form-validation.ts +1 -1
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
- package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
- package/src/components/FileItem/file-item.tsx +10 -8
- package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
- package/src/components/FileUpload/file-upload.spec.md +3 -2
- package/src/components/FileUpload/file-upload.tsx +5 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.spec.md +1 -1
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.tsx +3 -2
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
- package/src/components/HoverCard/hover-card.spec.md +2 -2
- package/src/components/HoverCard/hover-card.tsx +4 -2
- package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
- package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
- package/src/components/InlineEdit/inline-edit.spec.md +71 -46
- package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
- package/src/components/InlineEdit/inline-edit.tsx +211 -125
- package/src/components/Input/input.anatomy.stories.tsx +15 -15
- package/src/components/Input/input.principles.stories.tsx +3 -3
- package/src/components/Input/input.spec.md +4 -4
- package/src/components/Input/input.stories.tsx +3 -3
- package/src/components/Input/input.tsx +13 -13
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.spec.md +6 -2
- package/src/components/LinkInput/link-input.stories.tsx +8 -8
- package/src/components/LinkInput/link-input.tsx +21 -19
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.tsx +8 -2
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
- package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.spec.md +6 -6
- package/src/components/NumberInput/number-input.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.tsx +17 -5
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
- package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
- package/src/components/PeoplePicker/people-picker.tsx +39 -20
- package/src/components/PeoplePicker/person-display.tsx +3 -3
- package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
- package/src/components/Popover/popover.principles.stories.tsx +49 -28
- package/src/components/Popover/popover.spec.md +4 -2
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
- package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
- package/src/components/README.md +1 -0
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
- package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
- package/src/components/RadioGroup/radio-group.tsx +19 -14
- package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
- package/src/components/Rating/rating.principles.stories.tsx +3 -3
- package/src/components/Rating/rating.spec.md +2 -2
- package/src/components/Rating/rating.stories.tsx +4 -18
- package/src/components/Rating/rating.tsx +5 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +5 -2
- package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
- package/src/components/SegmentedControl/segmented-control.tsx +6 -3
- package/src/components/Select/select.anatomy.stories.tsx +13 -7
- package/src/components/Select/select.principles.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +9 -1
- package/src/components/Select/select.stories.tsx +41 -27
- package/src/components/Select/select.tsx +44 -26
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
- package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
- package/src/components/SelectMenu/select-menu.tsx +38 -5
- package/src/components/SelectionControl/boolean-value.tsx +2 -2
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
- package/src/components/Separator/separator.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
- package/src/components/Sheet/sheet.tsx +4 -1
- package/src/components/Sidebar/sidebar.tsx +1 -1
- package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
- package/src/components/Slider/slider.principles.stories.tsx +6 -6
- package/src/components/Slider/slider.spec.md +13 -1
- package/src/components/Slider/slider.stories.tsx +44 -32
- package/src/components/Slider/slider.tsx +13 -4
- package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +4 -2
- package/src/components/Steps/steps.stories.tsx +4 -56
- package/src/components/Steps/steps.tsx +31 -7
- package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Switch/switch.spec.md +4 -4
- package/src/components/Switch/switch.stories.tsx +3 -3
- package/src/components/Switch/switch.tsx +16 -10
- package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
- package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
- package/src/components/Tabs/tabs.spec.md +5 -2
- package/src/components/Tabs/tabs.stories.tsx +36 -44
- package/src/components/Tabs/tabs.tsx +101 -36
- package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
- package/src/components/Tag/tag.principles.stories.tsx +4 -4
- package/src/components/Tag/tag.spec.md +3 -1
- package/src/components/Tag/tag.tsx +5 -3
- package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
- package/src/components/Textarea/textarea.spec.md +5 -5
- package/src/components/Textarea/textarea.tsx +24 -24
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
- package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
- package/src/components/TimePicker/time-picker.spec.md +6 -5
- package/src/components/TimePicker/time-picker.stories.tsx +3 -3
- package/src/components/TimePicker/time-picker.tsx +24 -14
- package/src/components/Toast/toast.principles.stories.tsx +1 -1
- package/src/components/Toast/toast.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
- package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.spec.md +9 -3
- package/src/components/Tooltip/tooltip.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.tsx +12 -2
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
- package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
- package/src/components/TreeView/tree-view.spec.md +8 -6
- package/src/components/TreeView/tree-view.stories.tsx +9 -43
- package/src/components/TreeView/tree-view.tsx +36 -0
- package/src/index.ts +13 -10
- package/src/lib/drag-visual.ts +2 -2
- package/src/lib/utils.ts +19 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
- package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
- package/src/tokens/categorical-color.ts +5 -5
- package/src/tokens/color/color.spec.md +4 -4
- package/src/tokens/color/primitives.css +9 -2
- package/src/tokens/opacity/opacity.spec.md +1 -1
- package/src/tokens/orphan-tokens.spec.md +1 -1
- package/src/tokens/typography/typography.spec.md +2 -0
- package/src/tokens/uiSize/uiSize.css +5 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
//
|
|
5
5
|
// 對齊 M17 SSOT consolidation + audit recommendation:
|
|
6
6
|
// 原 `renderTypedValue` switch + `EditableCellContent` switch 兩條平行 type-switch 已 collapse
|
|
7
|
-
// 為**一張 type → cell component** registry。每個 cell component 同時處理
|
|
7
|
+
// 為**一張 type → cell component** registry。每個 cell component 同時處理 view / edit mode,
|
|
8
8
|
// 靠底層 Field control 的 `mode` prop 切換。
|
|
9
9
|
//
|
|
10
10
|
// 設計原則:
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import * as React from 'react'
|
|
20
20
|
import type { ComponentType } from 'react'
|
|
21
21
|
import { Pencil } from 'lucide-react'
|
|
22
|
-
import { cn } from '@/lib/utils'
|
|
22
|
+
import { cn, lineClampClass } from '@/lib/utils'
|
|
23
23
|
import type { ColumnType } from './column-types'
|
|
24
24
|
import { Input as InputPublic } from '@/design-system/components/Input/input'
|
|
25
25
|
import { Textarea as TextareaPublic } from '@/design-system/components/Textarea/textarea'
|
|
@@ -55,7 +55,7 @@ const Checkbox = CheckboxPublic as WithFieldVariantInternal<typeof CheckboxPubli
|
|
|
55
55
|
|
|
56
56
|
// ── Types ────────────────────────────────────────────────────────────────────
|
|
57
57
|
|
|
58
|
-
export type CellMode = '
|
|
58
|
+
export type CellMode = 'view' | 'edit'
|
|
59
59
|
export type CellSize = 'sm' | 'md' | 'lg'
|
|
60
60
|
|
|
61
61
|
export interface CellComponentProps {
|
|
@@ -65,13 +65,13 @@ export interface CellComponentProps {
|
|
|
65
65
|
meta: Record<string, any>
|
|
66
66
|
mode: CellMode
|
|
67
67
|
size: CellSize
|
|
68
|
+
/** 該 cell 的 accessible name(= 欄標題)。naked Field 控件在 cell 內無 FieldLabel,
|
|
69
|
+
* 漏此名 → editor 成無名控件(axe aria-input-field-name / select-name)。由 renderCellContent
|
|
70
|
+
* 從 columnDef.header 解析後注入。對齊 AG Grid / MUI X「editor aria-label = column headerName」。 */
|
|
71
|
+
ariaLabel?: string
|
|
68
72
|
autoRowHeight: boolean
|
|
69
73
|
/** 該 cell 是否可編。replaces 舊 `meta._editable` 私有 flag(Phase C M1 hack 移除)。 */
|
|
70
74
|
isEditable?: boolean
|
|
71
|
-
/** 2026-05-13:cell 是否 disabled(state overlay,orthogonal to display/edit lifecycle)。
|
|
72
|
-
* per codex Q3 verdict:不擴 CellMode='disabled',加 prop。各 Cell function 收 true 時
|
|
73
|
-
* 傳 `mode='disabled'` 給 inner Field control,各 Field 內部走具體 disabled token(非 wrapper opacity)。 */
|
|
74
|
-
isDisabled?: boolean
|
|
75
75
|
/** Cell 進 edit mode → 提交新值(blur / Enter / option select 都觸發)— 提交後**自動 exit edit**。
|
|
76
76
|
* 適用 single-shot commit:string / number / select(single)/ person(single)/ date / time / boolean / url。 */
|
|
77
77
|
onCommit?: (next: unknown) => void
|
|
@@ -112,44 +112,41 @@ function makeKeyHandler(
|
|
|
112
112
|
|
|
113
113
|
const sizeForInput = (size: CellSize): CellSize => size
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* 非 wrapper blanket opacity-disabled 逃生艙(per color.spec.md:729)。 */
|
|
119
|
-
const displayOrDisabled = (isDisabled?: boolean): 'display' | 'disabled' =>
|
|
120
|
-
isDisabled ? 'disabled' : 'display'
|
|
115
|
+
// 2026-07-16 round16:cell「disabled」態廢除(世界級 grid 無 disabled cell — MUI X / AG Grid /
|
|
116
|
+
// Handsontable 皆只有 editable/readonly;meta.disabled 全庫 0 消費)。cell view 態一律 mode="view",
|
|
117
|
+
// 鎖定用 `editable:(row)=>false` 閘(= isCellEditable 模型)。原 displayOrDisabled helper 已移除。
|
|
121
118
|
|
|
122
119
|
// ── Cell Components ──────────────────────────────────────────────────────────
|
|
123
120
|
|
|
124
|
-
function StringCell({ value, meta, mode, size,
|
|
121
|
+
function StringCell({ value, meta, mode, size, autoRowHeight, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {
|
|
125
122
|
// 2026-05-14 I9 fix(per codex+Layer A 共識):meta.maxLines opt-in line-clamp。
|
|
126
|
-
//
|
|
123
|
+
// view autoRow 用 Tailwind arbitrary line-clamp 支援 N rows;edit textarea field-sizing
|
|
127
124
|
// 已 auto-grow to content,natural match clamp。
|
|
128
125
|
// 2026-05-16 Round 5 audit Dim 27 fix:narrow type 取代 `as any` cast。
|
|
129
126
|
const maxLines: number | undefined = (meta as { maxLines?: number } | undefined)?.maxLines
|
|
130
|
-
const clampClass =
|
|
127
|
+
const clampClass = autoRowHeight ? lineClampClass(maxLines) : undefined
|
|
131
128
|
// string type canonical(2026-05-05 v2 user 校正:input space ≥ display space):
|
|
132
|
-
// - autoRowHeight: Textarea(
|
|
129
|
+
// - autoRowHeight: Textarea(view + edit)— view wrap text 撐高 row,edit textarea
|
|
133
130
|
// 多行輸入、`!h-full` 填 cell。對齊 Notion long-text cell canonical。
|
|
134
|
-
// - fixed: Input(
|
|
135
|
-
// 高 = cell 高 = h-field-md,文字位置
|
|
131
|
+
// - fixed: Input(view + edit)— 單行 truncate view,單行 input edit;Field naked intrinsic
|
|
132
|
+
// 高 = cell 高 = h-field-md,文字位置 view↔edit 完全一致。對齊 AG Grid / Material X-Grid。
|
|
136
133
|
// - autoRowHeight 是 table 框架決定(consumer 不需 per-column 設 meta.wrap)。
|
|
137
134
|
// - 互動(Textarea):Esc cancel / Cmd|Ctrl+Enter commit / blur commit;Enter 保留換行
|
|
138
135
|
// - 互動(Input):Esc cancel / Enter commit / blur commit
|
|
139
136
|
const v = value != null ? String(value) : ''
|
|
140
|
-
if (mode === '
|
|
137
|
+
if (mode === 'view') {
|
|
141
138
|
// size 必傳:DataTable cell 字級隨 size 變(sm/md text-body / lg text-body-lg),
|
|
142
139
|
// 對齊 Field family size→font SSOT(field-wrapper.tsx:60-64)。漏傳 → fallback md → lg 表格
|
|
143
140
|
// 字卡 14px 跟 Select/Date 等有傳 size 的 cell 不一致(2026-06-08 user 抓 frozen string 欄字偏小)。
|
|
144
141
|
return autoRowHeight
|
|
145
|
-
? <Textarea variant="naked" mode=
|
|
146
|
-
: <Input variant="naked" mode=
|
|
142
|
+
? <Textarea variant="naked" mode="view" value={v} size={size} className={clampClass} aria-label={ariaLabel} />
|
|
143
|
+
: <Input variant="naked" mode="view" value={v} size={size} aria-label={ariaLabel} />
|
|
147
144
|
}
|
|
148
145
|
if (autoRowHeight) {
|
|
149
146
|
// 2026-05-14 I8 fix(per codex verdict + user 抓「edit cell shrink」):
|
|
150
147
|
// 原 `wrapRows = value.length / 40` 字元估算不準(對應實際 column width 不同
|
|
151
148
|
// → cell 進 edit shrink)。改 CSS `field-sizing: content`(Chrome 123+ / FF 122+ /
|
|
152
|
-
// Safari 17+)讓 textarea 自動 grow to content,匹配
|
|
149
|
+
// Safari 17+)讓 textarea 自動 grow to content,匹配 view wrap 真實高度。
|
|
153
150
|
// Fallback rows 仍保留給舊 browser(rows attr 在 field-sizing 支援時被覆蓋)。
|
|
154
151
|
const newlineRows = (v.match(/\n/g) || []).length + 1
|
|
155
152
|
const wrapRows = Math.ceil(v.length / 40)
|
|
@@ -158,6 +155,7 @@ function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onComm
|
|
|
158
155
|
<Textarea
|
|
159
156
|
autoFocus
|
|
160
157
|
variant="naked"
|
|
158
|
+
aria-label={ariaLabel}
|
|
161
159
|
size={sizeForInput(size)}
|
|
162
160
|
rows={estimateRows}
|
|
163
161
|
defaultValue={v}
|
|
@@ -180,6 +178,7 @@ function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onComm
|
|
|
180
178
|
<Input
|
|
181
179
|
autoFocus
|
|
182
180
|
variant="naked"
|
|
181
|
+
aria-label={ariaLabel}
|
|
183
182
|
size={sizeForInput(size)}
|
|
184
183
|
defaultValue={v}
|
|
185
184
|
onChange={(e) => onDraft?.(e.target.value)}
|
|
@@ -189,20 +188,21 @@ function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onComm
|
|
|
189
188
|
)
|
|
190
189
|
}
|
|
191
190
|
|
|
192
|
-
function NumberCell({ value, meta, mode, size,
|
|
191
|
+
function NumberCell({ value, meta, mode, size, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {
|
|
193
192
|
// currency 透過 columnType-aware prefix:type='currency' → 預設 '$'(可 override)
|
|
194
193
|
const isCurrency = meta?.type === 'currency'
|
|
195
194
|
const prefix = isCurrency ? (meta?.prefix ?? '$') : meta?.prefix
|
|
196
|
-
// React #310 fix:useState 必在
|
|
197
|
-
// 在
|
|
195
|
+
// React #310 fix:useState 必在 view early-return 前無條件呼叫。同一 memo'd cell instance
|
|
196
|
+
// 在 view↔edit 切換時被重用(render site 無 key={mode},data-table.tsx:1352),hook 數量不可變,
|
|
198
197
|
// 否則 Rules of Hooks violation → React #310 crash。對齊 combobox/select hoist pattern。
|
|
199
198
|
const initial = typeof value === 'number' ? value : null
|
|
200
199
|
const [localValue, setLocalValue] = React.useState<number | null>(initial)
|
|
201
|
-
if (mode === '
|
|
200
|
+
if (mode === 'view') {
|
|
202
201
|
return (
|
|
203
202
|
<NumberInput
|
|
204
203
|
variant="naked"
|
|
205
|
-
mode=
|
|
204
|
+
mode="view"
|
|
205
|
+
aria-label={ariaLabel}
|
|
206
206
|
value={value as number | null}
|
|
207
207
|
// size 必傳(同 StringCell)— currency/number cell 字級隨 DataTable size 變,對齊 Field SSOT。
|
|
208
208
|
size={size}
|
|
@@ -215,13 +215,14 @@ function NumberCell({ value, meta, mode, size, isDisabled, onCommit, onCancel, o
|
|
|
215
215
|
}
|
|
216
216
|
// Edit mode value pre-fill canonical(2026-05-05):NumberInput edit 強制 controlled
|
|
217
217
|
// (`value={value ?? ''}`)— 若 NumberCell 以 `defaultValue` 傳入,NumberInput value=undefined → ''
|
|
218
|
-
// empty。對齊 cell-as-input「edit mode 自動帶入
|
|
218
|
+
// empty。對齊 cell-as-input「edit mode 自動帶入 view 值」(對齊 Notion / Airtable 共識),
|
|
219
219
|
// 改用 local state controlled。User typing → setLocalValue;blur/Enter → onCommit(localValue)。
|
|
220
|
-
// (initial + useState 已 hoist 到
|
|
220
|
+
// (initial + useState 已 hoist 到 view-return 前 — 見上方 React #310 fix。)
|
|
221
221
|
return (
|
|
222
222
|
<NumberInput
|
|
223
223
|
autoFocus
|
|
224
224
|
variant="naked"
|
|
225
|
+
aria-label={ariaLabel}
|
|
225
226
|
size={sizeForInput(size)}
|
|
226
227
|
value={localValue}
|
|
227
228
|
onChange={(v) => { setLocalValue(v); onDraft?.(v) }}
|
|
@@ -244,25 +245,25 @@ function NumberCell({ value, meta, mode, size, isDisabled, onCommit, onCancel, o
|
|
|
244
245
|
// (對齊 Airtable / Notion canonical:click 外即關)。
|
|
245
246
|
const dismissOnClose = (onCancel?: () => void) => (open: boolean) => { if (!open) onCancel?.() }
|
|
246
247
|
|
|
247
|
-
// Mode-keyed remount canonical(2026-05-05):
|
|
248
|
-
// position 會重用 instance,導致 `useState(defaultOpen)` 只在首次 mount 跑(那時 mode='
|
|
248
|
+
// Mode-keyed remount canonical(2026-05-05):view↔edit 切換時,因 React reconciliation 同 type 同
|
|
249
|
+
// position 會重用 instance,導致 `useState(defaultOpen)` 只在首次 mount 跑(那時 mode='view'
|
|
249
250
|
// defaultOpen 沒給→預設 false)。後續 mode='edit' 即使傳 defaultOpen=true 也無效。
|
|
250
251
|
// Fix:`key={mode}` 強制 React unmount + remount,每次切 mode 都重跑 useState init。
|
|
251
|
-
// 對齊 Notion / Airtable cell-as-input「
|
|
252
|
+
// 對齊 Notion / Airtable cell-as-input「view 跟 edit 是不同 mount cycle」語義。
|
|
252
253
|
|
|
253
|
-
function DateCell({ value, meta, mode, size,
|
|
254
|
-
if (mode === '
|
|
254
|
+
function DateCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {
|
|
255
|
+
if (mode === 'view') {
|
|
255
256
|
return (
|
|
256
257
|
<DatePicker
|
|
257
|
-
key="
|
|
258
|
+
key="view"
|
|
258
259
|
variant="naked"
|
|
259
|
-
mode=
|
|
260
|
+
mode="view"
|
|
260
261
|
value={value as string | null}
|
|
261
262
|
size={size}
|
|
262
263
|
formatOptions={meta?.formatOptions}
|
|
263
264
|
locale={meta?.locale}
|
|
264
265
|
// 2026-07-08 user 拍板 A 案(推翻 2026-05-10/06-26 兩次拍板,per 6 家 benchmark 6/6 共識
|
|
265
|
-
// Ant/MUI X/AG Grid/Atlaskit/Notion/Airtable:
|
|
266
|
+
// Ant/MUI X/AG Grid/Atlaskit/Notion/Airtable:view 態零恆顯型別 icon;editable
|
|
266
267
|
// affordance 統一 = hover outline(field.spec.md L4)。showDisplayEndIcon 不再傳
|
|
267
268
|
//(prop 保留為 spreadsheet-flavored 消費端 opt-in 逃生門,見 field.spec.md L6)。
|
|
268
269
|
/>
|
|
@@ -283,18 +284,18 @@ function DateCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: C
|
|
|
283
284
|
)
|
|
284
285
|
}
|
|
285
286
|
|
|
286
|
-
function TimeCell({ value, meta, mode, size,
|
|
287
|
-
if (mode === '
|
|
287
|
+
function TimeCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {
|
|
288
|
+
if (mode === 'view') {
|
|
288
289
|
return (
|
|
289
290
|
<TimePicker
|
|
290
|
-
key="
|
|
291
|
+
key="view"
|
|
291
292
|
variant="naked"
|
|
292
|
-
mode=
|
|
293
|
+
mode="view"
|
|
293
294
|
value={value as string | null}
|
|
294
295
|
size={size}
|
|
295
296
|
formatOptions={meta?.formatOptions}
|
|
296
297
|
locale={meta?.locale}
|
|
297
|
-
// showDisplayEndIcon 不傳 — 2026-07-08 A 案:
|
|
298
|
+
// showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
|
|
298
299
|
/>
|
|
299
300
|
)
|
|
300
301
|
}
|
|
@@ -314,22 +315,22 @@ function TimeCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: C
|
|
|
314
315
|
)
|
|
315
316
|
}
|
|
316
317
|
|
|
317
|
-
function SelectCell({ value, meta, mode, size,
|
|
318
|
-
//
|
|
318
|
+
function SelectCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {
|
|
319
|
+
// View canonical(2026-05-05):cell IS variant,default plain text(no Tag pill 疊在 cell border 內)。
|
|
319
320
|
// Consumer 可在 column meta.display='tag' opt-in 內容導向的 Tag 視覺(category 含色彩標籤等)。
|
|
320
321
|
// 對齊 JTable / AG Grid「renderer/editor 視覺一致」canonical。
|
|
321
322
|
const displayMode = (meta?.display as 'plain' | 'tag' | undefined) ?? 'plain'
|
|
322
|
-
if (mode === '
|
|
323
|
+
if (mode === 'view') {
|
|
323
324
|
return (
|
|
324
325
|
<Select
|
|
325
|
-
key="
|
|
326
|
+
key="view"
|
|
326
327
|
variant="naked"
|
|
327
|
-
mode=
|
|
328
|
+
mode="view"
|
|
328
329
|
value={value as string | null}
|
|
329
330
|
options={meta?.options ?? []}
|
|
330
331
|
size={size}
|
|
331
332
|
display={displayMode}
|
|
332
|
-
// showDisplayEndIcon 不傳 — 2026-07-08 A 案:
|
|
333
|
+
// showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
|
|
333
334
|
selectedItemRenderer={meta?.selectedItemRenderer} // 2026-07-08 WM 戰役:status 類彩色 cell 顯示通道
|
|
334
335
|
/>
|
|
335
336
|
)
|
|
@@ -354,19 +355,19 @@ function SelectCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }:
|
|
|
354
355
|
)
|
|
355
356
|
}
|
|
356
357
|
|
|
357
|
-
function MultiSelectCell({ value, meta, mode, size,
|
|
358
|
+
function MultiSelectCell({ value, meta, mode, size, autoRowHeight, onCommitLive, onCancel }: CellComponentProps) {
|
|
358
359
|
const wrap = autoRowHeight && meta?.wrap === true
|
|
359
|
-
if (mode === '
|
|
360
|
+
if (mode === 'view') {
|
|
360
361
|
return (
|
|
361
362
|
<Combobox
|
|
362
|
-
key="
|
|
363
|
+
key="view"
|
|
363
364
|
variant="naked"
|
|
364
|
-
mode=
|
|
365
|
+
mode="view"
|
|
365
366
|
value={(value as string[] | null) ?? []}
|
|
366
367
|
options={meta?.options ?? []}
|
|
367
368
|
wrap={wrap}
|
|
368
369
|
size={size}
|
|
369
|
-
// showDisplayEndIcon 不傳 — 2026-07-08 A 案:
|
|
370
|
+
// showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
|
|
370
371
|
/>
|
|
371
372
|
)
|
|
372
373
|
}
|
|
@@ -386,10 +387,10 @@ function MultiSelectCell({ value, meta, mode, size, isDisabled, autoRowHeight, o
|
|
|
386
387
|
)
|
|
387
388
|
}
|
|
388
389
|
|
|
389
|
-
function PersonCell({ value, mode, size,
|
|
390
|
-
if (mode === '
|
|
391
|
-
// 2026-07-08 A 案:
|
|
392
|
-
return <PeoplePicker key="
|
|
390
|
+
function PersonCell({ value, mode, size, onCommit, onCancel, meta }: CellComponentProps) {
|
|
391
|
+
if (mode === 'view') {
|
|
392
|
+
// 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
|
|
393
|
+
return <PeoplePicker key="view" variant="naked" mode="view" value={value as PersonValue | null} size={size} />
|
|
393
394
|
}
|
|
394
395
|
return (
|
|
395
396
|
<PeoplePicker
|
|
@@ -406,10 +407,10 @@ function PersonCell({ value, mode, size, isDisabled, onCommit, onCancel, meta }:
|
|
|
406
407
|
)
|
|
407
408
|
}
|
|
408
409
|
|
|
409
|
-
function MultiPersonCell({ value, mode, size,
|
|
410
|
-
if (mode === '
|
|
411
|
-
// 2026-07-08 A 案:
|
|
412
|
-
return <PeoplePicker key="
|
|
410
|
+
function MultiPersonCell({ value, mode, size, onCommitLive, onCancel, meta }: CellComponentProps) {
|
|
411
|
+
if (mode === 'view') {
|
|
412
|
+
// 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
|
|
413
|
+
return <PeoplePicker key="view" variant="naked" mode="view" value={(value as PersonValue[]) ?? []} size={size} />
|
|
413
414
|
}
|
|
414
415
|
// Multi 用 onCommitLive(commit 但不 exit edit)— 每勾一人即時生效,popover 持續開
|
|
415
416
|
// 直到點外面;onOpenChange(false) → onCancel exit edit。對齊 multiSelect canonical。
|
|
@@ -427,14 +428,12 @@ function MultiPersonCell({ value, mode, size, isDisabled, onCommitLive, onCancel
|
|
|
427
428
|
)
|
|
428
429
|
}
|
|
429
430
|
|
|
430
|
-
function BooleanCell({ value, mode, meta, size, isEditable,
|
|
431
|
-
// boolean 不分 read/edit mode —
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
// 走 display branch,Checkbox 拿 disabled mode + 不接 onCheckedChange。
|
|
435
|
-
if (mode === 'display' && (!isEditable || isDisabled)) {
|
|
431
|
+
function BooleanCell({ value, mode, meta, size, isEditable, onCommit }: CellComponentProps) {
|
|
432
|
+
// boolean 不分 read/edit mode — view 渲 mode='view' 純展示;editable 時直接 toggle Checkbox。
|
|
433
|
+
// 不可編(!isEditable)→ 走 view branch,Checkbox mode="view" 純展示不接 onCheckedChange。
|
|
434
|
+
if (mode === 'view' && !isEditable) {
|
|
436
435
|
// size 傳入 → boolean 值 icon(Check/X)@lg 縮放對齊其他 cell(對齊 editable 分支同 size 邏輯)
|
|
437
|
-
return <Checkbox variant="naked" size={size === 'lg' ? 'lg' : 'md'} mode=
|
|
436
|
+
return <Checkbox variant="naked" size={size === 'lg' ? 'lg' : 'md'} mode="view" checked={value === true} />
|
|
438
437
|
}
|
|
439
438
|
return (
|
|
440
439
|
<Checkbox
|
|
@@ -448,21 +447,21 @@ function BooleanCell({ value, mode, meta, size, isEditable, isDisabled, onCommit
|
|
|
448
447
|
|
|
449
448
|
/**
|
|
450
449
|
* UrlCell(2026-07-14 docblock 對齊實作):
|
|
451
|
-
*
|
|
450
|
+
* view branch = `<LinkInput mode="view">`(URL parse / hostname
|
|
452
451
|
* 顯示一致性 SSOT);editable 互動:hover 時右側出 Pencil 鈕 → 進 edit(保留 link click 語意)。
|
|
453
452
|
* edit branch = plain `<Input variant="naked">`(LinkInput edit 的 controlled value 衝突
|
|
454
453
|
* revert,詳下方 edit branch 註解);URL 驗證 deferred 到 onCommit(consumer 端 validate)。
|
|
455
454
|
*/
|
|
456
|
-
function UrlCell({ value, meta, mode, size,
|
|
457
|
-
if (mode === '
|
|
455
|
+
function UrlCell({ value, meta, mode, size, isEditable, onRequestEdit, onCommit, onCancel }: CellComponentProps) {
|
|
456
|
+
if (mode === 'view') {
|
|
458
457
|
// showDisplayEndIcon ← D path Phase 2(2026-05-08):Field naked wrapper 包 anchor,與 Input edit 同 chrome。
|
|
459
458
|
// LinkInput 此 prop = wrapper-only(無 icon,field.spec.md L6 例外)→ A 案(2026-07-08)不撤;
|
|
460
459
|
// 但修 I1:原無條件 true 違反「= isEditable」knob 等式(field-controls.spec.md cell 例外),改等式。
|
|
461
460
|
const display = (
|
|
462
|
-
<LinkInput variant="naked" mode=
|
|
461
|
+
<LinkInput variant="naked" mode="view" value={value as string | null} label={meta?.linkLabel} size={size} showDisplayEndIcon={isEditable === true} />
|
|
463
462
|
)
|
|
464
|
-
//
|
|
465
|
-
if (!isEditable
|
|
463
|
+
// 不可編 URL 不顯 Pencil affordance(純 view 顯示連結,無編輯入口)
|
|
464
|
+
if (!isEditable) return display
|
|
466
465
|
// editable read mode:hover Pencil 鈕(對齊 spec 第十二段「url:read = 連結 + Pencil」)
|
|
467
466
|
return (
|
|
468
467
|
<span className="group/cell relative flex items-center w-full"> {/* @naked-row-mode-allow: URL hover-Pencil 是 inline action 不是 value content,items-center 鎖 Pencil 對齊行高第一行(autoRow 跟 fixed 皆同視覺正確) */}
|
|
@@ -540,7 +539,7 @@ function buildCellWithSurface(Inner: ComponentType<CellComponentProps>, key: str
|
|
|
540
539
|
漏傳 size 的 cell 也自動繼承(根治「新 cell 漏傳 size」class);size primitive 不破壞 memo identity。*/}
|
|
541
540
|
<FieldSurfaceSizeProvider size={props.size}>
|
|
542
541
|
{/* 2026-07-08 user 拍板:cell 可編輯訊號經獨立 boolean context 注給 child Field controls,
|
|
543
|
-
讓 useFieldEmptyDisplay 分流「可編輯 cell 空
|
|
542
|
+
讓 useFieldEmptyDisplay 分流「可編輯 cell 空 view → 空白」vs「不可編輯 cell → '-'」。
|
|
544
543
|
boolean primitive 不破壞 memo identity(同 size context)。 */}
|
|
545
544
|
<FieldSurfaceEditableProvider isEditable={props.isEditable ?? false}>
|
|
546
545
|
<Inner {...props} />
|
|
@@ -65,7 +65,7 @@ declare module '@tanstack/react-table' {
|
|
|
65
65
|
wrap?: boolean
|
|
66
66
|
/**
|
|
67
67
|
* Max visible lines before ellipsis(2026-05-14 I9 per codex verdict + user 拍板)。
|
|
68
|
-
* Only effective when `autoRowHeight + wrap=true`。
|
|
68
|
+
* Only effective when `autoRowHeight + wrap=true`。view 用 `line-clamp-N`,edit textarea
|
|
69
69
|
* 高度 match clamp。對齊 Notion 「Truncate」row toggle / AG Grid `cellClassRules` 上限 row height。
|
|
70
70
|
* Default = undefined(無 clamp,完整 wrap)。
|
|
71
71
|
*/
|
|
@@ -162,22 +162,9 @@ declare module '@tanstack/react-table' {
|
|
|
162
162
|
* Esc cancel / blur or Enter commit。Commit 觸發 `onCellCommit`。
|
|
163
163
|
*/
|
|
164
164
|
editable?: boolean | ((row: TData) => boolean)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
* - `true`:cell 永遠 disabled
|
|
169
|
-
* - `false` / undef(default):cell normal
|
|
170
|
-
* - `(row) => boolean`:per-row 動態(e.g. row.archived 或 row.locked 才 disabled)
|
|
171
|
-
*
|
|
172
|
-
* 視覺(per `color.spec.md` `--bg-disabled` component-state token):
|
|
173
|
-
* - TD 外殼:`bg-disabled` + `cursor-not-allowed` + 抑制 hover ring
|
|
174
|
-
* - Cell content(Field family):`mode='disabled'` → 各 Field type 內部走具體 disabled token
|
|
175
|
-
* - edit entry 抑制:disabled cell 點擊不進 edit(對齊 `editable && !disabled` invariant)
|
|
176
|
-
*
|
|
177
|
-
* 跟 `editable=false` 區分:editable=false = readonly(可看不可編);disabled = 不可操作 state。
|
|
178
|
-
* 對齊 MUI X `isCellEditable` + cellClassName / AG Grid `cellClassRules` / Notion locked properties。
|
|
179
|
-
*/
|
|
180
|
-
disabled?: boolean | ((row: TData) => boolean)
|
|
165
|
+
// 2026-07-16 round16:cell `disabled` 已廢除。世界級 grid(MUI X isCellEditable / AG Grid editable /
|
|
166
|
+
// Handsontable readOnly)皆無 disabled cell 態 — 鎖定用 `editable:(row)=>false`(可看不可編、不灰化),
|
|
167
|
+
// 非 disabled 灰化態。原 `disabled?: boolean | ((row)=>boolean)` + bg-disabled TD 灰化全移除(全庫 0 消費)。
|
|
181
168
|
/**
|
|
182
169
|
* Locked column — column reorder 不可拖,Notion 「primary column」 pattern。
|
|
183
170
|
* 對齊 SKU / ID 等不可移欄位。
|
|
@@ -27,8 +27,7 @@ import { Eye, EyeOff, Lock, GripVertical, Search, RotateCcw, X as XIcon } from '
|
|
|
27
27
|
import { Button } from '@/design-system/components/Button/button'
|
|
28
28
|
import { ButtonDivider } from '@/design-system/components/Button/button-group'
|
|
29
29
|
import { Input } from '@/design-system/components/Input/input'
|
|
30
|
-
import {
|
|
31
|
-
import { PopoverHeader, PopoverFooter, PopoverTitle, PopoverClose } from '@/design-system/components/Popover/popover'
|
|
30
|
+
import { PopoverHeader, PopoverBody, PopoverFooter, PopoverTitle, PopoverClose } from '@/design-system/components/Popover/popover'
|
|
32
31
|
import { ItemPrefix, ItemLabel, ItemInlineActionButton, ROW_PADDING_BY_SIZE } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
33
32
|
import { cn } from '@/lib/utils'
|
|
34
33
|
import { DndContext, closestCenter, type DragEndEvent } from '@dnd-kit/core'
|
|
@@ -130,8 +129,19 @@ export function DataTableColumnVisibilityPanel({
|
|
|
130
129
|
onColumnOrderChange!(next)
|
|
131
130
|
}
|
|
132
131
|
|
|
132
|
+
// 2026-07-18 決策16 錯誤史(明記以免再犯):原本這個 panel 是 Fragment + fixed `ScrollArea max-h-72`,
|
|
133
|
+
// 與 sibling FilterPanel/SortManager(root-div + viewport-aware SurfaceBody)不一致。我給過**兩個都錯**
|
|
134
|
+
// 的辯護理由 —— (1)「PopoverHeader 用 -mx 負邊距、包 root 會破壞」= 錯(SurfaceHeader 用正 px-loose+border-b,
|
|
135
|
+
// 無 -mx);(2)「sibling 自刻 header 不用 primitive」= 錯(三 panel 皆消費 SurfaceHeader/PopoverHeader primitive)。
|
|
136
|
+
// 真正差異只是 body/scroll 策略。multi-agent SSOT consistency 稽核定案:**是 drift,該統一**(fixed 288px cap
|
|
137
|
+
// 在高螢幕多欄下劣於 sibling 的 viewport-adaptive;且是唯一不能當 template 複製的 panel)。故下方已改成 canonical shape。
|
|
133
138
|
return (
|
|
134
|
-
|
|
139
|
+
// 決策16 定案(2026-07-18,SSOT consistency 稽核後):對齊 sibling FilterPanel/SortManager 的
|
|
140
|
+
// overlay-surface canonical shape —— root `<div flex flex-col h-full min-h-0>`(M25 viewport-aware
|
|
141
|
+
// scroll chain)+ viewport-adaptive `PopoverBody`(取代原 fixed `ScrollArea max-h-72`)。三個
|
|
142
|
+
// DataTable state-panel 收斂成同一形狀,body 隨視窗高度自適應(高螢幕多欄不再硬卡 288px)。
|
|
143
|
+
// 寬度仍由 consumer 的 `<PopoverContent w-72>` 提供(panel root w-full 撐滿)。
|
|
144
|
+
<div className="flex flex-col h-full min-h-0 w-full">
|
|
135
145
|
<PopoverHeader hideClose>
|
|
136
146
|
<div className="flex items-center gap-1 w-full min-w-0">
|
|
137
147
|
<PopoverTitle className="flex-1">欄位顯示</PopoverTitle>
|
|
@@ -151,17 +161,20 @@ export function DataTableColumnVisibilityPanel({
|
|
|
151
161
|
</div>
|
|
152
162
|
</PopoverHeader>
|
|
153
163
|
{searchable && (
|
|
154
|
-
<div className="px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)]">
|
|
164
|
+
<div className="shrink-0 px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)]">
|
|
155
165
|
<Input
|
|
156
166
|
size="md"
|
|
157
167
|
placeholder="搜尋欄位…"
|
|
168
|
+
aria-label="搜尋欄位"
|
|
158
169
|
value={search}
|
|
159
170
|
onChange={(e) => setSearch(e.target.value)}
|
|
160
171
|
startIcon={Search}
|
|
161
172
|
/>
|
|
162
173
|
</div>
|
|
163
174
|
)}
|
|
164
|
-
|
|
175
|
+
{/* viewport-adaptive body(List-as-region idiom:PopoverBody !px-0 !py-0 撤 chrome padding,
|
|
176
|
+
內層 py-2 給垂直呼吸、row 自帶 px-loose 水平 padding)。取代原 fixed ScrollArea max-h-72。 */}
|
|
177
|
+
<PopoverBody className="!px-0 !py-0">
|
|
165
178
|
<div className="py-2 flex flex-col" style={{ '--item-prefix-slot': '16px' } as React.CSSProperties}>
|
|
166
179
|
{dndEnabled ? (
|
|
167
180
|
<DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
|
@@ -196,13 +209,13 @@ export function DataTableColumnVisibilityPanel({
|
|
|
196
209
|
))
|
|
197
210
|
)}
|
|
198
211
|
</div>
|
|
199
|
-
</
|
|
212
|
+
</PopoverBody>
|
|
200
213
|
<PopoverFooter className="justify-start">
|
|
201
214
|
<Button variant="tertiary" size="sm" onClick={handleBulkToggle}>
|
|
202
215
|
{allVisible ? '全部隱藏' : '顯示全部'}
|
|
203
216
|
</Button>
|
|
204
217
|
</PopoverFooter>
|
|
205
|
-
|
|
218
|
+
</div>
|
|
206
219
|
)
|
|
207
220
|
}
|
|
208
221
|
|
|
@@ -126,8 +126,9 @@ const newEmptyGroup = (): FilterGroup => ({
|
|
|
126
126
|
// ── Component Props ─────────────────────────────────────────────────────
|
|
127
127
|
|
|
128
128
|
export interface DataTableFilterPanelProps<TData> {
|
|
129
|
-
|
|
130
|
-
mode
|
|
129
|
+
// 2026-07-18 決策17:移除獨立 `mode` prop(單一真相源 = `value.mode` discriminant)——
|
|
130
|
+
// 舊設計 mode + value.mode 兩來源型別允許矛盾(mode='nested' 配 flat value → CTA 錯文案 + 死操作);
|
|
131
|
+
// 無外部消費者傳 mode(grep 0),全由 value.mode 推導。對齊 MUI X GridFilterModel / AG Grid 單一 model。
|
|
131
132
|
/** 可被 filter 的 columns */
|
|
132
133
|
columns: ColumnDef<TData, any>[]
|
|
133
134
|
/** 當前 FilterTree(controlled) */
|
|
@@ -151,7 +152,6 @@ export interface DataTableFilterPanelProps<TData> {
|
|
|
151
152
|
|
|
152
153
|
// 內部 fn — generic + ref 轉發。export 走 cast(對齊 DataTable 同 pattern)
|
|
153
154
|
function DataTableFilterPanelInner<TData>({
|
|
154
|
-
mode,
|
|
155
155
|
columns,
|
|
156
156
|
value,
|
|
157
157
|
onChange,
|
|
@@ -314,7 +314,7 @@ function DataTableFilterPanelInner<TData>({
|
|
|
314
314
|
// 必加 `min-h-0` 才能讓 panel 在 PopoverContent max-h cap 下正確 shrink + body scroll。
|
|
315
315
|
<div ref={ref} className={cn(
|
|
316
316
|
'flex flex-col h-full min-h-0',
|
|
317
|
-
mode === 'nested'
|
|
317
|
+
value.mode === 'nested'
|
|
318
318
|
? 'w-[min(760px,calc(100vw-2rem))]'
|
|
319
319
|
: 'w-[min(640px,calc(100vw-2rem))]',
|
|
320
320
|
className,
|
|
@@ -387,9 +387,9 @@ function DataTableFilterPanelInner<TData>({
|
|
|
387
387
|
<div>
|
|
388
388
|
<Button
|
|
389
389
|
variant="tertiary" size="sm" startIcon={Plus}
|
|
390
|
-
onClick={mode === 'flat' ? addFlatCondition : addGroup}
|
|
390
|
+
onClick={value.mode === 'flat' ? addFlatCondition : addGroup}
|
|
391
391
|
>
|
|
392
|
-
{mode === 'nested' ? '加入篩選器' : '加篩選'}
|
|
392
|
+
{value.mode === 'nested' ? '加入篩選器' : '加篩選'}
|
|
393
393
|
</Button>
|
|
394
394
|
</div>
|
|
395
395
|
</SurfaceBody>
|
|
@@ -63,8 +63,8 @@ interface DataTableInteractionLayerProps {
|
|
|
63
63
|
* truthy → layer call this 拿 React node(已 bind value/onCommit/onCancel from controller),
|
|
64
64
|
* 在 ActiveEditorHost portal(z 3,float rect)render 之。
|
|
65
65
|
*
|
|
66
|
-
* Per codex Q6.2 outline:cell 永遠 mode="
|
|
67
|
-
* mode="edit" 同 registry component;float pass-through + z-index 3 cover
|
|
66
|
+
* Per codex Q6.2 outline:cell 永遠 mode="view"(SSOT preserved);portal host 渲
|
|
67
|
+
* mode="edit" 同 registry component;float pass-through + z-index 3 cover view below。
|
|
68
68
|
*/
|
|
69
69
|
activeEditorRender?: (cellId: CellId, rect: CellRect) => React.ReactNode
|
|
70
70
|
}
|
|
@@ -441,7 +441,7 @@ function ClipMask({ clipRect, children }: { clipRect: CellRect; children: React.
|
|
|
441
441
|
*
|
|
442
442
|
* Per codex Q2 verdict:不該進 CellRingOverlay primitive — 它是 host 不是 ring。
|
|
443
443
|
* - pointerEvents:auto(child Field 接收 click / keyboard)
|
|
444
|
-
* - background:var(--canvas)(opaque cover
|
|
444
|
+
* - background:var(--canvas)(opaque cover view Field below;Cell SSOT 保留)
|
|
445
445
|
* - z-index 3(above hover / selected / range)
|
|
446
446
|
* - children = activeEditorRender 的回傳 React node
|
|
447
447
|
*
|
|
@@ -197,11 +197,11 @@ function SortRow({
|
|
|
197
197
|
{...listeners}
|
|
198
198
|
/>
|
|
199
199
|
<div className="flex-1 min-w-0">
|
|
200
|
-
<Select size="sm" options={optionsForRow} value={sort.id} onChange={onChangeId} />
|
|
200
|
+
<Select size="sm" aria-label="排序欄位" options={optionsForRow} value={sort.id} onChange={onChangeId} />
|
|
201
201
|
</div>
|
|
202
202
|
<div className="w-32 shrink-0">
|
|
203
203
|
{/* minRows={2} — 升冪/降冪只 2 選項,顯式縮 menu 高度(Q5) */}
|
|
204
|
-
<Select size="sm" options={DIRECTION_OPTIONS} value={sort.desc ? 'desc' : 'asc'} onChange={onChangeDir} minRows={2} />
|
|
204
|
+
<Select size="sm" aria-label="排序方向" options={DIRECTION_OPTIONS} value={sort.desc ? 'desc' : 'asc'} onChange={onChangeDir} minRows={2} />
|
|
205
205
|
</div>
|
|
206
206
|
{/* Trash 用 text Button(Q4 對齊 filter panel)— form-control row 必 Field 同高 */}
|
|
207
207
|
<Button variant="text" size="sm" iconOnly startIcon={Trash2} aria-label="刪除" onClick={onRemove} />
|