@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
|
@@ -22,7 +22,7 @@ benchmark:
|
|
|
22
22
|
|
|
23
23
|
## 定位
|
|
24
24
|
|
|
25
|
-
FileUpload 是**拖放 /
|
|
25
|
+
FileUpload 是**拖放 / 點擊上傳區塊**——可拖曳檔案進入或點擊觸發檔案選取浮窗。核心職責是「上傳觸發 + 拖放偵測」;它**不 own 單筆檔案列的視覺規格**(狀態圖示 / 縮圖 / 進度條 / 列排版屬 `FileItem` 的 SSOT),但**可 orchestrate 內建清單**——透過 `files` prop 內部組合 `FileItem` 渲染已上傳清單(dual-path,見「Props 行為」與「禁止事項」);consumer 自組 `FileItem` 清單亦合法。
|
|
26
26
|
|
|
27
27
|
**實作基礎**:自建 — native HTML5 `<input type="file">` + drag-and-drop event(dragenter/dragover/dragleave/drop)+ DOM-level state 切換。無 external primitive,因為 Radix 沒 File Upload 對應 primitive,其他 UI kit 的 file upload 多數也是自建這層。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
28
28
|
|
|
@@ -146,7 +146,8 @@ FileUpload 是**拖放 / 點擊上傳區塊**——可拖曳檔案進入或點
|
|
|
146
146
|
- `role="button"` + `tabIndex=0`(disabled 或 loading 時 `-1`)
|
|
147
147
|
- Enter / Space 鍵觸發檔案選取浮窗(模擬 click)
|
|
148
148
|
- `aria-disabled={true}` 當 disabled
|
|
149
|
-
- `<input type="file">` 以 `className="hidden"`(`display:none`)隱藏 — 移出無障礙樹、不可聚焦;互動由外層 `role="button"` wrapper
|
|
149
|
+
- `<input type="file">` 以 `className="hidden"`(`display:none`)隱藏 — 移出無障礙樹、不可聚焦;互動由外層 `role="button"` wrapper 承載
|
|
150
|
+
- **Accessible name(name-from-content + custom children 例外)**:預設(未傳 children)時 name 來自 wrapper 內 `<Empty>` 的 title + description 文字,非 input 本身。**但 `children` 會整個覆寫預設結構**——若 consumer 傳入**只有 icon / branding 圖像、無可見文字**的 children,`role="button"` wrapper 就失去 accessible name(SR 讀不出用途)。此情況 consumer **必須**在 `<FileUpload>` root 傳 `aria-label`(經 `{...props}` spread 到 wrapper div),或確保 children 內含可見文字。dropzone 與 button 兩 variant 同理
|
|
150
151
|
|
|
151
152
|
---
|
|
152
153
|
|
|
@@ -222,7 +222,11 @@ const FileUpload = React.forwardRef<HTMLDivElement, FileUploadProps>(
|
|
|
222
222
|
<div ref={ref} className={cn('w-full', hasFiles && 'flex flex-col')}>
|
|
223
223
|
{variant === 'button' ? (
|
|
224
224
|
// ── button variant:緊湊觸發(form-friendly,省空間),click-only(無拖放區)──
|
|
225
|
-
|
|
225
|
+
// consumer onClick 在此 wrapper div 承載(type = MouseEvent<HTMLDivElement>,對齊 FileUploadProps
|
|
226
|
+
// extends HTMLAttributes<HTMLDivElement>)。Button 觸發開檔會冒泡至此 → 同時觸發 consumer handler。
|
|
227
|
+
// 2026-07-17 修:onClick 於 L128 destructure 後未再 compose,button variant 靜默丟失公開 DOM prop
|
|
228
|
+
// (dropzone variant 經 handleClick 的 onClick?.(e) 正確 compose,button variant 漏接)。
|
|
229
|
+
<div className={className} onClick={onClick} {...props}>
|
|
226
230
|
<input
|
|
227
231
|
ref={inputRef}
|
|
228
232
|
type="file"
|
|
@@ -710,7 +710,7 @@ export const SizeMatrix: Story = {
|
|
|
710
710
|
<tr>
|
|
711
711
|
<Td>Body 垂直 padding</Td>
|
|
712
712
|
<Td mono>pt-[var(--layout-space-tight)] pb-[var(--layout-space-loose)]</Td>
|
|
713
|
-
<Td>非對稱:top tight / bottom loose(
|
|
713
|
+
<Td>非對稱:top tight / bottom loose(bounded region 容器底部留白較寬鬆,內容不貼底、捲動時收尾更透氣)</Td>
|
|
714
714
|
</tr>
|
|
715
715
|
<tr>
|
|
716
716
|
<Td>Section 間 gap</Td>
|
|
@@ -423,7 +423,7 @@ export const ReadOnlyRule: Story = {
|
|
|
423
423
|
|
|
424
424
|
<Rule
|
|
425
425
|
title="✅ readOnly — 其他人上傳的 / 公開公告 / 只讀 link 分享"
|
|
426
|
-
note="readOnly=true 時說明區依 DS Textarea readonly canonical:有值 → 可聚焦選取但不可改的 native readonly textarea;空值 →
|
|
426
|
+
note="readOnly=true 時說明區依 DS Textarea readonly canonical:有值 → 可聚焦選取但不可改的 native readonly textarea;空值 → view div 顯 emptyDisplay(`-`,非 placeholder);onDescriptionChange 不觸發。故 readonly 無 description 時顯示 `-`,不會出現「為這個檔案加上說明...」的編輯誘導 placeholder"
|
|
427
427
|
>
|
|
428
428
|
<Button variant="tertiary" startIcon={FolderOpen} onClick={() => setRoOpen(true)}>
|
|
429
429
|
開啟公司公告(readOnly)
|
|
@@ -140,7 +140,7 @@ FileViewer Toolbar 消費 `patterns/action-bar/action-bar.spec.md` 的**左中
|
|
|
140
140
|
- **zoom** — 同一張檔案的微調(影響範圍:當前 renderer 的 transform state),影響最小
|
|
141
141
|
- **info** — 切換附加資訊面板(影響範圍:layout,不破壞現有內容)
|
|
142
142
|
- **download** — 把內容搬出 viewer(影響範圍:外部檔案系統,不可逆副作用)
|
|
143
|
-
- **close** — 結束整個 viewing session(影響範圍:最大)。註:close = `setOpen(false)`,**僅卸載 `DialogContent` 子樹**;外層 FileViewer 元件恆掛載,shell state(zoom / infoOpen
|
|
143
|
+
- **close** — 結束整個 viewing session(影響範圍:最大)。註:close = `setOpen(false)`,**僅卸載 `DialogContent` 子樹**;外層 FileViewer 元件恆掛載,shell state(zoom / infoOpen 等 `useState`)**保留** —— 重開同一檔沿用上次 zoom / infoOpen,非 fresh state(**index 例外**:uncontrolled 時開啟即重置為 `initialIndex`,`file-viewer.tsx` 開啟 effect)
|
|
144
144
|
|
|
145
145
|
### Dismiss canonical(Close X)
|
|
146
146
|
|
|
@@ -203,7 +203,7 @@ const figmaDesignFile: FileInfo[] = [
|
|
|
203
203
|
mimeType: 'image/png',
|
|
204
204
|
size: 2_840_000,
|
|
205
205
|
description:
|
|
206
|
-
'
|
|
206
|
+
'營運儀表板 v2 最終設計稿 — 凍結欄與列操作已定案,可 zoom 檢視 spacing 與色彩細節。',
|
|
207
207
|
metadata: {
|
|
208
208
|
'設計師': 'Claire Wu',
|
|
209
209
|
'Figma link': 'figma.com/file/xyz/Dashboard',
|
|
@@ -530,13 +530,13 @@ const InfoPanel = React.memo(function InfoPanel({
|
|
|
530
530
|
{/* 檔案資訊 — 用 DS DescriptionList horizontal + divided(Google Drive /
|
|
531
531
|
Notion file info panel 模式):
|
|
532
532
|
- section header 用 FieldLabel 同款 typography 保視覺一致
|
|
533
|
-
- DescriptionList
|
|
533
|
+
- DescriptionList orientation="horizontal" divided 提供 row 下底線
|
|
534
534
|
對齊格線,key 長度不一也易讀
|
|
535
535
|
- 不再手刻 dl/dt/dd — canonical 由 DS primitive own */}
|
|
536
536
|
{/* heading → first-item gap = item → item gap(Gestalt proximity,見 description-list.spec.md) */}
|
|
537
537
|
<div className="flex flex-col gap-[var(--layout-space-tight)]">
|
|
538
538
|
<span className="text-body font-normal text-foreground">{labels.fileInfoHeading}</span>
|
|
539
|
-
<DescriptionList
|
|
539
|
+
<DescriptionList orientation="horizontal" divided>
|
|
540
540
|
<DescriptionItem label="檔名">{file.name}</DescriptionItem>
|
|
541
541
|
<DescriptionItem label="類型">{file.mimeType || '-'}</DescriptionItem>
|
|
542
542
|
{sizeText && (
|
|
@@ -775,6 +775,7 @@ const FileViewer = React.forwardRef<HTMLDivElement, FileViewerProps>(function Fi
|
|
|
775
775
|
allowDownload = true,
|
|
776
776
|
onDownload,
|
|
777
777
|
labels: labelsOverride,
|
|
778
|
+
className,
|
|
778
779
|
...props
|
|
779
780
|
}, ref) {
|
|
780
781
|
const labels = React.useMemo(
|
|
@@ -89,7 +89,7 @@ export const VisualVariants: Story = {
|
|
|
89
89
|
<div className="flex items-center gap-6">
|
|
90
90
|
<HoverCard>
|
|
91
91
|
<HoverCardTrigger asChild>
|
|
92
|
-
<Button variant="tertiary" size="sm">
|
|
92
|
+
<Button variant="tertiary" size="sm">Ada Chen</Button>
|
|
93
93
|
</HoverCardTrigger>
|
|
94
94
|
<HoverCardContent className="bg-surface-raised border border-border rounded-lg p-4 shadow-[var(--elevation-200)]">
|
|
95
95
|
<div className="w-56">
|
|
@@ -108,11 +108,13 @@ export const VisualVariants: Story = {
|
|
|
108
108
|
<div className="flex items-center gap-6">
|
|
109
109
|
<HoverCard>
|
|
110
110
|
<HoverCardTrigger asChild>
|
|
111
|
-
<Button variant="tertiary" size="sm"
|
|
111
|
+
<Button variant="tertiary" size="sm">+3 位協作者</Button>
|
|
112
112
|
</HoverCardTrigger>
|
|
113
113
|
<HoverCardContent className="bg-tooltip rounded-md px-3 py-2" data-theme="dark">
|
|
114
|
-
<div className="text-caption w-56">
|
|
115
|
-
|
|
114
|
+
<div className="text-caption w-56 flex flex-col gap-1">
|
|
115
|
+
<span>林思妤</span>
|
|
116
|
+
<span>陳柏宇</span>
|
|
117
|
+
<span>Aisha Khan</span>
|
|
116
118
|
</div>
|
|
117
119
|
</HoverCardContent>
|
|
118
120
|
</HoverCard>
|
|
@@ -97,7 +97,12 @@ export const UsageGuidance: Story = {
|
|
|
97
97
|
>
|
|
98
98
|
<HoverCard>
|
|
99
99
|
<HoverCardTrigger asChild>
|
|
100
|
-
<a
|
|
100
|
+
<a
|
|
101
|
+
href="https://help.acme.com/user-manual"
|
|
102
|
+
target="_blank"
|
|
103
|
+
rel="noreferrer"
|
|
104
|
+
className="text-primary underline cursor-pointer inline-flex items-center gap-1"
|
|
105
|
+
>
|
|
101
106
|
使用者手冊 <ExternalLink size={12} />
|
|
102
107
|
</a>
|
|
103
108
|
</HoverCardTrigger>
|
|
@@ -22,7 +22,7 @@ Hover 觸發的**可互動浮層**,基於 Radix HoverCard。
|
|
|
22
22
|
**分類**:Internal primitive——不進 root barrel front-door、不裸用;DS 內由 Avatar(`hoverCard`)/ OverflowIndicator / ProfileCard 場景組合消費;consumer 需要時可經 per-component subpath 包裝並自行確認後使用(`.claude/rules/ui-development.md`「Root barrel front-door 排除」SSOT,internal ≠ 禁用)(frontmatter `isInternal`:root barrel 排除,storybook `Design System/Internal/HoverCard`)。
|
|
23
23
|
|
|
24
24
|
- **是**:hover 顯示可互動內容(按鈕、連結、可選取文字——**滑鼠互動**;鍵盤進不了卡片,見「A11y 預設」)的浮層容器,定位為滑鼠 / focus 使用者的補充閱讀 surface
|
|
25
|
-
- **不是**:Tooltip
|
|
25
|
+
- **不是**:Tooltip(純文字提示、**內容不可互動**;指標可短暫移到浮層屬 WCAG 1.4.13 hoverable grace,非「立即消失」);也不是鍵盤可操作的互動浮層(那是 Popover)
|
|
26
26
|
|
|
27
27
|
**Layout Family**:非上述 family — composite / multi-section(多區塊組合,自 own layout)。
|
|
28
28
|
|
|
@@ -54,7 +54,7 @@ Hover 觸發的**可互動浮層**,基於 Radix HoverCard。
|
|
|
54
54
|
|---|---|---|
|
|
55
55
|
| 觸發 | hover | hover |
|
|
56
56
|
| **內容可互動** | 是——限滑鼠(Radix 設 content 內 tabbable node 為 `tabindex="-1"`,鍵盤不可達,見「A11y 預設」) | 否(純文字) |
|
|
57
|
-
| 停留行為 |
|
|
57
|
+
| 停留行為 | 滑鼠可移到浮層互動不消失 | 滑鼠可短暫移到浮層(WCAG 1.4.13 grace,`tooltip.tsx` 未設 `disableHoverableContent`),但內容不可互動 |
|
|
58
58
|
| 視覺樣式 | 由 consumer 決定(亮色 card 或深色 tooltip 風格皆可) | 統一深色背景 |
|
|
59
59
|
| 典型用例 | ProfileCard、內容預覽、溢出清單 | icon 用途、shortcut、截斷文字補全 |
|
|
60
60
|
|
|
@@ -85,8 +85,10 @@ export const hoverCardMeta = {
|
|
|
85
85
|
},
|
|
86
86
|
states: ['default'],
|
|
87
87
|
tokens: {
|
|
88
|
-
|
|
89
|
-
fg
|
|
88
|
+
// 2026-07-16 deep-audit A.1b:清 Phase-1 佔位 — HoverCard 為純行為 primitive,
|
|
89
|
+
// Content 不套任何 bg/fg(spec「純行為 primitive」段);bg-surface-raised 屬 consumer(ProfileCard)。
|
|
90
|
+
bg: [],
|
|
91
|
+
fg: [],
|
|
90
92
|
ring: [],
|
|
91
93
|
},
|
|
92
94
|
} as const
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import { InlineEdit } from './inline-edit'
|
|
4
|
+
import { Select } from '@/design-system/components/Select/select'
|
|
5
|
+
import { Field, FieldLabel } from '@/design-system/components/Field/field'
|
|
6
|
+
|
|
7
|
+
// 就地編輯無 disabled 態的世界級對照(cite,per M22):
|
|
8
|
+
// MUI X isCellEditable/cellMode https://mui.com/x/react-data-grid/editing/
|
|
9
|
+
// AG Grid editable https://www.ag-grid.com/react-data-grid/cell-editing/
|
|
10
|
+
// Atlassian inline-edit readView/editView https://github.com/pioug/atlassian-frontend-mirror/blob/main/design-system/inline-edit/src/internal/read-view.tsx
|
|
11
|
+
//
|
|
12
|
+
// InlineEdit 設計規格(anatomy)—— view ↔ edit 二態就地編輯 primitive。
|
|
13
|
+
// Model A(2026-07-16):view 不自帶幾何 cva,委派控件 view mode / fieldViewGeometry helper;read↔edit 零跳。
|
|
14
|
+
const meta: Meta<typeof InlineEdit> = {
|
|
15
|
+
title: 'Design System/Components/InlineEdit/設計規格',
|
|
16
|
+
component: InlineEdit,
|
|
17
|
+
parameters: { layout: 'padded' },
|
|
18
|
+
}
|
|
19
|
+
export default meta
|
|
20
|
+
type Story = StoryObj<typeof InlineEdit>
|
|
21
|
+
|
|
22
|
+
// ── shared UI ────────────────────────────────────────────────────────────────
|
|
23
|
+
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
|
24
|
+
return (
|
|
25
|
+
<section className="mb-8">
|
|
26
|
+
<h3 className="mb-3 border-b border-divider pb-2 text-body-lg font-semibold text-foreground">{title}</h3>
|
|
27
|
+
{children}
|
|
28
|
+
</section>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
function PropRow({ name, type, def, desc }: { name: string; type: string; def: string; desc: string }) {
|
|
32
|
+
return (
|
|
33
|
+
<tr className="border-b border-divider align-top">
|
|
34
|
+
<td className="py-2 pr-4 font-mono text-caption text-foreground">{name}</td>
|
|
35
|
+
<td className="py-2 pr-4 font-mono text-caption text-fg-secondary">{type}</td>
|
|
36
|
+
<td className="py-2 pr-4 font-mono text-caption text-fg-muted">{def}</td>
|
|
37
|
+
<td className="py-2 text-caption text-fg-secondary">{desc}</td>
|
|
38
|
+
</tr>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
function Stateful({ value: initial, ...props }: Omit<React.ComponentProps<typeof InlineEdit>, 'onCommit'>) {
|
|
42
|
+
const [value, setValue] = React.useState(initial)
|
|
43
|
+
return <InlineEdit {...props} value={value} onCommit={setValue} />
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const Overview: Story = {
|
|
47
|
+
name: '元件總覽',
|
|
48
|
+
render: () => (
|
|
49
|
+
<div className="max-w-[720px]">
|
|
50
|
+
<Section title="定位">
|
|
51
|
+
<p className="text-body text-fg-secondary">
|
|
52
|
+
就地編輯 primitive:值平常以 <b>view 態</b>(純內容)呈現,滑鼠移入顯示灰底提示、點擊(或鍵盤 Enter)切成
|
|
53
|
+
<b> edit 態</b>(真正的 Field 控件)。與 DataTable cell 同一份就地編輯語義 —— 只有 <code>view ↔ edit</code> 兩態
|
|
54
|
+
+ <code>editable</code> 判準閘,<b>無 disabled 態</b>(世界級就地編輯共識,cite 見檔頭)。
|
|
55
|
+
</p>
|
|
56
|
+
</Section>
|
|
57
|
+
<Section title="Model A —— view 幾何來源">
|
|
58
|
+
<p className="mb-2 text-body text-fg-secondary">
|
|
59
|
+
InlineEdit <b>不自帶</b> geometry cva(消 M17 重複)。view 幾何來源分兩路,read↔edit 零跳因兩態同一顆控件、只差 chrome:
|
|
60
|
+
</p>
|
|
61
|
+
<ul className="ml-5 list-disc text-body text-fg-secondary">
|
|
62
|
+
<li><b>值-格式化</b>(Select→Tag / 日期 / avatar):<code>renderRead</code> 委派 <code>{'<Control mode="view">'}</code>,
|
|
63
|
+
幾何 + 內部間距(多 tag gap / avatar↔label)皆由控件 view×default 提供。</li>
|
|
64
|
+
<li><b>純值 / 標題</b>(<code>as="h1"</code>):套 <code>fieldViewGeometry(size, multiline)</code> helper
|
|
65
|
+
(= view×default 幾何 SSOT:<code>px-field-px</code> + <code>min-h-field</code> + 多行 <code>py-2</code>)。</li>
|
|
66
|
+
</ul>
|
|
67
|
+
</Section>
|
|
68
|
+
</div>
|
|
69
|
+
),
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const Inspector: Story = {
|
|
73
|
+
name: '屬性一覽',
|
|
74
|
+
render: () => (
|
|
75
|
+
<div className="max-w-[860px]">
|
|
76
|
+
<table className="w-full">
|
|
77
|
+
<thead>
|
|
78
|
+
<tr className="border-b-2 border-border text-left">
|
|
79
|
+
<th className="py-2 pr-4 text-caption font-semibold text-fg-muted">Prop</th>
|
|
80
|
+
<th className="py-2 pr-4 text-caption font-semibold text-fg-muted">型別</th>
|
|
81
|
+
<th className="py-2 pr-4 text-caption font-semibold text-fg-muted">預設</th>
|
|
82
|
+
<th className="py-2 text-caption font-semibold text-fg-muted">說明</th>
|
|
83
|
+
</tr>
|
|
84
|
+
</thead>
|
|
85
|
+
<tbody>
|
|
86
|
+
<PropRow name="value" type="T" def="—" desc="已提交的欄位值(view 顯示 / edit 初值)。泛型:string / number / string[] / PersonValue" />
|
|
87
|
+
<PropRow name="onCommit" type="(next: T) => void" def="—" desc="blur / Enter 且草稿有變更時提交" />
|
|
88
|
+
<PropRow name="editable" type="boolean" def="true" desc="false → view 無 hover 入口、無藍框、不可進 edit、不灰化(鎖定 = 純 view)" />
|
|
89
|
+
<PropRow name="renderRead" type="(v: T) => ReactNode" def="String(value)" desc="格式化 view;鐵律:渲染對應控件 mode='view',不可自刻" />
|
|
90
|
+
<PropRow name="renderEdit" type="(p) => ReactNode" def="Input/Textarea" desc="edit 控件(必 mode='edit');非 string 值必傳" />
|
|
91
|
+
<PropRow name="multiline" type="boolean" def="false" desc="Jira description 類:view 換行 + edit 用 Textarea(py-2 = Textarea)" />
|
|
92
|
+
<PropRow name="as" type="'span'|'h1'..'h6'|'p'|'div'" def="'span'" desc="view 語意標籤;標題保留文件大綱 a11y" />
|
|
93
|
+
<PropRow name="size" type="'sm'|'md'|'lg'" def="sm(fieldCtx cascade)" desc="接 fieldCtx.size;standalone fallback sm。靜態 fieldPreferredSize='sm' 讓外層 Field 自動收 sm" />
|
|
94
|
+
<PropRow name="label" type="string" def="—" desc="view 按鈕 aria-label(「編輯 {label}」)+ 控件 aria-label" />
|
|
95
|
+
</tbody>
|
|
96
|
+
</table>
|
|
97
|
+
</div>
|
|
98
|
+
),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const StateBehavior: Story = {
|
|
102
|
+
name: '狀態行為',
|
|
103
|
+
render: () => (
|
|
104
|
+
<div className="grid max-w-[720px] grid-cols-[140px_1fr] gap-x-6 gap-y-5">
|
|
105
|
+
<span className="text-body font-medium text-foreground">view(可編)</span>
|
|
106
|
+
<div><Stateful value="Fix flaky e2e test" label="標題" /></div>
|
|
107
|
+
<span className="text-body font-medium text-foreground">view(鎖定)</span>
|
|
108
|
+
<div><Stateful value="PROJ-482(系統產生)" label="編號" editable={false} /></div>
|
|
109
|
+
<span className="text-body font-medium text-foreground">多行</span>
|
|
110
|
+
<div><Stateful value={'第一行說明\n第二行說明(換行保留上下 padding)'} label="說明" multiline /></div>
|
|
111
|
+
<span className="text-body font-medium text-foreground">格式化(Tag)</span>
|
|
112
|
+
<div>
|
|
113
|
+
<Stateful
|
|
114
|
+
value="in-progress"
|
|
115
|
+
label="狀態"
|
|
116
|
+
renderRead={(v) => (
|
|
117
|
+
<Select mode="view" display="tag" size="sm" value={v as string} options={[
|
|
118
|
+
{ value: 'in-progress', label: '進行中', tagVariant: 'blue' },
|
|
119
|
+
{ value: 'done', label: '完成', tagVariant: 'green' },
|
|
120
|
+
]} />
|
|
121
|
+
)}
|
|
122
|
+
renderEdit={(p) => (
|
|
123
|
+
<Select
|
|
124
|
+
autoFocus
|
|
125
|
+
display="tag"
|
|
126
|
+
size="sm"
|
|
127
|
+
defaultOpen
|
|
128
|
+
value={p.value as string}
|
|
129
|
+
aria-label={p['aria-label']}
|
|
130
|
+
options={[
|
|
131
|
+
{ value: 'in-progress', label: '進行中', tagVariant: 'blue' },
|
|
132
|
+
{ value: 'done', label: '完成', tagVariant: 'green' },
|
|
133
|
+
]}
|
|
134
|
+
onChange={(next) => { p.onChange(next as string); p.commit() }}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
/>
|
|
138
|
+
</div>
|
|
139
|
+
<span className="text-body font-medium text-foreground">空值</span>
|
|
140
|
+
<div><Stateful value="" label="負責人" placeholder="指派負責人…" /></div>
|
|
141
|
+
</div>
|
|
142
|
+
),
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// auto-sm 靠 Field 偵測 child 靜態 `fieldPreferredSize`(對齊 detectControlLayout 讀 fieldLayout)——
|
|
146
|
+
// **必 InlineEdit 為 Field 直接子**(包一層 wrapper 元件會遮蔽靜態,Field 偵測不到 → 退回 md)。
|
|
147
|
+
function CascadeDemo() {
|
|
148
|
+
const [title, setTitle] = React.useState('Fix flaky checkout e2e test')
|
|
149
|
+
const [owner, setOwner] = React.useState('')
|
|
150
|
+
return (
|
|
151
|
+
<div className="w-[420px] rounded-lg border border-border bg-surface p-[var(--layout-space-loose)]">
|
|
152
|
+
{/* Field 偵測 InlineEdit 靜態 fieldPreferredSize='sm' → 未指定 size 自動收 sm;
|
|
153
|
+
vertical orientation → InlineEdit -mx 讓 view 值落 FieldLabel 同左緣 */}
|
|
154
|
+
<Field className="mb-4">
|
|
155
|
+
<FieldLabel>任務標題</FieldLabel>
|
|
156
|
+
<InlineEdit value={title} onCommit={setTitle} label="任務標題" />
|
|
157
|
+
</Field>
|
|
158
|
+
<Field>
|
|
159
|
+
<FieldLabel>負責人</FieldLabel>
|
|
160
|
+
<InlineEdit value={owner} onCommit={setOwner} label="負責人" placeholder="指派…" />
|
|
161
|
+
</Field>
|
|
162
|
+
</div>
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
export const InFieldCascade: Story = {
|
|
166
|
+
name: '包進表單欄位:尺寸自動收斂與左緣對齊',
|
|
167
|
+
render: () => <CascadeDemo />,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export const Accessibility: Story = {
|
|
171
|
+
name: '無障礙',
|
|
172
|
+
render: () => (
|
|
173
|
+
<div className="max-w-[640px] text-body text-fg-secondary">
|
|
174
|
+
<ul className="ml-5 list-disc space-y-1">
|
|
175
|
+
<li>view 疊隱形 <code>{'<button aria-label="編輯 {label}">'}</code> —— Tab 可聚焦、Enter/Space 進 edit;
|
|
176
|
+
與 <code>as="h1"</code> 分離(HTML 不允許 heading 巢狀於 button),標題大綱不破壞。</li>
|
|
177
|
+
<li>鍵盤 focus 顯 <code>border-primary</code> 藍框(<code>focus-visible</code>,僅鍵盤);滑鼠點擊不顯藍框。</li>
|
|
178
|
+
<li>結算焦點路徑分流:鍵盤 Enter/Esc → 焦點回 view 按鈕;滑鼠 blur → 純 view 不搶焦。</li>
|
|
179
|
+
<li><code>editable=false</code>:不渲染 Pressable,鍵盤跳過,語意 = 唯讀值(非 disabled)。</li>
|
|
180
|
+
<li>edit 態 = 真正的 Field 控件,繼承其 a11y(Input/Textarea/Select 各自 ARIA)。</li>
|
|
181
|
+
</ul>
|
|
182
|
+
</div>
|
|
183
|
+
),
|
|
184
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — 本檔 brand 引用(Jira/Linear/Notion)為真實業務場景示意(mindset #4),非 URL-citable 的 DS 行為 benchmark claim。
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
4
|
+
import { InlineEdit } from './inline-edit'
|
|
5
|
+
import { Field, FieldLabel } from '@/design-system/components/Field/field'
|
|
6
|
+
import { Input } from '@/design-system/components/Input/input'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* InlineEdit 設計原則(principles)—— 何時用 / 何時不用 / 近親分界 / 內容準則。
|
|
10
|
+
*/
|
|
11
|
+
const meta: Meta<typeof InlineEdit> = {
|
|
12
|
+
title: 'Design System/Components/InlineEdit/設計原則',
|
|
13
|
+
component: InlineEdit,
|
|
14
|
+
parameters: { layout: 'padded' },
|
|
15
|
+
}
|
|
16
|
+
export default meta
|
|
17
|
+
type Story = StoryObj<typeof InlineEdit>
|
|
18
|
+
|
|
19
|
+
function Card({ tone, title, children }: { tone: 'do' | 'dont' | 'neutral'; title: string; children: React.ReactNode }) {
|
|
20
|
+
const ring = tone === 'do' ? 'border-success' : tone === 'dont' ? 'border-error' : 'border-border'
|
|
21
|
+
const tag = tone === 'do' ? '✓ 適用' : tone === 'dont' ? '✕ 不適用' : '—'
|
|
22
|
+
const tagColor = tone === 'do' ? 'text-success' : tone === 'dont' ? 'text-error' : 'text-fg-muted'
|
|
23
|
+
return (
|
|
24
|
+
<div className={`rounded-lg border ${ring} bg-surface p-[var(--layout-space-loose)]`}>
|
|
25
|
+
<p className={`mb-1 text-caption font-semibold ${tagColor}`}>{tag}</p>
|
|
26
|
+
<p className="mb-2 text-body font-medium text-foreground">{title}</p>
|
|
27
|
+
<div className="text-body text-fg-secondary">{children}</div>
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
function Stateful({ value: initial, ...props }: Omit<React.ComponentProps<typeof InlineEdit>, 'onCommit'>) {
|
|
32
|
+
const [value, setValue] = React.useState(initial)
|
|
33
|
+
return <InlineEdit {...props} value={value} onCommit={setValue} />
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const WhenToUse: Story = {
|
|
37
|
+
name: '何時用',
|
|
38
|
+
render: () => (
|
|
39
|
+
<div className="grid max-w-[860px] grid-cols-2 gap-4">
|
|
40
|
+
<Card tone="do" title="詳情面板的可編欄位">
|
|
41
|
+
Jira / Linear issue 詳情、Notion property —— 值平常是純內容,原地點擊即可改,不跳表單。
|
|
42
|
+
<div className="mt-3"><Stateful value="Fix flaky checkout e2e test" label="標題" /></div>
|
|
43
|
+
</Card>
|
|
44
|
+
<Card tone="do" title="標題型就地編輯">
|
|
45
|
+
頁面 / 文件標題 <code>as="h1"</code>,保留文件大綱,同時可點擊改名。
|
|
46
|
+
<div className="mt-3"><Stateful as="h2" value="Q3 產品路線圖" readClassName="text-h5 font-bold" label="文件標題" /></div>
|
|
47
|
+
</Card>
|
|
48
|
+
<Card tone="do" title="唯讀值同場並列(editable=false)">
|
|
49
|
+
系統產生值(訂單編號、建立時間)與可編欄位並列 —— 用 <code>editable=false</code>,視覺一致但無編輯入口、不灰化。
|
|
50
|
+
<div className="mt-3"><Stateful value="PROJ-482" label="編號" editable={false} /></div>
|
|
51
|
+
</Card>
|
|
52
|
+
<Card tone="do" title="格式化值就地編輯">
|
|
53
|
+
狀態 Tag / 日期 / 負責人頭像 —— <code>renderRead</code> 委派控件 view mode,edit 換該控件 edit mode。
|
|
54
|
+
</Card>
|
|
55
|
+
</div>
|
|
56
|
+
),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const WhenNotToUse: Story = {
|
|
60
|
+
name: '何時不用',
|
|
61
|
+
render: () => (
|
|
62
|
+
<div className="grid max-w-[860px] grid-cols-2 gap-4">
|
|
63
|
+
<Card tone="dont" title="整張表單填寫">
|
|
64
|
+
新增 / 建立流程要一次填多欄 —— 用 <code><Field> + 控件</code> 明確表單,不用逐欄就地編輯。
|
|
65
|
+
<div className="mt-3">
|
|
66
|
+
<Field><FieldLabel>Email</FieldLabel><Input placeholder="you@company.com" /></Field>
|
|
67
|
+
</div>
|
|
68
|
+
</Card>
|
|
69
|
+
<Card tone="dont" title="永久唯讀、不同場可編欄位">
|
|
70
|
+
純展示頁(唯讀報表)—— 直接用 <code><Control mode="view"></code> 或純文字,不需就地編輯的 hover 入口成本。
|
|
71
|
+
</Card>
|
|
72
|
+
<Card tone="dont" title="需要即時驗證 / 複雜互動">
|
|
73
|
+
密碼、需即時錯誤回饋、multi-step 的欄位 —— 用完整 Field + FieldError,不塞進二態就地編輯。
|
|
74
|
+
</Card>
|
|
75
|
+
<Card tone="dont" title="條件停用的欄位">
|
|
76
|
+
「選國家前城市不可填」這種表單條件停用 —— 用 <code><Field mode="disabled"></code>,不是 InlineEdit
|
|
77
|
+
(就地編輯無 disabled 態;鎖定 = editable=false 純 view)。
|
|
78
|
+
</Card>
|
|
79
|
+
</div>
|
|
80
|
+
),
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const VsControlView: Story = {
|
|
84
|
+
name: '近親分界:就地編輯 vs 唯讀展示 vs 表單',
|
|
85
|
+
render: () => (
|
|
86
|
+
<div className="max-w-[820px]">
|
|
87
|
+
<table className="w-full">
|
|
88
|
+
<thead>
|
|
89
|
+
<tr className="border-b-2 border-border text-left text-caption font-semibold text-fg-muted">
|
|
90
|
+
<th className="py-2 pr-4">用它</th>
|
|
91
|
+
<th className="py-2 pr-4">場景</th>
|
|
92
|
+
<th className="py-2">可編 / 入口</th>
|
|
93
|
+
</tr>
|
|
94
|
+
</thead>
|
|
95
|
+
<tbody className="text-body text-fg-secondary">
|
|
96
|
+
<tr className="border-b border-divider align-top">
|
|
97
|
+
<td className="py-2 pr-4 font-medium text-foreground">InlineEdit</td>
|
|
98
|
+
<td className="py-2 pr-4">詳情面板、可原地改的值</td>
|
|
99
|
+
<td className="py-2">view↔edit,hover 入口(editable=true)</td>
|
|
100
|
+
</tr>
|
|
101
|
+
<tr className="border-b border-divider align-top">
|
|
102
|
+
<td className="py-2 pr-4 font-medium text-foreground">InlineEdit editable=false</td>
|
|
103
|
+
<td className="py-2 pr-4">與可編欄位並列的唯讀值(訂單編號)</td>
|
|
104
|
+
<td className="py-2">純 view,無入口、不灰化</td>
|
|
105
|
+
</tr>
|
|
106
|
+
<tr className="border-b border-divider align-top">
|
|
107
|
+
<td className="py-2 pr-4 font-medium text-foreground">{'<Control mode="view">'}</td>
|
|
108
|
+
<td className="py-2 pr-4">永久唯讀展示頁的值</td>
|
|
109
|
+
<td className="py-2">純展示,無互動</td>
|
|
110
|
+
</tr>
|
|
111
|
+
<tr className="align-top">
|
|
112
|
+
<td className="py-2 pr-4 font-medium text-foreground">{'<Field> + 控件'}</td>
|
|
113
|
+
<td className="py-2 pr-4">表單填寫(一次多欄)</td>
|
|
114
|
+
<td className="py-2">恆 edit,label + error</td>
|
|
115
|
+
</tr>
|
|
116
|
+
</tbody>
|
|
117
|
+
</table>
|
|
118
|
+
</div>
|
|
119
|
+
),
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const ContentGuidelines: Story = {
|
|
123
|
+
name: '內容準則',
|
|
124
|
+
render: () => (
|
|
125
|
+
<div className="grid max-w-[860px] grid-cols-2 gap-4">
|
|
126
|
+
<Card tone="do" title="placeholder 用行動語氣">
|
|
127
|
+
空值提示寫「指派負責人…」「新增說明…」,告訴使用者能做什麼,而非「無」。
|
|
128
|
+
<div className="mt-3"><Stateful value="" label="負責人" placeholder="指派負責人…" /></div>
|
|
129
|
+
</Card>
|
|
130
|
+
<Card tone="do" title="label 傳人類可讀名稱">
|
|
131
|
+
<code>label</code> 組出 aria-label「編輯 負責人」—— 傳欄位真名,別傳代號。
|
|
132
|
+
</Card>
|
|
133
|
+
<Card tone="dont" title="別把格式化 Tag 自刻">
|
|
134
|
+
狀態值要顯示 Tag,<code>renderRead</code> 必須渲染 <code><Select mode="view" display="tag"></code> ——
|
|
135
|
+
自己拼 <code><Tag></code> 會與 edit 態格式漂移。
|
|
136
|
+
</Card>
|
|
137
|
+
<Card tone="neutral" title="多行用 multiline">
|
|
138
|
+
Jira description 類長文字傳 <code>multiline</code> —— view 保留換行、edit 換 Textarea,上下 padding 一致。
|
|
139
|
+
</Card>
|
|
140
|
+
</div>
|
|
141
|
+
),
|
|
142
|
+
}
|