@qijenchen/design-system 0.1.0-beta.145 → 0.1.0-beta.147
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/dist/components/Accordion/accordion.d.ts +1 -1
- package/dist/components/Accordion/accordion.d.ts.map +1 -1
- package/dist/components/Accordion/accordion.js +8 -3
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/AccountMenu/account-menu.d.ts.map +1 -1
- package/dist/components/AccountMenu/account-menu.js.map +1 -1
- package/dist/components/AgentPanel/agent-panel-fab.d.ts +7 -1
- package/dist/components/AgentPanel/agent-panel-fab.d.ts.map +1 -1
- package/dist/components/AgentPanel/agent-panel-fab.js +36 -14
- package/dist/components/AgentPanel/agent-panel-fab.js.map +1 -1
- package/dist/components/AgentPanel/agent-panel-logo.d.ts +3 -3
- package/dist/components/AgentPanel/agent-panel-logo.js.map +1 -1
- package/dist/components/AgentPanel/agent-panel.d.ts +1 -1
- package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -1
- package/dist/components/AgentPanel/agent-panel.js +28 -22
- package/dist/components/AgentPanel/agent-panel.js.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts +1 -1
- package/dist/components/AppShell/app-shell.js +1 -1
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts +95 -1
- package/dist/components/Avatar/avatar.d.ts.map +1 -1
- package/dist/components/Avatar/avatar.js +106 -15
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Avatar/index.js +14 -2
- package/dist/components/Breadcrumb/breadcrumb.d.ts +4 -2
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +2 -2
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +27 -2
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -2
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +118 -22
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +34 -10
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +210 -36
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts +1 -1
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +3 -2
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Chart/chart.d.ts +1 -0
- package/dist/components/Chart/chart.d.ts.map +1 -1
- package/dist/components/Chart/chart.js +8 -0
- package/dist/components/Chart/chart.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +1 -1
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +10 -2
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +1 -1
- package/dist/components/Chip/chip.d.ts.map +1 -1
- package/dist/components/Chip/chip.js +4 -2
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +1 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +37 -11
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts +1 -1
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +106 -8
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +3 -2
- package/dist/components/DataTable/cell-registry.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 +24 -24
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -1
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.js +3 -4
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +20 -20
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +8 -5
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +197 -71
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DateGrid/date-grid.d.ts +1 -1
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +358 -225
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +16 -1
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +55 -43
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu-keyboard.d.ts +86 -0
- package/dist/components/DropdownMenu/dropdown-menu-keyboard.d.ts.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu-keyboard.js +172 -0
- package/dist/components/DropdownMenu/dropdown-menu-keyboard.js.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +6 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +50 -39
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +4 -0
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js +1 -2
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-edit-keys.d.ts +8 -0
- package/dist/components/Field/field-edit-keys.d.ts.map +1 -1
- package/dist/components/Field/field-edit-keys.js +3 -0
- package/dist/components/Field/field-edit-keys.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +18 -1
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +39 -10
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +3 -2
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +2 -1
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts +26 -2
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +82 -25
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileItem/index.js +4 -2
- package/dist/components/FileUpload/file-upload.d.ts +1 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +132 -55
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +9 -4
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
- package/dist/components/InlineEdit/inline-edit.js +1 -1
- package/dist/components/InlineEdit/inline-edit.js.map +1 -1
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +6 -1
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +20 -4
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Notice/notice.js +1 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +6 -1
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/OverflowIndicator/index.js +2 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +19 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +47 -27
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/Pagination/pagination.d.ts +1 -1
- package/dist/components/Pagination/pagination.js +1 -1
- package/dist/components/Pagination/pagination.js.map +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +7 -6
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.js +6 -7
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker-helpers.js +1 -1
- package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +2 -2
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
- package/dist/components/PeoplePicker/person-display.js +26 -28
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +10 -4
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/rating.d.ts +28 -6
- package/dist/components/Rating/rating.d.ts.map +1 -1
- package/dist/components/Rating/rating.js +97 -80
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +1 -1
- package/dist/components/ScrollArea/scroll-area.js +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js +3 -2
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +15 -8
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/index.js +2 -1
- package/dist/components/SelectMenu/index.js.map +1 -1
- package/dist/components/SelectMenu/select-menu-keyboard.d.ts +59 -0
- package/dist/components/SelectMenu/select-menu-keyboard.d.ts.map +1 -0
- package/dist/components/SelectMenu/select-menu-keyboard.js +107 -0
- package/dist/components/SelectMenu/select-menu-keyboard.js.map +1 -0
- package/dist/components/SelectMenu/select-menu.d.ts +1 -22
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +18 -34
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
- package/dist/components/SelectionControl/selection-item.js +1 -0
- package/dist/components/SelectionControl/selection-item.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +7 -9
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +171 -50
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Slider/slider.d.ts +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +9 -4
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +54 -26
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +1 -1
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +7 -2
- 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 +39 -4
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/tag.d.ts +1 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +3 -2
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +8 -2
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
- package/dist/components/TimePicker/time-columns.js +8 -4
- package/dist/components/TimePicker/time-columns.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +1 -1
- package/dist/components/TimePicker/time-picker.js +1 -1
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +9 -5
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +266 -214
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/hooks/use-input-modality.d.ts +12 -17
- package/dist/hooks/use-input-modality.d.ts.map +1 -1
- package/dist/hooks/use-input-modality.js +4 -34
- package/dist/hooks/use-input-modality.js.map +1 -1
- package/dist/hooks/use-overflow-items.d.ts.map +1 -1
- package/dist/hooks/use-overflow-items.js +2 -0
- package/dist/hooks/use-overflow-items.js.map +1 -1
- package/dist/hooks/use-truncated.d.ts.map +1 -1
- package/dist/hooks/use-truncated.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/drag-announcements.d.ts +32 -0
- package/dist/lib/drag-announcements.d.ts.map +1 -1
- package/dist/lib/drag-announcements.js +39 -1
- package/dist/lib/drag-announcements.js.map +1 -1
- package/dist/lib/focus-after-trigger.d.ts +45 -0
- package/dist/lib/focus-after-trigger.d.ts.map +1 -0
- package/dist/lib/focus-after-trigger.js +66 -0
- package/dist/lib/focus-after-trigger.js.map +1 -0
- package/dist/lib/overlay-coexistence.js +1 -1
- package/dist/lib/roving-list-keyboard.d.ts +208 -0
- package/dist/lib/roving-list-keyboard.d.ts.map +1 -0
- package/dist/lib/roving-list-keyboard.js +174 -0
- package/dist/lib/roving-list-keyboard.js.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +6 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +4 -4
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +14 -4
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -1
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js +25 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
- package/dist/tokens/categorical-color.d.ts +6 -1
- package/dist/tokens/categorical-color.d.ts.map +1 -1
- package/dist/tokens/categorical-color.js.map +1 -1
- package/dist/tokens/uiSize/icon-size.d.ts +1 -1
- package/dist/tokens/uiSize/stack-gap.d.ts +18 -0
- package/dist/tokens/uiSize/stack-gap.d.ts.map +1 -0
- package/dist/tokens/uiSize/stack-gap.js +5 -0
- package/dist/tokens/uiSize/stack-gap.js.map +1 -0
- package/ds-canonical/fork/codex/agents/skills/performance-audit/SKILL.md +1 -1
- package/ds-canonical/fork/codex/hooks.json +1 -1
- package/ds-canonical/fork/consumer/lock.json +17 -14
- package/ds-canonical/fork/consumer/managed-files/423729840acdd43c812f17c245b871716c6b60f76e4d3e94864d0e34a815bf8d.blob +9 -0
- package/ds-canonical/fork/consumer/managed-files/46f10bc55cdfdf834d0749eebff42ea0bb8576f361b36d2b6ba1851354c50150.blob +47 -9
- package/ds-canonical/fork/consumer/managed-files/5a0d134a2645114c8caac20458070b00a7f0fd55b3e8805b7325cb4cf52fa15e.blob +110 -0
- package/ds-canonical/fork/consumer/managed-files/5af0a46760af338d51fd0f7950675f8e97f7d2f09386b8818fcd7a58e6654e75.blob +790 -0
- package/ds-canonical/fork/consumer/managed-files/68bfcddff9c4a16388c248cd34fb66163e9e64b3d809a48ef3984f6ae4ff6d12.blob +211 -0
- package/ds-canonical/fork/consumer/managed-files/7eb6cc60abfdabaf6617c336058fad1454ccde08889295767bfd9b7fd153cc6e.blob +45 -6
- package/ds-canonical/fork/consumer/managed-files/92e4828cdcb96ff0d01daa16f6885f24045a8e72820665650f2a1890dc3a446c.blob +42 -2
- package/ds-canonical/fork/consumer/managed-files/ab072e7f2eca51f0e18a5e18c4b333260ee5d219a12cc6df5bb2d683f0b2734d.blob +27 -1
- package/ds-canonical/fork/consumer/managed-files/e71c65f45c6af7ce12b6b3c0d8028f185da5b719e2050c9b2a6b243d41ae4878.blob +62 -14
- package/ds-canonical/fork/governance.lock +41 -17
- package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +16 -4
- package/ds-canonical/fork/hooks/check_consumer_code_quality.sh +3 -1
- package/ds-canonical/fork/hooks/check_pattern_invariants.sh +13 -9
- package/ds-canonical/fork/launchers/settings-hooks.json +1 -1
- package/ds-canonical/fork/manifest.json +17 -11
- package/ds-canonical/fork/providers/claude/skills/performance-audit/SKILL.md +1 -1
- package/ds-canonical/fork/providers/codex/hook-config.json +1 -1
- package/ds-canonical/fork/providers/codex/skills/performance-audit/SKILL.md +1 -1
- package/ds-canonical/fork/skills/performance-audit/SKILL.md +1 -1
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +16 -4
- package/ds-canonical/hooks/check_consumer_code_quality.sh +3 -1
- package/ds-canonical/hooks/check_datatable_invariants.sh +4 -1
- package/ds-canonical/hooks/check_pattern_invariants.sh +13 -9
- package/ds-canonical/hooks/check_plugin_fork_health.sh +8 -1
- package/ds-canonical/hooks/check_propose_discipline.sh +8 -1
- package/ds-canonical/hooks/check_storybook_addon_packaging.sh +8 -1
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +64 -2
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +5 -2
- package/ds-canonical/hooks/registrations.json +12 -7
- package/ds-canonical/hooks/session_start_governance_check.sh +16 -0
- package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +25 -0
- package/ds-canonical/hooks/tests/test_check_consumer_code_quality.sh +4 -0
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +14 -0
- package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +32 -0
- package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +59 -0
- package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +32 -1
- package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +21 -0
- package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +21 -0
- package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +97 -0
- package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +49 -0
- package/ds-canonical/references/README.md +12 -6
- package/ds-canonical/references/drag-canonical.md +3 -1
- package/ds-canonical/references/focus-canonical.md +26 -13
- package/ds-canonical/references/governance-audit-coverage.md +1 -1
- package/ds-canonical/references/hit-area-canonical.md +361 -0
- package/ds-canonical/references/item-anatomy-recipe.md +4 -2
- package/ds-canonical/references/keyboard-model-canonical.md +559 -0
- package/ds-canonical/rules/meta-patterns.md +4 -4
- package/ds-canonical/rules/self-verify.md +4 -4
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1 -1
- package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +96 -0
- package/ds-canonical/skills/knowledge-prune/SKILL.md +4 -1
- package/ds-canonical/skills/performance-audit/SKILL.md +1 -1
- package/ds-story-manifest.json +19 -7
- package/llms-full.txt +2 -2
- package/llms.txt +2 -2
- package/package.json +3 -1
- package/src/components/Accordion/accordion.anatomy.stories.tsx +3 -3
- package/src/components/Accordion/accordion.spec.md +1 -1
- package/src/components/Accordion/accordion.tsx +8 -3
- package/src/components/AccountMenu/account-menu.spec.md +2 -3
- package/src/components/AccountMenu/account-menu.tsx +0 -1
- package/src/components/AgentPanel/agent-decision-card.spec.md +88 -0
- package/src/components/AgentPanel/agent-panel-fab.spec.md +151 -0
- package/src/components/AgentPanel/agent-panel-fab.tsx +67 -24
- package/src/components/AgentPanel/agent-panel-logo.spec.md +87 -0
- package/src/components/AgentPanel/agent-panel-logo.tsx +3 -3
- package/src/components/AgentPanel/agent-panel.anatomy.stories.tsx +1 -1
- package/src/components/AgentPanel/agent-panel.principles.stories.tsx +1 -1
- package/src/components/AgentPanel/agent-panel.spec.md +30 -275
- package/src/components/AgentPanel/agent-panel.stories.tsx +113 -8
- package/src/components/AgentPanel/agent-panel.tsx +59 -22
- package/src/components/Alert/alert.anatomy.stories.tsx +1 -1
- package/src/components/AppShell/app-shell.tsx +1 -1
- package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +10 -15
- package/src/components/Avatar/avatar.anatomy.stories.tsx +23 -26
- package/src/components/Avatar/avatar.principles.stories.tsx +10 -10
- package/src/components/Avatar/avatar.spec.md +45 -6
- package/src/components/Avatar/avatar.stories.tsx +8 -8
- package/src/components/Avatar/avatar.tsx +227 -21
- package/src/components/Badge/badge.anatomy.stories.tsx +16 -21
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +3 -3
- package/src/components/Breadcrumb/breadcrumb.spec.md +3 -3
- package/src/components/Breadcrumb/breadcrumb.tsx +5 -3
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +1 -0
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +57 -2
- package/src/components/BulkActionBar/bulk-action-bar.tsx +32 -2
- package/src/components/Button/button.anatomy.stories.tsx +174 -33
- package/src/components/Button/button.spec.md +23 -8
- package/src/components/Button/button.tsx +116 -21
- package/src/components/Calendar/calendar.anatomy.stories.tsx +34 -11
- package/src/components/Calendar/calendar.principles.stories.tsx +44 -1
- package/src/components/Calendar/calendar.spec.md +97 -20
- package/src/components/Calendar/calendar.stories.tsx +101 -4
- package/src/components/Calendar/calendar.tsx +379 -74
- package/src/components/Carousel/carousel.anatomy.stories.tsx +16 -17
- package/src/components/Carousel/carousel.spec.md +48 -2
- package/src/components/Carousel/carousel.tsx +9 -3
- package/src/components/Chart/chart.anatomy.stories.tsx +7 -5
- package/src/components/Chart/chart.spec.md +32 -7
- package/src/components/Chart/chart.tsx +9 -0
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +21 -28
- package/src/components/Checkbox/checkbox.spec.md +4 -2
- package/src/components/Checkbox/checkbox.tsx +10 -2
- package/src/components/Chip/chip.anatomy.stories.tsx +1 -1
- package/src/components/Chip/chip.spec.md +2 -1
- package/src/components/Chip/chip.tsx +4 -2
- package/src/components/Combobox/combobox.anatomy.stories.tsx +30 -37
- package/src/components/Combobox/combobox.spec.md +11 -3
- package/src/components/Combobox/combobox.tsx +43 -12
- package/src/components/Command/command.spec.md +11 -0
- package/src/components/Command/command.tsx +143 -10
- package/src/components/DataTable/cell-registry.tsx +5 -1
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +5 -6
- package/src/components/DataTable/data-table-interaction-layer.tsx +27 -14
- package/src/components/DataTable/data-table-known-defects.spec.md +72 -0
- package/src/components/DataTable/data-table-scroll-performance.spec.md +295 -0
- package/src/components/DataTable/data-table-sort-manager.tsx +5 -6
- package/src/components/DataTable/data-table.anatomy.stories.tsx +1 -1
- package/src/components/DataTable/data-table.css +64 -0
- package/src/components/DataTable/data-table.spec.md +70 -346
- package/src/components/DataTable/data-table.stories.tsx +56 -9
- package/src/components/DataTable/data-table.tsx +392 -103
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +2 -2
- package/src/components/DateGrid/date-grid.spec.md +163 -1
- package/src/components/DateGrid/date-grid.tsx +270 -7
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +18 -27
- package/src/components/DatePicker/date-picker.spec.md +6 -2
- package/src/components/DatePicker/date-picker.tsx +20 -1
- package/src/components/Dialog/dialog.spec.md +6 -2
- package/src/components/Dialog/dialog.stories.tsx +18 -9
- package/src/components/Dialog/dialog.tsx +83 -48
- package/src/components/DropdownMenu/dropdown-menu-keyboard.ts +255 -0
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +32 -33
- package/src/components/DropdownMenu/dropdown-menu.spec.md +18 -5
- package/src/components/DropdownMenu/dropdown-menu.stories.tsx +58 -1
- package/src/components/DropdownMenu/dropdown-menu.tsx +70 -33
- package/src/components/Empty/empty.spec.md +1 -2
- package/src/components/Field/field-context.ts +9 -4
- package/src/components/Field/field-controls.spec.md +5 -2
- package/src/components/Field/field-edit-keys.ts +12 -0
- package/src/components/Field/field-wrapper.tsx +76 -10
- package/src/components/Field/field.anatomy.stories.tsx +1 -1
- package/src/components/Field/field.spec.md +11 -6
- package/src/components/Field/field.stories.tsx +24 -1
- package/src/components/Field/field.tsx +10 -4
- package/src/components/FileItem/file-item.anatomy.stories.tsx +20 -10
- package/src/components/FileItem/file-item.principles.stories.tsx +14 -7
- package/src/components/FileItem/file-item.spec.md +50 -48
- package/src/components/FileItem/file-item.stories.tsx +41 -28
- package/src/components/FileItem/file-item.tsx +184 -50
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +11 -15
- package/src/components/FileUpload/file-upload.spec.md +27 -1
- package/src/components/FileUpload/file-upload.stories.tsx +33 -0
- package/src/components/FileUpload/file-upload.tsx +173 -43
- package/src/components/FileViewer/file-viewer.tsx +9 -4
- package/src/components/HoverCard/hover-card.stories.tsx +2 -2
- package/src/components/InlineEdit/inline-edit.spec.md +2 -0
- package/src/components/InlineEdit/inline-edit.tsx +8 -3
- package/src/components/Input/input.anatomy.stories.tsx +23 -31
- package/src/components/Input/input.spec.md +11 -0
- package/src/components/Input/input.tsx +6 -1
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +18 -21
- package/src/components/LinkInput/link-input.principles.stories.tsx +4 -4
- package/src/components/LinkInput/link-input.spec.md +12 -1
- package/src/components/LinkInput/link-input.tsx +37 -4
- package/src/components/Menu/menu-item.anatomy.stories.tsx +50 -56
- package/src/components/Menu/menu-item.spec.md +1 -1
- package/src/components/Menu/menu-item.stories.tsx +48 -42
- package/src/components/Notice/notice.anatomy.stories.tsx +8 -16
- package/src/components/Notice/notice.spec.md +1 -1
- package/src/components/Notice/notice.tsx +1 -1
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +21 -28
- package/src/components/NumberInput/number-input.spec.md +2 -0
- package/src/components/NumberInput/number-input.tsx +8 -1
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +28 -48
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +13 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +12 -9
- package/src/components/OverflowIndicator/overflow-indicator.tsx +32 -12
- package/src/components/Pagination/pagination.spec.md +1 -0
- package/src/components/Pagination/pagination.tsx +1 -1
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +14 -13
- package/src/components/PeoplePicker/people-picker-helpers.ts +5 -2
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +1 -1
- package/src/components/PeoplePicker/people-picker.spec.md +4 -2
- package/src/components/PeoplePicker/people-picker.tsx +1 -4
- package/src/components/PeoplePicker/person-display.tsx +45 -28
- package/src/components/Popover/popover.anatomy.stories.tsx +1 -1
- package/src/components/Popover/popover.principles.stories.tsx +3 -12
- package/src/components/Popover/popover.spec.md +7 -3
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.spec.md +1 -1
- package/src/components/ProfileCard/profile-card.tsx +0 -3
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +11 -21
- package/src/components/ProgressBar/progress-bar.spec.md +1 -1
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +17 -24
- package/src/components/RadioGroup/radio-group.spec.md +1 -1
- package/src/components/RadioGroup/radio-group.tsx +22 -4
- package/src/components/Rating/rating.anatomy.stories.tsx +131 -124
- package/src/components/Rating/rating.principles.stories.tsx +69 -43
- package/src/components/Rating/rating.spec.md +142 -63
- package/src/components/Rating/rating.stories.tsx +11 -15
- package/src/components/Rating/rating.tsx +131 -117
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +6 -3
- package/src/components/ScrollArea/scroll-area.spec.md +3 -1
- package/src/components/ScrollArea/scroll-area.stories.tsx +5 -2
- package/src/components/ScrollArea/scroll-area.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +2 -2
- package/src/components/SegmentedControl/segmented-control.tsx +3 -2
- package/src/components/Select/select.anatomy.stories.tsx +26 -35
- package/src/components/Select/select.spec.md +4 -3
- package/src/components/Select/select.tsx +11 -4
- package/src/components/SelectMenu/select-menu-keyboard.ts +218 -0
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +6 -17
- package/src/components/SelectMenu/select-menu.spec.md +12 -4
- package/src/components/SelectMenu/select-menu.tsx +21 -56
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +9 -33
- package/src/components/SelectionControl/selection-item.spec.md +2 -2
- package/src/components/SelectionControl/selection-item.tsx +3 -1
- package/src/components/Separator/separator.stories.tsx +4 -4
- package/src/components/Sheet/sheet.principles.stories.tsx +31 -13
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +1 -1
- package/src/components/Sidebar/sidebar.spec.md +73 -6
- package/src/components/Sidebar/sidebar.stories.tsx +82 -4
- package/src/components/Sidebar/sidebar.tsx +281 -64
- package/src/components/Skeleton/skeleton.spec.md +1 -1
- package/src/components/Slider/slider.anatomy.stories.tsx +1 -1
- package/src/components/Slider/slider.spec.md +6 -5
- package/src/components/Slider/slider.tsx +13 -8
- package/src/components/Steps/steps-state-visuals.spec.md +157 -0
- package/src/components/Steps/steps.anatomy.stories.tsx +1 -0
- package/src/components/Steps/steps.spec.md +59 -142
- package/src/components/Steps/steps.stories.tsx +1 -1
- package/src/components/Steps/steps.tsx +125 -33
- package/src/components/Switch/switch.spec.md +3 -3
- package/src/components/Switch/switch.tsx +6 -1
- package/src/components/Tabs/tabs.spec.md +5 -1
- package/src/components/Tabs/tabs.tsx +42 -3
- package/src/components/Tag/tag.anatomy.stories.tsx +24 -28
- package/src/components/Tag/tag.spec.md +10 -11
- package/src/components/Tag/tag.tsx +3 -3
- package/src/components/Textarea/textarea.tsx +7 -1
- package/src/components/TimePicker/time-columns.tsx +9 -4
- package/src/components/TimePicker/time-picker.spec.md +4 -1
- package/src/components/TimePicker/time-picker.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +6 -15
- package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -16
- package/src/components/Tooltip/tooltip.spec.md +2 -1
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +35 -13
- package/src/components/TreeView/tree-view.spec.md +67 -38
- package/src/components/TreeView/tree-view.stories.tsx +221 -12
- package/src/components/TreeView/tree-view.tsx +463 -356
- package/src/hooks/use-input-modality.ts +17 -46
- package/src/hooks/use-overflow-items.ts +4 -0
- package/src/hooks/use-truncated.ts +3 -2
- package/src/index.ts +17 -0
- package/src/lib/README.md +2 -0
- package/src/lib/drag-announcements.ts +78 -0
- package/src/lib/focus-after-trigger.ts +102 -0
- package/src/lib/roving-list-keyboard.ts +400 -0
- package/src/lib/utils.ts +5 -0
- package/src/patterns/action-bar/action-bar.spec.md +2 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +16 -12
- package/src/patterns/element-anatomy/item-anatomy.spec.md +98 -6
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +75 -70
- package/src/patterns/element-anatomy/item-anatomy.tsx +17 -6
- package/src/patterns/element-anatomy/truncated-text.spec.md +1 -0
- package/src/patterns/header-canonical/header-canonical.spec.md +3 -2
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +2 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +36 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +28 -0
- package/src/patterns/overlay-surface/overlay-chrome-sizing.spec.md +180 -0
- package/src/patterns/overlay-surface/overlay-surface.spec.md +8 -162
- package/src/patterns/overlay-surface/overlay-surface.tsx +5 -3
- package/src/patterns/resize-handle/resize-handle.spec.md +3 -3
- package/src/styles/base.css +1 -1
- package/src/tokens/categorical-color.ts +6 -1
- package/src/tokens/color/color.spec.md +91 -24
- package/src/tokens/color/color.stories.tsx +50 -2
- package/src/tokens/color/primitives.css +41 -38
- package/src/tokens/color/semantic.css +105 -36
- package/src/tokens/layoutSpace/layoutSpace.spec.md +2 -0
- package/src/tokens/motion/motion.spec.md +31 -8
- package/src/tokens/orphan-tokens.spec.md +1 -1
- package/src/tokens/uiSize/icon-size.ts +1 -1
- package/src/tokens/uiSize/stack-gap.ts +17 -0
- package/src/tokens/uiSize/uiSize.css +12 -0
- package/src/tokens/uiSize/uiSize.spec.md +17 -16
- package/src/tokens/uiSize/uiSize.stories.tsx +1 -1
- package/dist/node_modules/aria-hidden/dist/es2015/index.js +0 -147
- package/dist/node_modules/aria-hidden/dist/es2015/index.js.map +0 -1
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { Avatar, avatarMeta } from "./avatar.js";
|
|
1
|
+
import { AVATAR_DISMISS_OVERLAY_PX, AVATAR_OWN_CUTOUT_CLASS, AVATAR_STACK_CLASS, AVATAR_STACK_CUTOUT_CLASS, AVATAR_STACK_GAP_PX, AVATAR_STACK_ITEM_CLASS, AVATAR_STACK_OVERLAP_PX, AVATAR_STACK_OWN_CUTOUT_CLASS, Avatar, avatarMeta, avatarOverlayCutout, avatarStackCutoutImage, avatarStackCutoutStyle, avatarStackItemStyle } from "./avatar.js";
|
|
2
2
|
export {
|
|
3
|
+
AVATAR_DISMISS_OVERLAY_PX,
|
|
4
|
+
AVATAR_OWN_CUTOUT_CLASS,
|
|
5
|
+
AVATAR_STACK_CLASS,
|
|
6
|
+
AVATAR_STACK_CUTOUT_CLASS,
|
|
7
|
+
AVATAR_STACK_GAP_PX,
|
|
8
|
+
AVATAR_STACK_ITEM_CLASS,
|
|
9
|
+
AVATAR_STACK_OVERLAP_PX,
|
|
10
|
+
AVATAR_STACK_OWN_CUTOUT_CLASS,
|
|
3
11
|
Avatar,
|
|
4
|
-
avatarMeta
|
|
12
|
+
avatarMeta,
|
|
13
|
+
avatarOverlayCutout,
|
|
14
|
+
avatarStackCutoutImage,
|
|
15
|
+
avatarStackCutoutStyle,
|
|
16
|
+
avatarStackItemStyle
|
|
5
17
|
};
|
|
6
18
|
//# sourceMappingURL=index.js.map
|
|
@@ -27,7 +27,9 @@ import { ItemInlineActionButton } from '../../patterns/element-anatomy/item-anat
|
|
|
27
27
|
*
|
|
28
28
|
* ── 視覺 ──
|
|
29
29
|
* Link (預設): text-fg-secondary
|
|
30
|
-
* Link hover: text-primary-hover
|
|
30
|
+
* Link hover: text-primary-hover(連結滑過換色 canonical,owner color.spec.md「連結 hover = 換色」;
|
|
31
|
+
* 跟 Tabs / Chip 不是同一條 —— Tabs 滑過是字轉 foreground、Chip 只有選中態滑過才轉 primary-hover;
|
|
32
|
+
* 2026-09-27 更正舊句「跟 Tabs / Chip 用法一致」)
|
|
31
33
|
* Page (當前): text-foreground(不加粗 — 加粗會讓 breadcrumb 最右端視覺過重,見 spec)
|
|
32
34
|
* Separator: ChevronRight (size 跟 list 一致), text-fg-muted
|
|
33
35
|
*
|
|
@@ -168,7 +170,7 @@ export declare const breadcrumbMeta: {
|
|
|
168
170
|
readonly tokens: {
|
|
169
171
|
readonly bg: readonly [];
|
|
170
172
|
readonly fg: readonly ["text-fg-muted", "text-fg-secondary", "text-foreground"];
|
|
171
|
-
readonly ring: readonly ["ring
|
|
173
|
+
readonly ring: readonly ["--ring"];
|
|
172
174
|
};
|
|
173
175
|
};
|
|
174
176
|
export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumb/breadcrumb.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAE5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,uDAAuD,CAAA;AAa9F
|
|
1
|
+
{"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumb/breadcrumb.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAE5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,uDAAuD,CAAA;AAa9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,KAAK,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AA2BxC,QAAA,MAAM,UAAU,0JAKd,CAAA;AAKF;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,UAAU,CAAA;CACvB;AAED,UAAU,mBAAoB,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC1F;;;;;OAKG;IACH,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAGD,QAAA,MAAM,cAAc,8FA6LnB,CAAA;AAKD;;;;;;;;;;;;GAYG;AACH,UAAU,mBAAoB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,IAAI,CAAC;IACxE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;CAClD;AAED,QAAA,MAAM,cAAc,2FA4BnB,CAAA;AAKD,UAAU,mBAAoB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,GAAG,CAAC;IACvE,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,UAAU,CAAA;CACvB;AAED,QAAA,MAAM,cAAc,+FAwCnB,CAAA;AAKD,UAAU,mBAAoB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,MAAM,CAAC;IAC1E,wEAAwE;IACxE,SAAS,CAAC,EAAE,UAAU,CAAA;CACvB;AAED,QAAA,MAAM,cAAc,6FAqBnB,CAAA;AAKD,UAAU,wBAAyB,SAAQ,KAAK,CAAC,wBAAwB,CAAC,IAAI,CAAC;IAC7E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAGD,QAAA,MAAM,mBAAmB,gGAgBxB,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,KAAK,uBAAuB,GAAG,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,sBAAsB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAEnH,QAAA,MAAM,kBAAkB,mGAavB,CAAA;AAKD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;CAmBjB,CAAA;AAEV,OAAO,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,kBAAkB,GACnB,CAAA;AACD,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,CAAA"}
|
|
@@ -165,8 +165,8 @@ const BreadcrumbLink = React.forwardRef(
|
|
|
165
165
|
"inline-flex items-center gap-2",
|
|
166
166
|
"min-w-0 max-w-full",
|
|
167
167
|
"text-fg-secondary",
|
|
168
|
+
// hover 字色瞬間切換,不寫 transition-colors(tokens/motion/motion.spec.md「hover 回饋不做過渡」;2026-09-26 由底色延伸到字色,待辦總帳 L9 / N4(3))
|
|
168
169
|
"hover:text-primary-hover",
|
|
169
|
-
"transition-colors duration-150",
|
|
170
170
|
"rounded-md",
|
|
171
171
|
className
|
|
172
172
|
);
|
|
@@ -251,7 +251,7 @@ const breadcrumbMeta = {
|
|
|
251
251
|
tokens: {
|
|
252
252
|
bg: [],
|
|
253
253
|
fg: ["text-fg-muted", "text-fg-secondary", "text-foreground"],
|
|
254
|
-
ring: ["ring
|
|
254
|
+
ring: ["--ring"]
|
|
255
255
|
}
|
|
256
256
|
};
|
|
257
257
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breadcrumb.js","sources":["../../../src/components/Breadcrumb/breadcrumb.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — Breadcrumb 含 BreadcrumbList(主)+ BreadcrumbItem + BreadcrumbEllipsis + items-collapse logic,split 會破壞 collapse/overflow Tooltip subtree\nimport * as React from 'react'\nimport { Slot } from '@radix-ui/react-slot'\nimport { ChevronRight, MoreHorizontal, type LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { ItemInlineActionButton } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { TruncatedText } from '@/design-system/patterns/element-anatomy/truncated-text'\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '@/design-system/components/DropdownMenu/dropdown-menu'\n\n// ── TruncatedText ── 2026-07-19:truncate+tooltip 引擎 + presentation 已抽成 SSOT primitive\n// `patterns/element-anatomy/truncated-text`(`<TruncatedText>` 消費 `useTruncated` hook)。本檔改為\n// 消費 `<TruncatedText display=\"block\" tooltip={fullText}>`,原 file-local shared RO + TruncatedLabel 已移除。\n\n/**\n * Breadcrumb — 顯示當前頁面在階層中的位置\n *\n * 基於 shadcn/ui Breadcrumb 結構(純 HTML nav + ol + li + a/span),\n * 橋接設計系統 token。\n *\n * ── 結構 ──\n * <Breadcrumb>\n * <BreadcrumbList size=\"md\">\n * <BreadcrumbItem>\n * <BreadcrumbLink href=\"/projects\">專案</BreadcrumbLink>\n * </BreadcrumbItem>\n * <BreadcrumbSeparator />\n * <BreadcrumbItem>\n * <BreadcrumbPage>目前頁面</BreadcrumbPage>\n * </BreadcrumbItem>\n * </BreadcrumbList>\n * </Breadcrumb>\n *\n * ── Size(跟 page title 配對) ──\n * sm text-body(14) → 建議配 text-h4(20) title —— Dialog / panel / drawer\n * md text-body(14) → 建議配 text-h3(24) title —— 一般頁面 header (預設)\n * lg text-body-lg(16) → 建議配 text-h2(32) title —— Detail page hero / landing\n *\n * ── 視覺 ──\n * Link (預設): text-fg-secondary\n * Link hover: text-primary-hover (canonical「互動高亮」, 跟 Tabs / Chip 用法一致)\n * Page (當前): text-foreground(不加粗 — 加粗會讓 breadcrumb 最右端視覺過重,見 spec)\n * Separator: ChevronRight (size 跟 list 一致), text-fg-muted\n *\n * ── 詳見 breadcrumb.spec.md ──\n */\n\n// ── Size context ─────────────────────────────────────────────────────────────\n\ntype BreadcrumbSize = 'sm' | 'md' | 'lg'\n\ninterface BreadcrumbContextValue {\n size: BreadcrumbSize\n}\n\nconst BreadcrumbContext = React.createContext<BreadcrumbContextValue>({ size: 'md' })\n\nconst BREADCRUMB_TEXT_CLASS: Record<BreadcrumbSize, string> = {\n sm: 'text-body',\n md: 'text-body',\n lg: 'text-body-lg',\n}\n\n// Separator chevron + BreadcrumbLink/Item start icon 尺寸 — 對齊 uiSize.spec.md「Icon Size Tier」(field-height-sm/md→16,lg→20)。\n// 注意:BreadcrumbEllipsis 不消費此常數,固定 md(16px icon,見 BreadcrumbEllipsis 定義),size='lg' 時不隨 chevron 放大到 20\n// 2026-05-18 改 per user 拍板「A 先改 16/16/20」+「做完」approval:\n// 撤回 text-flow 例外設計,Breadcrumb chevron 跟其他 chrome icon 同 tier。\n// World-class 對齊:Atlassian Breadcrumb chevron 16 default / Material 3 / Ant Design 同。\nconst BREADCRUMB_ICON_SIZE: Record<BreadcrumbSize, number> = {\n sm: 16,\n md: 16,\n lg: 20,\n}\n\n// ── Breadcrumb (nav root) ────────────────────────────────────────────────────\n\nconst Breadcrumb = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'>\n>(({ ...props }, ref) => (\n <nav ref={ref} aria-label=\"Breadcrumb\" {...props} />\n))\nBreadcrumb.displayName = 'Breadcrumb'\n\n// ── BreadcrumbList (ol) ──────────────────────────────────────────────────────\n\n/**\n * Phase B(2026-05-10):declarative items mode 啟用 auto-collapse + auto-separator + auto-page-end。\n * 對齊 Material UI source `Breadcrumbs.js renderItemsBeforeAndAfter` mechanism(`maxItems`\n * default 8;本 DS 採 user-tuned 4 — 更積極 collapse 適合 single-line 緊湊 layout)。\n */\n// code-quality-allow: dead-export — public consumer-facing item spec type;對齊 BreadcrumbProps API contract,允許 consumer 構造 items array 外部\nexport interface BreadcrumbItemSpec {\n label: React.ReactNode\n href?: string\n asChild?: boolean\n /**\n * 起始 icon(per `ui-development.md`「icon prop 命名 4 條」:slot 只接 icon → `startIcon`)。\n * 業界慣例:Breadcrumb 首項用 Home icon 強化視覺錨點(Material / Atlassian)。\n * 內部消費 `BREADCRUMB_ICON_SIZE[size]` SSOT(sm/md=16, lg=20,對齊 uiSize.spec.md Icon Size Tier)。\n * Consumer **不傳** size,DS 統一管。\n */\n startIcon?: LucideIcon\n}\n\ninterface BreadcrumbListProps extends Omit<React.ComponentPropsWithoutRef<'ol'>, 'children'> {\n /**\n * 字體尺寸 — 依據與之配對的 page title 選擇:\n * sm → 配 text-h4(20) title (Dialog / panel / drawer)\n * md → 配 text-h3(24) title (一般頁面 header,預設)\n * lg → 配 text-h2(32) title (Detail page hero / landing)\n */\n size?: BreadcrumbSize\n /**\n * Declarative items mode(opt-in)。當 provided 時 `children` 被忽略,List 內部自動:\n * - 插 separator\n * - 末位 spec(無 `href`)自動 BreadcrumbPage(per Title-breadcrumb-end SSOT)\n * - 超 `maxItems` auto-collapse 中段成 BreadcrumbEllipsis + DropdownMenu(對齊 Material UI\n * source `renderItemsBeforeAndAfter`)\n */\n items?: BreadcrumbItemSpec[]\n /**\n * Auto-collapse 閾值。Default 4(user-tuned;Material UI source 預設 8)。`items.length > maxItems`\n * 才 collapse。\n */\n maxItems?: number\n /** Collapse 後保留首 N 個(default 1)。對齊 Material UI source default。 */\n itemsBeforeCollapse?: number\n /** Collapse 後保留末 N 個(default 1)。對齊 Material UI source default。 */\n itemsAfterCollapse?: number\n children?: React.ReactNode\n}\n\n// code-quality-allow: long-function — items props × children narrowing × collapse-with-overflow × tooltip 4 軸組合在 BreadcrumbList,拆 sub-fn 會跨 fn 傳 itemsBeforeCollapse/After collapsed-tooltip refs\nconst BreadcrumbList = React.forwardRef<HTMLOListElement, BreadcrumbListProps>(\n ({ className, size = 'md', items, maxItems = 4, itemsBeforeCollapse = 1, itemsAfterCollapse = 1, children, ...props }, ref) => {\n // Memoize provider value(2026-04-22 D3 perf audit):單 field wrapper memoize\n const ctxValue = React.useMemo(() => ({ size }), [size])\n\n // Declarative mode(items prop provided):自動 render + auto-collapse\n const declarativeContent = React.useMemo(() => {\n if (!items) return null\n // 2026-07-04 修:非字串 label 的 key 原用 Math.random() → 每次 render 新 key 造成\n // BreadcrumbItem unmount/remount(重置 TruncatedText ResizeObserver 與 state)→ 改 stable idx key\n const renderItem = (spec: BreadcrumbItemSpec, role: 'root' | 'middle' | 'current', idx: number) => (\n <BreadcrumbItem key={`${role}-${typeof spec.label === 'string' ? spec.label : idx}`} role={role}>\n {role === 'current'\n ? <BreadcrumbPage startIcon={spec.startIcon}>\n <TruncatedText display=\"block\" tooltip={typeof spec.label === 'string' ? spec.label : undefined}>{spec.label}</TruncatedText>\n </BreadcrumbPage>\n : <BreadcrumbLink href={spec.href} asChild={spec.asChild} startIcon={spec.startIcon}>\n <TruncatedText display=\"block\" tooltip={typeof spec.label === 'string' ? spec.label : undefined}>{spec.label}</TruncatedText>\n </BreadcrumbLink>\n }\n </BreadcrumbItem>\n )\n\n const shouldCollapse = items.length > maxItems\n const beforeN = Math.max(0, itemsBeforeCollapse)\n const afterN = Math.max(1, itemsAfterCollapse) // 末位永遠 ≥ 1(current page)\n\n type VisibleItem = { spec: BreadcrumbItemSpec; role: 'root' | 'middle' | 'current' }\n let visible: Array<VisibleItem | { ellipsisOf: BreadcrumbItemSpec[] }>\n if (!shouldCollapse) {\n visible = items.map((spec, i) => ({\n spec,\n role: i === 0 ? 'root' : (i === items.length - 1 ? 'current' : 'middle') as 'root' | 'middle' | 'current',\n }))\n } else {\n const before = items.slice(0, beforeN).map((spec, i) => ({\n spec,\n role: (i === 0 ? 'root' : 'middle') as 'root' | 'middle' | 'current',\n }))\n const collapsed = items.slice(beforeN, items.length - afterN)\n const after = items.slice(items.length - afterN).map((spec, i, arr) => ({\n spec,\n role: (i === arr.length - 1 ? 'current' : 'middle') as 'root' | 'middle' | 'current',\n }))\n visible = [...before, { ellipsisOf: collapsed }, ...after]\n }\n\n // Interleave with separators\n const rendered: React.ReactNode[] = []\n visible.forEach((entry, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-${i}`} />)\n if ('ellipsisOf' in entry) {\n rendered.push(\n <BreadcrumbItem key=\"ellipsis\" role=\"ellipsis\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <BreadcrumbEllipsis />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {entry.ellipsisOf.map((s, j) => (\n <DropdownMenuItem key={j} asChild={!!s.href}>\n {s.href ? <a href={s.href}>{s.label}</a> : <span>{s.label}</span>}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n )\n } else {\n rendered.push(renderItem(entry.spec, entry.role, i))\n }\n })\n return rendered\n }, [items, maxItems, itemsBeforeCollapse, itemsAfterCollapse])\n\n // 2026-05-12 fix(user 抓 image 2 Deep story 違反 single-line + max-levels canonical):\n // Compositional path 也走 auto-collapse + flex-shrink hierarchy。Walk children, 找\n // BreadcrumbItem 並按 index 分派 role (first=root / last=current / middle=middle)。\n // > maxItems 自動 collapse 中段成 ellipsis(對齊 declarative path canonical SSOT)。\n const compositionalContent = React.useMemo(() => {\n if (items) return null\n const childArr = React.Children.toArray(children)\n // 抓 BreadcrumbItem children(skip BreadcrumbSeparator — auto re-interleave)\n // 2026-05-12 Round 4.5 fix(codex M31 Layer C 抓):type-identity primary path + displayName fallback。\n // 純 `displayName` check 在 HOC / React.memo / consumer alias 場景脆弱(production build / wrap\n // 可能改寫 displayName)。`c.type === BreadcrumbItem` 是 React fiber reference-identity 最穩\n // primary(對齊 Radix children-walk pattern);displayName fallback 給 HOC 場景。\n const itemChildren = childArr.filter((c): c is React.ReactElement<BreadcrumbItemProps> =>\n React.isValidElement(c) && (c.type === BreadcrumbItem ||\n (c.type as React.ComponentType)?.displayName === 'BreadcrumbItem')\n )\n // 無 item 或全是 separator → pass-through(consumer raw children,e.g. spinners)\n if (itemChildren.length === 0) return children\n // Assign role by position; clone with role prop\n const total = itemChildren.length\n const cloneWithRole = (item: React.ReactElement<BreadcrumbItemProps>, idx: number, role: 'root' | 'middle' | 'current') =>\n React.cloneElement(item, { role: item.props.role ?? role, key: `bc-${role}-${idx}` })\n const shouldCollapse = total > maxItems\n const beforeN = Math.max(0, itemsBeforeCollapse)\n const afterN = Math.max(1, itemsAfterCollapse)\n const rendered: React.ReactNode[] = []\n if (!shouldCollapse) {\n itemChildren.forEach((item, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-${i}`} />)\n const role: 'root' | 'middle' | 'current' = i === 0 ? 'root' : (i === total - 1 ? 'current' : 'middle')\n rendered.push(cloneWithRole(item, i, role))\n })\n } else {\n // before(first N) + ellipsis + after(last M)\n const beforeItems = itemChildren.slice(0, beforeN)\n const collapsedItems = itemChildren.slice(beforeN, total - afterN)\n const afterItems = itemChildren.slice(total - afterN)\n beforeItems.forEach((item, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-bef-${i}`} />)\n const role: 'root' | 'middle' = i === 0 ? 'root' : 'middle'\n rendered.push(cloneWithRole(item, i, role))\n })\n if (rendered.length > 0) rendered.push(<BreadcrumbSeparator key=\"sep-ellipsis-before\" />)\n rendered.push(\n <BreadcrumbItem key=\"bc-ellipsis\" role=\"ellipsis\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <BreadcrumbEllipsis />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {collapsedItems.map((item, j) => {\n // 2026-05-12 Round 4.5 fix(codex M31 Layer C 抓):consumer BreadcrumbItem children 常包\n // `<BreadcrumbLink href>` = anchor button-like。直接放進 `<DropdownMenuItem>` 會 nested\n // interactive(menuitem within button violates HTML / a11y)。Fix:把實際 link 元素接到\n // menuitem `asChild`,對齊 declarative path canonical pattern。\n // 2026-07-19 fix(DA3 對抗稽核抓):原只讀 `c.props.href` → `<BreadcrumbLink asChild>\n // <RouterLink to=…>` 這種(BreadcrumbLink 無 href、RouterLink child 帶 `to`)摺疊後\n // dropdown 失去導航目標。修:asChild 時**保留整個 link 子元素**(RouterLink/<Link to>/<a>,\n // 含 to/href/onClick/state 全 forward,前端路由不退化成整頁重載);純 href 才重建 <a>。\n const innerChildren = (item.props as { children?: React.ReactNode }).children\n let menuChild: React.ReactNode | undefined // 接進 menuitem(asChild)的實際 link 元素\n let label: React.ReactNode = innerChildren // fallback:無 link 時的純內容\n React.Children.forEach(innerChildren, (c) => {\n if (!React.isValidElement<{ href?: string; asChild?: boolean; children?: React.ReactNode }>(c)) return\n if (c.props.asChild && React.isValidElement(c.props.children)) {\n // BreadcrumbLink asChild → 實際 link = 其 child(RouterLink / <Link to> / <a>),整個保留\n menuChild = c.props.children\n const grand = (c.props.children.props as { children?: React.ReactNode }).children\n if (grand != null) label = grand\n } else if (c.props.href != null) {\n // BreadcrumbLink href → 重建 <a href>(對齊原 canonical,避免 nested interactive)\n menuChild = <a href={c.props.href}>{c.props.children}</a>\n if (c.props.children != null) label = c.props.children\n }\n })\n return menuChild\n ? <DropdownMenuItem key={`collapsed-${j}`} asChild>{menuChild}</DropdownMenuItem>\n : <DropdownMenuItem key={`collapsed-${j}`}>{label}</DropdownMenuItem>\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n )\n rendered.push(<BreadcrumbSeparator key=\"sep-ellipsis-after\" />)\n afterItems.forEach((item, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-aft-${i}`} />)\n const role: 'middle' | 'current' = i === afterItems.length - 1 ? 'current' : 'middle'\n rendered.push(cloneWithRole(item, i, role))\n })\n }\n return rendered\n }, [items, children, maxItems, itemsBeforeCollapse, itemsAfterCollapse])\n\n return (\n <BreadcrumbContext.Provider value={ctxValue}>\n <ol\n ref={ref}\n // gap-1 (4px) — separator 與兩邊 items 間距;緊湊節奏,符合 breadcrumb 密集流動感。\n // 2026-05-10 Phase A single-line canonical(per user + Material UI source verified):\n // `flex-nowrap` 不 wrap。長路徑走中段折疊。\n // 2026-05-12 fix:compositional 也走 auto-collapse + role-assignment(`compositionalContent`)\n // → declarative / compositional 兩 path 都符合 single-line + max-levels + width 分配 canonical SSOT。\n className={cn(\n 'flex flex-nowrap items-center gap-1 text-fg-secondary leading-compact min-w-0',\n BREADCRUMB_TEXT_CLASS[size],\n className\n )}\n {...props}\n >\n {items ? declarativeContent : compositionalContent}\n </ol>\n </BreadcrumbContext.Provider>\n )\n },\n)\nBreadcrumbList.displayName = 'BreadcrumbList'\n\n// ── BreadcrumbItem (li) ──────────────────────────────────────────────────────\n\n/**\n * Phase B(2026-05-10):`role` prop emit `data-bc-role` attr → CSS flex-shrink hierarchy。\n * Per BreadcrumbItem 在 row 中的角色決定 shrink 優先級:\n * - `root`(首位)→ shrink:3(縮最積極;root context 可弱化)\n * - `middle`(中段)→ shrink:2\n * - `current`(末位 / page)→ shrink:1(最後縮;a11y current page anchor)\n * - `ellipsis`(BreadcrumbEllipsis 包裝)→ shrink:0(永遠完整 ⋯)\n *\n * 設計回應 user 兩 challenges:\n * (a) Root 也 truncate(shrink:3,不是 shrink-0)\n * (b) 不用 fixed max-width — flex-shrink hierarchy 容器寬時自然展開不浪費空間,\n * 窄時按優先級縮 + TruncatedText 內部 CSS truncate + tooltip。\n */\ninterface BreadcrumbItemProps extends React.ComponentPropsWithoutRef<'li'> {\n role?: 'root' | 'middle' | 'current' | 'ellipsis'\n}\n\nconst BreadcrumbItem = React.forwardRef<HTMLLIElement, BreadcrumbItemProps>(\n ({ className, role, style, ...props }, ref) => {\n // 2026-05-20 fix v3(user 抓「專案 後方多 4px 間距 / 我的新專案 沒有」chevron 不對稱):\n // v2 `minWidth: '2rem'`(32px)在寬容器強制 li ≥ 32px → 短 label「專案」(natural ~28px)\n // 被撐 4px,長 label「我的新專案」(natural ~70px)hug content → chevron 兩側不對稱。\n //\n // v3 解法:minWidth `2rem` → `1.5rem`(24px)\n // 數學:中文「X…」最小寬度 = 1 char(~14-16px)+ ellipsis(~6-8px)≈ 22-24px → 24px 剛 cover\n // 結果:\n // - 寬容器:所有自然 label ≥ 24px → li hug content,chevron 緊貼,對稱(本 fix 主目的)\n // - 窄容器 truncate:shrink 不過 24px → 「X…」仍可見 ellipsis 保險\n // - 短英文「OK / ID」(natural ~20px)→ 多 ~4px(原 12px → 縮到 4px,顯著改善)\n // 對齊 user verbatim「minWidth 再調小一點」+ ellipsis 數學最小值。\n const shrinkStyle: React.CSSProperties = role === 'root' ? { flexShrink: 3, minWidth: '1.5rem' }\n : role === 'middle' ? { flexShrink: 2, minWidth: '1.5rem' }\n : role === 'current' ? { flexShrink: 1, minWidth: '1.5rem' }\n : role === 'ellipsis' ? { flexShrink: 0 }\n : {}\n return (\n <li\n ref={ref}\n data-bc-role={role}\n className={cn('inline-flex items-center min-w-0', className)}\n style={{ ...shrinkStyle, ...style }}\n {...props}\n />\n )\n }\n)\nBreadcrumbItem.displayName = 'BreadcrumbItem'\n\n// ── BreadcrumbLink (a) ───────────────────────────────────────────────────────\n\ninterface BreadcrumbLinkProps extends React.ComponentPropsWithoutRef<'a'> {\n /** 將樣式套用至子元件(e.g. React Router Link) */\n asChild?: boolean\n /**\n * 起始 icon(per `ui-development.md`「icon prop 命名 4 條」:slot 只接 icon → `startIcon`)。\n * 內部消費 `BREADCRUMB_ICON_SIZE[size]` SSOT,DS 統一尺寸不允許 consumer override。\n * 對齊 uiSize.spec.md Icon Size Tier(2026-05-18 撤回 14 例外,統一 16/16/20)。\n */\n startIcon?: LucideIcon\n}\n\nconst BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(\n ({ asChild, className, children, startIcon: StartIcon, ...props }, ref) => {\n const { size } = React.useContext(BreadcrumbContext)\n // 2026-05-12 fix(user 抓 image 2 Deep story 麵包屑沒符合 single-line + truncate canonical):\n // 純文字 children → auto-wrap TruncatedText(canonical「single-line + ellipsis + tooltip\n // on truncate」per spec.md / Polaris breadcrumb)。Non-string children(consumer 自訂 icon+text\n // 結構)→ pass-through 不 force-wrap(consumer own truncate)。\n const wrappedChildren = typeof children === 'string'\n ? <TruncatedText display=\"block\" tooltip={children}>{children}</TruncatedText>\n : children\n const sharedClassName = cn(\n 'inline-flex items-center gap-2',\n 'min-w-0 max-w-full',\n 'text-fg-secondary',\n 'hover:text-primary-hover',\n 'transition-colors duration-150',\n 'rounded-md',\n className\n )\n // 2026-05-25 fix(user 抓 Breadcrumb asChild story React.Children.only runtime fail):\n // Radix Slot 規範 children 必為單 element;原 unified Comp render 在 asChild path 內\n // 仍輸出「{StartIcon && ...} + {wrappedChildren}」雙 JSX expression → Slot 收到 array\n // → React.Children.only(array) throws「expected to receive a single React element child」。\n // 分支 render 解 — asChild path 只傳 consumer-supplied child(icon 由 consumer 自管,\n // 對齊 Radix Slot canonical「single child contract」);非 asChild path 維持原 native\n // <a> + DS-controlled icon + wrapped label。\n if (asChild) {\n return (\n <Slot ref={ref} className={sharedClassName} {...props}>\n {wrappedChildren}\n </Slot>\n )\n }\n return (\n <a ref={ref} className={sharedClassName} {...props}>\n {StartIcon && <StartIcon size={BREADCRUMB_ICON_SIZE[size]} aria-hidden className=\"shrink-0\" />}\n {wrappedChildren}\n </a>\n )\n }\n)\nBreadcrumbLink.displayName = 'BreadcrumbLink'\n\n// ── BreadcrumbPage (current, non-clickable) ──────────────────────────────────\n\ninterface BreadcrumbPageProps extends React.ComponentPropsWithoutRef<'span'> {\n /** 起始 icon。內部消費 `BREADCRUMB_ICON_SIZE[size]` SSOT。對齊 BreadcrumbLink. */\n startIcon?: LucideIcon\n}\n\nconst BreadcrumbPage = React.forwardRef<HTMLSpanElement, BreadcrumbPageProps>(\n ({ className, children, startIcon: StartIcon, ...props }, ref) => {\n const { size } = React.useContext(BreadcrumbContext)\n // 2026-05-12 fix(同 BreadcrumbLink):純文字 children → auto-wrap TruncatedText。\n const wrappedChildren = typeof children === 'string'\n ? <TruncatedText display=\"block\" tooltip={children}>{children}</TruncatedText>\n : children\n return (\n <span\n ref={ref}\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn('inline-flex items-center gap-2 min-w-0 max-w-full text-foreground', className)}\n {...props}\n >\n {StartIcon && <StartIcon size={BREADCRUMB_ICON_SIZE[size]} aria-hidden className=\"shrink-0\" />}\n {wrappedChildren}\n </span>\n )\n }\n)\nBreadcrumbPage.displayName = 'BreadcrumbPage'\n\n// ── BreadcrumbSeparator ──────────────────────────────────────────────────────\n\ninterface BreadcrumbSeparatorProps extends React.ComponentPropsWithoutRef<'li'> {\n children?: React.ReactNode\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst BreadcrumbSeparator = React.forwardRef<HTMLLIElement, BreadcrumbSeparatorProps>(\n ({ children, className, ...props }, ref) => {\n const { size } = React.useContext(BreadcrumbContext)\n return (\n <li\n ref={ref}\n role=\"presentation\"\n aria-hidden=\"true\"\n // Phase B(2026-05-10):separator 永遠 shrink-0(必完整顯示,否則 path 視覺斷裂)\n className={cn('inline-flex items-center text-fg-muted shrink-0', className)}\n {...props}\n >\n {children ?? <ChevronRight size={BREADCRUMB_ICON_SIZE[size]} aria-hidden />}\n </li>\n )\n }\n)\nBreadcrumbSeparator.displayName = 'BreadcrumbSeparator'\n\n// ── BreadcrumbEllipsis ───────────────────────────────────────────────────────\n\n/**\n * BreadcrumbEllipsis — 折疊路徑的 \"⋯\" 按鈕\n *\n * 2026-05-10 重寫:消費 `ItemInlineActionButton`(primitive SSOT)取代自刻 `<button>`。\n * Per inline-action.spec.md L106-131 predicate Q1+Q2+Q3 全指向 Inline Action:\n * - Q1 點了要做事嗎?是(展開折疊路徑 dropdown)\n * - Q2 位置?BreadcrumbList row inline flow(host 內)\n * - Q3 row 多大?14-16px text row(compact tier)→ Inline Action\n * + 對齊 M1「視覺決策前必消費 SSOT」+ Mindset #2「優先消費既有」。\n *\n * 配合 DropdownMenuTrigger asChild 使用:\n *\n * ```tsx\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <BreadcrumbEllipsis />\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem asChild><a href=\"/org\">組織</a></DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * `overlayTrigger=true` 視覺鎖:DropdownMenu open 期間 button 維持 hover bg(對齊\n * shadcn / Radix Themes / Material 的 overlay trigger canonical,inline-action.spec.md\n * 「Overlay trigger canonical」段)。\n */\ntype BreadcrumbEllipsisProps = Omit<React.ComponentPropsWithoutRef<typeof ItemInlineActionButton>, 'icon' | 'size'>\n\nconst BreadcrumbEllipsis = React.forwardRef<HTMLButtonElement, BreadcrumbEllipsisProps>(\n ({ 'aria-label': ariaLabel = '顯示折疊路徑' /* i18n-allow: DS default; consumer override via aria-label prop */, ...props }, ref) => {\n return (\n <ItemInlineActionButton\n ref={ref}\n icon={MoreHorizontal}\n size=\"md\" // Breadcrumb 不在 RowSizeProvider 樹內,固定 md(16px icon + 18px hover bg,對齊 inline-action.spec.md 尺寸表)\n aria-label={ariaLabel}\n overlayTrigger\n {...props}\n />\n )\n }\n)\nBreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const breadcrumbMeta = {\n component: 'Breadcrumb',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n // 值源 = code SSOT:BREADCRUMB_TEXT_CLASS(sm/md=text-body, lg=text-body-lg)+ BREADCRUMB_ICON_SIZE(sm/md=16, lg=20)。\n // Breadcrumb 是文字列無固定高度 token,故不列 height(對照 Tag meta 有自身 h-* 才列)。\n sm: { iconSize: 16, typography: 'body' },\n md: { iconSize: 16, typography: 'body' },\n lg: { iconSize: 20, typography: 'body-lg' },\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: [],\n fg: ['text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n}\nexport type { BreadcrumbSize, BreadcrumbListProps, BreadcrumbEllipsisProps }\n// BreadcrumbItemSpec 已在上方 `export interface BreadcrumbItemSpec` 直接 export\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"breadcrumb.js","sources":["../../../src/components/Breadcrumb/breadcrumb.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — Breadcrumb 含 BreadcrumbList(主)+ BreadcrumbItem + BreadcrumbEllipsis + items-collapse logic,split 會破壞 collapse/overflow Tooltip subtree\nimport * as React from 'react'\nimport { Slot } from '@radix-ui/react-slot'\nimport { ChevronRight, MoreHorizontal, type LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { ItemInlineActionButton } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { TruncatedText } from '@/design-system/patterns/element-anatomy/truncated-text'\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '@/design-system/components/DropdownMenu/dropdown-menu'\n\n// ── TruncatedText ── 2026-07-19:truncate+tooltip 引擎 + presentation 已抽成 SSOT primitive\n// `patterns/element-anatomy/truncated-text`(`<TruncatedText>` 消費 `useTruncated` hook)。本檔改為\n// 消費 `<TruncatedText display=\"block\" tooltip={fullText}>`,原 file-local shared RO + TruncatedLabel 已移除。\n\n/**\n * Breadcrumb — 顯示當前頁面在階層中的位置\n *\n * 基於 shadcn/ui Breadcrumb 結構(純 HTML nav + ol + li + a/span),\n * 橋接設計系統 token。\n *\n * ── 結構 ──\n * <Breadcrumb>\n * <BreadcrumbList size=\"md\">\n * <BreadcrumbItem>\n * <BreadcrumbLink href=\"/projects\">專案</BreadcrumbLink>\n * </BreadcrumbItem>\n * <BreadcrumbSeparator />\n * <BreadcrumbItem>\n * <BreadcrumbPage>目前頁面</BreadcrumbPage>\n * </BreadcrumbItem>\n * </BreadcrumbList>\n * </Breadcrumb>\n *\n * ── Size(跟 page title 配對) ──\n * sm text-body(14) → 建議配 text-h4(20) title —— Dialog / panel / drawer\n * md text-body(14) → 建議配 text-h3(24) title —— 一般頁面 header (預設)\n * lg text-body-lg(16) → 建議配 text-h2(32) title —— Detail page hero / landing\n *\n * ── 視覺 ──\n * Link (預設): text-fg-secondary\n * Link hover: text-primary-hover(連結滑過換色 canonical,owner color.spec.md「連結 hover = 換色」;\n * 跟 Tabs / Chip 不是同一條 —— Tabs 滑過是字轉 foreground、Chip 只有選中態滑過才轉 primary-hover;\n * 2026-09-27 更正舊句「跟 Tabs / Chip 用法一致」)\n * Page (當前): text-foreground(不加粗 — 加粗會讓 breadcrumb 最右端視覺過重,見 spec)\n * Separator: ChevronRight (size 跟 list 一致), text-fg-muted\n *\n * ── 詳見 breadcrumb.spec.md ──\n */\n\n// ── Size context ─────────────────────────────────────────────────────────────\n\ntype BreadcrumbSize = 'sm' | 'md' | 'lg'\n\ninterface BreadcrumbContextValue {\n size: BreadcrumbSize\n}\n\nconst BreadcrumbContext = React.createContext<BreadcrumbContextValue>({ size: 'md' })\n\nconst BREADCRUMB_TEXT_CLASS: Record<BreadcrumbSize, string> = {\n sm: 'text-body',\n md: 'text-body',\n lg: 'text-body-lg',\n}\n\n// Separator chevron + BreadcrumbLink/Item start icon 尺寸 — 對齊 uiSize.spec.md「Icon Size Tier」(field-height-sm/md→16,lg→20)。\n// 注意:BreadcrumbEllipsis 不消費此常數,固定 md(16px icon,見 BreadcrumbEllipsis 定義),size='lg' 時不隨 chevron 放大到 20\n// 2026-05-18 改 per user 拍板「A 先改 16/16/20」+「做完」approval:\n// 撤回 text-flow 例外設計,Breadcrumb chevron 跟其他 chrome icon 同 tier。\n// World-class 對齊:Atlassian Breadcrumb chevron 16 default / Material 3 / Ant Design 同。\nconst BREADCRUMB_ICON_SIZE: Record<BreadcrumbSize, number> = {\n sm: 16,\n md: 16,\n lg: 20,\n}\n\n// ── Breadcrumb (nav root) ────────────────────────────────────────────────────\n\nconst Breadcrumb = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'>\n>(({ ...props }, ref) => (\n <nav ref={ref} aria-label=\"Breadcrumb\" {...props} />\n))\nBreadcrumb.displayName = 'Breadcrumb'\n\n// ── BreadcrumbList (ol) ──────────────────────────────────────────────────────\n\n/**\n * Phase B(2026-05-10):declarative items mode 啟用 auto-collapse + auto-separator + auto-page-end。\n * 對齊 Material UI source `Breadcrumbs.js renderItemsBeforeAndAfter` mechanism(`maxItems`\n * default 8;本 DS 採 user-tuned 4 — 更積極 collapse 適合 single-line 緊湊 layout)。\n */\n// code-quality-allow: dead-export — public consumer-facing item spec type;對齊 BreadcrumbProps API contract,允許 consumer 構造 items array 外部\nexport interface BreadcrumbItemSpec {\n label: React.ReactNode\n href?: string\n asChild?: boolean\n /**\n * 起始 icon(per `ui-development.md`「icon prop 命名 4 條」:slot 只接 icon → `startIcon`)。\n * 業界慣例:Breadcrumb 首項用 Home icon 強化視覺錨點(Material / Atlassian)。\n * 內部消費 `BREADCRUMB_ICON_SIZE[size]` SSOT(sm/md=16, lg=20,對齊 uiSize.spec.md Icon Size Tier)。\n * Consumer **不傳** size,DS 統一管。\n */\n startIcon?: LucideIcon\n}\n\ninterface BreadcrumbListProps extends Omit<React.ComponentPropsWithoutRef<'ol'>, 'children'> {\n /**\n * 字體尺寸 — 依據與之配對的 page title 選擇:\n * sm → 配 text-h4(20) title (Dialog / panel / drawer)\n * md → 配 text-h3(24) title (一般頁面 header,預設)\n * lg → 配 text-h2(32) title (Detail page hero / landing)\n */\n size?: BreadcrumbSize\n /**\n * Declarative items mode(opt-in)。當 provided 時 `children` 被忽略,List 內部自動:\n * - 插 separator\n * - 末位 spec(無 `href`)自動 BreadcrumbPage(per Title-breadcrumb-end SSOT)\n * - 超 `maxItems` auto-collapse 中段成 BreadcrumbEllipsis + DropdownMenu(對齊 Material UI\n * source `renderItemsBeforeAndAfter`)\n */\n items?: BreadcrumbItemSpec[]\n /**\n * Auto-collapse 閾值。Default 4(user-tuned;Material UI source 預設 8)。`items.length > maxItems`\n * 才 collapse。\n */\n maxItems?: number\n /** Collapse 後保留首 N 個(default 1)。對齊 Material UI source default。 */\n itemsBeforeCollapse?: number\n /** Collapse 後保留末 N 個(default 1)。對齊 Material UI source default。 */\n itemsAfterCollapse?: number\n children?: React.ReactNode\n}\n\n// code-quality-allow: long-function — items props × children narrowing × collapse-with-overflow × tooltip 4 軸組合在 BreadcrumbList,拆 sub-fn 會跨 fn 傳 itemsBeforeCollapse/After collapsed-tooltip refs\nconst BreadcrumbList = React.forwardRef<HTMLOListElement, BreadcrumbListProps>(\n ({ className, size = 'md', items, maxItems = 4, itemsBeforeCollapse = 1, itemsAfterCollapse = 1, children, ...props }, ref) => {\n // Memoize provider value(2026-04-22 D3 perf audit):單 field wrapper memoize\n const ctxValue = React.useMemo(() => ({ size }), [size])\n\n // Declarative mode(items prop provided):自動 render + auto-collapse\n const declarativeContent = React.useMemo(() => {\n if (!items) return null\n // 2026-07-04 修:非字串 label 的 key 原用 Math.random() → 每次 render 新 key 造成\n // BreadcrumbItem unmount/remount(重置 TruncatedText ResizeObserver 與 state)→ 改 stable idx key\n const renderItem = (spec: BreadcrumbItemSpec, role: 'root' | 'middle' | 'current', idx: number) => (\n <BreadcrumbItem key={`${role}-${typeof spec.label === 'string' ? spec.label : idx}`} role={role}>\n {role === 'current'\n ? <BreadcrumbPage startIcon={spec.startIcon}>\n <TruncatedText display=\"block\" tooltip={typeof spec.label === 'string' ? spec.label : undefined}>{spec.label}</TruncatedText>\n </BreadcrumbPage>\n : <BreadcrumbLink href={spec.href} asChild={spec.asChild} startIcon={spec.startIcon}>\n <TruncatedText display=\"block\" tooltip={typeof spec.label === 'string' ? spec.label : undefined}>{spec.label}</TruncatedText>\n </BreadcrumbLink>\n }\n </BreadcrumbItem>\n )\n\n const shouldCollapse = items.length > maxItems\n const beforeN = Math.max(0, itemsBeforeCollapse)\n const afterN = Math.max(1, itemsAfterCollapse) // 末位永遠 ≥ 1(current page)\n\n type VisibleItem = { spec: BreadcrumbItemSpec; role: 'root' | 'middle' | 'current' }\n let visible: Array<VisibleItem | { ellipsisOf: BreadcrumbItemSpec[] }>\n if (!shouldCollapse) {\n visible = items.map((spec, i) => ({\n spec,\n role: i === 0 ? 'root' : (i === items.length - 1 ? 'current' : 'middle') as 'root' | 'middle' | 'current',\n }))\n } else {\n const before = items.slice(0, beforeN).map((spec, i) => ({\n spec,\n role: (i === 0 ? 'root' : 'middle') as 'root' | 'middle' | 'current',\n }))\n const collapsed = items.slice(beforeN, items.length - afterN)\n const after = items.slice(items.length - afterN).map((spec, i, arr) => ({\n spec,\n role: (i === arr.length - 1 ? 'current' : 'middle') as 'root' | 'middle' | 'current',\n }))\n visible = [...before, { ellipsisOf: collapsed }, ...after]\n }\n\n // Interleave with separators\n const rendered: React.ReactNode[] = []\n visible.forEach((entry, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-${i}`} />)\n if ('ellipsisOf' in entry) {\n rendered.push(\n <BreadcrumbItem key=\"ellipsis\" role=\"ellipsis\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <BreadcrumbEllipsis />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {entry.ellipsisOf.map((s, j) => (\n <DropdownMenuItem key={j} asChild={!!s.href}>\n {s.href ? <a href={s.href}>{s.label}</a> : <span>{s.label}</span>}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n )\n } else {\n rendered.push(renderItem(entry.spec, entry.role, i))\n }\n })\n return rendered\n }, [items, maxItems, itemsBeforeCollapse, itemsAfterCollapse])\n\n // 2026-05-12 fix(user 抓 image 2 Deep story 違反 single-line + max-levels canonical):\n // Compositional path 也走 auto-collapse + flex-shrink hierarchy。Walk children, 找\n // BreadcrumbItem 並按 index 分派 role (first=root / last=current / middle=middle)。\n // > maxItems 自動 collapse 中段成 ellipsis(對齊 declarative path canonical SSOT)。\n const compositionalContent = React.useMemo(() => {\n if (items) return null\n const childArr = React.Children.toArray(children)\n // 抓 BreadcrumbItem children(skip BreadcrumbSeparator — auto re-interleave)\n // 2026-05-12 Round 4.5 fix(codex M31 Layer C 抓):type-identity primary path + displayName fallback。\n // 純 `displayName` check 在 HOC / React.memo / consumer alias 場景脆弱(production build / wrap\n // 可能改寫 displayName)。`c.type === BreadcrumbItem` 是 React fiber reference-identity 最穩\n // primary(對齊 Radix children-walk pattern);displayName fallback 給 HOC 場景。\n const itemChildren = childArr.filter((c): c is React.ReactElement<BreadcrumbItemProps> =>\n React.isValidElement(c) && (c.type === BreadcrumbItem ||\n (c.type as React.ComponentType)?.displayName === 'BreadcrumbItem')\n )\n // 無 item 或全是 separator → pass-through(consumer raw children,e.g. spinners)\n if (itemChildren.length === 0) return children\n // Assign role by position; clone with role prop\n const total = itemChildren.length\n const cloneWithRole = (item: React.ReactElement<BreadcrumbItemProps>, idx: number, role: 'root' | 'middle' | 'current') =>\n React.cloneElement(item, { role: item.props.role ?? role, key: `bc-${role}-${idx}` })\n const shouldCollapse = total > maxItems\n const beforeN = Math.max(0, itemsBeforeCollapse)\n const afterN = Math.max(1, itemsAfterCollapse)\n const rendered: React.ReactNode[] = []\n if (!shouldCollapse) {\n itemChildren.forEach((item, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-${i}`} />)\n const role: 'root' | 'middle' | 'current' = i === 0 ? 'root' : (i === total - 1 ? 'current' : 'middle')\n rendered.push(cloneWithRole(item, i, role))\n })\n } else {\n // before(first N) + ellipsis + after(last M)\n const beforeItems = itemChildren.slice(0, beforeN)\n const collapsedItems = itemChildren.slice(beforeN, total - afterN)\n const afterItems = itemChildren.slice(total - afterN)\n beforeItems.forEach((item, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-bef-${i}`} />)\n const role: 'root' | 'middle' = i === 0 ? 'root' : 'middle'\n rendered.push(cloneWithRole(item, i, role))\n })\n if (rendered.length > 0) rendered.push(<BreadcrumbSeparator key=\"sep-ellipsis-before\" />)\n rendered.push(\n <BreadcrumbItem key=\"bc-ellipsis\" role=\"ellipsis\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <BreadcrumbEllipsis />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {collapsedItems.map((item, j) => {\n // 2026-05-12 Round 4.5 fix(codex M31 Layer C 抓):consumer BreadcrumbItem children 常包\n // `<BreadcrumbLink href>` = anchor button-like。直接放進 `<DropdownMenuItem>` 會 nested\n // interactive(menuitem within button violates HTML / a11y)。Fix:把實際 link 元素接到\n // menuitem `asChild`,對齊 declarative path canonical pattern。\n // 2026-07-19 fix(DA3 對抗稽核抓):原只讀 `c.props.href` → `<BreadcrumbLink asChild>\n // <RouterLink to=…>` 這種(BreadcrumbLink 無 href、RouterLink child 帶 `to`)摺疊後\n // dropdown 失去導航目標。修:asChild 時**保留整個 link 子元素**(RouterLink/<Link to>/<a>,\n // 含 to/href/onClick/state 全 forward,前端路由不退化成整頁重載);純 href 才重建 <a>。\n const innerChildren = (item.props as { children?: React.ReactNode }).children\n let menuChild: React.ReactNode | undefined // 接進 menuitem(asChild)的實際 link 元素\n let label: React.ReactNode = innerChildren // fallback:無 link 時的純內容\n React.Children.forEach(innerChildren, (c) => {\n if (!React.isValidElement<{ href?: string; asChild?: boolean; children?: React.ReactNode }>(c)) return\n if (c.props.asChild && React.isValidElement(c.props.children)) {\n // BreadcrumbLink asChild → 實際 link = 其 child(RouterLink / <Link to> / <a>),整個保留\n menuChild = c.props.children\n const grand = (c.props.children.props as { children?: React.ReactNode }).children\n if (grand != null) label = grand\n } else if (c.props.href != null) {\n // BreadcrumbLink href → 重建 <a href>(對齊原 canonical,避免 nested interactive)\n menuChild = <a href={c.props.href}>{c.props.children}</a>\n if (c.props.children != null) label = c.props.children\n }\n })\n return menuChild\n ? <DropdownMenuItem key={`collapsed-${j}`} asChild>{menuChild}</DropdownMenuItem>\n : <DropdownMenuItem key={`collapsed-${j}`}>{label}</DropdownMenuItem>\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n )\n rendered.push(<BreadcrumbSeparator key=\"sep-ellipsis-after\" />)\n afterItems.forEach((item, i) => {\n if (i > 0) rendered.push(<BreadcrumbSeparator key={`sep-aft-${i}`} />)\n const role: 'middle' | 'current' = i === afterItems.length - 1 ? 'current' : 'middle'\n rendered.push(cloneWithRole(item, i, role))\n })\n }\n return rendered\n }, [items, children, maxItems, itemsBeforeCollapse, itemsAfterCollapse])\n\n return (\n <BreadcrumbContext.Provider value={ctxValue}>\n <ol\n ref={ref}\n // gap-1 (4px) — separator 與兩邊 items 間距;緊湊節奏,符合 breadcrumb 密集流動感。\n // 2026-05-10 Phase A single-line canonical(per user + Material UI source verified):\n // `flex-nowrap` 不 wrap。長路徑走中段折疊。\n // 2026-05-12 fix:compositional 也走 auto-collapse + role-assignment(`compositionalContent`)\n // → declarative / compositional 兩 path 都符合 single-line + max-levels + width 分配 canonical SSOT。\n className={cn(\n 'flex flex-nowrap items-center gap-1 text-fg-secondary leading-compact min-w-0',\n BREADCRUMB_TEXT_CLASS[size],\n className\n )}\n {...props}\n >\n {items ? declarativeContent : compositionalContent}\n </ol>\n </BreadcrumbContext.Provider>\n )\n },\n)\nBreadcrumbList.displayName = 'BreadcrumbList'\n\n// ── BreadcrumbItem (li) ──────────────────────────────────────────────────────\n\n/**\n * Phase B(2026-05-10):`role` prop emit `data-bc-role` attr → CSS flex-shrink hierarchy。\n * Per BreadcrumbItem 在 row 中的角色決定 shrink 優先級:\n * - `root`(首位)→ shrink:3(縮最積極;root context 可弱化)\n * - `middle`(中段)→ shrink:2\n * - `current`(末位 / page)→ shrink:1(最後縮;a11y current page anchor)\n * - `ellipsis`(BreadcrumbEllipsis 包裝)→ shrink:0(永遠完整 ⋯)\n *\n * 設計回應 user 兩 challenges:\n * (a) Root 也 truncate(shrink:3,不是 shrink-0)\n * (b) 不用 fixed max-width — flex-shrink hierarchy 容器寬時自然展開不浪費空間,\n * 窄時按優先級縮 + TruncatedText 內部 CSS truncate + tooltip。\n */\ninterface BreadcrumbItemProps extends React.ComponentPropsWithoutRef<'li'> {\n role?: 'root' | 'middle' | 'current' | 'ellipsis'\n}\n\nconst BreadcrumbItem = React.forwardRef<HTMLLIElement, BreadcrumbItemProps>(\n ({ className, role, style, ...props }, ref) => {\n // 2026-05-20 fix v3(user 抓「專案 後方多 4px 間距 / 我的新專案 沒有」chevron 不對稱):\n // v2 `minWidth: '2rem'`(32px)在寬容器強制 li ≥ 32px → 短 label「專案」(natural ~28px)\n // 被撐 4px,長 label「我的新專案」(natural ~70px)hug content → chevron 兩側不對稱。\n //\n // v3 解法:minWidth `2rem` → `1.5rem`(24px)\n // 數學:中文「X…」最小寬度 = 1 char(~14-16px)+ ellipsis(~6-8px)≈ 22-24px → 24px 剛 cover\n // 結果:\n // - 寬容器:所有自然 label ≥ 24px → li hug content,chevron 緊貼,對稱(本 fix 主目的)\n // - 窄容器 truncate:shrink 不過 24px → 「X…」仍可見 ellipsis 保險\n // - 短英文「OK / ID」(natural ~20px)→ 多 ~4px(原 12px → 縮到 4px,顯著改善)\n // 對齊 user verbatim「minWidth 再調小一點」+ ellipsis 數學最小值。\n const shrinkStyle: React.CSSProperties = role === 'root' ? { flexShrink: 3, minWidth: '1.5rem' }\n : role === 'middle' ? { flexShrink: 2, minWidth: '1.5rem' }\n : role === 'current' ? { flexShrink: 1, minWidth: '1.5rem' }\n : role === 'ellipsis' ? { flexShrink: 0 }\n : {}\n return (\n <li\n ref={ref}\n data-bc-role={role}\n className={cn('inline-flex items-center min-w-0', className)}\n style={{ ...shrinkStyle, ...style }}\n {...props}\n />\n )\n }\n)\nBreadcrumbItem.displayName = 'BreadcrumbItem'\n\n// ── BreadcrumbLink (a) ───────────────────────────────────────────────────────\n\ninterface BreadcrumbLinkProps extends React.ComponentPropsWithoutRef<'a'> {\n /** 將樣式套用至子元件(e.g. React Router Link) */\n asChild?: boolean\n /**\n * 起始 icon(per `ui-development.md`「icon prop 命名 4 條」:slot 只接 icon → `startIcon`)。\n * 內部消費 `BREADCRUMB_ICON_SIZE[size]` SSOT,DS 統一尺寸不允許 consumer override。\n * 對齊 uiSize.spec.md Icon Size Tier(2026-05-18 撤回 14 例外,統一 16/16/20)。\n */\n startIcon?: LucideIcon\n}\n\nconst BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(\n ({ asChild, className, children, startIcon: StartIcon, ...props }, ref) => {\n const { size } = React.useContext(BreadcrumbContext)\n // 2026-05-12 fix(user 抓 image 2 Deep story 麵包屑沒符合 single-line + truncate canonical):\n // 純文字 children → auto-wrap TruncatedText(canonical「single-line + ellipsis + tooltip\n // on truncate」per spec.md / Polaris breadcrumb)。Non-string children(consumer 自訂 icon+text\n // 結構)→ pass-through 不 force-wrap(consumer own truncate)。\n const wrappedChildren = typeof children === 'string'\n ? <TruncatedText display=\"block\" tooltip={children}>{children}</TruncatedText>\n : children\n const sharedClassName = cn(\n 'inline-flex items-center gap-2',\n 'min-w-0 max-w-full',\n 'text-fg-secondary',\n // hover 字色瞬間切換,不寫 transition-colors(tokens/motion/motion.spec.md「hover 回饋不做過渡」;2026-09-26 由底色延伸到字色,待辦總帳 L9 / N4(3))\n 'hover:text-primary-hover',\n 'rounded-md',\n className\n )\n // 2026-05-25 fix(user 抓 Breadcrumb asChild story React.Children.only runtime fail):\n // Radix Slot 規範 children 必為單 element;原 unified Comp render 在 asChild path 內\n // 仍輸出「{StartIcon && ...} + {wrappedChildren}」雙 JSX expression → Slot 收到 array\n // → React.Children.only(array) throws「expected to receive a single React element child」。\n // 分支 render 解 — asChild path 只傳 consumer-supplied child(icon 由 consumer 自管,\n // 對齊 Radix Slot canonical「single child contract」);非 asChild path 維持原 native\n // <a> + DS-controlled icon + wrapped label。\n if (asChild) {\n return (\n <Slot ref={ref} className={sharedClassName} {...props}>\n {wrappedChildren}\n </Slot>\n )\n }\n return (\n <a ref={ref} className={sharedClassName} {...props}>\n {StartIcon && <StartIcon size={BREADCRUMB_ICON_SIZE[size]} aria-hidden className=\"shrink-0\" />}\n {wrappedChildren}\n </a>\n )\n }\n)\nBreadcrumbLink.displayName = 'BreadcrumbLink'\n\n// ── BreadcrumbPage (current, non-clickable) ──────────────────────────────────\n\ninterface BreadcrumbPageProps extends React.ComponentPropsWithoutRef<'span'> {\n /** 起始 icon。內部消費 `BREADCRUMB_ICON_SIZE[size]` SSOT。對齊 BreadcrumbLink. */\n startIcon?: LucideIcon\n}\n\nconst BreadcrumbPage = React.forwardRef<HTMLSpanElement, BreadcrumbPageProps>(\n ({ className, children, startIcon: StartIcon, ...props }, ref) => {\n const { size } = React.useContext(BreadcrumbContext)\n // 2026-05-12 fix(同 BreadcrumbLink):純文字 children → auto-wrap TruncatedText。\n const wrappedChildren = typeof children === 'string'\n ? <TruncatedText display=\"block\" tooltip={children}>{children}</TruncatedText>\n : children\n return (\n <span\n ref={ref}\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn('inline-flex items-center gap-2 min-w-0 max-w-full text-foreground', className)}\n {...props}\n >\n {StartIcon && <StartIcon size={BREADCRUMB_ICON_SIZE[size]} aria-hidden className=\"shrink-0\" />}\n {wrappedChildren}\n </span>\n )\n }\n)\nBreadcrumbPage.displayName = 'BreadcrumbPage'\n\n// ── BreadcrumbSeparator ──────────────────────────────────────────────────────\n\ninterface BreadcrumbSeparatorProps extends React.ComponentPropsWithoutRef<'li'> {\n children?: React.ReactNode\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst BreadcrumbSeparator = React.forwardRef<HTMLLIElement, BreadcrumbSeparatorProps>(\n ({ children, className, ...props }, ref) => {\n const { size } = React.useContext(BreadcrumbContext)\n return (\n <li\n ref={ref}\n role=\"presentation\"\n aria-hidden=\"true\"\n // Phase B(2026-05-10):separator 永遠 shrink-0(必完整顯示,否則 path 視覺斷裂)\n className={cn('inline-flex items-center text-fg-muted shrink-0', className)}\n {...props}\n >\n {children ?? <ChevronRight size={BREADCRUMB_ICON_SIZE[size]} aria-hidden />}\n </li>\n )\n }\n)\nBreadcrumbSeparator.displayName = 'BreadcrumbSeparator'\n\n// ── BreadcrumbEllipsis ───────────────────────────────────────────────────────\n\n/**\n * BreadcrumbEllipsis — 折疊路徑的 \"⋯\" 按鈕\n *\n * 2026-05-10 重寫:消費 `ItemInlineActionButton`(primitive SSOT)取代自刻 `<button>`。\n * Per inline-action.spec.md L106-131 predicate Q1+Q2+Q3 全指向 Inline Action:\n * - Q1 點了要做事嗎?是(展開折疊路徑 dropdown)\n * - Q2 位置?BreadcrumbList row inline flow(host 內)\n * - Q3 row 多大?14-16px text row(compact tier)→ Inline Action\n * + 對齊 M1「視覺決策前必消費 SSOT」+ Mindset #2「優先消費既有」。\n *\n * 配合 DropdownMenuTrigger asChild 使用:\n *\n * ```tsx\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <BreadcrumbEllipsis />\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem asChild><a href=\"/org\">組織</a></DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n *\n * `overlayTrigger=true` 視覺鎖:DropdownMenu open 期間 button 維持 hover bg(對齊\n * shadcn / Radix Themes / Material 的 overlay trigger canonical,inline-action.spec.md\n * 「Overlay trigger canonical」段)。\n */\ntype BreadcrumbEllipsisProps = Omit<React.ComponentPropsWithoutRef<typeof ItemInlineActionButton>, 'icon' | 'size'>\n\nconst BreadcrumbEllipsis = React.forwardRef<HTMLButtonElement, BreadcrumbEllipsisProps>(\n ({ 'aria-label': ariaLabel = '顯示折疊路徑' /* i18n-allow: DS default; consumer override via aria-label prop */, ...props }, ref) => {\n return (\n <ItemInlineActionButton\n ref={ref}\n icon={MoreHorizontal}\n size=\"md\" // Breadcrumb 不在 RowSizeProvider 樹內,固定 md(16px icon + 18px hover bg,對齊 inline-action.spec.md 尺寸表)\n aria-label={ariaLabel}\n overlayTrigger\n {...props}\n />\n )\n }\n)\nBreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const breadcrumbMeta = {\n component: 'Breadcrumb',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n // 值源 = code SSOT:BREADCRUMB_TEXT_CLASS(sm/md=text-body, lg=text-body-lg)+ BREADCRUMB_ICON_SIZE(sm/md=16, lg=20)。\n // Breadcrumb 是文字列無固定高度 token,故不列 height(對照 Tag meta 有自身 h-* 才列)。\n sm: { iconSize: 16, typography: 'body' },\n md: { iconSize: 16, typography: 'body' },\n lg: { iconSize: 20, typography: 'body-lg' },\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: [],\n fg: ['text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: ['--ring'],\n },\n} as const\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n}\nexport type { BreadcrumbSize, BreadcrumbListProps, BreadcrumbEllipsisProps }\n// BreadcrumbItemSpec 已在上方 `export interface BreadcrumbItemSpec` 直接 export\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-action-bar.d.ts","sourceRoot":"","sources":["../../../src/components/BulkActionBar/bulk-action-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IACxC,8GAA8G;IAC9G,gBAAgB,EAAE,MAAM,CAAA;IACxB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAGD,eAAO,MAAM,8BAA8B,EAAE,mBAK5C,CAAA;AAID,MAAM,WAAW,kBAAmB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC9E,wCAAwC;IACxC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;CACtC;AAeD,QAAA,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"bulk-action-bar.d.ts","sourceRoot":"","sources":["../../../src/components/BulkActionBar/bulk-action-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IACxC,8GAA8G;IAC9G,gBAAgB,EAAE,MAAM,CAAA;IACxB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAGD,eAAO,MAAM,8BAA8B,EAAE,mBAK5C,CAAA;AAID,MAAM,WAAW,kBAAmB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC9E,wCAAwC;IACxC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;CACtC;AAeD,QAAA,MAAM,aAAa,2FAoGlB,CAAA;AAID,eAAO,MAAM,iBAAiB;;;;;;;;;;CAUpB,CAAA;AAEV,OAAO,EAAE,aAAa,EAAE,CAAA"}
|
|
@@ -12,15 +12,40 @@ const BULK_ACTION_BAR_DEFAULT_LABELS = {
|
|
|
12
12
|
};
|
|
13
13
|
const BulkActionBar = React.forwardRef(
|
|
14
14
|
function BulkActionBar2({ selection, onClearSelection, actions, hiddenByFilter, totalSelected, labels: labelsOverride, className, ...props }, ref) {
|
|
15
|
+
const { onFocus: _onFocus, onBlur: _onBlur, ...propsWithoutFocusHandlers } = props;
|
|
15
16
|
const labels = React.useMemo(
|
|
16
17
|
() => ({ ...BULK_ACTION_BAR_DEFAULT_LABELS, ...labelsOverride }),
|
|
17
18
|
[labelsOverride]
|
|
18
19
|
);
|
|
19
|
-
|
|
20
|
+
const visible = !(selection.length === 0 && (totalSelected ?? 0) === 0);
|
|
21
|
+
const focusWithinRef = React.useRef(false);
|
|
22
|
+
const returnFocusToRef = React.useRef(null);
|
|
23
|
+
React.useLayoutEffect(() => {
|
|
24
|
+
if (visible || !focusWithinRef.current) return;
|
|
25
|
+
focusWithinRef.current = false;
|
|
26
|
+
const target = returnFocusToRef.current;
|
|
27
|
+
returnFocusToRef.current = null;
|
|
28
|
+
if (target && target.isConnected && (document.activeElement === document.body || document.activeElement === null)) {
|
|
29
|
+
target.focus({ preventScroll: true });
|
|
30
|
+
}
|
|
31
|
+
}, [visible]);
|
|
32
|
+
if (!visible) return null;
|
|
20
33
|
return /* @__PURE__ */ jsxs(
|
|
21
34
|
"div",
|
|
22
35
|
{
|
|
23
36
|
ref,
|
|
37
|
+
onFocus: (e) => {
|
|
38
|
+
var _a;
|
|
39
|
+
(_a = props.onFocus) == null ? void 0 : _a.call(props, e);
|
|
40
|
+
focusWithinRef.current = true;
|
|
41
|
+
const from = e.relatedTarget;
|
|
42
|
+
if (from && !e.currentTarget.contains(from)) returnFocusToRef.current = from;
|
|
43
|
+
},
|
|
44
|
+
onBlur: (e) => {
|
|
45
|
+
var _a;
|
|
46
|
+
(_a = props.onBlur) == null ? void 0 : _a.call(props, e);
|
|
47
|
+
if (!e.currentTarget.contains(e.relatedTarget)) focusWithinRef.current = false;
|
|
48
|
+
},
|
|
24
49
|
role: "group",
|
|
25
50
|
"aria-label": labels.ariaLabel ?? labels.toolbarAriaLabel,
|
|
26
51
|
className: cn(
|
|
@@ -30,7 +55,7 @@ const BulkActionBar = React.forwardRef(
|
|
|
30
55
|
"border-t border-divider",
|
|
31
56
|
className
|
|
32
57
|
),
|
|
33
|
-
...
|
|
58
|
+
...propsWithoutFocusHandlers,
|
|
34
59
|
children: [
|
|
35
60
|
onClearSelection && /* @__PURE__ */ jsx(
|
|
36
61
|
Button,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-action-bar.js","sources":["../../../src/components/BulkActionBar/bulk-action-bar.tsx"],"sourcesContent":["import * as React from 'react'\nimport { X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/design-system/components/Button/button'\nimport { ButtonDivider } from '@/design-system/components/Button/button-group'\n\n// ── 消費的 SSOT ───────────────────────────────────────────────────────────────\n// - bulk-action-bar.spec.md(本元件 SSOT)\n// - DataTable/data-table.spec.md「L2 選取」(整合方式)\n// - button.spec.md + button-group.tsx(action variant=tertiary,size=md,\n// gap-2 + ButtonDivider 自帶 mx-1 = 12px 視覺距離)\n// - inline-action.spec.md「same-row consistency rule」(close X 同尺寸 md)\n// - tokens/layoutSpace/layoutSpace.spec.md(footer 用 px-loose py-tight)\n// - patterns/overlay-surface/overlay-surface.spec.md SurfaceFooter canonical\n// - Alert(banner)用 title ReactNode 帶 inline link CTA\n\n// ── i18n labels ─────────────────────────────────────────────────────────────\n\n// code-quality-allow: dead-export — public API per spec.md(consumer i18n override hook)\nexport interface BulkActionBarLabels {\n count: (n: number) => string\n clear: string\n hiddenSuffix: (hidden: number) => string\n /** @deprecated 2026-07-06 role 已降級 \"group\"(user 拍板),改用 `ariaLabel`;此 key 保留 backward-compat(值仍作 fallback)。 */\n toolbarAriaLabel: string\n /** root `role=\"group\"` 的 aria-label(2026-07-06 新名;未傳 fallback toolbarAriaLabel)。 */\n ariaLabel?: string\n}\n\n// code-quality-allow: dead-export — public API per spec.md(consumer spread + override)\nexport const BULK_ACTION_BAR_DEFAULT_LABELS: BulkActionBarLabels = {\n count: (n) => `已選 ${n} 項`,\n clear: '清除選取',\n hiddenSuffix: (hidden) => `· ${hidden} 個被 filter 隱藏`,\n toolbarAriaLabel: '批次操作',\n}\n\n// ── Props ───────────────────────────────────────────────────────────────────\n\nexport interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** 已選 ID,length === 0 時自動隱藏(回傳 null) */\n selection: readonly string[]\n /** Clear 觸發,user 點 X icon 或 Esc(consumer 在 page-level 監聽) */\n onClearSelection?: () => void\n /** 批次 actions(consumer 提供 md Button,一律 variant=tertiary;不用 primary/danger) */\n actions?: React.ReactNode\n /** Filter 模式:hidden 數量,顯示在 count 區 inline「已選 {N} 項 · {M} 個被 filter 隱藏」 */\n hiddenByFilter?: number\n /**\n * 「擴選整個 dataset」狀態(2026-05-13 ship,per user 抓 Alert「已選 5370」但 BulkActionBar\n * 仍顯「已選 50 項」regression):\n * - undefined / null(default):count 走 `selection.length`(page-level 視覺選取)\n * - number:count 走此數值(整個 dataset 擴選後 user 已選的真總數)\n *\n * Canonical pattern:consumer 把 BulkActionBar 跟「Alert info banner(提示擴選 dataset)」\n * 一起 mount,Alert 點「點此選取全部 N 個」→ setTotalSelected(N) → BulkActionBar count 同步。\n * 對齊 Gmail / Linear / Notion 全選 dataset hint pattern。\n * 詳 `bulk-action-bar.spec.md`「Extend dataset pattern」段。\n */\n totalSelected?: number | null\n /** i18n labels(Partial,merge with default) */\n labels?: Partial<BulkActionBarLabels>\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n// 視覺結構(同 SurfaceFooter / DataTable toolbar canonical):\n// px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]\n// gap-2 between elements\n// 全 md Buttons(same-row consistency)\n// <ButtonDivider /> 自帶 mx-1 = 12px 視覺距離\n//\n// Hint banner(擴 dataset 提示)完全外包給 Alert 元件 — consumer 視 ref 圖\n// 黏在 BulkActionBar 上方/下方,用 Alert variant=\"info\" placement=\"fixed\"\n// title={inline link JSX}。BulkActionBar 自己不再有 hint banner slot。\n//\n// 浮起 / fixed positioning 由 consumer wrap 決定(BulkActionBar 不限定 placement)。\n\nconst BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(\n function BulkActionBar(\n { selection, onClearSelection, actions, hiddenByFilter, totalSelected, labels: labelsOverride, className, ...props },\n ref\n ) {\n const labels: BulkActionBarLabels = React.useMemo(\n () => ({ ...BULK_ACTION_BAR_DEFAULT_LABELS, ...labelsOverride }),\n [labelsOverride]\n )\n\n // selection.length === 0 自動藏(對齊 spec 禁止事項 #3)。\n // 反向選取(DataTable all 模式)例外:visible 全被 excluded 但 totalSelected>0 仍有選取 → 顯示(2026-06-22)\n if (selection.length === 0 && (totalSelected ?? 0) === 0) return null\n\n return (\n <div\n ref={ref}\n // 2026-07-06 user 拍板:role \"toolbar\" → \"group\" — 原宣告 toolbar 但未實作 APG toolbar\n // 方向鍵 roving 契約(AT 告知「工具列」但方向鍵無反應 = 空承諾);group 語意誠實,\n // Tab 序照 DOM(spec 本有 canonical),Gmail / Linear bulk bar 實務同款。\n role=\"group\"\n aria-label={labels.ariaLabel ?? labels.toolbarAriaLabel}\n className={cn(\n 'flex items-center gap-2',\n 'px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]',\n // 上分隔線:bottom toolbar canonical(Linear / Apple Mail / Notion 共識)— 視覺從上方內容收尾\n 'border-t border-divider',\n className\n )}\n {...props}\n >\n {/* X close — md dismiss(2026-05-04 spec update:default placement = footer variant,\n visual weight 對齊 Dialog footer commitment buttons md;same-row consistency 維持)\n 未來若有 top-toolbar variant(覆蓋 sm-density toolbar)→ 該 variant override sm */}\n {onClearSelection && (\n <Button\n variant=\"text\"\n size=\"md\"\n iconOnly\n dismiss\n startIcon={X}\n aria-label={labels.clear}\n onClick={onClearSelection}\n />\n )}\n\n {/* count + filter hidden inline\n color canonical(2026-05-04):count = primary foreground + medium weight\n 理由:count 是 state-bearing 主資訊(「你在 selection mode + N items」),非裝飾\n World-class 共識:Linear/Notion/Carbon/Polaris 均用 primary foreground;muted 化弱化 state signal\n hiddenByFilter suffix 維持 muted(這是次資訊,視覺層次正確) */}\n {/* 2026-05-31 #3:aria-live 通知 SR 選取數變更;#20:補 font-medium 對齊 spec「Count text color canonical」表 + 上方 comment(state-bearing 主資訊) */}\n <span className=\"text-body text-foreground font-medium tabular-nums\" aria-live=\"polite\" aria-atomic=\"true\">\n {/* 2026-05-13:totalSelected override 走 dataset 擴選後真總數,否則 fallback page-level selection.length */}\n {labels.count(typeof totalSelected === 'number' ? totalSelected : selection.length)}\n {hiddenByFilter !== undefined && hiddenByFilter > 0 && (\n <span className=\"text-fg-muted font-normal\"> {labels.hiddenSuffix(hiddenByFilter)}</span>\n )}\n </span>\n\n {/* divider */}\n {actions && <ButtonDivider />}\n\n {/* batch actions slot(consumer 提供 md Buttons) */}\n {actions && (\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">{actions}</div>\n )}\n </div>\n )\n }\n)\nBulkActionBar.displayName = 'BulkActionBar'\n\n// Story auto-compile metadata\nexport const bulkActionBarMeta = {\n component: 'BulkActionBar',\n family: null,\n variants: {},\n sizes: {},\n states: ['default'],\n tokens: {\n fg: ['text-foreground', 'text-fg-muted'],\n border: ['border-divider'],\n },\n} as const\n\nexport { BulkActionBar }\n"],"names":["BulkActionBar"],"mappings":";;;;;;AA8BO,MAAM,iCAAsD;AAAA,EACjE,OAAO,CAAC,MAAM,MAAM,CAAC;AAAA,EACrB,OAAO;AAAA,EACP,cAAc,CAAC,WAAW,KAAK,MAAM;AAAA,EACrC,kBAAkB;AACpB;AA0CA,MAAM,gBAAgB,MAAM;AAAA,EAC1B,SAASA,eACP,EAAE,WAAW,kBAAkB,SAAS,gBAAgB,eAAe,QAAQ,gBAAgB,WAAW,GAAG,MAAA,GAC7G,KACA;AACA,UAAM,SAA8B,MAAM;AAAA,MACxC,OAAO,EAAE,GAAG,gCAAgC,GAAG;MAC/C,CAAC,cAAc;AAAA,IAAA;AAKjB,QAAI,UAAU,WAAW,MAAM,iBAAiB,OAAO,EAAG,QAAO;AAEjE,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QAIA,MAAK;AAAA,QACL,cAAY,OAAO,aAAa,OAAO;AAAA,QACvC,WAAW;AAAA,UACT;AAAA,UACA;AAAA;AAAA,UAEA;AAAA,UACA;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAKH,UAAA;AAAA,UAAA,oBACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,UAAQ;AAAA,cACR,SAAO;AAAA,cACP,WAAW;AAAA,cACX,cAAY,OAAO;AAAA,cACnB,SAAS;AAAA,YAAA;AAAA,UAAA;AAAA,+BAUZ,QAAA,EAAK,WAAU,sDAAqD,aAAU,UAAS,eAAY,QAEjG,UAAA;AAAA,YAAA,OAAO,MAAM,OAAO,kBAAkB,WAAW,gBAAgB,UAAU,MAAM;AAAA,YACjF,mBAAmB,UAAa,iBAAiB,KAChD,qBAAC,QAAA,EAAK,WAAU,6BAA4B,UAAA;AAAA,cAAA;AAAA,cAAE,OAAO,aAAa,cAAc;AAAA,YAAA,EAAA,CAAE;AAAA,UAAA,GAEtF;AAAA,UAGC,+BAAY,eAAA,EAAc;AAAA,UAG1B,WACC,oBAAC,OAAA,EAAI,WAAU,0CAA0C,UAAA,QAAA,CAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIzE;AACF;AACA,cAAc,cAAc;AAGrB,MAAM,oBAAoB;AAAA,EAC/B,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU,CAAA;AAAA,EACV,OAAO,CAAA;AAAA,EACP,QAAQ,CAAC,SAAS;AAAA,EAClB,QAAQ;AAAA,IACN,IAAI,CAAC,mBAAmB,eAAe;AAAA,IACvC,QAAQ,CAAC,gBAAgB;AAAA,EAAA;AAE7B;"}
|
|
1
|
+
{"version":3,"file":"bulk-action-bar.js","sources":["../../../src/components/BulkActionBar/bulk-action-bar.tsx"],"sourcesContent":["import * as React from 'react'\nimport { X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/design-system/components/Button/button'\nimport { ButtonDivider } from '@/design-system/components/Button/button-group'\n\n// ── 消費的 SSOT ───────────────────────────────────────────────────────────────\n// - bulk-action-bar.spec.md(本元件 SSOT)\n// - DataTable/data-table.spec.md「L2 選取」(整合方式)\n// - button.spec.md + button-group.tsx(action variant=tertiary,size=md,\n// gap-2 + ButtonDivider 自帶 mx-1 = 12px 視覺距離)\n// - inline-action.spec.md「same-row consistency rule」(close X 同尺寸 md)\n// - tokens/layoutSpace/layoutSpace.spec.md(footer 用 px-loose py-tight)\n// - patterns/overlay-surface/overlay-surface.spec.md SurfaceFooter canonical\n// - Alert(banner)用 title ReactNode 帶 inline link CTA\n\n// ── i18n labels ─────────────────────────────────────────────────────────────\n\n// code-quality-allow: dead-export — public API per spec.md(consumer i18n override hook)\nexport interface BulkActionBarLabels {\n count: (n: number) => string\n clear: string\n hiddenSuffix: (hidden: number) => string\n /** @deprecated 2026-07-06 role 已降級 \"group\"(user 拍板),改用 `ariaLabel`;此 key 保留 backward-compat(值仍作 fallback)。 */\n toolbarAriaLabel: string\n /** root `role=\"group\"` 的 aria-label(2026-07-06 新名;未傳 fallback toolbarAriaLabel)。 */\n ariaLabel?: string\n}\n\n// code-quality-allow: dead-export — public API per spec.md(consumer spread + override)\nexport const BULK_ACTION_BAR_DEFAULT_LABELS: BulkActionBarLabels = {\n count: (n) => `已選 ${n} 項`,\n clear: '清除選取',\n hiddenSuffix: (hidden) => `· ${hidden} 個被 filter 隱藏`,\n toolbarAriaLabel: '批次操作',\n}\n\n// ── Props ───────────────────────────────────────────────────────────────────\n\nexport interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** 已選 ID,length === 0 時自動隱藏(回傳 null) */\n selection: readonly string[]\n /** Clear 觸發,user 點 X icon 或 Esc(consumer 在 page-level 監聽) */\n onClearSelection?: () => void\n /** 批次 actions(consumer 提供 md Button,一律 variant=tertiary;不用 primary/danger) */\n actions?: React.ReactNode\n /** Filter 模式:hidden 數量,顯示在 count 區 inline「已選 {N} 項 · {M} 個被 filter 隱藏」 */\n hiddenByFilter?: number\n /**\n * 「擴選整個 dataset」狀態(2026-05-13 ship,per user 抓 Alert「已選 5370」但 BulkActionBar\n * 仍顯「已選 50 項」regression):\n * - undefined / null(default):count 走 `selection.length`(page-level 視覺選取)\n * - number:count 走此數值(整個 dataset 擴選後 user 已選的真總數)\n *\n * Canonical pattern:consumer 把 BulkActionBar 跟「Alert info banner(提示擴選 dataset)」\n * 一起 mount,Alert 點「點此選取全部 N 個」→ setTotalSelected(N) → BulkActionBar count 同步。\n * 對齊 Gmail / Linear / Notion 全選 dataset hint pattern。\n * 詳 `bulk-action-bar.spec.md`「Extend dataset pattern」段。\n */\n totalSelected?: number | null\n /** i18n labels(Partial,merge with default) */\n labels?: Partial<BulkActionBarLabels>\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n// 視覺結構(同 SurfaceFooter / DataTable toolbar canonical):\n// px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]\n// gap-2 between elements\n// 全 md Buttons(same-row consistency)\n// <ButtonDivider /> 自帶 mx-1 = 12px 視覺距離\n//\n// Hint banner(擴 dataset 提示)完全外包給 Alert 元件 — consumer 視 ref 圖\n// 黏在 BulkActionBar 上方/下方,用 Alert variant=\"info\" placement=\"fixed\"\n// title={inline link JSX}。BulkActionBar 自己不再有 hint banner slot。\n//\n// 浮起 / fixed positioning 由 consumer wrap 決定(BulkActionBar 不限定 placement)。\n\nconst BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(\n function BulkActionBar(\n { selection, onClearSelection, actions, hiddenByFilter, totalSelected, labels: labelsOverride, className, ...props },\n ref\n ) {\n const { onFocus: _onFocus, onBlur: _onBlur, ...propsWithoutFocusHandlers } = props\n void _onFocus; void _onBlur\n const labels: BulkActionBarLabels = React.useMemo(\n () => ({ ...BULK_ACTION_BAR_DEFAULT_LABELS, ...labelsOverride }),\n [labelsOverride]\n )\n\n // selection.length === 0 自動藏(對齊 spec 禁止事項 #3)。\n // 反向選取(DataTable all 模式)例外:visible 全被 excluded 但 totalSelected>0 仍有選取 → 顯示(2026-06-22)\n const visible = !(selection.length === 0 && (totalSelected ?? 0) === 0)\n\n // ── 焦點接力(2026-09-29,待辦總帳 N46 子項「批次動作列消失後焦點回表格」;spec「a11y 預設」)──\n // 選取清空 / 批次動作把選取消掉時本列整個卸載;鍵盤使用者若正停在列內(清除 × 或某個動作鈕),焦點會掉到 body、\n // 下一次 Tab 從文件開頭重來。卸載時把焦點還給「進入本列之前」的元素(通常是列的勾選框或表格),同 Dialog 的\n // return-focus 契約;它已不在文件裡就不動。沒有新 prop:進入前的元素由 focus 事件的 relatedTarget 記下(內建 fallback,M23(f))。\n const focusWithinRef = React.useRef(false)\n const returnFocusToRef = React.useRef<HTMLElement | null>(null)\n React.useLayoutEffect(() => {\n if (visible || !focusWithinRef.current) return\n focusWithinRef.current = false\n const target = returnFocusToRef.current\n returnFocusToRef.current = null\n if (target && target.isConnected && (document.activeElement === document.body || document.activeElement === null)) {\n target.focus({ preventScroll: true })\n }\n }, [visible])\n\n if (!visible) return null\n\n return (\n <div\n ref={ref}\n onFocus={(e) => {\n props.onFocus?.(e)\n focusWithinRef.current = true\n const from = e.relatedTarget as HTMLElement | null\n if (from && !e.currentTarget.contains(from)) returnFocusToRef.current = from\n }}\n onBlur={(e) => {\n props.onBlur?.(e)\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) focusWithinRef.current = false\n }}\n // 2026-07-06 user 拍板:role \"toolbar\" → \"group\" — 原宣告 toolbar 但未實作 APG toolbar\n // 方向鍵 roving 契約(AT 告知「工具列」但方向鍵無反應 = 空承諾);group 語意誠實,\n // Tab 序照 DOM(spec 本有 canonical),Gmail / Linear bulk bar 實務同款。\n role=\"group\"\n aria-label={labels.ariaLabel ?? labels.toolbarAriaLabel}\n className={cn(\n 'flex items-center gap-2',\n 'px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]',\n // 上分隔線:bottom toolbar canonical(Linear / Apple Mail / Notion 共識)— 視覺從上方內容收尾\n 'border-t border-divider',\n className\n )}\n {...propsWithoutFocusHandlers}\n >\n {/* X close — md dismiss(2026-05-04 spec update:default placement = footer variant,\n visual weight 對齊 Dialog footer commitment buttons md;same-row consistency 維持)\n 未來若有 top-toolbar variant(覆蓋 sm-density toolbar)→ 該 variant override sm */}\n {onClearSelection && (\n <Button\n variant=\"text\"\n size=\"md\"\n iconOnly\n dismiss\n startIcon={X}\n aria-label={labels.clear}\n onClick={onClearSelection}\n />\n )}\n\n {/* count + filter hidden inline\n color canonical(2026-05-04):count = primary foreground + medium weight\n 理由:count 是 state-bearing 主資訊(「你在 selection mode + N items」),非裝飾\n World-class 共識:Linear/Notion/Carbon/Polaris 均用 primary foreground;muted 化弱化 state signal\n hiddenByFilter suffix 維持 muted(這是次資訊,視覺層次正確) */}\n {/* 2026-05-31 #3:aria-live 通知 SR 選取數變更;#20:補 font-medium 對齊 spec「Count text color canonical」表 + 上方 comment(state-bearing 主資訊) */}\n <span className=\"text-body text-foreground font-medium tabular-nums\" aria-live=\"polite\" aria-atomic=\"true\">\n {/* 2026-05-13:totalSelected override 走 dataset 擴選後真總數,否則 fallback page-level selection.length */}\n {labels.count(typeof totalSelected === 'number' ? totalSelected : selection.length)}\n {hiddenByFilter !== undefined && hiddenByFilter > 0 && (\n <span className=\"text-fg-muted font-normal\"> {labels.hiddenSuffix(hiddenByFilter)}</span>\n )}\n </span>\n\n {/* divider */}\n {actions && <ButtonDivider />}\n\n {/* batch actions slot(consumer 提供 md Buttons) */}\n {actions && (\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">{actions}</div>\n )}\n </div>\n )\n }\n)\nBulkActionBar.displayName = 'BulkActionBar'\n\n// Story auto-compile metadata\nexport const bulkActionBarMeta = {\n component: 'BulkActionBar',\n family: null,\n variants: {},\n sizes: {},\n states: ['default'],\n tokens: {\n fg: ['text-foreground', 'text-fg-muted'],\n border: ['border-divider'],\n },\n} as const\n\nexport { BulkActionBar }\n"],"names":["BulkActionBar"],"mappings":"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"}
|
|
@@ -89,8 +89,8 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
89
89
|
* Pressed 視覺色調(2026-05-21 v12 加):
|
|
90
90
|
* - `'emphasis'`(預設)→ 淡藍底 / primary 字(對齊 Figma toolbar / Linear toolbar /
|
|
91
91
|
* Material ToggleButton 共識 — toolbar functional toggle / 篩選啟用 / 面板開關)
|
|
92
|
-
* - `'neutral'` → 灰底 / foreground 字
|
|
93
|
-
*
|
|
92
|
+
* - `'neutral'` → 灰底 / foreground 字 —— **可取消**的切換鈕(再點一次就關掉)需要低一級強調時;
|
|
93
|
+
* 導覽 / 目前頁不用它(那是選中列,滑過釘住;button.spec.md pressedTone 表,2026-09-25 更正)
|
|
94
94
|
*
|
|
95
95
|
* 僅在 `pressed` 啟用且 variant ∈ {secondary, tertiary, text} 時生效。
|
|
96
96
|
* 跨 toggle context 維持單一 prop API,consumer 視語意選 tone 不另開 variant。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAK9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,QAAA,MAAM,cAAc;;;;;
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAK9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,QAAA,MAAM,cAAc;;;;;8EAiQnB,CAAA;AAKD,UAAU,uBAAuB;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AACD,yIAAyI;AACzI,QAAA,MAAM,kBAAkB,wCAAmD,CAAA;AAI3E,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EACnD,IAAI,CAAC,YAAY,CAAC,OAAO,cAAc,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjE;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;IAChE,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;IACpC,sDAAsD;IACtD,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,oCAAoC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,cAAc;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAcD,QAAA,MAAM,MAAM,uFA0NX,CAAA;AAGD;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Bb,CAAA;AAEV,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAA"}
|