@exxatdesignux/ui 0.2.19 → 0.4.0
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/CHANGELOG.md +662 -7
- package/bin/sync-extras.mjs +116 -29
- package/consumer-extras/README.md +42 -7
- package/consumer-extras/cursor-rules/exxat-accessibility.mdc +39 -0
- package/consumer-extras/cursor-rules/exxat-board-cards.mdc +26 -0
- package/consumer-extras/cursor-rules/exxat-breadcrumbs-no-back.mdc +21 -0
- package/consumer-extras/cursor-rules/exxat-card-vs-list-rows.mdc +21 -0
- package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +44 -0
- package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +32 -0
- package/consumer-extras/cursor-rules/exxat-command-menu.mdc +22 -0
- package/consumer-extras/cursor-rules/exxat-dashboard-view-charts.mdc +53 -0
- package/consumer-extras/cursor-rules/exxat-data-tables.mdc +43 -0
- package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +25 -0
- package/consumer-extras/cursor-rules/exxat-drawer-vs-dialog.mdc +22 -0
- package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +56 -0
- package/consumer-extras/cursor-rules/exxat-fontawesome-icons.mdc +31 -0
- package/consumer-extras/cursor-rules/exxat-kbd-shortcuts.mdc +100 -0
- package/consumer-extras/cursor-rules/exxat-kpi-flat-band.mdc +28 -0
- package/consumer-extras/cursor-rules/exxat-kpi-max-four.mdc +21 -0
- package/consumer-extras/cursor-rules/exxat-kpi-trends.mdc +31 -0
- package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +28 -0
- package/consumer-extras/cursor-rules/exxat-list-page-connected-views.mdc +24 -0
- package/consumer-extras/cursor-rules/exxat-list-page-view-shells.mdc +31 -0
- package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +30 -0
- package/consumer-extras/cursor-rules/exxat-no-slds-leakage.mdc +78 -0
- package/consumer-extras/cursor-rules/exxat-no-toast.mdc +25 -0
- package/consumer-extras/cursor-rules/exxat-page-vs-drawer.mdc +23 -0
- package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +47 -0
- package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +52 -0
- package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +34 -0
- package/consumer-extras/cursor-rules/exxat-table-properties-drawer.mdc +77 -0
- package/consumer-extras/cursor-rules/exxat-token-discipline.mdc +103 -0
- package/consumer-extras/cursor-skills/exxat-accessibility/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +3 -3
- package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +5 -16
- package/consumer-extras/cursor-skills/exxat-collaboration-access/SKILL.md +3 -3
- package/consumer-extras/cursor-skills/exxat-dedicated-search-surfaces/SKILL.md +2 -2
- package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +19 -34
- package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +1 -1
- package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-list-page-view-shells/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-mono-ids/SKILL.md +4 -4
- package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +10 -12
- package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +277 -0
- package/consumer-extras/handbook/HANDBOOK.md +187 -0
- package/consumer-extras/handbook/glossary.md +58 -0
- package/consumer-extras/handbook/reference-implementations.md +153 -0
- package/consumer-extras/handbook/voice-and-tone.md +262 -0
- package/consumer-extras/patterns/collaboration-access-pattern.md +7 -7
- package/consumer-extras/patterns/command-menu-pattern.md +1 -1
- package/consumer-extras/patterns/consumer-upgrade-checklist.md +0 -20
- package/consumer-extras/patterns/data-views-pattern.md +31 -66
- package/consumer-extras/patterns/kpi-flat-band-pattern.md +2 -2
- package/consumer-extras/patterns/shell-surface-elevation-pattern.md +3 -5
- package/dist/components/data-table/filter-date-calendar.d.ts +10 -0
- package/dist/components/data-table/filter-date-calendar.js +280 -0
- package/dist/components/data-table/filter-date-calendar.js.map +1 -0
- package/dist/components/data-table/filter-text-value-input.d.ts +15 -0
- package/dist/components/data-table/filter-text-value-input.js +561 -0
- package/dist/components/data-table/filter-text-value-input.js.map +1 -0
- package/dist/components/data-table/index.d.ts +45 -0
- package/dist/components/data-table/index.js +3085 -0
- package/dist/components/data-table/index.js.map +1 -0
- package/dist/components/data-table/pagination.d.ts +28 -0
- package/dist/components/data-table/pagination.js +3264 -0
- package/dist/components/data-table/pagination.js.map +1 -0
- package/dist/components/data-table/types.d.ts +84 -0
- package/dist/components/data-table/types.js +3 -0
- package/dist/components/data-table/types.js.map +1 -0
- package/dist/components/data-table/use-table-state.d.ts +116 -0
- package/dist/components/data-table/use-table-state.js +670 -0
- package/dist/components/data-table/use-table-state.js.map +1 -0
- package/dist/components/data-views/board-card-primitives.d.ts +22 -0
- package/dist/components/data-views/board-card-primitives.js +84 -0
- package/dist/components/data-views/board-card-primitives.js.map +1 -0
- package/dist/components/data-views/data-row-list.d.ts +33 -0
- package/dist/components/data-views/data-row-list.js +106 -0
- package/dist/components/data-views/data-row-list.js.map +1 -0
- package/dist/components/data-views/finder-panel-view.d.ts +54 -0
- package/dist/components/data-views/finder-panel-view.js +388 -0
- package/dist/components/data-views/finder-panel-view.js.map +1 -0
- package/dist/components/data-views/folder-grid-view.d.ts +22 -0
- package/dist/components/data-views/folder-grid-view.js +58 -0
- package/dist/components/data-views/folder-grid-view.js.map +1 -0
- package/dist/components/data-views/hub-table.d.ts +173 -0
- package/dist/components/data-views/hub-table.js +5783 -0
- package/dist/components/data-views/hub-table.js.map +1 -0
- package/dist/components/data-views/index.d.ts +27 -0
- package/dist/components/data-views/index.js +6797 -0
- package/dist/components/data-views/index.js.map +1 -0
- package/dist/components/data-views/list-page-board-card.d.ts +72 -0
- package/dist/components/data-views/list-page-board-card.js +264 -0
- package/dist/components/data-views/list-page-board-card.js.map +1 -0
- package/dist/components/data-views/list-page-board-template.d.ts +24 -0
- package/dist/components/data-views/list-page-board-template.js +137 -0
- package/dist/components/data-views/list-page-board-template.js.map +1 -0
- package/dist/components/data-views/list-page-connected-view-body.d.ts +19 -0
- package/dist/components/data-views/list-page-connected-view-body.js +116 -0
- package/dist/components/data-views/list-page-connected-view-body.js.map +1 -0
- package/dist/components/data-views/list-page-split-details-placeholder.d.ts +14 -0
- package/dist/components/data-views/list-page-split-details-placeholder.js +38 -0
- package/dist/components/data-views/list-page-split-details-placeholder.js.map +1 -0
- package/dist/components/data-views/list-page-split-hub-chrome.d.ts +17 -0
- package/dist/components/data-views/list-page-split-hub-chrome.js +54 -0
- package/dist/components/data-views/list-page-split-hub-chrome.js.map +1 -0
- package/dist/components/data-views/list-page-split-hub-tokens.d.ts +12 -0
- package/dist/components/data-views/list-page-split-hub-tokens.js +8 -0
- package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -0
- package/dist/components/data-views/list-page-tree-column-header.d.ts +15 -0
- package/dist/components/data-views/list-page-tree-column-header.js +22 -0
- package/dist/components/data-views/list-page-tree-column-header.js.map +1 -0
- package/dist/components/data-views/list-page-tree-panel-shell.d.ts +25 -0
- package/dist/components/data-views/list-page-tree-panel-shell.js +146 -0
- package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -0
- package/dist/components/data-views/os-folder-glyph.d.ts +35 -0
- package/dist/components/data-views/os-folder-glyph.js +104 -0
- package/dist/components/data-views/os-folder-glyph.js.map +1 -0
- package/dist/components/data-views/outline-tree-menu.d.ts +36 -0
- package/dist/components/data-views/outline-tree-menu.js +131 -0
- package/dist/components/data-views/outline-tree-menu.js.map +1 -0
- package/dist/components/table-properties/column-row.d.ts +22 -0
- package/dist/components/table-properties/column-row.js +153 -0
- package/dist/components/table-properties/column-row.js.map +1 -0
- package/dist/components/table-properties/draggable-list.d.ts +24 -0
- package/dist/components/table-properties/draggable-list.js +53 -0
- package/dist/components/table-properties/draggable-list.js.map +1 -0
- package/dist/components/table-properties/drawer-button.d.ts +110 -0
- package/dist/components/table-properties/drawer-button.js +2748 -0
- package/dist/components/table-properties/drawer-button.js.map +1 -0
- package/dist/components/table-properties/drawer.d.ts +100 -0
- package/dist/components/table-properties/drawer.js +2595 -0
- package/dist/components/table-properties/drawer.js.map +1 -0
- package/dist/components/table-properties/filter-card.d.ts +24 -0
- package/dist/components/table-properties/filter-card.js +854 -0
- package/dist/components/table-properties/filter-card.js.map +1 -0
- package/dist/components/table-properties/index.d.ts +14 -0
- package/dist/components/table-properties/index.js +2768 -0
- package/dist/components/table-properties/index.js.map +1 -0
- package/dist/components/table-properties/sort-card.d.ts +20 -0
- package/dist/components/table-properties/sort-card.js +102 -0
- package/dist/components/table-properties/sort-card.js.map +1 -0
- package/dist/components/templates/dedicated-search-landing-template.d.ts +21 -0
- package/dist/components/templates/dedicated-search-landing-template.js +254 -0
- package/dist/components/templates/dedicated-search-landing-template.js.map +1 -0
- package/dist/components/templates/dedicated-search-results-template.d.ts +15 -0
- package/dist/components/templates/dedicated-search-results-template.js +16 -0
- package/dist/components/templates/dedicated-search-results-template.js.map +1 -0
- package/dist/components/templates/index.d.ts +9 -0
- package/dist/components/templates/index.js +2720 -0
- package/dist/components/templates/index.js.map +1 -0
- package/dist/components/templates/list-page.d.ts +83 -0
- package/dist/components/templates/list-page.js +2433 -0
- package/dist/components/templates/list-page.js.map +1 -0
- package/dist/components/templates/nested-secondary-panel-shell.d.ts +20 -0
- package/dist/components/templates/nested-secondary-panel-shell.js +54 -0
- package/dist/components/templates/nested-secondary-panel-shell.js.map +1 -0
- package/dist/components/ui/accordion.d.ts +10 -0
- package/dist/components/ui/accordion.js +74 -0
- package/dist/components/ui/accordion.js.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +37 -0
- package/dist/components/ui/alert-dialog.js +201 -0
- package/dist/components/ui/alert-dialog.js.map +1 -0
- package/dist/components/ui/avatar.d.ts +84 -0
- package/dist/components/ui/avatar.js +328 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.d.ts +13 -0
- package/dist/components/ui/badge.js +49 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/banner.d.ts +62 -0
- package/dist/components/ui/banner.js +364 -0
- package/dist/components/ui/banner.js.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +14 -0
- package/dist/components/ui/breadcrumb.js +114 -0
- package/dist/components/ui/breadcrumb.js.map +1 -0
- package/dist/components/ui/button.d.ts +16 -0
- package/dist/components/ui/button.js +59 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/calendar.d.ts +13 -0
- package/dist/components/ui/calendar.js +238 -0
- package/dist/components/ui/calendar.js.map +1 -0
- package/dist/components/ui/card.d.ts +14 -0
- package/dist/components/ui/card.js +102 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/chart.d.ts +58 -0
- package/dist/components/ui/chart.js +292 -0
- package/dist/components/ui/chart.js.map +1 -0
- package/dist/components/ui/checkbox.d.ts +23 -0
- package/dist/components/ui/checkbox.js +155 -0
- package/dist/components/ui/checkbox.js.map +1 -0
- package/dist/components/ui/coach-mark.d.ts +27 -0
- package/dist/components/ui/coach-mark.js +306 -0
- package/dist/components/ui/coach-mark.js.map +1 -0
- package/dist/components/ui/collapsible.d.ts +8 -0
- package/dist/components/ui/collapsible.js +35 -0
- package/dist/components/ui/collapsible.js.map +1 -0
- package/dist/components/ui/command.d.ts +36 -0
- package/dist/components/ui/command.js +274 -0
- package/dist/components/ui/command.js.map +1 -0
- package/dist/components/ui/context-menu.d.ts +32 -0
- package/dist/components/ui/context-menu.js +245 -0
- package/dist/components/ui/context-menu.js.map +1 -0
- package/dist/components/ui/date-picker-field.d.ts +38 -0
- package/dist/components/ui/date-picker-field.js +550 -0
- package/dist/components/ui/date-picker-field.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +22 -0
- package/dist/components/ui/dialog.js +200 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/ui/dot-pattern.d.ts +21 -0
- package/dist/components/ui/dot-pattern.js +139 -0
- package/dist/components/ui/dot-pattern.js.map +1 -0
- package/dist/components/ui/drag-handle-grip.d.ts +10 -0
- package/dist/components/ui/drag-handle-grip.js +15 -0
- package/dist/components/ui/drag-handle-grip.js.map +1 -0
- package/dist/components/ui/drawer.d.ts +16 -0
- package/dist/components/ui/drawer.js +125 -0
- package/dist/components/ui/drawer.js.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +45 -0
- package/dist/components/ui/dropdown-menu.js +353 -0
- package/dist/components/ui/dropdown-menu.js.map +1 -0
- package/dist/components/ui/export-drawer.d.ts +11 -0
- package/dist/components/ui/export-drawer.js +1658 -0
- package/dist/components/ui/export-drawer.js.map +1 -0
- package/dist/components/ui/field.d.ts +30 -0
- package/dist/components/ui/field.js +249 -0
- package/dist/components/ui/field.js.map +1 -0
- package/dist/components/ui/form.d.ts +28 -0
- package/dist/components/ui/form.js +110 -0
- package/dist/components/ui/form.js.map +1 -0
- package/dist/components/ui/hover-card.d.ts +9 -0
- package/dist/components/ui/hover-card.js +43 -0
- package/dist/components/ui/hover-card.js.map +1 -0
- package/dist/components/ui/input-group.d.ts +20 -0
- package/dist/components/ui/input-group.js +219 -0
- package/dist/components/ui/input-group.js.map +1 -0
- package/dist/components/ui/input-mask.d.ts +39 -0
- package/dist/components/ui/input-mask.js +118 -0
- package/dist/components/ui/input-mask.js.map +1 -0
- package/dist/components/ui/input.d.ts +5 -0
- package/dist/components/ui/input.js +30 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/kbd.d.ts +20 -0
- package/dist/components/ui/kbd.js +45 -0
- package/dist/components/ui/kbd.js.map +1 -0
- package/dist/components/ui/key-metrics-context.d.ts +19 -0
- package/dist/components/ui/key-metrics-context.js +26 -0
- package/dist/components/ui/key-metrics-context.js.map +1 -0
- package/dist/components/ui/key-metrics.d.ts +131 -0
- package/dist/components/ui/key-metrics.js +1015 -0
- package/dist/components/ui/key-metrics.js.map +1 -0
- package/dist/components/ui/label.d.ts +6 -0
- package/dist/components/ui/label.js +28 -0
- package/dist/components/ui/label.js.map +1 -0
- package/dist/components/ui/list-page-view-frame.d.ts +22 -0
- package/dist/components/ui/list-page-view-frame.js +24 -0
- package/dist/components/ui/list-page-view-frame.js.map +1 -0
- package/dist/components/ui/page-header.d.ts +51 -0
- package/dist/components/ui/page-header.js +372 -0
- package/dist/components/ui/page-header.js.map +1 -0
- package/dist/components/ui/payment-card-fields.d.ts +10 -0
- package/dist/components/ui/payment-card-fields.js +80 -0
- package/dist/components/ui/payment-card-fields.js.map +1 -0
- package/dist/components/ui/popover.d.ts +10 -0
- package/dist/components/ui/popover.js +47 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/radio-group.d.ts +29 -0
- package/dist/components/ui/radio-group.js +190 -0
- package/dist/components/ui/radio-group.js.map +1 -0
- package/dist/components/ui/resizable.d.ts +16 -0
- package/dist/components/ui/resizable.js +51 -0
- package/dist/components/ui/resizable.js.map +1 -0
- package/dist/components/ui/scroll-area.d.ts +8 -0
- package/dist/components/ui/scroll-area.js +66 -0
- package/dist/components/ui/scroll-area.js.map +1 -0
- package/dist/components/ui/select.d.ts +18 -0
- package/dist/components/ui/select.js +186 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/selection-tile-grid.d.ts +52 -0
- package/dist/components/ui/selection-tile-grid.js +347 -0
- package/dist/components/ui/selection-tile-grid.js.map +1 -0
- package/dist/components/ui/separator.d.ts +7 -0
- package/dist/components/ui/separator.js +33 -0
- package/dist/components/ui/separator.js.map +1 -0
- package/dist/components/ui/sheet.d.ts +18 -0
- package/dist/components/ui/sheet.js +181 -0
- package/dist/components/ui/sheet.js.map +1 -0
- package/dist/components/ui/sidebar.d.ts +94 -0
- package/dist/components/ui/sidebar.js +805 -0
- package/dist/components/ui/sidebar.js.map +1 -0
- package/dist/components/ui/skeleton.d.ts +5 -0
- package/dist/components/ui/skeleton.js +22 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/components/ui/slider.d.ts +7 -0
- package/dist/components/ui/slider.js +66 -0
- package/dist/components/ui/slider.js.map +1 -0
- package/dist/components/ui/sonner.d.ts +6 -0
- package/dist/components/ui/sonner.js +38 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/components/ui/status-badge.d.ts +38 -0
- package/dist/components/ui/status-badge.js +77 -0
- package/dist/components/ui/status-badge.js.map +1 -0
- package/dist/components/ui/table.d.ts +13 -0
- package/dist/components/ui/table.js +115 -0
- package/dist/components/ui/table.js.map +1 -0
- package/dist/components/ui/tabs.d.ts +15 -0
- package/dist/components/ui/tabs.js +93 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/textarea.d.ts +6 -0
- package/dist/components/ui/textarea.js +25 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/components/ui/tip.d.ts +12 -0
- package/dist/components/ui/tip.js +61 -0
- package/dist/components/ui/tip.js.map +1 -0
- package/dist/components/ui/toggle-group.d.ts +14 -0
- package/dist/components/ui/toggle-group.js +104 -0
- package/dist/components/ui/toggle-group.js.map +1 -0
- package/dist/components/ui/toggle-switch.d.ts +10 -0
- package/dist/components/ui/toggle-switch.js +33 -0
- package/dist/components/ui/toggle-switch.js.map +1 -0
- package/dist/components/ui/toggle.d.ts +13 -0
- package/dist/components/ui/toggle.js +51 -0
- package/dist/components/ui/toggle.js.map +1 -0
- package/dist/components/ui/tooltip.d.ts +10 -0
- package/dist/components/ui/tooltip.js +68 -0
- package/dist/components/ui/tooltip.js.map +1 -0
- package/dist/components/ui/view-segmented-control.d.ts +31 -0
- package/dist/components/ui/view-segmented-control.js +167 -0
- package/dist/components/ui/view-segmented-control.js.map +1 -0
- package/dist/data-list-view-registry-CyBoBML4.d.ts +73 -0
- package/dist/hooks/use-app-theme.d.ts +24 -0
- package/dist/hooks/use-app-theme.js +286 -0
- package/dist/hooks/use-app-theme.js.map +1 -0
- package/dist/hooks/use-coach-mark.d.ts +86 -0
- package/dist/hooks/use-coach-mark.js +218 -0
- package/dist/hooks/use-coach-mark.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +3 -0
- package/dist/hooks/use-mobile.js +29 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/hooks/use-mod-key-label.d.ts +6 -0
- package/dist/hooks/use-mod-key-label.js +25 -0
- package/dist/hooks/use-mod-key-label.js.map +1 -0
- package/dist/index.d.ts +120 -0
- package/dist/index.js +13421 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/compose-refs.d.ts +6 -0
- package/dist/lib/compose-refs.js +17 -0
- package/dist/lib/compose-refs.js.map +1 -0
- package/dist/lib/conditional-rule-match.d.ts +30 -0
- package/dist/lib/conditional-rule-match.js +66 -0
- package/dist/lib/conditional-rule-match.js.map +1 -0
- package/dist/lib/data-list-display-options.d.ts +26 -0
- package/dist/lib/data-list-display-options.js +14 -0
- package/dist/lib/data-list-display-options.js.map +1 -0
- package/dist/lib/data-list-view-registry.d.ts +2 -0
- package/dist/lib/data-list-view-registry.js +102 -0
- package/dist/lib/data-list-view-registry.js.map +1 -0
- package/dist/lib/data-list-view-surface.d.ts +2 -0
- package/dist/lib/data-list-view-surface.js +80 -0
- package/dist/lib/data-list-view-surface.js.map +1 -0
- package/dist/lib/data-list-view.d.ts +21 -0
- package/dist/lib/data-list-view.js +25 -0
- package/dist/lib/data-list-view.js.map +1 -0
- package/dist/lib/date-filter.d.ts +22 -0
- package/dist/lib/date-filter.js +61 -0
- package/dist/lib/date-filter.js.map +1 -0
- package/dist/lib/dev-log.d.ts +8 -0
- package/dist/lib/dev-log.js +10 -0
- package/dist/lib/dev-log.js.map +1 -0
- package/dist/lib/dropdown-menu-surface.d.ts +14 -0
- package/dist/lib/dropdown-menu-surface.js +6 -0
- package/dist/lib/dropdown-menu-surface.js.map +1 -0
- package/dist/lib/editable-target.d.ts +12 -0
- package/dist/lib/editable-target.js +12 -0
- package/dist/lib/editable-target.js.map +1 -0
- package/dist/lib/list-page-table-properties.d.ts +35 -0
- package/dist/lib/list-page-table-properties.js +81 -0
- package/dist/lib/list-page-table-properties.js.map +1 -0
- package/dist/lib/raf-throttle.d.ts +23 -0
- package/dist/lib/raf-throttle.js +27 -0
- package/dist/lib/raf-throttle.js.map +1 -0
- package/dist/lib/row-height.d.ts +16 -0
- package/dist/lib/row-height.js +10 -0
- package/dist/lib/row-height.js.map +1 -0
- package/dist/lib/table-properties-types.d.ts +83 -0
- package/dist/lib/table-properties-types.js +19 -0
- package/dist/lib/table-properties-types.js.map +1 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +11 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +83 -19
- package/src/components/data-table/filter-date-calendar.tsx +38 -0
- package/src/components/data-table/filter-text-value-input.tsx +77 -0
- package/src/components/data-table/index.tsx +1678 -0
- package/src/components/data-table/pagination.tsx +259 -0
- package/src/components/data-table/types.ts +96 -0
- package/src/components/data-table/use-table-state.ts +767 -0
- package/src/components/data-views/board-card-primitives.tsx +93 -0
- package/src/components/data-views/data-row-list.tsx +183 -0
- package/src/components/data-views/finder-panel-view.tsx +405 -0
- package/src/components/data-views/folder-grid-view.tsx +86 -0
- package/src/components/data-views/hub-table.tsx +606 -0
- package/src/components/data-views/index.ts +28 -0
- package/src/components/data-views/list-page-board-card.tsx +192 -0
- package/src/components/data-views/list-page-board-template.tsx +122 -0
- package/src/components/data-views/list-page-connected-view-body.tsx +66 -0
- package/src/components/data-views/list-page-split-details-placeholder.tsx +39 -0
- package/src/components/data-views/list-page-split-hub-chrome.tsx +60 -0
- package/src/components/data-views/list-page-split-hub-tokens.ts +16 -0
- package/src/components/data-views/list-page-tree-column-header.tsx +31 -0
- package/src/components/data-views/list-page-tree-panel-shell.tsx +91 -0
- package/src/components/data-views/os-folder-glyph.tsx +141 -0
- package/src/components/data-views/outline-tree-menu.tsx +157 -0
- package/src/components/table-properties/column-row.tsx +90 -0
- package/src/components/table-properties/draggable-list.ts +54 -0
- package/src/components/table-properties/drawer-button.tsx +300 -0
- package/src/components/table-properties/drawer.tsx +1148 -0
- package/src/components/table-properties/filter-card.tsx +251 -0
- package/src/components/table-properties/index.ts +36 -0
- package/src/components/table-properties/sort-card.tsx +63 -0
- package/src/components/templates/dedicated-search-landing-template.tsx +124 -0
- package/src/components/templates/dedicated-search-results-template.tsx +19 -0
- package/src/components/templates/index.ts +33 -0
- package/src/components/templates/list-page.tsx +602 -0
- package/src/components/templates/nested-secondary-panel-shell.tsx +70 -0
- package/src/components/ui/accordion.tsx +92 -0
- package/src/components/ui/alert-dialog.tsx +221 -0
- package/src/components/ui/avatar.tsx +13 -2
- package/src/components/ui/banner.tsx +2 -2
- package/src/components/ui/button.tsx +4 -4
- package/src/components/ui/calendar.tsx +1 -1
- package/src/components/ui/coach-mark.tsx +1 -1
- package/src/components/ui/context-menu.tsx +291 -0
- package/src/components/ui/date-picker-field.tsx +2 -2
- package/src/components/ui/dot-pattern.tsx +183 -0
- package/src/components/ui/export-drawer.tsx +375 -0
- package/src/components/ui/hover-card.tsx +66 -0
- package/src/components/ui/key-metrics-context.tsx +78 -0
- package/src/components/ui/key-metrics.tsx +1133 -0
- package/src/components/ui/list-page-view-frame.tsx +64 -0
- package/src/components/ui/page-header.tsx +244 -0
- package/src/components/ui/payment-card-fields.tsx +2 -2
- package/src/components/ui/resizable.tsx +68 -0
- package/src/components/ui/scroll-area.tsx +72 -0
- package/src/components/ui/selection-tile-grid.tsx +9 -2
- package/src/components/ui/sidebar.tsx +84 -12
- package/src/components/ui/slider.tsx +83 -0
- package/src/globals.css +2201 -7
- package/src/globals.d.ts +20 -0
- package/src/index.ts +68 -1
- package/src/lib/conditional-rule-match.ts +119 -0
- package/src/lib/data-list-display-options.ts +35 -0
- package/src/lib/data-list-view-registry.ts +104 -0
- package/src/lib/data-list-view-surface.ts +83 -0
- package/src/lib/data-list-view.ts +47 -0
- package/src/lib/dev-log.ts +10 -0
- package/src/lib/editable-target.ts +20 -0
- package/src/lib/list-page-table-properties.ts +48 -0
- package/src/lib/raf-throttle.ts +45 -0
- package/src/lib/row-height.ts +19 -0
- package/src/lib/table-properties-types.ts +98 -0
- package/template/.claude/skills/exxat-ds-skill/SKILL.md +8 -7
- package/template/.cursor/rules/exxat-accessibility.mdc +1 -1
- package/template/.cursor/rules/exxat-command-menu.mdc +2 -2
- package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +7 -7
- package/template/.cursor/rules/exxat-data-tables.mdc +3 -3
- package/template/.cursor/rules/exxat-ds-agents.mdc +2 -2
- package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +7 -7
- package/template/.cursor/rules/exxat-mono-ids.mdc +1 -1
- package/template/.cursor/rules/exxat-page-vs-drawer.mdc +1 -1
- package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
- package/template/AGENTS.md +135 -103
- package/template/app/(app)/columns/page.tsx +11 -0
- package/template/app/(app)/dashboard/loading.tsx +15 -3
- package/template/app/(app)/dashboard/page.tsx +14 -2
- package/template/app/(app)/layout.tsx +17 -4
- package/template/app/(app)/library/all/page.tsx +11 -0
- package/template/app/(app)/library/find/page.tsx +12 -0
- package/template/app/(app)/{question-bank → library}/layout.tsx +17 -17
- package/template/app/(app)/library/list/page.tsx +12 -0
- package/template/app/(app)/library/new/page.tsx +45 -0
- package/template/app/(app)/library/page.tsx +11 -0
- package/template/app/(app)/loading.tsx +18 -1
- package/template/app/(app)/settings/page.tsx +5 -4
- package/template/app/(app)/tokens-themes/page.tsx +11 -0
- package/template/app/globals.css +14 -16
- package/template/components/ask-leo-composer.tsx +2 -2
- package/template/components/ask-leo-sidebar.tsx +5 -1
- package/template/components/brand-color-picker.tsx +2 -2
- package/template/components/charts-overview.tsx +1 -1
- package/template/components/columns-client.tsx +158 -0
- package/template/components/columns-showcase.tsx +541 -0
- package/template/components/dashboard-report-charts.tsx +1 -1
- package/template/components/dashboard-tabs.tsx +1 -1
- package/template/components/data-table/filter-date-calendar.tsx +1 -38
- package/template/components/data-table/filter-text-value-input.tsx +1 -77
- package/template/components/data-table/index.tsx +1 -1634
- package/template/components/data-table/pagination.tsx +1 -255
- package/template/components/data-table/types.ts +1 -94
- package/template/components/data-table/use-table-state.test.ts +420 -0
- package/template/components/data-table/use-table-state.ts +1 -758
- package/template/components/data-views/board-card-primitives.tsx +1 -93
- package/template/components/data-views/data-row-list.tsx +1 -183
- package/template/components/data-views/finder-panel-view.tsx +1 -405
- package/template/components/data-views/folder-grid-view.tsx +1 -86
- package/template/components/data-views/hub-table.tsx +1 -0
- package/template/components/data-views/index.ts +77 -38
- package/template/components/data-views/{question-bank-folder-tree-branch.tsx → library-folder-tree-branch.tsx} +19 -19
- package/template/components/data-views/list-page-board-card.tsx +1 -192
- package/template/components/data-views/list-page-board-template.tsx +1 -122
- package/template/components/data-views/list-page-connected-view-body.tsx +1 -66
- package/template/components/data-views/list-page-split-details-placeholder.tsx +1 -39
- package/template/components/data-views/list-page-split-hub-chrome.tsx +1 -68
- package/template/components/data-views/list-page-split-hub-tokens.ts +1 -16
- package/template/components/data-views/list-page-tree-column-header.tsx +1 -31
- package/template/components/data-views/list-page-tree-panel-shell.tsx +1 -91
- package/template/components/data-views/list-page-view-frame.tsx +5 -53
- package/template/components/data-views/os-folder-glyph.tsx +1 -129
- package/template/components/data-views/outline-tree-menu.tsx +1 -157
- package/template/components/data-views/table-cells.tsx +673 -0
- package/template/components/export-drawer.test.tsx +71 -0
- package/template/components/export-drawer.tsx +1 -375
- package/template/components/exxat-product-logo.tsx +5 -5
- package/template/components/folder-details-shell.tsx +11 -11
- package/template/components/hub-tree-panel-view.tsx +26 -26
- package/template/components/invite-collaborators-drawer.tsx +3 -3
- package/template/components/key-metrics-ask-leo-bridge.tsx +40 -0
- package/template/components/key-metrics.tsx +1 -1063
- package/template/components/leo-insight-indicator.tsx +2 -2
- package/template/components/{question-bank-board-view.tsx → library-board-view.tsx} +44 -44
- package/template/components/{question-bank-client.tsx → library-client.tsx} +83 -83
- package/template/components/{question-bank-dashboard-charts.tsx → library-dashboard-charts.tsx} +14 -14
- package/template/components/{question-bank-favorite-button.tsx → library-favorite-button.tsx} +7 -7
- package/template/components/{question-bank-hub-client.tsx → library-hub-client.tsx} +44 -44
- package/template/components/{question-bank-new-folder-sheet.tsx → library-new-folder-sheet.tsx} +16 -16
- package/template/components/{question-bank-os-folder-view.tsx → library-os-folder-view.tsx} +31 -31
- package/template/components/{question-bank-page-header.tsx → library-page-header.tsx} +6 -6
- package/template/components/library-panel-activator.tsx +8 -0
- package/template/components/{question-bank-secondary-nav.tsx → library-secondary-nav.tsx} +63 -63
- package/template/components/library-table.tsx +839 -0
- package/template/components/list-hub-status-badge.tsx +2 -2
- package/template/components/{new-question-composer.tsx → new-library-item-form.tsx} +489 -441
- package/template/components/onboarding/index.ts +9 -0
- package/template/components/onboarding/onboarding-01.tsx +1 -1
- package/template/components/onboarding/onboarding-02.tsx +1 -1
- package/template/components/onboarding/onboarding-03.tsx +1 -1
- package/template/components/onboarding/onboarding-04.tsx +1 -1
- package/template/components/page-header.tsx +8 -226
- package/template/components/product-switcher.tsx +3 -4
- package/template/components/product-wordmark.tsx +2 -1
- package/template/components/settings-appearance-card.tsx +3 -4
- package/template/components/settings-client.tsx +15 -59
- package/template/components/settings-form-row.tsx +4 -9
- package/template/components/{app-sidebar-dynamic.tsx → sidebar/app-sidebar-dynamic.tsx} +1 -1
- package/template/components/{app-sidebar.tsx → sidebar/app-sidebar.tsx} +114 -73
- package/template/components/sidebar/index.ts +16 -0
- package/template/components/{secondary-nav.tsx → sidebar/secondary-nav.tsx} +2 -2
- package/template/components/sidebar/secondary-panel.tsx +316 -0
- package/template/components/sidebar/sidebar-auto-collapse.tsx +27 -0
- package/template/components/{sidebar-auto-open.tsx → sidebar/sidebar-auto-open.tsx} +2 -1
- package/template/components/{sidebar-shell.tsx → sidebar/sidebar-shell.tsx} +1 -1
- package/template/components/site-header.tsx +1 -1
- package/template/components/table-properties/column-row.tsx +1 -90
- package/template/components/table-properties/draggable-list.ts +1 -49
- package/template/components/table-properties/drawer-button.tsx +1 -262
- package/template/components/table-properties/drawer.tsx +1 -1166
- package/template/components/table-properties/filter-card.tsx +1 -251
- package/template/components/table-properties/sort-card.tsx +1 -59
- package/template/components/table-properties/types.ts +28 -71
- package/template/components/templates/dedicated-search-landing-template.tsx +1 -124
- package/template/components/templates/dedicated-search-results-template.tsx +1 -19
- package/template/components/templates/discovery-hub-template.tsx +1 -1
- package/template/components/templates/list-page.tsx +1 -608
- package/template/components/templates/nested-secondary-panel-shell.tsx +1 -63
- package/template/components/templates/new-focus-template.tsx +659 -0
- package/template/components/templates/secondary-panel-hub-template.tsx +2 -2
- package/template/components/tokens-secondary-nav.tsx +192 -0
- package/template/components/tokens-themes-client.tsx +476 -0
- package/template/components/tokens-themes-section.tsx +386 -0
- package/template/components/ui/accordion.tsx +1 -0
- package/template/components/ui/alert-dialog.tsx +1 -0
- package/template/components/ui/context-menu.tsx +1 -0
- package/template/components/ui/dot-pattern.tsx +1 -183
- package/template/components/ui/hover-card.tsx +1 -0
- package/template/components/ui/resizable.tsx +1 -68
- package/template/components/ui/scroll-area.tsx +1 -0
- package/template/components/ui/slider.tsx +1 -0
- package/template/docs/HANDBOOK.md +187 -0
- package/template/docs/blueprints/README.md +86 -0
- package/template/docs/blueprints/_template.md +91 -0
- package/template/docs/blueprints/board-card.md +123 -0
- package/template/docs/blueprints/data-table.md +139 -0
- package/template/docs/blueprints/key-metrics.md +128 -0
- package/template/docs/blueprints/list-page-template.md +123 -0
- package/template/docs/blueprints/page-header.md +130 -0
- package/template/docs/collaboration-access-pattern.md +7 -7
- package/template/docs/command-menu-pattern.md +1 -1
- package/template/docs/component-selection-guide.md +224 -0
- package/template/docs/components-audit-2026-05.md +158 -0
- package/template/docs/data-views-pattern.md +31 -66
- package/template/docs/drawer-vs-dialog-pattern.md +1 -3
- package/template/docs/glossary.md +58 -0
- package/template/docs/kpi-flat-band-pattern.md +3 -3
- package/template/docs/kpi-trend-pattern.md +18 -3
- package/template/docs/large-dataset-strategy.md +155 -0
- package/template/docs/library-hub-header-pattern.md +25 -0
- package/template/docs/migrations/0001-brand-deep-alias-stabilization.md +95 -0
- package/template/docs/migrations/0002-exxat-token-namespace.md +154 -0
- package/template/docs/migrations/0003-globals-css-canonical.md +110 -0
- package/template/docs/migrations/README.md +100 -0
- package/template/docs/migrations/_template.md +64 -0
- package/template/docs/reference-implementations.md +151 -0
- package/template/docs/shell-surface-elevation-pattern.md +3 -5
- package/template/docs/token-taxonomy.md +416 -0
- package/template/docs/voice-and-tone.md +262 -0
- package/template/eslint.config.mjs +27 -0
- package/template/hooks/use-secondary-panel-hub-nav.ts +11 -11
- package/template/lib/ask-leo-route-context.ts +6 -18
- package/template/lib/coach-mark-registry.ts +0 -16
- package/template/lib/command-menu-config.ts +5 -13
- package/template/lib/command-menu-search-data.ts +8 -23
- package/template/lib/conditional-rule-match.ts +6 -97
- package/template/lib/data-list-display-options.ts +1 -49
- package/template/lib/data-list-view-registry.ts +1 -104
- package/template/lib/data-list-view-surface.ts +1 -83
- package/template/lib/data-list-view.ts +1 -47
- package/template/lib/data-view-dashboard-storage.ts +35 -38
- package/template/lib/dev-log.ts +1 -8
- package/template/lib/editable-target.ts +1 -10
- package/template/lib/{question-bank-authoring.ts → library-authoring.ts} +89 -88
- package/template/lib/library-dedicated-search.ts +19 -0
- package/template/lib/library-hub-search.ts +90 -0
- package/template/lib/library-nav.ts +477 -0
- package/template/lib/library-recent-searches.ts +22 -0
- package/template/lib/{question-bank-supported-views.ts → library-supported-views.ts} +2 -3
- package/template/lib/list-page-table-properties.ts +1 -48
- package/template/lib/list-status-badges.ts +16 -11
- package/template/lib/mock/dashboard.ts +1 -1
- package/template/lib/mock/{question-bank-folders.ts → library-folders.ts} +30 -30
- package/template/lib/mock/library-header-collaborators.ts +54 -0
- package/template/lib/mock/{question-bank-inspector.ts → library-inspector.ts} +29 -29
- package/template/lib/mock/{question-bank-kpi.ts → library-kpi.ts} +20 -20
- package/template/lib/mock/library.ts +249 -0
- package/template/lib/mock/navigation.tsx +32 -35
- package/template/lib/raf-throttle.ts +1 -45
- package/template/lib/row-height.ts +4 -10
- package/template/lib/sidebar-state-cookie.ts +11 -2
- package/template/lib/table-state-lifecycle.ts +3 -3
- package/template/next.config.mjs +7 -4
- package/template/package.json +1 -0
- package/template/tests/setup.ts +25 -0
- package/consumer-extras/AGENTS.md +0 -76
- package/consumer-extras/cursor-skills/exxat-consumer-app/SKILL.md +0 -37
- package/consumer-extras/cursor-skills/exxat-focused-workflow-page/SKILL.md +0 -57
- package/consumer-extras/patterns/consumer-app-pattern.md +0 -39
- package/consumer-extras/patterns/focused-workflow-page-pattern.md +0 -84
- package/src/components/ui/button-group.tsx +0 -81
- package/src/theme.css +0 -16
- package/src/tokens/README.md +0 -15
- package/src/tokens/base.css +0 -337
- package/src/tokens/high-contrast.css +0 -1195
- package/src/tokens/layers.css +0 -224
- package/src/tokens/tailwind-bridge.css +0 -118
- package/src/tokens/themes.css +0 -201
- package/template/app/(app)/data-list/layout.tsx +0 -43
- package/template/app/(app)/data-list/page.tsx +0 -10
- package/template/app/(app)/examples/focused-workflow/page.tsx +0 -5
- package/template/app/(app)/examples/page.tsx +0 -43
- package/template/app/(app)/question-bank/find/page.tsx +0 -13
- package/template/app/(app)/question-bank/library/page.tsx +0 -12
- package/template/app/(app)/question-bank/list/page.tsx +0 -13
- package/template/app/(app)/question-bank/new/page.tsx +0 -50
- package/template/app/(app)/question-bank/page.tsx +0 -12
- package/template/components/app-route-loading.tsx +0 -14
- package/template/components/dashboard-onboarding-gallery.tsx +0 -13
- package/template/components/dashboard-onboarding.tsx +0 -21
- package/template/components/data-views/list-page-calendar-view.tsx +0 -593
- package/template/components/data-views/list-page-folder-columns-panel.tsx +0 -345
- package/template/components/examples/focused-workflow-showcase.tsx +0 -183
- package/template/components/list-hub-board-view.tsx +0 -68
- package/template/components/list-hub-client.tsx +0 -186
- package/template/components/list-hub-list-view.tsx +0 -36
- package/template/components/list-hub-panel-activator.tsx +0 -8
- package/template/components/list-hub-secondary-nav.tsx +0 -121
- package/template/components/list-hub-table.tsx +0 -336
- package/template/components/question-bank-folder-columns-panel.tsx +0 -104
- package/template/components/question-bank-list-view.tsx +0 -53
- package/template/components/question-bank-panel-activator.tsx +0 -8
- package/template/components/question-bank-table.tsx +0 -729
- package/template/components/secondary-panel/nav-link-rows.tsx +0 -83
- package/template/components/secondary-panel.tsx +0 -220
- package/template/components/secondary-panels/list-hub-panel.tsx +0 -39
- package/template/components/secondary-panels/question-bank-panel.tsx +0 -39
- package/template/components/secondary-panels/registry.tsx +0 -15
- package/template/components/section-cards.tsx +0 -106
- package/template/components/sidebar-auto-collapse.tsx +0 -23
- package/template/components/templates/focused-workflow-layouts.tsx +0 -448
- package/template/components/templates/focused-workflow-page-template.tsx +0 -69
- package/template/components/templates/page-loading-shell.tsx +0 -262
- package/template/components/ui/button-group.tsx +0 -1
- package/template/docs/consumer-app-pattern.md +0 -39
- package/template/docs/focused-workflow-page-pattern.md +0 -84
- package/template/docs/question-bank-hub-header-pattern.md +0 -25
- package/template/lib/list-hub-nav.ts +0 -121
- package/template/lib/mock/list-hub-directory.ts +0 -27
- package/template/lib/mock/list-hub-kpi.ts +0 -27
- package/template/lib/mock/question-bank-header-collaborators.ts +0 -54
- package/template/lib/mock/question-bank.ts +0 -249
- package/template/lib/page-loading-variant.ts +0 -40
- package/template/lib/question-bank-dedicated-search.ts +0 -19
- package/template/lib/question-bank-hub-search.ts +0 -90
- package/template/lib/question-bank-nav.ts +0 -477
- package/template/lib/question-bank-recent-searches.ts +0 -22
- /package/template/components/{getting-started.tsx → onboarding/getting-started.tsx} +0 -0
- /package/template/components/{nav-documents.tsx → sidebar/nav-documents.tsx} +0 -0
- /package/template/components/{nav-main.tsx → sidebar/nav-main.tsx} +0 -0
- /package/template/components/{nav-secondary.tsx → sidebar/nav-secondary.tsx} +0 -0
- /package/template/components/{nav-user.tsx → sidebar/nav-user.tsx} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ListPageViewFrame — shared horizontal gutter + optional centered max-width
|
|
5
|
+
* for list-hub **view bodies** (folder icon grid, finder panel chrome,
|
|
6
|
+
* OS-style folder explorer, dashboard slices, etc.).
|
|
7
|
+
*
|
|
8
|
+
* MUST be used instead of ad-hoc `mx-4 lg:mx-6` + `mx-auto max-w-*` pairs on
|
|
9
|
+
* each page — see `apps/web/AGENTS.md` §4.5 and
|
|
10
|
+
* `.cursor/rules/exxat-list-page-view-shells.mdc`.
|
|
11
|
+
*
|
|
12
|
+
* MUST NOT wrap `DataTable` when its toolbar already applies the same inset
|
|
13
|
+
* (avoid double gutter); use this for **non-table** view branches or
|
|
14
|
+
* **sections below** the shared toolbar.
|
|
15
|
+
*
|
|
16
|
+
* Promotion note: this file lived at
|
|
17
|
+
* `apps/web/components/data-views/list-page-view-frame.tsx` until
|
|
18
|
+
* 2026-05-20. It moved into `@exxatdesignux/ui` because the gutter / max-
|
|
19
|
+
* width contract is entity-agnostic and other consumers (a future docs
|
|
20
|
+
* site, partner apps) need the same rhythm without dragging in the whole
|
|
21
|
+
* `data-views/` family.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import * as React from "react"
|
|
25
|
+
|
|
26
|
+
import { cn } from "../../lib/utils"
|
|
27
|
+
|
|
28
|
+
/** Default horizontal rhythm for view bodies under `ListPageTemplate` (matches `FolderGridView`). */
|
|
29
|
+
export const LIST_PAGE_VIEW_FRAME_GUTTER = "mx-4 mb-6 lg:mx-6"
|
|
30
|
+
|
|
31
|
+
/** Typical max width for icon grids / dense tile views on ultra-wide monitors. */
|
|
32
|
+
export const LIST_PAGE_VIEW_FRAME_MAX_ICON_GRID = "max-w-6xl"
|
|
33
|
+
|
|
34
|
+
/** Slightly wider shell when a view includes toolbar + breadcrumbs + grid (e.g. OS folder explorer). */
|
|
35
|
+
export const LIST_PAGE_VIEW_FRAME_MAX_WIDE = "max-w-7xl"
|
|
36
|
+
|
|
37
|
+
export interface ListPageViewFrameProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
38
|
+
children: React.ReactNode
|
|
39
|
+
/**
|
|
40
|
+
* When set, children are wrapped in `mx-auto w-full min-w-0` + this
|
|
41
|
+
* max-width so the block stays centered inside the primary page column.
|
|
42
|
+
*/
|
|
43
|
+
maxWidthClassName?: string
|
|
44
|
+
/** Override outer gutter; default `LIST_PAGE_VIEW_FRAME_GUTTER`. */
|
|
45
|
+
gutterClassName?: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function ListPageViewFrame({
|
|
49
|
+
children,
|
|
50
|
+
className,
|
|
51
|
+
maxWidthClassName,
|
|
52
|
+
gutterClassName = LIST_PAGE_VIEW_FRAME_GUTTER,
|
|
53
|
+
...rest
|
|
54
|
+
}: ListPageViewFrameProps) {
|
|
55
|
+
return (
|
|
56
|
+
<div className={cn(gutterClassName, className)} {...rest}>
|
|
57
|
+
{maxWidthClassName ? (
|
|
58
|
+
<div className={cn("mx-auto w-full min-w-0", maxWidthClassName)}>{children}</div>
|
|
59
|
+
) : (
|
|
60
|
+
children
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PageHeader — Full-width content area header.
|
|
5
|
+
*
|
|
6
|
+
* Sits at the top of a page's main content, BELOW the breadcrumb / topbar.
|
|
7
|
+
* Uses Ivy Presto (Adobe Fonts) for the title via the `--font-heading`
|
|
8
|
+
* CSS variable.
|
|
9
|
+
*
|
|
10
|
+
* **Variant `collaboration`** — optional access line + collaborator faces
|
|
11
|
+
* (or **Add collaborator** when the roster is empty) ahead of the primary
|
|
12
|
+
* `actions` slot. The full **Invite people** flow lives in the consuming
|
|
13
|
+
* page's `actions` overflow menu — this primitive only renders the face row.
|
|
14
|
+
*
|
|
15
|
+
* WCAG 2.1 AA:
|
|
16
|
+
* - `<h1>` landmark — one per page (WCAG 1.3.1)
|
|
17
|
+
* - Sufficient colour contrast >= 4.5:1 on title + subtitle (SC 1.4.3)
|
|
18
|
+
* - Face row: `role="group"` + aggregate `aria-label`; each face has a
|
|
19
|
+
* `Tooltip` name (SC 4.1.2)
|
|
20
|
+
*
|
|
21
|
+
* Promotion note: this file lived at `apps/web/components/page-header.tsx`
|
|
22
|
+
* until 2026-05-20. It moved into `@exxatdesignux/ui` so other apps (and
|
|
23
|
+
* future docs sites) can compose hub headers without duplicating the
|
|
24
|
+
* collaboration variant, h1 styling, or face-row a11y wiring. The
|
|
25
|
+
* `CollaboratorAccessRole` union is duplicated here as a narrow string
|
|
26
|
+
* literal so the primitive stays free of `apps/web/lib/` couplings — the
|
|
27
|
+
* authoritative role labels / icons / capability helpers continue to live
|
|
28
|
+
* in `apps/web/lib/collaborator-access.ts`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import * as React from "react"
|
|
32
|
+
|
|
33
|
+
import { Avatar, AvatarFallback, AvatarImage } from "./avatar"
|
|
34
|
+
import { Button } from "./button"
|
|
35
|
+
import { Separator } from "./separator"
|
|
36
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip"
|
|
37
|
+
import { cn } from "../../lib/utils"
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Library access role for shared hubs. Mirrors
|
|
41
|
+
* `apps/web/lib/collaborator-access.ts > CollaboratorAccessRole` — kept
|
|
42
|
+
* structurally identical so the apps/web type and this type are mutually
|
|
43
|
+
* assignable wherever consumers pass collaborator rosters to `PageHeader`.
|
|
44
|
+
*/
|
|
45
|
+
export type PageHeaderCollaboratorAccessRole =
|
|
46
|
+
| "owner"
|
|
47
|
+
| "editor"
|
|
48
|
+
| "commenter"
|
|
49
|
+
| "viewer"
|
|
50
|
+
|
|
51
|
+
export type PageHeaderVariant = "default" | "collaboration"
|
|
52
|
+
|
|
53
|
+
export interface PageHeaderCollaborator {
|
|
54
|
+
id: string
|
|
55
|
+
name: string
|
|
56
|
+
imageUrl?: string | null
|
|
57
|
+
initials?: string
|
|
58
|
+
email?: string
|
|
59
|
+
access?: PageHeaderCollaboratorAccessRole
|
|
60
|
+
/** Org / directory role tags (e.g. Faculty, Program coordinator). */
|
|
61
|
+
roles?: string[]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface PageHeaderProps {
|
|
65
|
+
/** Primary page title — rendered as `<h1>` in Ivy Presto serif. */
|
|
66
|
+
title: string
|
|
67
|
+
/** Short descriptor or date shown below the title (and below `accessInfo` when set). */
|
|
68
|
+
subtitle?: React.ReactNode
|
|
69
|
+
/** Layout preset — `collaboration` enables access line + face row ahead of `actions`. */
|
|
70
|
+
variant?: PageHeaderVariant
|
|
71
|
+
/**
|
|
72
|
+
* Role / access copy or badges — rendered between the title and subtitle
|
|
73
|
+
* when `variant="collaboration"` (e.g. lock icon + "Editors can modify").
|
|
74
|
+
*/
|
|
75
|
+
accessInfo?: React.ReactNode
|
|
76
|
+
/** People with access — shown as a horizontal row of faces when `variant="collaboration"`. */
|
|
77
|
+
collaborators?: PageHeaderCollaborator[]
|
|
78
|
+
/** Max faces before a `+N` chip — default 3. */
|
|
79
|
+
collaboratorDisplayLimit?: number
|
|
80
|
+
/** Opens the invite collaborators sheet when a face, overflow chip, or empty-state CTA is activated. */
|
|
81
|
+
onCollaboratorsOpen?: () => void
|
|
82
|
+
/** Label for the empty-roster header control — default `"Add collaborator"`. */
|
|
83
|
+
addCollaboratorLabel?: string
|
|
84
|
+
/** Optional slot for right-aligned actions (buttons, selectors, etc.). */
|
|
85
|
+
actions?: React.ReactNode
|
|
86
|
+
/** Extra className for the outer wrapper. */
|
|
87
|
+
className?: string
|
|
88
|
+
/** When false, the title + subtitle are visually hidden (actions remain). */
|
|
89
|
+
showTitleBlock?: boolean
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function PageHeaderCollaborationAccess({
|
|
93
|
+
people,
|
|
94
|
+
limit,
|
|
95
|
+
onOpenCollaborators,
|
|
96
|
+
addCollaboratorLabel,
|
|
97
|
+
}: {
|
|
98
|
+
people: PageHeaderCollaborator[]
|
|
99
|
+
limit: number
|
|
100
|
+
onOpenCollaborators?: () => void
|
|
101
|
+
addCollaboratorLabel: string
|
|
102
|
+
}) {
|
|
103
|
+
if (people.length === 0) {
|
|
104
|
+
return (
|
|
105
|
+
<div
|
|
106
|
+
role="group"
|
|
107
|
+
aria-label="People with access"
|
|
108
|
+
className="flex shrink-0 items-center"
|
|
109
|
+
>
|
|
110
|
+
<Button
|
|
111
|
+
type="button"
|
|
112
|
+
variant="outline"
|
|
113
|
+
size="lg"
|
|
114
|
+
onClick={onOpenCollaborators}
|
|
115
|
+
disabled={!onOpenCollaborators}
|
|
116
|
+
>
|
|
117
|
+
<i className="fa-light fa-user-plus" aria-hidden="true" />
|
|
118
|
+
{addCollaboratorLabel}
|
|
119
|
+
</Button>
|
|
120
|
+
</div>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const visible = people.slice(0, limit)
|
|
125
|
+
const overflow = Math.max(0, people.length - visible.length)
|
|
126
|
+
const names = people.map((p) => p.name).join(", ")
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<div
|
|
130
|
+
role="group"
|
|
131
|
+
aria-label={names ? `People with access: ${names}` : "People with access"}
|
|
132
|
+
className="flex shrink-0 items-center gap-2 sm:gap-2.5"
|
|
133
|
+
>
|
|
134
|
+
<div className="flex shrink-0 items-center gap-1.5">
|
|
135
|
+
{visible.map((c) => (
|
|
136
|
+
<Tooltip key={c.id}>
|
|
137
|
+
<TooltipTrigger asChild>
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
className="relative shrink-0 rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
141
|
+
aria-label={`Open collaborators — ${c.name}`}
|
|
142
|
+
onClick={onOpenCollaborators}
|
|
143
|
+
disabled={!onOpenCollaborators}
|
|
144
|
+
>
|
|
145
|
+
<Avatar size="sm" shape="circle" className="pointer-events-none">
|
|
146
|
+
{c.imageUrl ? (
|
|
147
|
+
<AvatarImage src={c.imageUrl} alt="" referrerPolicy="no-referrer" />
|
|
148
|
+
) : null}
|
|
149
|
+
<AvatarFallback className="text-xs font-semibold">
|
|
150
|
+
{(c.initials ?? c.name.slice(0, 2)).toUpperCase()}
|
|
151
|
+
</AvatarFallback>
|
|
152
|
+
</Avatar>
|
|
153
|
+
</button>
|
|
154
|
+
</TooltipTrigger>
|
|
155
|
+
<TooltipContent side="bottom">{c.name}</TooltipContent>
|
|
156
|
+
</Tooltip>
|
|
157
|
+
))}
|
|
158
|
+
{overflow > 0 && (
|
|
159
|
+
<button
|
|
160
|
+
type="button"
|
|
161
|
+
className="flex size-6 shrink-0 items-center justify-center rounded-full bg-muted text-[11px] font-semibold tabular-nums text-muted-foreground ring-1 ring-border/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
162
|
+
aria-label={`Open collaborators — ${overflow} more people with access`}
|
|
163
|
+
onClick={onOpenCollaborators}
|
|
164
|
+
disabled={!onOpenCollaborators}
|
|
165
|
+
>
|
|
166
|
+
+{overflow}
|
|
167
|
+
</button>
|
|
168
|
+
)}
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function PageHeader({
|
|
175
|
+
title,
|
|
176
|
+
subtitle,
|
|
177
|
+
variant = "default",
|
|
178
|
+
accessInfo,
|
|
179
|
+
collaborators,
|
|
180
|
+
collaboratorDisplayLimit = 3,
|
|
181
|
+
onCollaboratorsOpen,
|
|
182
|
+
addCollaboratorLabel = "Add collaborator",
|
|
183
|
+
actions,
|
|
184
|
+
className,
|
|
185
|
+
showTitleBlock = true,
|
|
186
|
+
}: PageHeaderProps) {
|
|
187
|
+
const isCollaboration = variant === "collaboration"
|
|
188
|
+
const showAccess = Boolean(isCollaboration && accessInfo)
|
|
189
|
+
const showCollaborationAccess = isCollaboration
|
|
190
|
+
const showActionsColumn = Boolean(actions) || showCollaborationAccess
|
|
191
|
+
const showCollaboratorActionsSeparator =
|
|
192
|
+
showCollaborationAccess && Boolean(actions)
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<div
|
|
196
|
+
className={cn(
|
|
197
|
+
"flex flex-col gap-1 px-4 pt-2 pb-4 lg:px-6",
|
|
198
|
+
"sm:flex-row sm:items-end sm:gap-4",
|
|
199
|
+
showTitleBlock ? "sm:justify-between" : "sm:justify-end",
|
|
200
|
+
className,
|
|
201
|
+
)}
|
|
202
|
+
>
|
|
203
|
+
{/* Title block — hidden visually when showTitleBlock is false; keep h1 for a11y. */}
|
|
204
|
+
<div className={cn("flex min-w-0 flex-col gap-0.5", !showTitleBlock && "sr-only")}>
|
|
205
|
+
<h1
|
|
206
|
+
className="text-2xl font-semibold tracking-tight leading-tight text-foreground"
|
|
207
|
+
style={{ fontFamily: "var(--font-heading)" }}
|
|
208
|
+
suppressHydrationWarning
|
|
209
|
+
>
|
|
210
|
+
{title}
|
|
211
|
+
</h1>
|
|
212
|
+
{showAccess && (
|
|
213
|
+
<div className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs leading-snug text-muted-foreground">
|
|
214
|
+
{accessInfo}
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
{subtitle && (
|
|
218
|
+
<p className="text-sm text-muted-foreground leading-none">{subtitle}</p>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
{showActionsColumn && (
|
|
223
|
+
<div className="flex flex-wrap items-center gap-2 sm:gap-3 shrink-0 sm:ms-auto sm:justify-end">
|
|
224
|
+
{showCollaborationAccess ? (
|
|
225
|
+
<PageHeaderCollaborationAccess
|
|
226
|
+
people={collaborators ?? []}
|
|
227
|
+
limit={collaboratorDisplayLimit}
|
|
228
|
+
onOpenCollaborators={onCollaboratorsOpen}
|
|
229
|
+
addCollaboratorLabel={addCollaboratorLabel}
|
|
230
|
+
/>
|
|
231
|
+
) : null}
|
|
232
|
+
{showCollaboratorActionsSeparator ? (
|
|
233
|
+
<Separator
|
|
234
|
+
orientation="vertical"
|
|
235
|
+
decorative
|
|
236
|
+
className="h-8 shrink-0"
|
|
237
|
+
/>
|
|
238
|
+
) : null}
|
|
239
|
+
{actions}
|
|
240
|
+
</div>
|
|
241
|
+
)}
|
|
242
|
+
</div>
|
|
243
|
+
)
|
|
244
|
+
}
|
|
@@ -49,14 +49,14 @@ export function PaymentCardFieldsGroup({ className }: { className?: string }) {
|
|
|
49
49
|
<Input
|
|
50
50
|
{...getExpiryDateProps()}
|
|
51
51
|
id={`card-expiry-${id}`}
|
|
52
|
-
className="rounded-t-none rounded-
|
|
52
|
+
className="rounded-t-none rounded-e-none shadow-none"
|
|
53
53
|
/>
|
|
54
54
|
</div>
|
|
55
55
|
<div className="-ms-px min-w-0 flex-1 focus-within:z-1">
|
|
56
56
|
<Input
|
|
57
57
|
{...getCVCProps()}
|
|
58
58
|
id={`card-cvc-${id}`}
|
|
59
|
-
className="rounded-t-none rounded-
|
|
59
|
+
className="rounded-t-none rounded-s-none shadow-none"
|
|
60
60
|
/>
|
|
61
61
|
</div>
|
|
62
62
|
</div>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { GripVertical } from "lucide-react"
|
|
5
|
+
import { Group, Panel, Separator } from "react-resizable-panels"
|
|
6
|
+
import type { GroupProps, PanelProps, SeparatorProps } from "react-resizable-panels"
|
|
7
|
+
|
|
8
|
+
import { cn } from "../../lib/utils"
|
|
9
|
+
|
|
10
|
+
// ─── ResizablePanelGroup ──────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
export type ResizablePanelGroupProps = Omit<GroupProps, "orientation"> & {
|
|
13
|
+
direction?: "horizontal" | "vertical"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function ResizablePanelGroup({
|
|
17
|
+
direction = "horizontal",
|
|
18
|
+
className,
|
|
19
|
+
...props
|
|
20
|
+
}: ResizablePanelGroupProps) {
|
|
21
|
+
return (
|
|
22
|
+
<Group
|
|
23
|
+
orientation={direction}
|
|
24
|
+
className={cn(
|
|
25
|
+
"flex h-full w-full",
|
|
26
|
+
direction === "vertical" && "flex-col",
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── ResizablePanel ───────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
export type ResizablePanelProps = PanelProps
|
|
37
|
+
|
|
38
|
+
export const ResizablePanel = Panel
|
|
39
|
+
|
|
40
|
+
// ─── ResizableHandle ──────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
export type ResizableHandleProps = Omit<SeparatorProps, "children"> & {
|
|
43
|
+
/** Render a visible grip icon on the handle. */
|
|
44
|
+
withHandle?: boolean
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function ResizableHandle({ withHandle, className, ...props }: ResizableHandleProps) {
|
|
48
|
+
return (
|
|
49
|
+
<Separator
|
|
50
|
+
className={cn(
|
|
51
|
+
// Base — horizontal handle (between side-by-side panels)
|
|
52
|
+
"relative flex w-1 shrink-0 cursor-col-resize items-center justify-center bg-border/60",
|
|
53
|
+
"transition-colors hover:bg-border active:bg-primary/30",
|
|
54
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
55
|
+
// Vertical handle (between stacked panels)
|
|
56
|
+
"data-[orientation=vertical]:h-1 data-[orientation=vertical]:w-full data-[orientation=vertical]:cursor-row-resize data-[orientation=vertical]:flex-row",
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
>
|
|
61
|
+
{withHandle && (
|
|
62
|
+
<div className="z-10 flex h-5 w-3.5 items-center justify-center rounded-sm border border-border bg-background shadow-sm">
|
|
63
|
+
<GripVertical className="h-3 w-3 text-muted-foreground" />
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
</Separator>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ScrollArea — Radix-backed scroll container with always-visible-on-hover
|
|
5
|
+
* scrollbars that respect platform conventions.
|
|
6
|
+
*
|
|
7
|
+
* Use when you need an **explicitly bounded** scrolling region (lists in
|
|
8
|
+
* popovers, sidebar nav trees, long config panels) and the default
|
|
9
|
+
* browser scrollbar is too coarse or visually noisy.
|
|
10
|
+
*
|
|
11
|
+
* Accessibility:
|
|
12
|
+
* - Radix manages keyboard scrolling parity with native overflow.
|
|
13
|
+
* - The viewport is `role="region"`-compatible — give the wrapper an
|
|
14
|
+
* `aria-label` when the content is a meaningful landmark.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import * as React from "react"
|
|
18
|
+
import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
|
|
19
|
+
|
|
20
|
+
import { cn } from "../../lib/utils"
|
|
21
|
+
|
|
22
|
+
function ScrollArea({
|
|
23
|
+
className,
|
|
24
|
+
children,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
|
27
|
+
return (
|
|
28
|
+
<ScrollAreaPrimitive.Root
|
|
29
|
+
data-slot="scroll-area"
|
|
30
|
+
className={cn("relative", className)}
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
<ScrollAreaPrimitive.Viewport
|
|
34
|
+
data-slot="scroll-area-viewport"
|
|
35
|
+
className="size-full rounded-[inherit] outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</ScrollAreaPrimitive.Viewport>
|
|
39
|
+
<ScrollBar />
|
|
40
|
+
<ScrollAreaPrimitive.Corner />
|
|
41
|
+
</ScrollAreaPrimitive.Root>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function ScrollBar({
|
|
46
|
+
className,
|
|
47
|
+
orientation = "vertical",
|
|
48
|
+
...props
|
|
49
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
|
50
|
+
return (
|
|
51
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
52
|
+
data-slot="scroll-area-scrollbar"
|
|
53
|
+
orientation={orientation}
|
|
54
|
+
className={cn(
|
|
55
|
+
"flex touch-none select-none p-px transition-colors",
|
|
56
|
+
orientation === "vertical" &&
|
|
57
|
+
"h-full w-2.5 border-s border-s-transparent",
|
|
58
|
+
orientation === "horizontal" &&
|
|
59
|
+
"h-2.5 w-full flex-col border-t border-t-transparent",
|
|
60
|
+
className,
|
|
61
|
+
)}
|
|
62
|
+
{...props}
|
|
63
|
+
>
|
|
64
|
+
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
65
|
+
data-slot="scroll-area-thumb"
|
|
66
|
+
className="relative flex-1 rounded-full bg-border hover:bg-border/80"
|
|
67
|
+
/>
|
|
68
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { ScrollArea, ScrollBar }
|
|
@@ -15,10 +15,17 @@ export interface SelectionTileOption<T extends string = string> {
|
|
|
15
15
|
leading?: React.ReactNode
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/** Shared surface classes for icon+label tiles (Properties view type, Export format, etc.).
|
|
18
|
+
/** Shared surface classes for icon+label tiles (Properties view type, Export format, etc.).
|
|
19
|
+
*
|
|
20
|
+
* `aspect-square` + horizontal padding keeps every tile a uniform square regardless of how
|
|
21
|
+
* many tiles are in the row — without it, the last row of a `grid-cols-N` grid (e.g. 3 tiles
|
|
22
|
+
* in a 4-col grid for the Properties view selector) renders the same width per cell but the
|
|
23
|
+
* eye reads them as inconsistent when the row's empty trailing cell shifts visual rhythm.
|
|
24
|
+
* Two-line labels (e.g. "List & details", "Tree & details") still fit because the icon
|
|
25
|
+
* column is only ~18px and the square grows with the cell. */
|
|
19
26
|
export function selectionTileClassNames(selected: boolean) {
|
|
20
27
|
return cn(
|
|
21
|
-
"flex flex-col items-center justify-center gap-1.5 rounded-lg border py-3 text-xs transition-colors",
|
|
28
|
+
"flex aspect-square flex-col items-center justify-center gap-1.5 rounded-lg border px-2 py-3 text-xs leading-tight transition-colors",
|
|
22
29
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
23
30
|
selected
|
|
24
31
|
? "border-brand bg-brand/5 text-foreground font-medium shadow-sm"
|
|
@@ -16,7 +16,21 @@ import {
|
|
|
16
16
|
TooltipTrigger,
|
|
17
17
|
} from "./tooltip"
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Cookie persisting the user's explicit expanded/collapsed preference.
|
|
21
|
+
*
|
|
22
|
+
* Versioned (`_v2`) on 2026-05-21 to drop stale values written by the
|
|
23
|
+
* pre-fix code where incidental layout collapses (secondary panel open,
|
|
24
|
+
* route auto-collapse) would clobber the user's preference on every
|
|
25
|
+
* navigation. Anyone on the old `sidebar_state` cookie falls back to
|
|
26
|
+
* the `defaultOpen` default (expanded), and the next explicit toggle
|
|
27
|
+
* starts persisting under the new name. The old cookie self-expires
|
|
28
|
+
* by `max-age` within a week; if you want immediate cleanup, the
|
|
29
|
+
* client clears it explicitly on first mount (see `useLayoutEffect`
|
|
30
|
+
* below).
|
|
31
|
+
*/
|
|
32
|
+
const SIDEBAR_COOKIE_NAME = "sidebar_state_v2"
|
|
33
|
+
const SIDEBAR_COOKIE_LEGACY_NAME = "sidebar_state"
|
|
20
34
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
|
|
21
35
|
/** Matches `useIsMobile` / Tailwind `md:` — do not apply desktop cookie to mobile overlay. */
|
|
22
36
|
const SIDEBAR_COOKIE_VIEWPORT_MQ = "(max-width: 767px)"
|
|
@@ -24,14 +38,37 @@ const SIDEBAR_WIDTH = "16rem"
|
|
|
24
38
|
const SIDEBAR_WIDTH_ICON = "3rem"
|
|
25
39
|
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
|
26
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Options for {@link SidebarContextProps.setOpen}.
|
|
43
|
+
*
|
|
44
|
+
* `persist: false` updates the visual sidebar state **without** writing the
|
|
45
|
+
* `sidebar_state` cookie. Pass it from incidental layout effects — e.g. a
|
|
46
|
+
* secondary panel taking the rail space, a route-level auto-collapse — so
|
|
47
|
+
* the user's explicit preference (their ⌘B toggle / sidebar button) is the
|
|
48
|
+
* only thing that ever rewrites the cookie. Defaults to `true` for
|
|
49
|
+
* backward compatibility with the toggle button and existing callsites.
|
|
50
|
+
*/
|
|
51
|
+
type SetOpenOptions = { persist?: boolean }
|
|
52
|
+
|
|
27
53
|
type SidebarContextProps = {
|
|
28
54
|
state: "expanded" | "collapsed"
|
|
29
55
|
open: boolean
|
|
30
|
-
setOpen: (
|
|
56
|
+
setOpen: (
|
|
57
|
+
open: boolean | ((value: boolean) => boolean),
|
|
58
|
+
opts?: SetOpenOptions,
|
|
59
|
+
) => void
|
|
31
60
|
openMobile: boolean
|
|
32
61
|
setOpenMobile: (open: boolean) => void
|
|
33
62
|
isMobile: boolean
|
|
34
63
|
toggleSidebar: () => void
|
|
64
|
+
/**
|
|
65
|
+
* Snap the rail back to the user's saved preference — the value persisted in
|
|
66
|
+
* `sidebar_state_v2`, or `defaultOpen` if no cookie was ever written. Use
|
|
67
|
+
* this from incidental-collapse cleanups (secondary panel closing, route
|
|
68
|
+
* leaves) so the rail doesn't stay stuck in its incidental state once the
|
|
69
|
+
* thing that caused the collapse is gone. Always uses `persist: false`.
|
|
70
|
+
*/
|
|
71
|
+
restoreSavedOpen: () => void
|
|
35
72
|
}
|
|
36
73
|
|
|
37
74
|
const SidebarContext = React.createContext<SidebarContextProps | null>(null)
|
|
@@ -73,19 +110,35 @@ function SidebarProvider({
|
|
|
73
110
|
const [_open, _setOpen] = React.useState(defaultOpen)
|
|
74
111
|
const open = openProp ?? _open
|
|
75
112
|
|
|
76
|
-
// `setOpen` already persists `
|
|
113
|
+
// `setOpen` already persists `sidebar_state_v2` to a cookie on desktop; restore it on mount so
|
|
77
114
|
// full reloads and new tabs keep the rail expanded/collapsed. Skip when controlled or on mobile.
|
|
115
|
+
// Also actively drop the legacy `sidebar_state` cookie (pre-2026-05-21) so stale
|
|
116
|
+
// collapsed-by-default values written by the old incidental-collapse bug don't linger.
|
|
117
|
+
//
|
|
118
|
+
// MOUNT-ONLY: deps are `[]` so this runs once per `SidebarProvider` mount, NOT
|
|
119
|
+
// every time `open` flips. That matters because incidental collapses
|
|
120
|
+
// (`setOpen(false, { persist: false })` from a secondary panel opening or
|
|
121
|
+
// `SidebarAutoCollapse` route) must NOT trigger a re-reconcile that reads the
|
|
122
|
+
// saved cookie back as "expanded" and snaps the rail open again.
|
|
123
|
+
// The functional setter avoids closing over a stale `open` value.
|
|
124
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
78
125
|
React.useLayoutEffect(() => {
|
|
79
|
-
if (openProp !== undefined) return
|
|
80
126
|
if (typeof window === "undefined") return
|
|
127
|
+
if (typeof document !== "undefined" && document.cookie.includes(`${SIDEBAR_COOKIE_LEGACY_NAME}=`)) {
|
|
128
|
+
document.cookie = `${SIDEBAR_COOKIE_LEGACY_NAME}=; path=/; max-age=0`
|
|
129
|
+
}
|
|
130
|
+
if (openProp !== undefined) return
|
|
81
131
|
if (window.matchMedia(SIDEBAR_COOKIE_VIEWPORT_MQ).matches) return
|
|
82
132
|
const fromCookie = readSidebarStateCookie()
|
|
83
|
-
if (fromCookie === undefined
|
|
84
|
-
_setOpen(fromCookie)
|
|
85
|
-
}, [
|
|
133
|
+
if (fromCookie === undefined) return
|
|
134
|
+
_setOpen((prev) => (prev === fromCookie ? prev : fromCookie))
|
|
135
|
+
}, [])
|
|
86
136
|
|
|
87
137
|
const setOpen = React.useCallback(
|
|
88
|
-
(
|
|
138
|
+
(
|
|
139
|
+
value: boolean | ((value: boolean) => boolean),
|
|
140
|
+
opts?: SetOpenOptions,
|
|
141
|
+
) => {
|
|
89
142
|
const openState = typeof value === "function" ? value(open) : value
|
|
90
143
|
if (setOpenProp) {
|
|
91
144
|
setOpenProp(openState)
|
|
@@ -93,8 +146,12 @@ function SidebarProvider({
|
|
|
93
146
|
_setOpen(openState)
|
|
94
147
|
}
|
|
95
148
|
|
|
96
|
-
// Persist on desktop only — zooming in and closing shouldn't clobber the
|
|
97
|
-
|
|
149
|
+
// Persist on desktop only — zooming in and closing shouldn't clobber the
|
|
150
|
+
// desktop state. Callers can also opt out explicitly (`persist: false`)
|
|
151
|
+
// for incidental layout collapses such as a secondary panel opening or
|
|
152
|
+
// an auto-collapse route; those visual side-effects must not overwrite
|
|
153
|
+
// the user's saved expanded/collapsed preference.
|
|
154
|
+
if (!isMobile && opts?.persist !== false) {
|
|
98
155
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
|
99
156
|
}
|
|
100
157
|
},
|
|
@@ -106,6 +163,20 @@ function SidebarProvider({
|
|
|
106
163
|
setOpen((open) => !open)
|
|
107
164
|
}, [setOpen])
|
|
108
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Snap the rail back to the user's saved preference. Called when a secondary
|
|
168
|
+
* panel closes or an auto-collapse route is left — so an incidental collapse
|
|
169
|
+
* doesn't persist beyond the page that caused it. `persist: false` because
|
|
170
|
+
* this restore is itself incidental; the only writes to the cookie should
|
|
171
|
+
* still come from real user gestures (⌘B, sidebar button).
|
|
172
|
+
*/
|
|
173
|
+
const restoreSavedOpen = React.useCallback(() => {
|
|
174
|
+
if (typeof window === "undefined") return
|
|
175
|
+
const fromCookie = readSidebarStateCookie()
|
|
176
|
+
const target = fromCookie ?? defaultOpen
|
|
177
|
+
setOpen(target, { persist: false })
|
|
178
|
+
}, [defaultOpen, setOpen])
|
|
179
|
+
|
|
109
180
|
// Adds a keyboard shortcut to toggle the sidebar.
|
|
110
181
|
React.useEffect(() => {
|
|
111
182
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
@@ -138,8 +209,9 @@ function SidebarProvider({
|
|
|
138
209
|
openMobile,
|
|
139
210
|
setOpenMobile,
|
|
140
211
|
toggleSidebar,
|
|
212
|
+
restoreSavedOpen,
|
|
141
213
|
}),
|
|
142
|
-
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
|
214
|
+
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar, restoreSavedOpen]
|
|
143
215
|
)
|
|
144
216
|
|
|
145
217
|
return (
|
|
@@ -569,7 +641,7 @@ const SidebarMenuButton = React.forwardRef<
|
|
|
569
641
|
return button
|
|
570
642
|
}
|
|
571
643
|
|
|
572
|
-
|
|
644
|
+
const tooltipProps: React.ComponentProps<typeof TooltipContent> =
|
|
573
645
|
typeof tooltip === "string" ? { children: tooltip } : tooltip
|
|
574
646
|
|
|
575
647
|
return (
|