@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,26 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
|
|
2
|
+
import { isTextEntryElement } from "../lib/roving-list-keyboard.js";
|
|
3
3
|
let cursorMover = "pointer";
|
|
4
4
|
let observedAnyInput = false;
|
|
5
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
6
5
|
const moverListeners = /* @__PURE__ */ new Set();
|
|
7
6
|
const MODIFIER_KEYS = /* @__PURE__ */ new Set(["Shift", "Meta", "Alt", "Control", "CapsLock", "Fn", "OS"]);
|
|
8
7
|
const CURSOR_KEYS_IN_TEXT_ENTRY = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End", "PageUp", "PageDown", "Tab", "Escape"]);
|
|
9
|
-
const
|
|
10
|
-
function isTextEntryTarget(target) {
|
|
11
|
-
if (!(target instanceof Element)) return false;
|
|
12
|
-
if (target instanceof HTMLTextAreaElement) return true;
|
|
13
|
-
if (target instanceof HTMLInputElement) return !NON_TEXT_INPUT_TYPES.has(target.type);
|
|
14
|
-
return target.isContentEditable === true;
|
|
15
|
-
}
|
|
8
|
+
const isTextEntryTarget = (target) => target instanceof Element && isTextEntryElement(target);
|
|
16
9
|
let lastPointerX = Number.NaN;
|
|
17
10
|
let lastPointerY = Number.NaN;
|
|
18
11
|
let lastPointerMoveWasReal = false;
|
|
19
|
-
function set(next) {
|
|
20
|
-
if (modality === next) return;
|
|
21
|
-
modality = next;
|
|
22
|
-
listeners.forEach((l) => l());
|
|
23
|
-
}
|
|
24
12
|
function setMover(next) {
|
|
25
13
|
if (cursorMover === next) return;
|
|
26
14
|
cursorMover = next;
|
|
@@ -30,12 +18,9 @@ function onKeyDown(e) {
|
|
|
30
18
|
observedAnyInput = true;
|
|
31
19
|
const typing = isTextEntryTarget(e.target) && !CURSOR_KEYS_IN_TEXT_ENTRY.has(e.key);
|
|
32
20
|
if (!MODIFIER_KEYS.has(e.key) && !typing) setMover("keyboard");
|
|
33
|
-
if (e.metaKey || e.altKey || e.ctrlKey) return;
|
|
34
|
-
set("keyboard");
|
|
35
21
|
}
|
|
36
22
|
function onPointerDown() {
|
|
37
23
|
observedAnyInput = true;
|
|
38
|
-
set("pointer");
|
|
39
24
|
setMover("pointer");
|
|
40
25
|
}
|
|
41
26
|
function onPointerMove(e) {
|
|
@@ -57,17 +42,7 @@ function seedFromFocusVisible() {
|
|
|
57
42
|
ensureListening();
|
|
58
43
|
if (observedAnyInput || typeof document === "undefined") return;
|
|
59
44
|
const active = document.activeElement;
|
|
60
|
-
if (active && active !== document.body && active.matches(":focus-visible"))
|
|
61
|
-
modality = "keyboard";
|
|
62
|
-
cursorMover = "keyboard";
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function subscribe(cb) {
|
|
66
|
-
seedFromFocusVisible();
|
|
67
|
-
listeners.add(cb);
|
|
68
|
-
return () => {
|
|
69
|
-
listeners.delete(cb);
|
|
70
|
-
};
|
|
45
|
+
if (active && active !== document.body && active.matches(":focus-visible")) cursorMover = "keyboard";
|
|
71
46
|
}
|
|
72
47
|
function subscribeMover(cb) {
|
|
73
48
|
seedFromFocusVisible();
|
|
@@ -76,12 +51,8 @@ function subscribeMover(cb) {
|
|
|
76
51
|
moverListeners.delete(cb);
|
|
77
52
|
};
|
|
78
53
|
}
|
|
79
|
-
const getSnapshot = () => modality;
|
|
80
54
|
const getMoverSnapshot = () => cursorMover;
|
|
81
55
|
const getServerSnapshot = () => "pointer";
|
|
82
|
-
function useInputModality() {
|
|
83
|
-
return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
84
|
-
}
|
|
85
56
|
function useCursorMover() {
|
|
86
57
|
return React.useSyncExternalStore(subscribeMover, getMoverSnapshot, getServerSnapshot);
|
|
87
58
|
}
|
|
@@ -92,7 +63,6 @@ function markPointerGrab(_e) {
|
|
|
92
63
|
}
|
|
93
64
|
export {
|
|
94
65
|
markPointerGrab,
|
|
95
|
-
useCursorMover
|
|
96
|
-
useInputModality
|
|
66
|
+
useCursorMover
|
|
97
67
|
};
|
|
98
68
|
//# sourceMappingURL=use-input-modality.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-input-modality.js","sources":["../../src/hooks/use-input-modality.ts"],"sourcesContent":["import * as React from \"react\"\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"use-input-modality.js","sources":["../../src/hooks/use-input-modality.ts"],"sourcesContent":["import * as React from \"react\"\nimport { isTextEntryElement } from \"@/design-system/lib/roving-list-keyboard\"\n\n/**\n * **最後一次搬動「反白」的是誰**(SSOT:ds-canonical/references/focus-canonical.md 規則一「兩類元件」+ 規則二)。\n *\n * 2026-09-26 起本檔只剩這一個訊號。原本的第一個訊號 `useInputModality()`(最近一次輸入是鍵盤還是指標,WICG `:focus-visible`\n * 啟發式,給常駐清單的虛擬游標)唯一的消費者是 TreeView 的 `showRing`;2026-09-25 TreeView 改成列上的真焦點(待辦總帳 B9、\n * 批次細節 X8「樹改真焦點」),框改由瀏覽器的 `:focus-visible` 決定,那個訊號就沒有任何消費者了 —— 留著 = 一份沒人讀的第二套判準,\n * 下一個人會以為常駐清單還有兩種畫框依據。刪除依據:待辦總帳〇節「09-26 同意清單回覆」(同意的清單含「按鍵規則合併」與 X8),\n * user 逐字:「確保符合我們一致的設計語言且不違背世界級的設計且都有確保整個ds 是SSOT,避免漂移就照你建議做」。\n * 常駐清單(TreeView / Sidebar / FileUpload 檔案清單)現在全部是真焦點 + `focus-visible:`,不需要這裡。\n *\n * `useCursorMover()` + `markPointerGrab()` —— 給會搶反白的浮層選單(cmdk / Radix Menu)。\n * 這類選單裡反白只有一個主人:滑鼠移過項目就把反白搶走(cmdk `onPointerMove → select()` /\n * Radix `onPointerMove → item.focus()`),鍵盤方向鍵再搶回來;兩種畫法(滑鼠 → 底色、鍵盤 → 框)永遠不同時出現。\n * 所以這裡**滑鼠移過項目要算**(那就是搶),但**滑鼠停著不算**(只有移動才會觸發 pointermove)——\n * 這一點與瀏覽器的 `:focus-visible` 啟發式相反(那個只看按下,不看移動)。項目在 `onPointerMoveCapture` 呼叫 `markPointerGrab`,\n * keydown 統一在 document 記成鍵盤 ——\n * **但在文字輸入框裡打字不算搬游標**(2026-09-10 user:「滑鼠點擊輸入框然後輸入 a,再點 backspace,選單上會出現鍵盤焦點的藍色邊框」):\n * 字元 / Backspace / Delete / 空白 是在編輯文字,反白跳到第一個符合項是函式庫的自動落點(cmdk `search` 一變就\n * `schedule(1, selectFirstItem)`),沒有人「搬」它;只有方向鍵 / Home / End / PageUp / PageDown / Tab / Esc 才算鍵盤搬游標。\n * 世界級同判:React Aria `useFocusVisible` 對文字輸入框只認 Tab / Escape 為會顯示焦點的鍵(`FOCUS_VISIBLE_INPUT_KEYS`);\n * MUI Autocomplete 只在 `reason === 'keyboard'`(方向鍵)才加 `focusVisible`,打字後的 autoHighlight 不加;\n * Ant rc-select 在 searchValue 一變就 `setActive(第一項)`、樣式是 `optionActiveBg` 底色、`outline: none`。\n * 所以打字後的自動落點用「開啟那一下」的來歷畫:滑鼠點進輸入框 → 底色;Tab 進來 → 框。\n * 2026-09-09 user:「滑鼠會搶反白的元件,搶完之後,那鍵盤是否可以再搶回?且搶回去之後原本滑鼠的 hover 樣式即會消失\n * 直到滑鼠又搶回來才會再出現,且滑鼠的搶應該是包括鍵盤焦點一起搶吧?」—— 三題都是「對」,一手來源見 focus-canonical Sources。\n *\n * 由來(2026-09-08 user 抓到):滑鼠點開 Select,已選項立刻出現鍵盤焦點框。\n * 根因是 cmdk 開啟時把游標放在已選項上,而「已選 + 游標」的畫框規則沒有模態條件。\n * 同款在 DropdownMenu / AgentPanel 歷史清單各一份,TreeView 自帶一份 `isKeyboardRef` ——\n * 四份各自實作 = 四份 SSOT(M17),收攏到這裡(TreeView 那一份之後已隨改真焦點退役,見上)。\n *\n * 監聽掛在 document 的 capture 階段,**模組載入即安裝**(有 `document` 才裝,SSR 安全)。\n * 第一版是「第一個消費者掛載時才安裝」——實測會漏:鍵盤開啟選單時,Tab / ArrowDown 都發生在\n * 選單項目掛載**之前**,沒被觀察到,項目掛上時模態還是初始值 pointer,已選項就沒框\n * (2026-09-08 閘的 C 路徑當場紅)。WICG polyfill 也是載入即裝。\n *\n * 另外訂閱當下若還沒觀察到任何輸入(模組載入晚於使用者互動時會這樣),\n * 用瀏覽器自己的 `document.activeElement.matches(':focus-visible')` 當種子 ——\n * 「它就是『這次聚焦該不該給可見指示』的權威答案」。\n */\nexport type InputModality = \"keyboard\" | \"pointer\"\n\nlet cursorMover: InputModality = \"pointer\"\nlet observedAnyInput = false\nconst moverListeners = new Set<() => void>()\n/** 純修飾鍵不搬反白;其餘任何鍵(含 cmdk 的 ⌘↓ / Ctrl+N、Radix 的 typeahead)都可能搬,所以不沿用 WICG 的修飾鍵排除 */\nconst MODIFIER_KEYS = new Set([\"Shift\", \"Meta\", \"Alt\", \"Control\", \"CapsLock\", \"Fn\", \"OS\"])\n/** 在文字輸入框裡仍算「搬游標」的鍵;其餘(字元、Backspace、Delete、空白、Enter…)是在編輯文字,不改反白來歷。 */\nconst CURSOR_KEYS_IN_TEXT_ENTRY = new Set([\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\", \"PageUp\", \"PageDown\", \"Tab\", \"Escape\"])\n// 「是不是文字輸入」的判準與清單鍵盤共用一份(lib/roving-list-keyboard.ts `isTextEntryElement`;2026-09-26 前本檔另有一份)\nconst isTextEntryTarget = (target: EventTarget | null) => target instanceof Element && isTextEntryElement(target)\n// Chromium 在內容捲動後會補發一個**座標不變**的 pointermove(讓 :hover 重新計算),那不是使用者在搶;\n// 只有座標真的變了才算滑鼠在動。\nlet lastPointerX = Number.NaN\nlet lastPointerY = Number.NaN\nlet lastPointerMoveWasReal = false\n\nfunction setMover(next: InputModality) {\n if (cursorMover === next) return\n cursorMover = next\n moverListeners.forEach((l) => l())\n}\nfunction onKeyDown(e: KeyboardEvent) {\n observedAnyInput = true\n // 反白來歷:修飾鍵不算;在文字輸入框裡打字(非游標鍵)不算(見檔頭)\n const typing = isTextEntryTarget(e.target) && !CURSOR_KEYS_IN_TEXT_ENTRY.has(e.key)\n if (!MODIFIER_KEYS.has(e.key) && !typing) setMover(\"keyboard\")\n}\nfunction onPointerDown() {\n observedAnyInput = true\n setMover(\"pointer\")\n}\nfunction onPointerMove(e: PointerEvent) {\n // 每次滑鼠移動都會跑到這裡,所以不配置物件 —— 兩個數字分開存,省掉每一動一顆垃圾。\n lastPointerMoveWasReal = e.clientX !== lastPointerX || e.clientY !== lastPointerY\n lastPointerX = e.clientX\n lastPointerY = e.clientY\n}\n\n// **keydown / pointerdown 掛在模組頂層;只有 pointermove 惰性掛。**\n//\n// 2026-09-14:我一度把三個都改成「有人訂閱才掛」,理由是「呼叫 markPointerGrab 的元件都在同一棵樹裡\n// 呼叫 useCursorMover,語意等價」。**那是錯的**,CI 當場抓到(test:virtual-cursor-modality 的\n// Select / SelectMenu / PeoplePicker F 三條):模組層監聽的存在意義正是**在任何元件訂閱之前就已經在看** ——\n// 使用者「點開選單」那一下的 pointerdown 發生在選單掛載之前,惰性掛就漏掉它,模態沒被記成指標,\n// 接著在搜尋列打字就被判成鍵盤,冒出不該有的焦點框。\n//\n// 這兩個只在真的按鍵 / 真的按下指標時開火,一次互動一次,成本可以忽略 —— 放回頂層。\n// 真正貴的是 pointermove(隨滑鼠持續開火),而它只餵 `lastPointerMoveWasReal` 給 markPointerGrab;\n// 呼叫 markPointerGrab 的 command.tsx / dropdown-menu.tsx 都在同一棵樹裡呼叫 useCursorMover,\n// 所以它惰性掛是安全的 —— 指標搶得到反白時必定早已有訂閱者。掛上後不再卸載。\nif (typeof document !== \"undefined\") {\n document.addEventListener(\"keydown\", onKeyDown, { capture: true })\n document.addEventListener(\"pointerdown\", onPointerDown, { capture: true })\n}\nlet _movingHooked = false\nfunction ensureListening() {\n if (_movingHooked || typeof document === \"undefined\") return\n _movingHooked = true\n document.addEventListener(\"pointermove\", onPointerMove, { capture: true })\n}\n\nfunction seedFromFocusVisible() {\n ensureListening()\n if (observedAnyInput || typeof document === \"undefined\") return\n const active = document.activeElement\n if (active && active !== document.body && active.matches(\":focus-visible\")) cursorMover = \"keyboard\"\n}\nfunction subscribeMover(cb: () => void) {\n seedFromFocusVisible()\n moverListeners.add(cb)\n return () => { moverListeners.delete(cb) }\n}\nconst getMoverSnapshot = () => cursorMover\nconst getServerSnapshot = (): InputModality => \"pointer\"\n\n/** 最後一次搬動反白的是鍵盤還是指標(給會搶反白的浮層選單:cmdk / Radix Menu 的項目)。 */\nexport function useCursorMover(): InputModality {\n return React.useSyncExternalStore(subscribeMover, getMoverSnapshot, getServerSnapshot)\n}\n\n/**\n * 會搶反白的項目在 `onPointerMoveCapture` 呼叫:滑鼠**移過**這一列 = 指標把反白搶走。\n * capture 階段是為了搶在 cmdk / Radix 自己的 `onPointerMove`(它們在這一下把反白搬過來)之前記下來歷,\n * 同一次 render 就能用對的畫法;cmdk 會覆寫 consumer 的 `onPointerMove`,capture 版不會被蓋掉。\n * 座標沒變的 pointermove(捲動後瀏覽器補發的)不算。\n */\nexport function markPointerGrab(_e?: { pointerType?: string }) {\n if (!lastPointerMoveWasReal) return\n observedAnyInput = true\n setMover(\"pointer\")\n}\n"],"names":[],"mappings":";;AA6CA,IAAI,cAA6B;AACjC,IAAI,mBAAmB;AACvB,MAAM,qCAAqB,IAAA;AAE3B,MAAM,gBAAgB,oBAAI,IAAI,CAAC,SAAS,QAAQ,OAAO,WAAW,YAAY,MAAM,IAAI,CAAC;AAEzF,MAAM,4BAA4B,oBAAI,IAAI,CAAC,WAAW,aAAa,aAAa,cAAc,QAAQ,OAAO,UAAU,YAAY,OAAO,QAAQ,CAAC;AAEnJ,MAAM,oBAAoB,CAAC,WAA+B,kBAAkB,WAAW,mBAAmB,MAAM;AAGhH,IAAI,eAAe,OAAO;AAC1B,IAAI,eAAe,OAAO;AAC1B,IAAI,yBAAyB;AAE7B,SAAS,SAAS,MAAqB;AACrC,MAAI,gBAAgB,KAAM;AAC1B,gBAAc;AACd,iBAAe,QAAQ,CAAC,MAAM,EAAA,CAAG;AACnC;AACA,SAAS,UAAU,GAAkB;AACnC,qBAAmB;AAEnB,QAAM,SAAS,kBAAkB,EAAE,MAAM,KAAK,CAAC,0BAA0B,IAAI,EAAE,GAAG;AAClF,MAAI,CAAC,cAAc,IAAI,EAAE,GAAG,KAAK,CAAC,OAAQ,UAAS,UAAU;AAC/D;AACA,SAAS,gBAAgB;AACvB,qBAAmB;AACnB,WAAS,SAAS;AACpB;AACA,SAAS,cAAc,GAAiB;AAEtC,2BAAyB,EAAE,YAAY,gBAAgB,EAAE,YAAY;AACrE,iBAAe,EAAE;AACjB,iBAAe,EAAE;AACnB;AAcA,IAAI,OAAO,aAAa,aAAa;AACnC,WAAS,iBAAiB,WAAW,WAAW,EAAE,SAAS,MAAM;AACjE,WAAS,iBAAiB,eAAe,eAAe,EAAE,SAAS,MAAM;AAC3E;AACA,IAAI,gBAAgB;AACpB,SAAS,kBAAkB;AACzB,MAAI,iBAAiB,OAAO,aAAa,YAAa;AACtD,kBAAgB;AAChB,WAAS,iBAAiB,eAAe,eAAe,EAAE,SAAS,MAAM;AAC3E;AAEA,SAAS,uBAAuB;AAC9B,kBAAA;AACA,MAAI,oBAAoB,OAAO,aAAa,YAAa;AACzD,QAAM,SAAS,SAAS;AACxB,MAAI,UAAU,WAAW,SAAS,QAAQ,OAAO,QAAQ,gBAAgB,EAAG,eAAc;AAC5F;AACA,SAAS,eAAe,IAAgB;AACtC,uBAAA;AACA,iBAAe,IAAI,EAAE;AACrB,SAAO,MAAM;AAAE,mBAAe,OAAO,EAAE;AAAA,EAAE;AAC3C;AACA,MAAM,mBAAmB,MAAM;AAC/B,MAAM,oBAAoB,MAAqB;AAGxC,SAAS,iBAAgC;AAC9C,SAAO,MAAM,qBAAqB,gBAAgB,kBAAkB,iBAAiB;AACvF;AAQO,SAAS,gBAAgB,IAA+B;AAC7D,MAAI,CAAC,uBAAwB;AAC7B,qBAAmB;AACnB,WAAS,SAAS;AACpB;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-overflow-items.d.ts","sourceRoot":"","sources":["../../src/hooks/use-overflow-items.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAOH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,WAAW;IACzD,iCAAiC;IACjC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IAC7B,0BAA0B;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,0BAA0B;IAC1B,KAAK,EAAE,OAAO,CAAA;IACd,wBAAwB;IACxB,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,KAAK,oBAAoB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"use-overflow-items.d.ts","sourceRoot":"","sources":["../../src/hooks/use-overflow-items.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAOH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,WAAW;IACzD,iCAAiC;IACjC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IAC7B,0BAA0B;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,0BAA0B;IAC1B,KAAK,EAAE,OAAO,CAAA;IACd,wBAAwB;IACxB,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,KAAK,oBAAoB,CAAC,CAAC,CAAC,CAuC7F;AAMD,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAGD,MAAM,WAAW,wBAAwB,CAAC,CAAC,SAAS,WAAW;IAC7D,qBAAqB;IACrB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IAChC,sCAAsC;IACtC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IACjE,4CAA4C;IAC5C,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,oBAAoB;IACpB,WAAW,EAAE,OAAO,CAAA;IACpB,wDAAwD;IACxD,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAA;CACtD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EACpE,OAAO,GAAE,yBAA8B,GACtC,wBAAwB,CAAC,CAAC,CAAC,CAgF7B"}
|
|
@@ -19,10 +19,12 @@ function useScrollEdges() {
|
|
|
19
19
|
ro.observe(el);
|
|
20
20
|
const mo = new MutationObserver(update);
|
|
21
21
|
mo.observe(el, { childList: true, subtree: true, characterData: true });
|
|
22
|
+
el.setAttribute("data-overflow-scroller", "");
|
|
22
23
|
return () => {
|
|
23
24
|
el.removeEventListener("scroll", update);
|
|
24
25
|
ro.disconnect();
|
|
25
26
|
mo.disconnect();
|
|
27
|
+
el.removeAttribute("data-overflow-scroller");
|
|
26
28
|
};
|
|
27
29
|
}, []);
|
|
28
30
|
return { scrollRef, ...state };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-overflow-items.js","sources":["../../src/hooks/use-overflow-items.ts"],"sourcesContent":["import * as React from 'react'\n\n/**\n * 水平溢出追蹤 hooks — 給 Tabs / ChipGroup 等「一排水平 items 塞不下父容器」的元件共用。\n *\n * ── 設計原則 ──\n * Scroll 模式與 Menu 模式是兩種處理策略:\n *\n * 1. **Scroll 模式**(Material / Polaris / Primer / iOS 作法)\n * items 用原生 overflow-x-auto 水平滾動,邊緣 fade mask 指示還有內容。\n * 使用 `useScrollEdges()`:回傳 atStart / atEnd / canScroll,讓消費端\n * 決定 mask-image / scroll arrow 的顯示。\n *\n * 2. **Menu 模式**(Ant Design / Atlassian「動態 collapse-overflow」作法)\n * 塞不下的 items 收進 DropdownMenu。`useOverflowIndices()` 回傳 overflowIndices\n * 供消費端動態計算哪些 items 塞不下、渲染對應的 menu items。\n *\n * ⚠️ **目前 0 consumer(reserved primitive)**:DS 內現有 menu 模式實作(Tabs / Chip)走的是\n * 「**show-all navigator**」派 — dropdown 永遠列**全部** items(不需動態 overflow 計算),各自用\n * local registerItem,**刻意不用** `useOverflowIndices`(見 tabs.tsx:256 / chip.tsx:219 註解)。\n * 本 hook 保留給未來真正需要「collapse-overflow:只把塞不下的收進選單」的 consumer。\n * **roving tabindex / a11y 語意由 consumer 的渲染方式決定**(hook 只回傳 indices,不操作\n * DOM / tabindex),非 hook 本身保證。\n *\n * ── 為什麼分兩個 hook,不合一 ──\n * Scroll 的計算依據是 scroll 事件與 client/scroll width;Menu 的計算依據是\n * items 的 offsetLeft/offsetWidth 相對容器 clientWidth。訂閱的事件不同\n * (scroll vs resize),回傳的資料形狀不同。合一會讓 API 有一半是 noise。\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// useScrollEdges — 給 scroll 模式\n// ─────────────────────────────────────────────────────────────────────────────\n\n// code-quality-allow: dead-export — hook return type — API surface for consumers who want to annotate\nexport interface UseScrollEdgesResult<T extends HTMLElement> {\n /** 綁在 scroll container 上的 ref */\n scrollRef: React.RefObject<T>\n /** scroll 位置在最左側(無法再往左)*/\n atStart: boolean\n /** scroll 位置在最右側(無法再往右)*/\n atEnd: boolean\n /** 內容總寬度超過可視寬度,有滾動空間 */\n canScroll: boolean\n}\n\n/**\n * 追蹤 scroll container 的滾動位置,用來決定左右 fade mask 是否顯示。\n *\n * 典型用法:\n * ```tsx\n * const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n * const maskImage = canScroll\n * ? `linear-gradient(to right,\n * ${atStart ? 'black' : 'transparent'} 0,\n * black 16px,\n * black calc(100% - 16px),\n * ${atEnd ? 'black' : 'transparent'} 100%)`\n * : undefined\n * return <div ref={scrollRef} className=\"overflow-x-auto\" style={{ maskImage, WebkitMaskImage: maskImage }}>\n * {items}\n * </div>\n * ```\n */\nexport function useScrollEdges<T extends HTMLElement = HTMLElement>(): UseScrollEdgesResult<T> {\n const scrollRef = React.useRef<T | null>(null)\n const [state, setState] = React.useState({ atStart: true, atEnd: true, canScroll: false })\n\n React.useEffect(() => {\n const el = scrollRef.current\n if (!el) return\n\n const update = () => {\n const canScroll = el.scrollWidth > el.clientWidth + 1\n const atStart = el.scrollLeft <= 0\n const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 1\n setState((prev) =>\n prev.atStart === atStart && prev.atEnd === atEnd && prev.canScroll === canScroll\n ? prev\n : { atStart, atEnd, canScroll }\n )\n }\n\n update()\n el.addEventListener('scroll', update, { passive: true })\n const ro = new ResizeObserver(update)\n ro.observe(el)\n // 監聽 children 變化(items 增減、字體載入)\n const mo = new MutationObserver(update)\n mo.observe(el, { childList: true, subtree: true, characterData: true })\n\n return () => {\n el.removeEventListener('scroll', update)\n ro.disconnect()\n mo.disconnect()\n }\n }, [])\n\n return { scrollRef, ...state }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// useOverflowIndices — 給 menu 模式\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface UseOverflowIndicesOptions {\n /**\n * 預留給 overflow trigger(如 \"More\" 按鈕)的右側寬度(px)。\n * 計算 items 是否溢出時會從 container clientWidth 扣掉這個值。\n */\n reserveTriggerWidth?: number\n}\n\n// code-quality-allow: dead-export — hook return type — API surface for consumers who want to annotate\nexport interface UseOverflowIndicesResult<C extends HTMLElement> {\n /** 綁在 items 的父容器上 */\n containerRef: React.RefObject<C>\n /** 為每個 item 註冊 ref(回傳 callback ref)*/\n registerItem: (index: number) => (el: HTMLElement | null) => void\n /** DOM 順序上溢出的 item 索引(連續區間,從某個 index 到尾端)*/\n overflowIndices: number[]\n /** 至少有一個 item 溢出 */\n hasOverflow: boolean\n /** 依 index 取得對應 item 的 DOM 元素,供 scrollIntoView 等操作使用 */\n getItemAt: (index: number) => HTMLElement | undefined\n}\n\n/**\n * 追蹤一排水平 items 裡哪些「當前不在可視範圍內」。\n *\n * ── 演算法 ──\n * 對每個 item 檢查 `[offsetLeft, offsetLeft+offsetWidth]` 是否完全落在\n * `[scrollLeft, scrollLeft + clientWidth - reserveTriggerWidth]` 範圍內。\n * 沒完全落在內的就算溢出。\n *\n * **關鍵**:overflow 集合跟 scrollLeft 連動,不是靜態「原始佈局不 fit」集合。\n * 這是 Ant Design / Atlassian 世界級作法 —— menu 顯示「當下看不到的 items」,\n * 不是「原始溢出的 items」。\n *\n * 為什麼這樣對:\n * - 使用者點 menu item → `scrollIntoView` → 原本 overflow 的 item 進入視圖,\n * 原本可見的 items 被推出去 → 下次開 menu 看到的是「剛被推出去的 items」,\n * 永遠能找到所有當前看不到的 items,不會卡住。\n * - 靜態 overflow (只算原始佈局) 會造成 scroll 後無法回到前面的 items。\n *\n * ── 觸發重算 ──\n * - ResizeObserver: 容器寬度變化 / item 尺寸變化\n * - scroll event: scroll 位置變化\n *\n * ── 前提 ──\n * items 在 DOM 裡始終存在 (不可 conditional render),並用 `registerItem(i)` 綁 ref。\n * 容器要可以 scroll (overflow-x-auto 或類似),否則 scrollLeft 永遠 0。\n *\n * 典型用法:\n * ```tsx\n * const { containerRef, registerItem, overflowIndices, hasOverflow, getItemAt } =\n * useOverflowIndices<HTMLDivElement>({ reserveTriggerWidth: 0 })\n *\n * const handleMenuSelect = (value: string, index: number) => {\n * onValueChange?.(value)\n * requestAnimationFrame(() => {\n * getItemAt(index)?.scrollIntoView({ behavior: 'smooth', inline: 'center' })\n * })\n * }\n *\n * return (\n * <div className=\"flex items-center\">\n * <div ref={containerRef} className=\"flex-1 min-w-0 overflow-x-auto\">\n * <ItemList>\n * {items.map((item, i) => React.cloneElement(item, { ref: registerItem(i) }))}\n * </ItemList>\n * </div>\n * {hasOverflow && <OverflowMenu items={overflowIndices.map(i => items[i])} />}\n * </div>\n * )\n * ```\n */\nexport function useOverflowIndices<C extends HTMLElement = HTMLElement>(\n options: UseOverflowIndicesOptions = {}\n): UseOverflowIndicesResult<C> {\n const { reserveTriggerWidth = 0 } = options\n const containerRef = React.useRef<C | null>(null)\n const itemRefsMap = React.useRef<Map<number, HTMLElement>>(new Map())\n const [overflowIndices, setOverflowIndices] = React.useState<number[]>([])\n\n const registerItem = React.useCallback((index: number) => {\n return (el: HTMLElement | null) => {\n if (el) {\n itemRefsMap.current.set(index, el)\n } else {\n itemRefsMap.current.delete(index)\n }\n }\n }, [])\n\n React.useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n const compute = () => {\n const containerWidth = container.clientWidth\n if (containerWidth === 0) return\n\n const scrollLeft = container.scrollLeft\n const visibleStart = scrollLeft\n const visibleEnd = scrollLeft + containerWidth - reserveTriggerWidth\n\n // 容許 1px 的像素取整誤差,避免邊界 item 被誤判為 overflow\n const tolerance = 1\n\n const indices = Array.from(itemRefsMap.current.keys()).sort((a, b) => a - b)\n\n const overflow: number[] = []\n for (const i of indices) {\n const el = itemRefsMap.current.get(i)\n if (!el) continue\n\n const left = el.offsetLeft\n const right = left + el.offsetWidth\n // 完全可見條件: item 的左右邊都在可視窗口內\n const fullyVisible =\n left >= visibleStart - tolerance && right <= visibleEnd + tolerance\n if (!fullyVisible) overflow.push(i)\n }\n\n setOverflowIndices((prev) => {\n if (prev.length === overflow.length && prev.every((v, i) => v === overflow[i])) {\n return prev\n }\n return overflow\n })\n }\n\n compute()\n const ro = new ResizeObserver(compute)\n ro.observe(container)\n // 也觀察每個 item 的尺寸變化(字體載入、label 更新等)\n itemRefsMap.current.forEach((el) => ro.observe(el))\n // Scroll event: overflow 集合隨 scroll 位置變化\n container.addEventListener('scroll', compute, { passive: true })\n\n return () => {\n ro.disconnect()\n container.removeEventListener('scroll', compute)\n }\n }, [reserveTriggerWidth])\n\n const getItemAt = React.useCallback(\n (index: number) => itemRefsMap.current.get(index),\n []\n )\n\n return {\n containerRef,\n registerItem,\n overflowIndices,\n hasOverflow: overflowIndices.length > 0,\n getItemAt,\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-overflow-items.js","sources":["../../src/hooks/use-overflow-items.ts"],"sourcesContent":["import * as React from 'react'\n\n/**\n * 水平溢出追蹤 hooks — 給 Tabs / ChipGroup 等「一排水平 items 塞不下父容器」的元件共用。\n *\n * ── 設計原則 ──\n * Scroll 模式與 Menu 模式是兩種處理策略:\n *\n * 1. **Scroll 模式**(Material / Polaris / Primer / iOS 作法)\n * items 用原生 overflow-x-auto 水平滾動,邊緣 fade mask 指示還有內容。\n * 使用 `useScrollEdges()`:回傳 atStart / atEnd / canScroll,讓消費端\n * 決定 mask-image / scroll arrow 的顯示。\n *\n * 2. **Menu 模式**(Ant Design / Atlassian「動態 collapse-overflow」作法)\n * 塞不下的 items 收進 DropdownMenu。`useOverflowIndices()` 回傳 overflowIndices\n * 供消費端動態計算哪些 items 塞不下、渲染對應的 menu items。\n *\n * ⚠️ **目前 0 consumer(reserved primitive)**:DS 內現有 menu 模式實作(Tabs / Chip)走的是\n * 「**show-all navigator**」派 — dropdown 永遠列**全部** items(不需動態 overflow 計算),各自用\n * local registerItem,**刻意不用** `useOverflowIndices`(見 tabs.tsx:256 / chip.tsx:219 註解)。\n * 本 hook 保留給未來真正需要「collapse-overflow:只把塞不下的收進選單」的 consumer。\n * **roving tabindex / a11y 語意由 consumer 的渲染方式決定**(hook 只回傳 indices,不操作\n * DOM / tabindex),非 hook 本身保證。\n *\n * ── 為什麼分兩個 hook,不合一 ──\n * Scroll 的計算依據是 scroll 事件與 client/scroll width;Menu 的計算依據是\n * items 的 offsetLeft/offsetWidth 相對容器 clientWidth。訂閱的事件不同\n * (scroll vs resize),回傳的資料形狀不同。合一會讓 API 有一半是 noise。\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// useScrollEdges — 給 scroll 模式\n// ─────────────────────────────────────────────────────────────────────────────\n\n// code-quality-allow: dead-export — hook return type — API surface for consumers who want to annotate\nexport interface UseScrollEdgesResult<T extends HTMLElement> {\n /** 綁在 scroll container 上的 ref */\n scrollRef: React.RefObject<T>\n /** scroll 位置在最左側(無法再往左)*/\n atStart: boolean\n /** scroll 位置在最右側(無法再往右)*/\n atEnd: boolean\n /** 內容總寬度超過可視寬度,有滾動空間 */\n canScroll: boolean\n}\n\n/**\n * 追蹤 scroll container 的滾動位置,用來決定左右 fade mask 是否顯示。\n *\n * 典型用法:\n * ```tsx\n * const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n * const maskImage = canScroll\n * ? `linear-gradient(to right,\n * ${atStart ? 'black' : 'transparent'} 0,\n * black 16px,\n * black calc(100% - 16px),\n * ${atEnd ? 'black' : 'transparent'} 100%)`\n * : undefined\n * return <div ref={scrollRef} className=\"overflow-x-auto\" style={{ maskImage, WebkitMaskImage: maskImage }}>\n * {items}\n * </div>\n * ```\n */\nexport function useScrollEdges<T extends HTMLElement = HTMLElement>(): UseScrollEdgesResult<T> {\n const scrollRef = React.useRef<T | null>(null)\n const [state, setState] = React.useState({ atStart: true, atEnd: true, canScroll: false })\n\n React.useEffect(() => {\n const el = scrollRef.current\n if (!el) return\n\n const update = () => {\n const canScroll = el.scrollWidth > el.clientWidth + 1\n const atStart = el.scrollLeft <= 0\n const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 1\n setState((prev) =>\n prev.atStart === atStart && prev.atEnd === atEnd && prev.canScroll === canScroll\n ? prev\n : { atStart, atEnd, canScroll }\n )\n }\n\n update()\n el.addEventListener('scroll', update, { passive: true })\n const ro = new ResizeObserver(update)\n ro.observe(el)\n // 監聽 children 變化(items 增減、字體載入)\n const mo = new MutationObserver(update)\n mo.observe(el, { childList: true, subtree: true, characterData: true })\n // 標記捲動容器(2026-09-29,待辦總帳 OE26):OverflowScrollArrow 卸載時若焦點在它身上、另一側箭頭也不在,\n // 就把焦點交給這個容器 —— 靠這個屬性找到它,消費者不用多傳 ref。\n el.setAttribute('data-overflow-scroller', '')\n\n return () => {\n el.removeEventListener('scroll', update)\n ro.disconnect()\n mo.disconnect()\n el.removeAttribute('data-overflow-scroller')\n }\n }, [])\n\n return { scrollRef, ...state }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// useOverflowIndices — 給 menu 模式\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface UseOverflowIndicesOptions {\n /**\n * 預留給 overflow trigger(如 \"More\" 按鈕)的右側寬度(px)。\n * 計算 items 是否溢出時會從 container clientWidth 扣掉這個值。\n */\n reserveTriggerWidth?: number\n}\n\n// code-quality-allow: dead-export — hook return type — API surface for consumers who want to annotate\nexport interface UseOverflowIndicesResult<C extends HTMLElement> {\n /** 綁在 items 的父容器上 */\n containerRef: React.RefObject<C>\n /** 為每個 item 註冊 ref(回傳 callback ref)*/\n registerItem: (index: number) => (el: HTMLElement | null) => void\n /** DOM 順序上溢出的 item 索引(連續區間,從某個 index 到尾端)*/\n overflowIndices: number[]\n /** 至少有一個 item 溢出 */\n hasOverflow: boolean\n /** 依 index 取得對應 item 的 DOM 元素,供 scrollIntoView 等操作使用 */\n getItemAt: (index: number) => HTMLElement | undefined\n}\n\n/**\n * 追蹤一排水平 items 裡哪些「當前不在可視範圍內」。\n *\n * ── 演算法 ──\n * 對每個 item 檢查 `[offsetLeft, offsetLeft+offsetWidth]` 是否完全落在\n * `[scrollLeft, scrollLeft + clientWidth - reserveTriggerWidth]` 範圍內。\n * 沒完全落在內的就算溢出。\n *\n * **關鍵**:overflow 集合跟 scrollLeft 連動,不是靜態「原始佈局不 fit」集合。\n * 這是 Ant Design / Atlassian 世界級作法 —— menu 顯示「當下看不到的 items」,\n * 不是「原始溢出的 items」。\n *\n * 為什麼這樣對:\n * - 使用者點 menu item → `scrollIntoView` → 原本 overflow 的 item 進入視圖,\n * 原本可見的 items 被推出去 → 下次開 menu 看到的是「剛被推出去的 items」,\n * 永遠能找到所有當前看不到的 items,不會卡住。\n * - 靜態 overflow (只算原始佈局) 會造成 scroll 後無法回到前面的 items。\n *\n * ── 觸發重算 ──\n * - ResizeObserver: 容器寬度變化 / item 尺寸變化\n * - scroll event: scroll 位置變化\n *\n * ── 前提 ──\n * items 在 DOM 裡始終存在 (不可 conditional render),並用 `registerItem(i)` 綁 ref。\n * 容器要可以 scroll (overflow-x-auto 或類似),否則 scrollLeft 永遠 0。\n *\n * 典型用法:\n * ```tsx\n * const { containerRef, registerItem, overflowIndices, hasOverflow, getItemAt } =\n * useOverflowIndices<HTMLDivElement>({ reserveTriggerWidth: 0 })\n *\n * const handleMenuSelect = (value: string, index: number) => {\n * onValueChange?.(value)\n * requestAnimationFrame(() => {\n * getItemAt(index)?.scrollIntoView({ behavior: 'smooth', inline: 'center' })\n * })\n * }\n *\n * return (\n * <div className=\"flex items-center\">\n * <div ref={containerRef} className=\"flex-1 min-w-0 overflow-x-auto\">\n * <ItemList>\n * {items.map((item, i) => React.cloneElement(item, { ref: registerItem(i) }))}\n * </ItemList>\n * </div>\n * {hasOverflow && <OverflowMenu items={overflowIndices.map(i => items[i])} />}\n * </div>\n * )\n * ```\n */\nexport function useOverflowIndices<C extends HTMLElement = HTMLElement>(\n options: UseOverflowIndicesOptions = {}\n): UseOverflowIndicesResult<C> {\n const { reserveTriggerWidth = 0 } = options\n const containerRef = React.useRef<C | null>(null)\n const itemRefsMap = React.useRef<Map<number, HTMLElement>>(new Map())\n const [overflowIndices, setOverflowIndices] = React.useState<number[]>([])\n\n const registerItem = React.useCallback((index: number) => {\n return (el: HTMLElement | null) => {\n if (el) {\n itemRefsMap.current.set(index, el)\n } else {\n itemRefsMap.current.delete(index)\n }\n }\n }, [])\n\n React.useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n const compute = () => {\n const containerWidth = container.clientWidth\n if (containerWidth === 0) return\n\n const scrollLeft = container.scrollLeft\n const visibleStart = scrollLeft\n const visibleEnd = scrollLeft + containerWidth - reserveTriggerWidth\n\n // 容許 1px 的像素取整誤差,避免邊界 item 被誤判為 overflow\n const tolerance = 1\n\n const indices = Array.from(itemRefsMap.current.keys()).sort((a, b) => a - b)\n\n const overflow: number[] = []\n for (const i of indices) {\n const el = itemRefsMap.current.get(i)\n if (!el) continue\n\n const left = el.offsetLeft\n const right = left + el.offsetWidth\n // 完全可見條件: item 的左右邊都在可視窗口內\n const fullyVisible =\n left >= visibleStart - tolerance && right <= visibleEnd + tolerance\n if (!fullyVisible) overflow.push(i)\n }\n\n setOverflowIndices((prev) => {\n if (prev.length === overflow.length && prev.every((v, i) => v === overflow[i])) {\n return prev\n }\n return overflow\n })\n }\n\n compute()\n const ro = new ResizeObserver(compute)\n ro.observe(container)\n // 也觀察每個 item 的尺寸變化(字體載入、label 更新等)\n itemRefsMap.current.forEach((el) => ro.observe(el))\n // Scroll event: overflow 集合隨 scroll 位置變化\n container.addEventListener('scroll', compute, { passive: true })\n\n return () => {\n ro.disconnect()\n container.removeEventListener('scroll', compute)\n }\n }, [reserveTriggerWidth])\n\n const getItemAt = React.useCallback(\n (index: number) => itemRefsMap.current.get(index),\n []\n )\n\n return {\n containerRef,\n registerItem,\n overflowIndices,\n hasOverflow: overflowIndices.length > 0,\n getItemAt,\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-truncated.d.ts","sourceRoot":"","sources":["../../src/hooks/use-truncated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA4C9B,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,OAAO,GAAG,SAAS,CAAA;IAC1D,8EAA8E;IAC9E,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,CAAA;IAC3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,gHAAgH;IAChH,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAA;CACnC;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,GAAE,mBAAwB,GAChC;IAAE,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"use-truncated.d.ts","sourceRoot":"","sources":["../../src/hooks/use-truncated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA4C9B,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,OAAO,GAAG,SAAS,CAAA;IAC1D,8EAA8E;IAC9E,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,CAAA;IAC3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,gHAAgH;IAChH,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAA;CACnC;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,GAAE,mBAAwB,GAChC;IAAE,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAyCjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-truncated.js","sources":["../../src/hooks/use-truncated.ts"],"sourcesContent":["import * as React from 'react'\n\n// ── useTruncated — 單行文字截斷偵測引擎(SSOT)─────────────────────────────────\n// 收斂 Breadcrumb TruncatedLabel / DataTable TruncateCell(兩處 module-level shared ResizeObserver 引擎\n// **逐字重複**,僅變數名不同)+ Tag(原 per-instance `new ResizeObserver`)三處的截斷偵測 + isTruncated\n// 狀態機為唯一 owner(M17 SSOT);Tag 亦收斂進共用 shared RO,行為等價。\n//\n// 世界級對照(M8):MUI/MUI-X 官方無第一方 primitive,社群共識 = 「hook 量測 scrollWidth>clientWidth\n// + ref + 以 Tooltip `open` prop 條件控制」(issue #37211);此 hook 即該低階量測層,\n// 上層 `<TruncatedText>`(patterns/element-anatomy)對應 Ant `Typography.Text ellipsis` 高階元件。\n//\n// 三處變異點皆以 options 注入,**行為零漂移**:\n// - Breadcrumb / DataTable:預設 scrollWidth>clientWidth。\n// - Tag:trigger≠量測元素(observe root、量測內層 span)+ Canvas measureText(flex 內 scrollWidth\n// 不可靠)+ useLayoutEffect(避免 paint flash)+ deps=[children] → 全走 options。\n\ntype RoCallback = (entry: ResizeObserverEntry) => void\n\nlet sharedRO: ResizeObserver | null = null\nconst sharedROCallbacks = new WeakMap<Element, RoCallback>()\n\n// 全 DS 共用單一 ResizeObserver,dispatch 到 per-element callback(2026-04-22 DataTable D3 perf audit\n// 成果:10 col × 100 row = 1 RO 而非 1000)。element 卸載時 cleanup,singleton RO 本身不 disconnect。\nfunction getSharedRO(): ResizeObserver {\n if (sharedRO) return sharedRO\n sharedRO = new ResizeObserver((entries) => {\n entries.forEach((e) => {\n const cb = sharedROCallbacks.get(e.target)\n if (cb) cb(e)\n })\n })\n return sharedRO\n}\n\nfunction observeShared(el: Element, cb: RoCallback): () => void {\n const obs = getSharedRO()\n sharedROCallbacks.set(el, cb)\n obs.observe(el)\n return () => {\n sharedROCallbacks.delete(el)\n obs.unobserve(el)\n }\n}\n\nexport interface UseTruncatedOptions {\n /**\n * 偵測策略:回傳 `true` = 截斷、`false` = 未截斷、`undefined` = 本次無法量測(保留前一狀態)。\n * 預設 = `el.scrollWidth > el.clientWidth`(觀察元素自身)。\n * Tag 傳自訂 fn:observe root、內部 `querySelector('[data-tag-text]')` + Canvas measureText。\n */\n measure?: (observedEl: HTMLElement) => boolean | undefined\n /** deps 變更時 cleanup + 重新量測 / 重新訂閱(Tag 傳 `[children]`)。預設 `[]`(mount-once)。 */\n deps?: React.DependencyList\n /**\n * 是否在首次 paint 後以 `requestAnimationFrame` + `setTimeout(100)` 再量一次,捕獲首幀 layout\n * 未完成 / 字型 async load 的假陰性(Breadcrumb 已採此 robust 版)。預設 `true`。\n */\n recheckAfterPaint?: boolean\n /** `'layoutEffect'` = `useLayoutEffect`(量測在 paint 前,避免 flash;Tag 用)/ `'effect'` = `useEffect`。預設 `'effect'`。 */\n timing?: 'effect' | 'layoutEffect'\n}\n\nconst defaultMeasure = (el: HTMLElement): boolean => el.scrollWidth > el.clientWidth\n\n/**\n * 偵測 ref 所指元素的文字是否被截斷,回傳 `{ ref, isTruncated }`。\n * `isTruncated` 用來驅動 Tooltip「僅截斷時顯示」(對齊 `tooltip.principles.stories.tsx`「沒被截斷就不該顯示 tooltip」)。\n */\nexport function useTruncated<E extends HTMLElement = HTMLElement>(\n options: UseTruncatedOptions = {},\n): { ref: React.MutableRefObject<E | null>; isTruncated: boolean } {\n const { measure = defaultMeasure, deps = [], recheckAfterPaint = true, timing = 'effect' } = options\n // MutableRefObject(consumer 可經 callback ref 寫入 .current 以與 forwardedRef 合併,如 Tag)。\n const ref = React.useRef<E | null>(null)\n const [isTruncated, setIsTruncated] = React.useState(false)\n\n // measure 每 render 可能是新 closure(consumer inline);收進 ref 讓 effect 不因它重訂閱,\n // 但 RO 回呼仍讀到最新版。\n const measureRef = React.useRef(measure)\n measureRef.current = measure\n\n // timing 為 call-site 固定字面值(某 consumer 永遠同一值)→ 每個 component instance 每 render\n // 呼叫同一個 effect hook,符合 rules-of-hooks。\n const useIsoEffect = timing === 'layoutEffect' ? React.useLayoutEffect : React.useEffect\n\n useIsoEffect(() => {\n const el = ref.current\n if (!el) return\n const check = () => {\n const r = measureRef.current(el)\n if (r !== undefined) setIsTruncated(r)\n }\n check()\n let raf = 0\n let t: ReturnType<typeof setTimeout> | undefined\n if (recheckAfterPaint) {\n raf = requestAnimationFrame(check)\n t = setTimeout(check, 100)\n }\n const cleanup = observeShared(el, check)\n return () => {\n if (raf) cancelAnimationFrame(raf)\n if (t) clearTimeout(t)\n cleanup()\n }\n // deps 由 consumer 決定(
|
|
1
|
+
{"version":3,"file":"use-truncated.js","sources":["../../src/hooks/use-truncated.ts"],"sourcesContent":["import * as React from 'react'\n\n// ── useTruncated — 單行文字截斷偵測引擎(SSOT)─────────────────────────────────\n// 收斂 Breadcrumb TruncatedLabel / DataTable TruncateCell(兩處 module-level shared ResizeObserver 引擎\n// **逐字重複**,僅變數名不同)+ Tag(原 per-instance `new ResizeObserver`)三處的截斷偵測 + isTruncated\n// 狀態機為唯一 owner(M17 SSOT);Tag 亦收斂進共用 shared RO,行為等價。\n//\n// 世界級對照(M8):MUI/MUI-X 官方無第一方 primitive,社群共識 = 「hook 量測 scrollWidth>clientWidth\n// + ref + 以 Tooltip `open` prop 條件控制」(issue #37211);此 hook 即該低階量測層,\n// 上層 `<TruncatedText>`(patterns/element-anatomy)對應 Ant `Typography.Text ellipsis` 高階元件。\n//\n// 三處變異點皆以 options 注入,**行為零漂移**:\n// - Breadcrumb / DataTable:預設 scrollWidth>clientWidth。\n// - Tag:trigger≠量測元素(observe root、量測內層 span)+ Canvas measureText(flex 內 scrollWidth\n// 不可靠)+ useLayoutEffect(避免 paint flash)+ deps=[children] → 全走 options。\n\ntype RoCallback = (entry: ResizeObserverEntry) => void\n\nlet sharedRO: ResizeObserver | null = null\nconst sharedROCallbacks = new WeakMap<Element, RoCallback>()\n\n// 全 DS 共用單一 ResizeObserver,dispatch 到 per-element callback(2026-04-22 DataTable D3 perf audit\n// 成果:10 col × 100 row = 1 RO 而非 1000)。element 卸載時 cleanup,singleton RO 本身不 disconnect。\nfunction getSharedRO(): ResizeObserver {\n if (sharedRO) return sharedRO\n sharedRO = new ResizeObserver((entries) => {\n entries.forEach((e) => {\n const cb = sharedROCallbacks.get(e.target)\n if (cb) cb(e)\n })\n })\n return sharedRO\n}\n\nfunction observeShared(el: Element, cb: RoCallback): () => void {\n const obs = getSharedRO()\n sharedROCallbacks.set(el, cb)\n obs.observe(el)\n return () => {\n sharedROCallbacks.delete(el)\n obs.unobserve(el)\n }\n}\n\nexport interface UseTruncatedOptions {\n /**\n * 偵測策略:回傳 `true` = 截斷、`false` = 未截斷、`undefined` = 本次無法量測(保留前一狀態)。\n * 預設 = `el.scrollWidth > el.clientWidth`(觀察元素自身)。\n * Tag 傳自訂 fn:observe root、內部 `querySelector('[data-tag-text]')` + Canvas measureText。\n */\n measure?: (observedEl: HTMLElement) => boolean | undefined\n /** deps 變更時 cleanup + 重新量測 / 重新訂閱(Tag 傳 `[children]`)。預設 `[]`(mount-once)。 */\n deps?: React.DependencyList\n /**\n * 是否在首次 paint 後以 `requestAnimationFrame` + `setTimeout(100)` 再量一次,捕獲首幀 layout\n * 未完成 / 字型 async load 的假陰性(Breadcrumb 已採此 robust 版)。預設 `true`。\n */\n recheckAfterPaint?: boolean\n /** `'layoutEffect'` = `useLayoutEffect`(量測在 paint 前,避免 flash;Tag 用)/ `'effect'` = `useEffect`。預設 `'effect'`。 */\n timing?: 'effect' | 'layoutEffect'\n}\n\nconst defaultMeasure = (el: HTMLElement): boolean => el.scrollWidth > el.clientWidth\n\n/**\n * 偵測 ref 所指元素的文字是否被截斷,回傳 `{ ref, isTruncated }`。\n * `isTruncated` 用來驅動 Tooltip「僅截斷時顯示」(對齊 `tooltip.principles.stories.tsx`「沒被截斷就不該顯示 tooltip」)。\n */\nexport function useTruncated<E extends HTMLElement = HTMLElement>(\n options: UseTruncatedOptions = {},\n): { ref: React.MutableRefObject<E | null>; isTruncated: boolean } {\n const { measure = defaultMeasure, deps = [], recheckAfterPaint = true, timing = 'effect' } = options\n // MutableRefObject(consumer 可經 callback ref 寫入 .current 以與 forwardedRef 合併,如 Tag)。\n const ref = React.useRef<E | null>(null)\n const [isTruncated, setIsTruncated] = React.useState(false)\n\n // measure 每 render 可能是新 closure(consumer inline);收進 ref 讓 effect 不因它重訂閱,\n // 但 RO 回呼仍讀到最新版。\n const measureRef = React.useRef(measure)\n measureRef.current = measure\n\n // timing 為 call-site 固定字面值(某 consumer 永遠同一值)→ 每個 component instance 每 render\n // 呼叫同一個 effect hook,符合 rules-of-hooks。\n const useIsoEffect = timing === 'layoutEffect' ? React.useLayoutEffect : React.useEffect\n\n useIsoEffect(() => {\n const el = ref.current\n if (!el) return\n const check = () => {\n const r = measureRef.current(el)\n if (r !== undefined) setIsTruncated(r)\n }\n check()\n let raf = 0\n let t: ReturnType<typeof setTimeout> | undefined\n if (recheckAfterPaint) {\n raf = requestAnimationFrame(check)\n t = setTimeout(check, 100)\n }\n const cleanup = observeShared(el, check)\n return () => {\n if (raf) cancelAnimationFrame(raf)\n if (t) clearTimeout(t)\n cleanup()\n }\n // deps 由 consumer 決定(預設 [] = mount-once;Tag / Calendar / Select 等傳文字來源);measure 走 ref 不需進 deps;\n // recheckAfterPaint / timing 是 call-site 固定字面值,只在訂閱當下讀一次。exhaustive-deps 只認 useEffect /\n // useLayoutEffect 等已知名字(config 未設 additionalHooks),不檢查 `useIsoEffect` 別名 → 這裡不掛 eslint-disable。\n }, deps)\n\n return { ref, isTruncated }\n}\n"],"names":[],"mappings":";AAkBA,IAAI,WAAkC;AACtC,MAAM,wCAAwB,QAAA;AAI9B,SAAS,cAA8B;AACrC,MAAI,SAAU,QAAO;AACrB,aAAW,IAAI,eAAe,CAAC,YAAY;AACzC,YAAQ,QAAQ,CAAC,MAAM;AACrB,YAAM,KAAK,kBAAkB,IAAI,EAAE,MAAM;AACzC,UAAI,OAAO,CAAC;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEA,SAAS,cAAc,IAAa,IAA4B;AAC9D,QAAM,MAAM,YAAA;AACZ,oBAAkB,IAAI,IAAI,EAAE;AAC5B,MAAI,QAAQ,EAAE;AACd,SAAO,MAAM;AACX,sBAAkB,OAAO,EAAE;AAC3B,QAAI,UAAU,EAAE;AAAA,EAClB;AACF;AAoBA,MAAM,iBAAiB,CAAC,OAA6B,GAAG,cAAc,GAAG;AAMlE,SAAS,aACd,UAA+B,IACkC;AACjE,QAAM,EAAE,UAAU,gBAAgB,OAAO,CAAA,GAAI,oBAAoB,MAAM,SAAS,SAAA,IAAa;AAE7F,QAAM,MAAM,MAAM,OAAiB,IAAI;AACvC,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,KAAK;AAI1D,QAAM,aAAa,MAAM,OAAO,OAAO;AACvC,aAAW,UAAU;AAIrB,QAAM,eAAe,WAAW,iBAAiB,MAAM,kBAAkB,MAAM;AAE/E,eAAa,MAAM;AACjB,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,QAAQ,MAAM;AAClB,YAAM,IAAI,WAAW,QAAQ,EAAE;AAC/B,UAAI,MAAM,OAAW,gBAAe,CAAC;AAAA,IACvC;AACA,UAAA;AACA,QAAI,MAAM;AACV,QAAI;AACJ,QAAI,mBAAmB;AACrB,YAAM,sBAAsB,KAAK;AACjC,UAAI,WAAW,OAAO,GAAG;AAAA,IAC3B;AACA,UAAM,UAAU,cAAc,IAAI,KAAK;AACvC,WAAO,MAAM;AACX,UAAI,0BAA0B,GAAG;AACjC,UAAI,gBAAgB,CAAC;AACrB,cAAA;AAAA,IACF;AAAA,EAIF,GAAG,IAAI;AAEP,SAAO,EAAE,KAAK,YAAA;AAChB;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -117,6 +117,7 @@ export * from './tokens/elevation/overlay-geometry';
|
|
|
117
117
|
export * from './tokens/motion/motion';
|
|
118
118
|
export * from './tokens/motion/overlay-motion';
|
|
119
119
|
export * from './tokens/uiSize/icon-size';
|
|
120
|
+
export * from './tokens/uiSize/stack-gap';
|
|
120
121
|
export * from './hooks/use-controllable';
|
|
121
122
|
export * from './hooks/use-input-modality';
|
|
122
123
|
export * from './hooks/use-is-narrow-viewport';
|
|
@@ -126,7 +127,9 @@ export * from './hooks/use-overflow-items';
|
|
|
126
127
|
export * from './hooks/use-truncated';
|
|
127
128
|
export * from './lib/drag-announcements';
|
|
128
129
|
export * from './lib/drag-visual';
|
|
130
|
+
export * from './lib/focus-after-trigger';
|
|
129
131
|
export * from './lib/multi-select-ordering';
|
|
130
132
|
export * from './lib/overlay-coexistence';
|
|
133
|
+
export * from './lib/roving-list-keyboard';
|
|
131
134
|
export * from './lib/utils';
|
|
132
135
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -70,17 +70,20 @@ import { CATEGORICAL_HUES, CAT_ACCENT, CAT_EVENT, CAT_INTERACT, CAT_SOLID, CAT_S
|
|
|
70
70
|
import { OVERLAY_COLLISION_PADDING, OVERLAY_HIDE_WHEN_DETACHED, OVERLAY_SIDE_OFFSET } from "./tokens/elevation/overlay-geometry.js";
|
|
71
71
|
import { MOTION_DELAY_CLOSE_MS, MOTION_DELAY_PLAIN_MS, MOTION_DELAY_RICH_MS } from "./tokens/motion/motion.js";
|
|
72
72
|
import { overlayMotion, surfaceMotion } from "./tokens/motion/overlay-motion.js";
|
|
73
|
+
import { STACK_GAP_PX } from "./tokens/uiSize/stack-gap.js";
|
|
73
74
|
import { useControllable } from "./hooks/use-controllable.js";
|
|
74
|
-
import { markPointerGrab, useCursorMover
|
|
75
|
+
import { markPointerGrab, useCursorMover } from "./hooks/use-input-modality.js";
|
|
75
76
|
import { useIsNarrowViewport } from "./hooks/use-is-narrow-viewport.js";
|
|
76
77
|
import { useIsTouchDevice } from "./hooks/use-is-touch-device.js";
|
|
77
78
|
import { useKnownOptions } from "./hooks/use-known-options.js";
|
|
78
79
|
import { useOverflowIndices, useScrollEdges } from "./hooks/use-overflow-items.js";
|
|
79
80
|
import { useTruncated } from "./hooks/use-truncated.js";
|
|
80
|
-
import { createDragAnnouncements } from "./lib/drag-announcements.js";
|
|
81
|
+
import { DRAG_SCREEN_READER_INSTRUCTIONS, createDragAnnouncements, useDragAccessibility } from "./lib/drag-announcements.js";
|
|
81
82
|
import { DRAG_ACTIVATION_DISTANCE_PX, createStepToNeighborCoordinateGetter, dragActiveCursor, dragHandleCursorClass, dragSourceClass, dragSourceStyle, dropIndicatorColumn, dropIndicatorInside, dropIndicatorRow, forwardDragActivatorAttributes, isReorderNoop, reconstructFullRowGhost, snapToCursorModifier } from "./lib/drag-visual.js";
|
|
83
|
+
import { focusFromTrigger, isTabbableElement, tabStopFromTrigger, tabbableOrder } from "./lib/focus-after-trigger.js";
|
|
82
84
|
import { applySelectAll, clearSelection } from "./lib/multi-select-ordering.js";
|
|
83
85
|
import { CoexistenceMask, createPersistentGuard, useOverlayCoexistence } from "./lib/overlay-coexistence.js";
|
|
86
|
+
import { ROVING_CONTROL_SELECTOR, applyRovingAction, isRovingControlReachable, isTextEntryElement, listRovingControls, pickRovingTabStop, pickRovingTarget, removeRovingControlsFromTabOrder, resolveRovingKey, scopeRovingSelector, setRovingTabIndex } from "./lib/roving-list-keyboard.js";
|
|
84
87
|
import { cn, lineClampClass } from "./lib/utils.js";
|
|
85
88
|
import { DATA_TABLE_FILTER_PANEL_DEFAULT_LABELS } from "./components/DataTable/data-table-filter-labels.js";
|
|
86
89
|
import { MultiPersonDisplay, PersonAvatarTag, PersonDisplay, buildPersonProfileCard, resolvePerson } from "./components/PeoplePicker/person-display.js";
|
|
@@ -164,6 +167,7 @@ export {
|
|
|
164
167
|
Combobox,
|
|
165
168
|
DATA_TABLE_FILTER_PANEL_DEFAULT_LABELS,
|
|
166
169
|
DRAG_ACTIVATION_DISTANCE_PX,
|
|
170
|
+
DRAG_SCREEN_READER_INSTRUCTIONS,
|
|
167
171
|
DataTable,
|
|
168
172
|
DataTableColumnVisibilityPanel,
|
|
169
173
|
DataTableFilterPanel,
|
|
@@ -247,11 +251,13 @@ export {
|
|
|
247
251
|
ProfileCard,
|
|
248
252
|
ProfileCardDefaultActions,
|
|
249
253
|
ProgressBar,
|
|
254
|
+
ROVING_CONTROL_SELECTOR,
|
|
250
255
|
ROW_PADDING_BY_SIZE,
|
|
251
256
|
RadioGroup,
|
|
252
257
|
RadioGroupItem,
|
|
253
258
|
Rating,
|
|
254
259
|
ResizeHandle,
|
|
260
|
+
STACK_GAP_PX,
|
|
255
261
|
ScrollArea,
|
|
256
262
|
ScrollBar,
|
|
257
263
|
SegmentedControl,
|
|
@@ -311,6 +317,7 @@ export {
|
|
|
311
317
|
TreeItem,
|
|
312
318
|
TreeView,
|
|
313
319
|
alertVariants,
|
|
320
|
+
applyRovingAction,
|
|
314
321
|
applySelectAll,
|
|
315
322
|
badgeVariants,
|
|
316
323
|
buildPersonProfileCard,
|
|
@@ -334,6 +341,7 @@ export {
|
|
|
334
341
|
dropIndicatorInside,
|
|
335
342
|
dropIndicatorRow,
|
|
336
343
|
evaluateTree,
|
|
344
|
+
focusFromTrigger,
|
|
337
345
|
formatDate,
|
|
338
346
|
formatNumber,
|
|
339
347
|
forwardDragActivatorAttributes,
|
|
@@ -341,16 +349,26 @@ export {
|
|
|
341
349
|
getUniformPrefixSlotStyle,
|
|
342
350
|
isFilterTreeActive,
|
|
343
351
|
isReorderNoop,
|
|
352
|
+
isRovingControlReachable,
|
|
353
|
+
isTabbableElement,
|
|
354
|
+
isTextEntryElement,
|
|
344
355
|
itemPrefixAlignVariants,
|
|
345
356
|
lineClampClass,
|
|
357
|
+
listRovingControls,
|
|
346
358
|
markPointerGrab,
|
|
347
359
|
overlayMotion,
|
|
360
|
+
pickRovingTabStop,
|
|
361
|
+
pickRovingTarget,
|
|
348
362
|
radioItemVariants,
|
|
349
363
|
reconstructFullRowGhost,
|
|
350
364
|
registerFileRenderer,
|
|
365
|
+
removeRovingControlsFromTabOrder,
|
|
351
366
|
resolvePerson,
|
|
367
|
+
resolveRovingKey,
|
|
368
|
+
scopeRovingSelector,
|
|
352
369
|
segmentedControlItemVariants,
|
|
353
370
|
segmentedControlVariants,
|
|
371
|
+
setRovingTabIndex,
|
|
354
372
|
sheetVariants,
|
|
355
373
|
sliderRootVariants,
|
|
356
374
|
snapToCursorModifier,
|
|
@@ -358,6 +376,8 @@ export {
|
|
|
358
376
|
stepsRootVariants,
|
|
359
377
|
surfaceMotion,
|
|
360
378
|
switchVariants,
|
|
379
|
+
tabStopFromTrigger,
|
|
380
|
+
tabbableOrder,
|
|
361
381
|
tabsTriggerVariants,
|
|
362
382
|
tagVariants,
|
|
363
383
|
textareaVariants,
|
|
@@ -366,8 +386,8 @@ export {
|
|
|
366
386
|
useAppShell,
|
|
367
387
|
useControllable,
|
|
368
388
|
useCursorMover,
|
|
389
|
+
useDragAccessibility,
|
|
369
390
|
useFormValidation,
|
|
370
|
-
useInputModality,
|
|
371
391
|
useIsNarrowViewport,
|
|
372
392
|
useIsTouchDevice,
|
|
373
393
|
useKnownOptions,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
1
2
|
/** 拖曳結果。`null` = 沒有真的重排(被守衛擋下 / 使用者放在原位)。 */
|
|
2
3
|
export interface DragOutcome {
|
|
3
4
|
/** 播報時用來指稱被移動的東西,例如「列」「欄位」「項目」 */
|
|
@@ -55,5 +56,36 @@ export declare function createDragAnnouncements({ getOutcome, kind }: DragAnnoun
|
|
|
55
56
|
active: ActiveLike;
|
|
56
57
|
}) => string;
|
|
57
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* dnd-kit 掛在每顆把手 `aria-describedby` 上的操作說明(繁中;取代 dnd-kit 的英文預設)。
|
|
61
|
+
* 句型沿用 TreeView 既有的鍵盤重排說明(tree-view.tsx `DEFAULT_REORDER_ANNOUNCEMENTS.instructions`)。
|
|
62
|
+
*/
|
|
63
|
+
export declare const DRAG_SCREEN_READER_INSTRUCTIONS: {
|
|
64
|
+
draggable: string;
|
|
65
|
+
};
|
|
66
|
+
type DragAnnouncements = ReturnType<typeof createDragAnnouncements>;
|
|
67
|
+
/**
|
|
68
|
+
* 四個 `DndContext` 共用的無障礙接線:**繁中播報 + polite 區域 + 繁中操作說明**。
|
|
69
|
+
*
|
|
70
|
+
* 用法:
|
|
71
|
+
* ```tsx
|
|
72
|
+
* const drag = useDragAccessibility({ getOutcome: () => outcomeRef.current, kind: '列' })
|
|
73
|
+
* <DndContext sensors={…} onDragEnd={…} accessibility={drag.accessibility}>
|
|
74
|
+
* {children}
|
|
75
|
+
* {drag.liveRegion}
|
|
76
|
+
* </DndContext>
|
|
77
|
+
* ```
|
|
78
|
+
* `accessibility.announcements` 的四個函式把句子寫進 `liveRegion`(role=status、aria-live=polite)後
|
|
79
|
+
* **回傳空字串**:dnd-kit 只在回傳值非 null 時寫進它自己的 assertive 區域,空字串寫進去也沒有東西可唸。
|
|
80
|
+
* `liveRegion` 必須渲染在 DOM 裡(放在 DndContext 內外都可以);沒渲染 = 螢幕閱讀器整趟拖曳無聲,
|
|
81
|
+
* 靜態閘 `scripts/drag-announcement-invariant.mjs` 會抓。
|
|
82
|
+
*/
|
|
83
|
+
export declare function useDragAccessibility(args: DragAnnouncementArgs): {
|
|
84
|
+
accessibility: {
|
|
85
|
+
announcements: DragAnnouncements;
|
|
86
|
+
screenReaderInstructions: typeof DRAG_SCREEN_READER_INSTRUCTIONS;
|
|
87
|
+
};
|
|
88
|
+
liveRegion: React.ReactElement;
|
|
89
|
+
};
|
|
58
90
|
export {};
|
|
59
91
|
//# sourceMappingURL=drag-announcements.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drag-announcements.d.ts","sourceRoot":"","sources":["../../src/lib/drag-announcements.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drag-announcements.d.ts","sourceRoot":"","sources":["../../src/lib/drag-announcements.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,2CAA2C;AAC3C,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,UAAU,EAAE,MAAM,WAAW,GAAG,IAAI,CAAA;IACpC;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,CAAA;CAChD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,oBAAoB;8BAGpD;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE;2BAEzB;QAAE,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE;;+BAQpC;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE;EAGpD;AAED;;;GAGG;AACH,eAAO,MAAM,+BAA+B;;CAE3C,CAAA;AAED,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAEnE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,oBAAoB,GAAG;IAChE,aAAa,EAAE;QAAE,aAAa,EAAE,iBAAiB,CAAC;QAAC,wBAAwB,EAAE,OAAO,+BAA+B,CAAA;KAAE,CAAA;IACrH,UAAU,EAAE,KAAK,CAAC,YAAY,CAAA;CAC/B,CA4BA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as React from "react";
|
|
1
2
|
function createDragAnnouncements({ getOutcome, kind }) {
|
|
2
3
|
const kindOf = (active) => typeof kind === "function" ? kind(active) : kind;
|
|
3
4
|
return {
|
|
@@ -11,7 +12,44 @@ function createDragAnnouncements({ getOutcome, kind }) {
|
|
|
11
12
|
onDragCancel: ({ active }) => `已取消移動${kindOf(active)}『${String(active.id)}』,回到原位`
|
|
12
13
|
};
|
|
13
14
|
}
|
|
15
|
+
const DRAG_SCREEN_READER_INSTRUCTIONS = {
|
|
16
|
+
draggable: "按空白鍵提起,用方向鍵移動,再按空白鍵放下;按 Esc 取消。"
|
|
17
|
+
// i18n-allow: DS 預設文案
|
|
18
|
+
};
|
|
19
|
+
function useDragAccessibility(args) {
|
|
20
|
+
const [text, setText] = React.useState("");
|
|
21
|
+
const argsRef = React.useRef(args);
|
|
22
|
+
argsRef.current = args;
|
|
23
|
+
const accessibility = React.useMemo(() => {
|
|
24
|
+
const inner = createDragAnnouncements({
|
|
25
|
+
getOutcome: () => argsRef.current.getOutcome(),
|
|
26
|
+
kind: (active) => {
|
|
27
|
+
const k = argsRef.current.kind;
|
|
28
|
+
return typeof k === "function" ? k(active) : k;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const speak = (s) => {
|
|
32
|
+
setText(s);
|
|
33
|
+
return "";
|
|
34
|
+
};
|
|
35
|
+
const announcements = {
|
|
36
|
+
onDragStart: (e) => speak(inner.onDragStart(e)),
|
|
37
|
+
onDragOver: (e) => speak(inner.onDragOver(e)),
|
|
38
|
+
onDragEnd: () => speak(inner.onDragEnd()),
|
|
39
|
+
onDragCancel: (e) => speak(inner.onDragCancel(e))
|
|
40
|
+
};
|
|
41
|
+
return { announcements, screenReaderInstructions: DRAG_SCREEN_READER_INSTRUCTIONS };
|
|
42
|
+
}, []);
|
|
43
|
+
const liveRegion = React.createElement(
|
|
44
|
+
"div",
|
|
45
|
+
{ role: "status", "aria-live": "polite", "aria-atomic": true, className: "sr-only", "data-drag-live-region": "" },
|
|
46
|
+
text
|
|
47
|
+
);
|
|
48
|
+
return { accessibility, liveRegion };
|
|
49
|
+
}
|
|
14
50
|
export {
|
|
15
|
-
|
|
51
|
+
DRAG_SCREEN_READER_INSTRUCTIONS,
|
|
52
|
+
createDragAnnouncements,
|
|
53
|
+
useDragAccessibility
|
|
16
54
|
};
|
|
17
55
|
//# sourceMappingURL=drag-announcements.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drag-announcements.js","sources":["../../src/lib/drag-announcements.ts"],"sourcesContent":["// ═══════════════════════════════════════════════════════════════════════════\n// Drag announcements — 拖曳的螢幕閱讀器播報 SSOT\n// ═══════════════════════════════════════════════════════════════════════════\n//\n// **為什麼有這個檔**(2026-09-07):\n// 全 DS 有 4 個 `DndContext`(TreeView、DataTable 列/欄、排序面板、欄位顯示面板),\n// 先前**沒有任何一個**傳過 `accessibility` prop(grep 排除 stories = 0 命中),\n// 於是四處全部吃 dnd-kit 的英文預設播報(`core.esm.js:44-72`),而且是從它自己的\n// 生命週期發的 —— **不知道我們的守衛已經 return、根本沒重排**,會播假的成功訊息。\n//\n// 這一份是四處共用的繁中播報 SSOT。措辭沿用 DS 既有的 reorder 播報 canonical\n// (`TreeView` 的 `DEFAULT_REORDER_ANNOUNCEMENTS`,tree-view.tsx:130 起)的句型,\n// 不另創語氣。\n//\n// **誠實回報結果是本模組的核心契約**:`onDragEnd` 必須由呼叫端提供「有沒有真的\n// commit」的判定,沒 commit 就播「未變更」。dnd-kit 的 dispatch 順序是\n// `handler?.(event)` 先跑、`dispatchMonitorEvent`(播報)後跑(`core.esm.js:3166-3170`\n// 實查),所以呼叫端在自己的 `onDragEnd` 內設 ref,這裡讀它即可 —— 不重算一次\n// 判定,避免兩份邏輯漂移。\n//\n// **契約邊界(必須知道)**:這裡的「已移動」意思是**元件已經送出重排、而且自己的守衛\n// 全部通過**。它**看不到**消費者的 handler 有沒有真的把新順序寫回 state ——\n// 播報是同步回傳的字串,那時 React 還沒 re-render,量不到結果。\n// 所以受控的 `columnOrder` / 資料順序**必須列全**;漏列的那一欄會讓消費者的\n// handler 靜默 `return prev`,而螢幕閱讀器仍聽到「已移動」。\n// 2026-09-07 錨:ColumnReorder story 的 columnOrder 漏了 `seller`(畫面 7 欄、state 6 個),\n// 拖到該欄時就是這個情況;已修 story,並由 `scripts/drag-runtime-contract.mjs` 守著。\n\n/** 拖曳結果。`null` = 沒有真的重排(被守衛擋下 / 使用者放在原位)。 */\nexport interface DragOutcome {\n /** 播報時用來指稱被移動的東西,例如「列」「欄位」「項目」 */\n kind: string\n /** 被移動者的可讀名稱 */\n label: string\n}\n\n/** dnd-kit 傳給播報的 active 形狀(只取我們用得到的部分)。 */\ninterface ActiveLike {\n id: string | number\n data?: { current?: { type?: string } }\n}\n\nexport interface DragAnnouncementArgs {\n /** 讀取「這一趟到底有沒有 commit」。由呼叫端在自己的 onDragEnd 內設定。 */\n getOutcome: () => DragOutcome | null\n /**\n * 被拖曳者的種類,用於 onDragStart / onDragCancel 的措辭,例如「列」。\n *\n * 同一個 `DndContext` 可能拖不只一種東西(DataTable 的列與欄共用一個),\n * 所以也接受一個函式,由 `active.data.current.type` 決定當下該說什麼。\n * 2026-09-07 錨:寫死字串時 DataTable 起始說「已提起**項目**」、結束說「已移動**欄位**」,\n * 同一趟拖曳用了兩個名字。\n */\n kind: string | ((active: ActiveLike) => string)\n}\n\n/**\n * 建立一組繁中的 dnd-kit 播報。\n *\n * 用法:\n * ```tsx\n * const outcomeRef = React.useRef<DragOutcome | null>(null)\n * const announcements = React.useMemo(\n * () => createDragAnnouncements({ getOutcome: () => outcomeRef.current, kind: '列' }),\n * [],\n * )\n * // handleDragEnd 開頭 `outcomeRef.current = null`,真的 commit 時才設值\n * <DndContext onDragEnd={handleDragEnd} accessibility={{ announcements }}>\n * ```\n */\nexport function createDragAnnouncements({ getOutcome, kind }: DragAnnouncementArgs) {\n const kindOf = (active: ActiveLike) => (typeof kind === 'function' ? kind(active) : kind)\n return {\n onDragStart: ({ active }: { active: ActiveLike }) =>\n `已提起${kindOf(active)}『${String(active.id)}』,用方向鍵移動,放開或按 Enter 放下,Esc 取消`,\n onDragOver: ({ over }: { over: { id: string | number } | null }) =>\n over ? `移到『${String(over.id)}』上方` : '目前不在可放置的位置',\n onDragEnd: () => {\n const outcome = getOutcome()\n // **關鍵**:沒 commit 就誠實說沒變,不能沿用 dnd-kit 的「已放到 X」。\n if (!outcome) return '未變更順序'\n return `已移動${outcome.kind}『${outcome.label}』`\n },\n onDragCancel: ({ active }: { active: ActiveLike }) =>\n `已取消移動${kindOf(active)}『${String(active.id)}』,回到原位`,\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drag-announcements.js","sources":["../../src/lib/drag-announcements.ts"],"sourcesContent":["// ═══════════════════════════════════════════════════════════════════════════\n// Drag announcements — 拖曳的螢幕閱讀器播報 SSOT\n// ═══════════════════════════════════════════════════════════════════════════\n//\n// **為什麼有這個檔**(2026-09-07):\n// 全 DS 有 4 個 `DndContext`(TreeView、DataTable 列/欄、排序面板、欄位顯示面板),\n// 先前**沒有任何一個**傳過 `accessibility` prop(grep 排除 stories = 0 命中),\n// 於是四處全部吃 dnd-kit 的英文預設播報(`core.esm.js:44-72`),而且是從它自己的\n// 生命週期發的 —— **不知道我們的守衛已經 return、根本沒重排**,會播假的成功訊息。\n//\n// 這一份是四處共用的繁中播報 SSOT。措辭沿用 DS 既有的 reorder 播報 canonical\n// (`TreeView` 的 `DEFAULT_REORDER_ANNOUNCEMENTS`,tree-view.tsx:130 起)的句型,\n// 不另創語氣。\n//\n// **誠實回報結果是本模組的核心契約**:`onDragEnd` 必須由呼叫端提供「有沒有真的\n// commit」的判定,沒 commit 就播「未變更」。dnd-kit 的 dispatch 順序是\n// `handler?.(event)` 先跑、`dispatchMonitorEvent`(播報)後跑(`core.esm.js:3166-3170`\n// 實查),所以呼叫端在自己的 `onDragEnd` 內設 ref,這裡讀它即可 —— 不重算一次\n// 判定,避免兩份邏輯漂移。\n//\n// **契約邊界(必須知道)**:這裡的「已移動」意思是**元件已經送出重排、而且自己的守衛\n// 全部通過**。它**看不到**消費者的 handler 有沒有真的把新順序寫回 state ——\n// 播報是同步回傳的字串,那時 React 還沒 re-render,量不到結果。\n// 所以受控的 `columnOrder` / 資料順序**必須列全**;漏列的那一欄會讓消費者的\n// handler 靜默 `return prev`,而螢幕閱讀器仍聽到「已移動」。\n// 2026-09-07 錨:ColumnReorder story 的 columnOrder 漏了 `seller`(畫面 7 欄、state 6 個),\n// 拖到該欄時就是這個情況;已修 story,並由 `scripts/drag-runtime-contract.mjs` 守著。\n//\n// **播報的禮貌等級 = polite,不是 assertive**(2026-09-27,待辦總帳 OE10):\n// dnd-kit 6.3.1 自己的 live region 寫死 `aria-live=\"assertive\"`\n// (`@dnd-kit/accessibility` LiveRegion 的 `ariaLiveType = \"assertive\"`,`DndContext` 沒有任何 prop 能改),\n// 拖曳中每移到一個落點就打斷螢幕閱讀器正在唸的句子。WAI-ARIA 1.2 對 `assertive` 的定義:\n// \"Indicates that updates to the region have the highest priority and should be presented to the user immediately.\"\n// 並明文 \"don't use the assertive value unless the interruption is imperative\"\n// (<https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-live>,\n// 轉述 <https://www.w3.org/TR/wai-aria-1.2/#aria-live>)。拖曳的落點回饋不是「必須打斷」的事 ——\n// DS 內自己的先例也是這麼判的:TreeView 鍵盤重排的區域是 polite(tree-view.tsx)、Toast 只有 error / warning\n// 才 assertive(toast.tsx)、Alert 同(alert.tsx)。所以 `useDragAccessibility` 把文字寫進**本檔自己的 polite 區域**,\n// 交給 dnd-kit 的那份永遠是空字串(它的 assertive 區域因此一個字都不會唸)。\n// 世界級並非一致(react-beautiful-dnd 的 announcer 是 assertive),這裡依 DS 內既有 canonical(M23)取 polite。\n//\n// **操作說明也一併改成繁中**:dnd-kit 預設的 `screenReaderInstructions.draggable`\n// (\"To pick up a draggable item, press the space bar…\")會被掛到每一顆把手的 `aria-describedby`,\n// 四個 DndContext 先前全部唸英文。\n\nimport * as React from 'react'\n\n/** 拖曳結果。`null` = 沒有真的重排(被守衛擋下 / 使用者放在原位)。 */\nexport interface DragOutcome {\n /** 播報時用來指稱被移動的東西,例如「列」「欄位」「項目」 */\n kind: string\n /** 被移動者的可讀名稱 */\n label: string\n}\n\n/** dnd-kit 傳給播報的 active 形狀(只取我們用得到的部分)。 */\ninterface ActiveLike {\n id: string | number\n data?: { current?: { type?: string } }\n}\n\nexport interface DragAnnouncementArgs {\n /** 讀取「這一趟到底有沒有 commit」。由呼叫端在自己的 onDragEnd 內設定。 */\n getOutcome: () => DragOutcome | null\n /**\n * 被拖曳者的種類,用於 onDragStart / onDragCancel 的措辭,例如「列」。\n *\n * 同一個 `DndContext` 可能拖不只一種東西(DataTable 的列與欄共用一個),\n * 所以也接受一個函式,由 `active.data.current.type` 決定當下該說什麼。\n * 2026-09-07 錨:寫死字串時 DataTable 起始說「已提起**項目**」、結束說「已移動**欄位**」,\n * 同一趟拖曳用了兩個名字。\n */\n kind: string | ((active: ActiveLike) => string)\n}\n\n/**\n * 建立一組繁中的 dnd-kit 播報。\n *\n * 用法:\n * ```tsx\n * const outcomeRef = React.useRef<DragOutcome | null>(null)\n * const announcements = React.useMemo(\n * () => createDragAnnouncements({ getOutcome: () => outcomeRef.current, kind: '列' }),\n * [],\n * )\n * // handleDragEnd 開頭 `outcomeRef.current = null`,真的 commit 時才設值\n * <DndContext onDragEnd={handleDragEnd} accessibility={{ announcements }}>\n * ```\n */\nexport function createDragAnnouncements({ getOutcome, kind }: DragAnnouncementArgs) {\n const kindOf = (active: ActiveLike) => (typeof kind === 'function' ? kind(active) : kind)\n return {\n onDragStart: ({ active }: { active: ActiveLike }) =>\n `已提起${kindOf(active)}『${String(active.id)}』,用方向鍵移動,放開或按 Enter 放下,Esc 取消`,\n onDragOver: ({ over }: { over: { id: string | number } | null }) =>\n over ? `移到『${String(over.id)}』上方` : '目前不在可放置的位置',\n onDragEnd: () => {\n const outcome = getOutcome()\n // **關鍵**:沒 commit 就誠實說沒變,不能沿用 dnd-kit 的「已放到 X」。\n if (!outcome) return '未變更順序'\n return `已移動${outcome.kind}『${outcome.label}』`\n },\n onDragCancel: ({ active }: { active: ActiveLike }) =>\n `已取消移動${kindOf(active)}『${String(active.id)}』,回到原位`,\n }\n}\n\n/**\n * dnd-kit 掛在每顆把手 `aria-describedby` 上的操作說明(繁中;取代 dnd-kit 的英文預設)。\n * 句型沿用 TreeView 既有的鍵盤重排說明(tree-view.tsx `DEFAULT_REORDER_ANNOUNCEMENTS.instructions`)。\n */\nexport const DRAG_SCREEN_READER_INSTRUCTIONS = {\n draggable: '按空白鍵提起,用方向鍵移動,再按空白鍵放下;按 Esc 取消。', // i18n-allow: DS 預設文案\n}\n\ntype DragAnnouncements = ReturnType<typeof createDragAnnouncements>\n\n/**\n * 四個 `DndContext` 共用的無障礙接線:**繁中播報 + polite 區域 + 繁中操作說明**。\n *\n * 用法:\n * ```tsx\n * const drag = useDragAccessibility({ getOutcome: () => outcomeRef.current, kind: '列' })\n * <DndContext sensors={…} onDragEnd={…} accessibility={drag.accessibility}>\n * {children}\n * {drag.liveRegion}\n * </DndContext>\n * ```\n * `accessibility.announcements` 的四個函式把句子寫進 `liveRegion`(role=status、aria-live=polite)後\n * **回傳空字串**:dnd-kit 只在回傳值非 null 時寫進它自己的 assertive 區域,空字串寫進去也沒有東西可唸。\n * `liveRegion` 必須渲染在 DOM 裡(放在 DndContext 內外都可以);沒渲染 = 螢幕閱讀器整趟拖曳無聲,\n * 靜態閘 `scripts/drag-announcement-invariant.mjs` 會抓。\n */\nexport function useDragAccessibility(args: DragAnnouncementArgs): {\n accessibility: { announcements: DragAnnouncements; screenReaderInstructions: typeof DRAG_SCREEN_READER_INSTRUCTIONS }\n liveRegion: React.ReactElement\n} {\n const [text, setText] = React.useState('')\n // 呼叫端幾乎都傳 inline 箭頭函式;拿它們當 memo 依賴會每次 render 重建 announcements、DndContext 也跟著拿到新物件。\n // 所以 announcements 只建一份,讀取時再經 ref 取最新的 getOutcome / kind。\n const argsRef = React.useRef(args)\n argsRef.current = args\n const accessibility = React.useMemo(() => {\n const inner = createDragAnnouncements({\n getOutcome: () => argsRef.current.getOutcome(),\n kind: (active) => { const k = argsRef.current.kind; return typeof k === 'function' ? k(active) : k },\n })\n // 同一句連續兩次(例:拖曳中一直停在同一個落點)不重寫 —— 文字沒變,polite 區域本來就不會再唸;\n // 換成別句再回來則會唸(狀態真的變了)。\n const speak = (s: string) => { setText(s); return '' }\n const announcements: DragAnnouncements = {\n onDragStart: (e) => speak(inner.onDragStart(e)),\n onDragOver: (e) => speak(inner.onDragOver(e)),\n onDragEnd: () => speak(inner.onDragEnd()),\n onDragCancel: (e) => speak(inner.onDragCancel(e)),\n }\n return { announcements, screenReaderInstructions: DRAG_SCREEN_READER_INSTRUCTIONS }\n }, [])\n const liveRegion = React.createElement(\n 'div',\n { role: 'status', 'aria-live': 'polite', 'aria-atomic': true, className: 'sr-only', 'data-drag-live-region': '' },\n text,\n )\n return { accessibility, liveRegion }\n}\n"],"names":[],"mappings":";AAyFO,SAAS,wBAAwB,EAAE,YAAY,QAA8B;AAClF,QAAM,SAAS,CAAC,WAAwB,OAAO,SAAS,aAAa,KAAK,MAAM,IAAI;AACpF,SAAO;AAAA,IACL,aAAa,CAAC,EAAE,aACd,MAAM,OAAO,MAAM,CAAC,IAAI,OAAO,OAAO,EAAE,CAAC;AAAA,IAC3C,YAAY,CAAC,EAAE,KAAA,MACb,OAAO,MAAM,OAAO,KAAK,EAAE,CAAC,QAAQ;AAAA,IACtC,WAAW,MAAM;AACf,YAAM,UAAU,WAAA;AAEhB,UAAI,CAAC,QAAS,QAAO;AACrB,aAAO,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAK;AAAA,IAC5C;AAAA,IACA,cAAc,CAAC,EAAE,aACf,QAAQ,OAAO,MAAM,CAAC,IAAI,OAAO,OAAO,EAAE,CAAC;AAAA,EAAA;AAEjD;AAMO,MAAM,kCAAkC;AAAA,EAC7C,WAAW;AAAA;AACb;AAoBO,SAAS,qBAAqB,MAGnC;AACA,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,EAAE;AAGzC,QAAM,UAAU,MAAM,OAAO,IAAI;AACjC,UAAQ,UAAU;AAClB,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,UAAM,QAAQ,wBAAwB;AAAA,MACpC,YAAY,MAAM,QAAQ,QAAQ,WAAA;AAAA,MAClC,MAAM,CAAC,WAAW;AAAE,cAAM,IAAI,QAAQ,QAAQ;AAAM,eAAO,OAAO,MAAM,aAAa,EAAE,MAAM,IAAI;AAAA,MAAE;AAAA,IAAA,CACpG;AAGD,UAAM,QAAQ,CAAC,MAAc;AAAE,cAAQ,CAAC;AAAG,aAAO;AAAA,IAAG;AACrD,UAAM,gBAAmC;AAAA,MACvC,aAAa,CAAC,MAAM,MAAM,MAAM,YAAY,CAAC,CAAC;AAAA,MAC9C,YAAY,CAAC,MAAM,MAAM,MAAM,WAAW,CAAC,CAAC;AAAA,MAC5C,WAAW,MAAM,MAAM,MAAM,WAAW;AAAA,MACxC,cAAc,CAAC,MAAM,MAAM,MAAM,aAAa,CAAC,CAAC;AAAA,IAAA;AAElD,WAAO,EAAE,eAAe,0BAA0B,gCAAA;AAAA,EACpD,GAAG,CAAA,CAAE;AACL,QAAM,aAAa,MAAM;AAAA,IACvB;AAAA,IACA,EAAE,MAAM,UAAU,aAAa,UAAU,eAAe,MAAM,WAAW,WAAW,yBAAyB,GAAA;AAAA,IAC7G;AAAA,EAAA;AAEF,SAAO,EAAE,eAAe,WAAA;AAC1B;"}
|