@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,128 @@
|
|
|
1
|
+
# Blueprint: Key metrics (KPI strip + dashboard tiles)
|
|
2
|
+
|
|
3
|
+
> **Status:** Stable. **Owner:** Design system. **Implements:** SC 1.3.1, 1.4.3, 1.4.11, 2.4.6, 4.1.2.
|
|
4
|
+
|
|
5
|
+
## 1. Intent
|
|
6
|
+
|
|
7
|
+
A **key-metrics strip** summarizes a hub's headline numbers — count, % share,
|
|
8
|
+
average, freshness — in 1-4 horizontal tiles. Each tile carries a label, a
|
|
9
|
+
formatted value, and an optional **trend chip** (`+12% MoM`, `↓ 0.4 day`,
|
|
10
|
+
`stable`). The strip exists in two variants:
|
|
11
|
+
|
|
12
|
+
- `variant="flat"` — transparent band glued under `ListPageTemplate` headers
|
|
13
|
+
(brand glow + cell hairlines, no surface panel).
|
|
14
|
+
- `variant="card"` — solid card with header / actions / chart annotations
|
|
15
|
+
(dashboard "Key metrics" section).
|
|
16
|
+
|
|
17
|
+
Both feed from the **same row bag** the hub's `DataTable` shows, so the
|
|
18
|
+
numbers reflect active filters / search.
|
|
19
|
+
|
|
20
|
+
**Use when:**
|
|
21
|
+
|
|
22
|
+
- The hub's headline answer can be expressed in **≤ 4 numbers**.
|
|
23
|
+
- The numbers update in response to filters, search, or a date scope.
|
|
24
|
+
- The user benefits from a trend chip (signed delta + period label).
|
|
25
|
+
|
|
26
|
+
**Do NOT use when:**
|
|
27
|
+
|
|
28
|
+
- You need 5 + tiles (push secondary stats into a `MetricInsight`, a chart, or
|
|
29
|
+
another section — never raise `KEY_METRICS_KPI_COUNT_MAX` without DS review).
|
|
30
|
+
- The metric is a long-form chart (use `Chart` family, possibly with a
|
|
31
|
+
`MetricInsight` mini-callout inside).
|
|
32
|
+
|
|
33
|
+
## 2. Anatomy
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
flat:
|
|
37
|
+
─────────────────────────────────────────────────────────────────
|
|
38
|
+
│ Label Value [+12% MoM ▲] │ Label Value [−0.4d ▼] │
|
|
39
|
+
─────────────────────────────────────────────────────────────────
|
|
40
|
+
↑ hairline between cells (no panel)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
card:
|
|
45
|
+
┌──────────────────────────────────────────────┐
|
|
46
|
+
│ Key metrics [Ask Leo] │ ← header (label + actions)
|
|
47
|
+
│ ──────────────────────────────────────────── │
|
|
48
|
+
│ Label Value [trend] ↪ insight chip │ ← MetricItem rows
|
|
49
|
+
│ Label Value [trend] │
|
|
50
|
+
└──────────────────────────────────────────────┘
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Slot | Required? | What it carries |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `metrics` | required | `MetricItem[]` (≤ 4) — label, value, optional trend, optional polarity |
|
|
56
|
+
| `variant` | required | `"flat"` (list-hub strip) or `"card"` (dashboard tile) |
|
|
57
|
+
| `insight` | optional | `MetricInsight` — a narrative chip (e.g. "Renewals up 12% MoM") |
|
|
58
|
+
| `headerActions` | optional (card only) | Ask-Leo trigger or drill-down button |
|
|
59
|
+
| `loading` | optional | Skeleton state — same layout, no values |
|
|
60
|
+
|
|
61
|
+
## 3. States
|
|
62
|
+
|
|
63
|
+
| State | Visual / behavior |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Default | Tiles render label + value + optional trend |
|
|
66
|
+
| Loading | Skeleton bars in the value + trend positions, label visible |
|
|
67
|
+
| Empty | Value = `0` (or `—` for averages), trend = `neutral` |
|
|
68
|
+
| Trend up + favorable | Up arrow + positive tint |
|
|
69
|
+
| Trend up + unfavorable (`trendPolarity: "lower_is_better"`) | Up arrow + destructive tint |
|
|
70
|
+
| Trend neutral / informational | Muted tint, arrow still shows direction |
|
|
71
|
+
| RTL | Trend chip flips alignment; arrows stay direction-correct (logical, not visual) |
|
|
72
|
+
|
|
73
|
+
## 4. Tokens consumed
|
|
74
|
+
|
|
75
|
+
| Token | Used for |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `--exxat-color-surface-muted` / `--muted` | Card variant header band |
|
|
78
|
+
| `--exxat-color-surface-2` / `--card` | Card variant background |
|
|
79
|
+
| `--exxat-color-brand-tint-1` / `--brand-tint` | Flat variant OKLCH brand glow |
|
|
80
|
+
| `--exxat-color-border-1` / `--border` | Cell hairlines (flat variant) |
|
|
81
|
+
| `--exxat-color-ink-1` / `--foreground` | Value text |
|
|
82
|
+
| `--exxat-color-ink-2` / `--muted-foreground` | Label + meta text |
|
|
83
|
+
| Trend chip tokens (positive / destructive / neutral) | Trend tint + foreground |
|
|
84
|
+
|
|
85
|
+
## 5. Accessibility
|
|
86
|
+
|
|
87
|
+
| WCAG SC | How this blueprint complies |
|
|
88
|
+
|---|---|
|
|
89
|
+
| 1.3.1 Info & relationships | The strip is `role="group"` + `aria-label="Key metrics"`; each tile is a `<dl>`-style label / value pair |
|
|
90
|
+
| 1.4.3 Contrast | Trend chip text + tile value ≥ 4.5:1; trend icon ≥ 3:1 |
|
|
91
|
+
| 1.4.11 Non-text contrast | Trend chip border / glyph ≥ 3:1 against tile background |
|
|
92
|
+
| 2.4.6 Headings / labels | Each tile's label is the accessible name; value is `aria-describedby` |
|
|
93
|
+
| 4.1.2 Name / role / value | Trend chip has `aria-label` like "Trending up 12% month over month" (via `metricTrendAriaQualifier`) |
|
|
94
|
+
|
|
95
|
+
## 6. Variants
|
|
96
|
+
|
|
97
|
+
| Variant | When to use | Differences from default |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `flat` | List-page hub headers — transparent band under `ListPageTemplate` | No surface panel; OKLCH brand glow; hairlines only |
|
|
100
|
+
| `card` | Dashboards (Data tab, embed widgets) | Solid card chrome + header + optional Ask Leo trigger |
|
|
101
|
+
| `compact` | Embedded in another card (chart annotation) | 1-2 tiles inline with the chart legend |
|
|
102
|
+
| `mini` | Inside a chart card | Single tile rendered next to the chart title |
|
|
103
|
+
|
|
104
|
+
## 7. Implementation
|
|
105
|
+
|
|
106
|
+
| Framework | Component(s) | File |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| **React (this app)** | `KeyMetrics` + `MetricItem` + `MetricInsight` + `metricTrendTone` + `metricTrendAriaQualifier` | `@exxatdesignux/ui/components/key-metrics` |
|
|
109
|
+
| Service injection (Ask Leo) | `KeyMetricsProvider` (in `apps/web/components/key-metrics-ask-leo-bridge.tsx`) | Wires `useAskLeo` → DS context |
|
|
110
|
+
| Mobile | — | — |
|
|
111
|
+
| Figma | "Key metrics – flat" and "Key metrics – card" frames | — |
|
|
112
|
+
|
|
113
|
+
## 8. Do / Don't
|
|
114
|
+
|
|
115
|
+
| ✅ Do | ❌ Don't |
|
|
116
|
+
|---|---|
|
|
117
|
+
| Cap visible tiles at 4 (`KEY_METRICS_KPI_COUNT_MAX`) | Add a fifth tile by raising the constant without DS review |
|
|
118
|
+
| Set `trendPolarity: "lower_is_better"` for metrics where up = bad (defects, overdue, low-quality flags) | Always paint "up" as the favorable tint |
|
|
119
|
+
| Feed KPI builders with `tableState.rows` so numbers honor filters | Pass raw mock arrays — the numbers will lie when filters change |
|
|
120
|
+
| Use `variant="flat"` on hub headers and `variant="card"` in dashboards | Build a bespoke 3-column tile grid duplicating `KeyMetrics` |
|
|
121
|
+
| Pair trend with a `MetricInsight` for narrative context | Show a bare delta with no period header or qualifier |
|
|
122
|
+
|
|
123
|
+
## 9. References
|
|
124
|
+
|
|
125
|
+
- `apps/web/docs/kpi-flat-band-pattern.md`, `kpi-strip-max-four-pattern.md`, `kpi-trend-pattern.md`
|
|
126
|
+
- `.cursor/rules/exxat-kpi-flat-band.mdc`, `exxat-kpi-max-four.mdc`, `exxat-kpi-trends.mdc`
|
|
127
|
+
- `apps/web/AGENTS.md` §4.1 (template metrics slot), §4.3 (charts + mini-metrics)
|
|
128
|
+
- `apps/web/lib/dashboard-layout-merge.ts` — `KEY_METRICS_KPI_COUNT_MAX`, `clampKeyMetricsKpiCount`
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Blueprint: List page template
|
|
2
|
+
|
|
3
|
+
> **Status:** Stable. **Owner:** Design system. **Implements:** SC 1.3.1, 2.1.1, 2.4.3, 2.4.6, 4.1.2.
|
|
4
|
+
|
|
5
|
+
## 1. Intent
|
|
6
|
+
|
|
7
|
+
A **list page** is the canonical hub surface for browsing a homogeneous
|
|
8
|
+
collection of records (Placements, Team, Compliance, Library items, …).
|
|
9
|
+
It pairs a single `DataTable` with view-tab variants (table · list · board ·
|
|
10
|
+
dashboard · folder · panel · tree), one shared filter / sort / column model,
|
|
11
|
+
and a metric strip that consumes the same filtered row bag.
|
|
12
|
+
|
|
13
|
+
**Use when:**
|
|
14
|
+
|
|
15
|
+
- The route is the **primary** destination for an entity (a hub, not a detail).
|
|
16
|
+
- Users compare records and filter / sort across them.
|
|
17
|
+
- The same dataset can be productively shown as a table **and** as one or more
|
|
18
|
+
alternate views (board, dashboard, etc.).
|
|
19
|
+
|
|
20
|
+
**Do NOT use when:**
|
|
21
|
+
|
|
22
|
+
- The page is a **detail** view of a single record (use a record-home page).
|
|
23
|
+
- The dataset is < ~10 items and never needs filters (use a card grid).
|
|
24
|
+
- The flow is a multi-step **wizard** or **form** (use a primary-page template
|
|
25
|
+
with a focus mode).
|
|
26
|
+
|
|
27
|
+
## 2. Anatomy
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌──────────────────────────────────────────────────────────┐
|
|
31
|
+
│ PageHeader (title · subtitle · primary CTA · ⋯ menu) │ ← slot: header (required)
|
|
32
|
+
├──────────────────────────────────────────────────────────┤
|
|
33
|
+
│ KeyMetrics flat band (≤ 4 tiles · trend chips · …) │ ← slot: metrics (optional)
|
|
34
|
+
├──────────────────────────────────────────────────────────┤
|
|
35
|
+
│ View tabs [ Table · Board · Dashboard · Folder · … ] │ ← slot: viewTabs (required, ≥ 1)
|
|
36
|
+
├──────────────────────────────────────────────────────────┤
|
|
37
|
+
│ Toolbar (search · filter chips · ⋯ properties) │ ← managed by HubTable
|
|
38
|
+
│ ┌─────────────────────────────────────────────────┐ │
|
|
39
|
+
│ │ Active view body — TABLE / BOARD / … │ │ ← rendered by HubTable + renderers
|
|
40
|
+
│ └─────────────────────────────────────────────────┘ │
|
|
41
|
+
└──────────────────────────────────────────────────────────┘
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Slot | Required? | What it carries |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `header` | required | `PageHeader` (object-home / record-home / collaboration variant) |
|
|
47
|
+
| `metrics` | optional | `KeyMetrics variant="flat"` — ≤ 4 tiles fed by the same `tableState.rows` |
|
|
48
|
+
| `viewTabs` | required (≥ 1) | `ViewTab[]` with `viewType`, `icon`, `label`, optional `filterId` |
|
|
49
|
+
| `renderContent` | required | `(tab, updateTab) => ReactNode` that returns the active view body |
|
|
50
|
+
| `beforeSiteHeader` | optional | Banner / promo strip rendered above the site header |
|
|
51
|
+
| `tablePropertiesRef` | optional | Imperative handle so the ⋯ menu can open the Properties drawer |
|
|
52
|
+
|
|
53
|
+
`ListPageTemplate` itself owns the **header + metrics + view-tab control**.
|
|
54
|
+
The view body is rendered by `HubTable` (or a custom non-table view) and
|
|
55
|
+
**shares one `useTableState`** instance across every view.
|
|
56
|
+
|
|
57
|
+
## 3. States
|
|
58
|
+
|
|
59
|
+
| State | Visual / behavior |
|
|
60
|
+
|---|---|
|
|
61
|
+
| Default | Header + metrics + active view body |
|
|
62
|
+
| No metrics declared | Metrics band is omitted; no empty gap |
|
|
63
|
+
| No rows | Active view shows entity-specific empty state; KPI tiles show zeros + neutral trend |
|
|
64
|
+
| Filters applied | Toolbar chips reflect filters; KPI tiles recalculate against filtered rows |
|
|
65
|
+
| Switching views | `tab.id` is the React key so table state survives (sort, search, columns) |
|
|
66
|
+
| Loading | Render skeleton state in `renderContent`; metric tiles use the `metric-card` skeleton |
|
|
67
|
+
| RTL | All chrome (toolbar, view tabs, properties drawer) flips with `dir="rtl"` |
|
|
68
|
+
|
|
69
|
+
## 4. Tokens consumed
|
|
70
|
+
|
|
71
|
+
| Token | Used for |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `--exxat-color-surface-1` / `--background` | Page canvas |
|
|
74
|
+
| `--exxat-color-surface-2` / `--card` | Header + table chrome |
|
|
75
|
+
| `--exxat-color-surface-muted` / `--muted` | View-tab inactive bg, KPI flat band glow |
|
|
76
|
+
| `--exxat-color-brand-1` / `--brand-color` | Active view tab, primary CTA |
|
|
77
|
+
| `--exxat-color-border-1` / `--border` | Hairlines between chrome zones |
|
|
78
|
+
| `--exxat-color-focus-ring` / `--ring` | `:focus-visible` ring on toolbar / tabs |
|
|
79
|
+
| `--exxat-radius-2` / `--radius` | Page chrome radii |
|
|
80
|
+
|
|
81
|
+
## 5. Accessibility
|
|
82
|
+
|
|
83
|
+
| WCAG SC | How this blueprint complies |
|
|
84
|
+
|---|---|
|
|
85
|
+
| 1.3.1 Info & relationships | View tabs use `role="tablist"`; toolbar uses `role="toolbar"`; metrics use `role="group"` + name |
|
|
86
|
+
| 2.1.1 Keyboard | Tab through header → tabs → toolbar → grid; arrow keys between tabs and column headers |
|
|
87
|
+
| 2.4.3 Focus order | Tab order matches reading order top-to-bottom |
|
|
88
|
+
| 2.4.6 Headings / labels | Header title is the route `<h1>`; each view tab announces its label |
|
|
89
|
+
| 4.1.2 Name / role / value | View tabs expose `aria-selected`; properties drawer toggle has `aria-haspopup="dialog"` |
|
|
90
|
+
|
|
91
|
+
## 6. Variants
|
|
92
|
+
|
|
93
|
+
| Variant | When to use | Differences from default |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `base` | Most hubs | Header + metrics + tabs + view body |
|
|
96
|
+
| `no-metrics` | Hubs where KPI summary adds noise (e.g. Library: too many heterogeneous folders) | Omit `metrics` prop |
|
|
97
|
+
| `with-banner` | Pages that need a promo or alert above the header | Use `beforeSiteHeader` slot |
|
|
98
|
+
| `secondary-panel-hub` | Hubs scoped by a sidebar panel (Library) | Wrap in `SecondaryPanelHubTemplate`; same `useTableState` |
|
|
99
|
+
|
|
100
|
+
## 7. Implementation
|
|
101
|
+
|
|
102
|
+
| Framework | Component(s) | File |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| **React (this app)** | `ListPageTemplate` + `HubTable` + `useTableState` + `TablePropertiesDrawer` | `@exxatdesignux/ui/components/templates/list-page`, `@exxatdesignux/ui/components/data-views`, `@exxatdesignux/ui/components/data-table` |
|
|
105
|
+
| Mobile | — | — |
|
|
106
|
+
| Figma | Pattern: "List page – hub" frame in the DS library | — |
|
|
107
|
+
|
|
108
|
+
## 8. Do / Don't
|
|
109
|
+
|
|
110
|
+
| ✅ Do | ❌ Don't |
|
|
111
|
+
|---|---|
|
|
112
|
+
| One `useTableState` per hub; every view reads `tableState.rows` | Mount a second mock array for "board only" or "tree only" |
|
|
113
|
+
| Pass `currentView` + `onViewChange` into `TablePropertiesDrawer` | Leave `currentView` unset on a multi-view hub (Properties drawer assumes table) |
|
|
114
|
+
| Use `key={tab.id}` in `renderContent` so table state survives | Use `key={tab.viewType}` (resets state when switching views) |
|
|
115
|
+
| Pull metrics from `tableState.rows` so they react to filters / search | Pass raw mock arrays to KPI builders (numbers will lie when filters change) |
|
|
116
|
+
| Cap the metrics strip at 4 KPI tiles | Add a fifth tile by raising `KEY_METRICS_KPI_COUNT_MAX` without DS review |
|
|
117
|
+
|
|
118
|
+
## 9. References
|
|
119
|
+
|
|
120
|
+
- `apps/web/docs/data-views-pattern.md` — connected views narrative
|
|
121
|
+
- `apps/web/docs/kpi-flat-band-pattern.md`, `kpi-strip-max-four-pattern.md`, `kpi-trend-pattern.md`
|
|
122
|
+
- `.cursor/rules/exxat-list-page-connected-views.mdc`, `exxat-centralized-list-dataset.mdc`, `exxat-table-properties-drawer.mdc`, `exxat-list-page-view-shells.mdc`
|
|
123
|
+
- `apps/web/AGENTS.md` §4.1 (template), §4.2 (Properties drawer), §4.5 (view shells)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Blueprint: Page Header
|
|
2
|
+
|
|
3
|
+
> **Status:** Stable. **Owner:** Exxat DS core. **Implements:** WCAG 2.1 AA.
|
|
4
|
+
|
|
5
|
+
## 1. Intent
|
|
6
|
+
|
|
7
|
+
A page header **names the route** the user is on, communicates **freshness**
|
|
8
|
+
of the underlying data, and gives the user the **primary action** for that
|
|
9
|
+
route (and any secondary actions behind a `⋯` overflow). It is the visual
|
|
10
|
+
anchor of every primary hub.
|
|
11
|
+
|
|
12
|
+
**Use when:**
|
|
13
|
+
- The user lands on a primary nav destination (Placements, Team, Question
|
|
14
|
+
bank, Compliance, Settings, Dashboard).
|
|
15
|
+
- The user opens a detail/record view that should advertise its own identity
|
|
16
|
+
(placement record, question detail).
|
|
17
|
+
|
|
18
|
+
**Do NOT use when:**
|
|
19
|
+
- The surface is already inside a hub's view body (sub-sections never get
|
|
20
|
+
their own page header — they get a `DashboardSectionHeading` or similar).
|
|
21
|
+
- The surface is an overlay (drawer / dialog / sheet) — those use their own
|
|
22
|
+
`*Title` slots.
|
|
23
|
+
|
|
24
|
+
## 2. Anatomy
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ [icon] Title [face-rail] [primary] [⋯] │ ← title-row (required)
|
|
29
|
+
│ Subtitle · ID · count · freshness │ ← meta (optional)
|
|
30
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Slot | Required? | What it carries |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `icon` | optional | Product mark (`ExxatProductLogo`) or FA glyph |
|
|
36
|
+
| `title` | **required** | One H1 — the route name (e.g. "Placements") |
|
|
37
|
+
| `subtitle` | optional | One line: short context, ID, count, freshness |
|
|
38
|
+
| `face-rail` | optional | `+N collaborators` stack (variant `collaboration`) |
|
|
39
|
+
| `actions/primary` | optional | One filled `Button` (e.g. "New placement") |
|
|
40
|
+
| `actions/overflow` | optional | One outline icon `Button` opening a dropdown menu |
|
|
41
|
+
| `breadcrumb` | optional | Above title; never alongside it |
|
|
42
|
+
|
|
43
|
+
The header **never** carries search, filters, view-tabs, or KPIs — those belong
|
|
44
|
+
to `ListPageTemplate` / `KeyMetrics` / `DataTable`. The header is the route
|
|
45
|
+
identity, nothing more.
|
|
46
|
+
|
|
47
|
+
## 3. States
|
|
48
|
+
|
|
49
|
+
| State | Visual / behavior |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Default | Title + subtitle + actions; primary CTA filled. |
|
|
52
|
+
| Collaboration empty | Outline "Add collaborator" replaces face rail. |
|
|
53
|
+
| Collaboration populated | Face rail with `+N` opens `InviteCollaboratorsDrawer`. |
|
|
54
|
+
| Loading | Title skeleton (60% width), meta skeleton (30% width). |
|
|
55
|
+
| Error | The header still renders; errors land in the body's `LocalBanner`. |
|
|
56
|
+
| RTL | Slots mirror; FA glyphs auto-mirror via Tailwind's `rtl:`. |
|
|
57
|
+
|
|
58
|
+
## 4. Tokens consumed
|
|
59
|
+
|
|
60
|
+
| Token | Used for |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `--background` / `--foreground` | Surface + ink |
|
|
63
|
+
| `--muted-foreground` | Subtitle / meta line |
|
|
64
|
+
| `--brand-color` | Product mark fills (when icon is a product logo) |
|
|
65
|
+
| `--ring` | Focus ring on actions + face rail buttons |
|
|
66
|
+
| `--font-heading` | Title font family (Ivy Presto) — **not** body Inter |
|
|
67
|
+
| `--text-xs` | Meta line at min 11px (SC 1.4.3) |
|
|
68
|
+
| `--radius-md` | Action button corners |
|
|
69
|
+
|
|
70
|
+
For monospace IDs in the subtitle, see
|
|
71
|
+
[`exxat-mono-ids.mdc`](../../../.cursor/rules/exxat-mono-ids.mdc): only the
|
|
72
|
+
ID token gets `font-mono tabular-nums`, the rest of the line stays sans.
|
|
73
|
+
|
|
74
|
+
## 5. Accessibility
|
|
75
|
+
|
|
76
|
+
| WCAG SC | How this blueprint complies |
|
|
77
|
+
|---|---|
|
|
78
|
+
| 1.1.1 Non-text content | Product icon decorative (Case A — title sits beside it). If a header icon must stand alone, follow Case B (label + tooltip). |
|
|
79
|
+
| 1.3.1 Info & relationships | Title is exactly one `<h1>` — every route has one and only one. |
|
|
80
|
+
| 1.4.3 Contrast (text) | `--muted-foreground` is ≥ 5.5:1 on `--background`. |
|
|
81
|
+
| 2.1.1 Keyboard | Tab order: breadcrumb → title link (if any) → face rail → primary → overflow trigger. |
|
|
82
|
+
| 2.4.6 Headings / labels | Title strings match `<title>` (document title) where they describe the same route. |
|
|
83
|
+
| 2.4.11 Focus visible | All interactive slots inherit `:focus-visible` ring from `--ring`. |
|
|
84
|
+
|
|
85
|
+
## 6. Variants
|
|
86
|
+
|
|
87
|
+
| Variant | When to use | Differences |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `base` | Default — most routes | Title + actions only |
|
|
90
|
+
| `object-home` | Lists / hubs with optional metrics + tabs **below** the header | Adds a count/freshness slot under the title |
|
|
91
|
+
| `record-home` | Detail / record views | May expose a small detail row (label/value pairs) — keep ≤ 5 pairs |
|
|
92
|
+
| `collaboration` | Shared hubs (Library, future) | Adds face rail + invite entry — see [`exxat-collaboration-access.mdc`](../../../.cursor/rules/exxat-collaboration-access.mdc) |
|
|
93
|
+
|
|
94
|
+
Pick **one** variant per header. Combining `collaboration` with
|
|
95
|
+
`record-home` is allowed only when the record itself is a shareable
|
|
96
|
+
artifact (e.g. a question).
|
|
97
|
+
|
|
98
|
+
## 7. Implementation
|
|
99
|
+
|
|
100
|
+
| Framework | Component(s) | File |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| **React (this app)** | `PageHeader` (shell) + per-hub headers (composition) | [`apps/web/components/page-header.tsx`](../../components/page-header.tsx), [`apps/web/components/library-page-header.tsx`](../../components/library-page-header.tsx) |
|
|
103
|
+
| Mobile | — | — |
|
|
104
|
+
| Figma | — | — |
|
|
105
|
+
|
|
106
|
+
Reference hub-level compositions:
|
|
107
|
+
|
|
108
|
+
- **Placements** — filled primary CTA `New placement` + `⋯` (Export, Customize…)
|
|
109
|
+
- **Team** — same shape, count + freshness in subtitle
|
|
110
|
+
- **Library** — `variant="collaboration"` + folder-scoped customize entry
|
|
111
|
+
|
|
112
|
+
## 8. Do / Don't
|
|
113
|
+
|
|
114
|
+
| ✅ Do | ❌ Don't |
|
|
115
|
+
|---|---|
|
|
116
|
+
| Render exactly one `<h1>` per route | Render two H1s (e.g. one in header + one in body) |
|
|
117
|
+
| Put the primary CTA inside the header — filled, often `size="lg"` | Use `variant="outline"` for the sole primary action on an exportable page |
|
|
118
|
+
| Put **Export** under `⋯` → `ExportDrawer` | Put Export as a second primary button beside New |
|
|
119
|
+
| Use `ExxatProductLogo` for product marks | Substitute a logo.dev raster for the product mark |
|
|
120
|
+
| Keep subtitle to **one line**; truncate long meta | Stack two meta lines below the title |
|
|
121
|
+
| Show keyboard shortcuts via `Kbd` in tooltips on primary/overflow | Hard-code shortcut hints in the visible button label |
|
|
122
|
+
|
|
123
|
+
## 9. References
|
|
124
|
+
|
|
125
|
+
- [`apps/web/docs/data-views-pattern.md`](../data-views-pattern.md) — `PageHeader` in context of `ListPageTemplate`
|
|
126
|
+
- [`apps/web/docs/collaboration-access-pattern.md`](../collaboration-access-pattern.md) — `variant="collaboration"`
|
|
127
|
+
- [`apps/web/docs/library-hub-header-pattern.md`](../library-hub-header-pattern.md) — folder-scoped header
|
|
128
|
+
- [`.cursor/rules/exxat-collaboration-access.mdc`](../../../.cursor/rules/exxat-collaboration-access.mdc)
|
|
129
|
+
- [`.cursor/rules/exxat-mono-ids.mdc`](../../../.cursor/rules/exxat-mono-ids.mdc)
|
|
130
|
+
- [`apps/web/AGENTS.md`](../../AGENTS.md) §4.7, §6.2, §9
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Collaboration & access pattern
|
|
2
2
|
|
|
3
|
-
Shared UI for **who can access a hub** (face stack in the header) and **inviting people** (floating sheet). **Reference:**
|
|
3
|
+
Shared UI for **who can access a hub** (face stack in the header) and **inviting people** (floating sheet). **Reference:** Library — `LibraryPageHeader`, `LibraryClient`, `InviteCollaboratorsDrawer`.
|
|
4
4
|
|
|
5
|
-
**Folder-scoped
|
|
5
|
+
**Folder-scoped library:** When the library URL selects a folder (`?scope=folder&folderId=`), the same header **⋯ More** menu also exposes **Customize folder** (name / color / icon) via **`LibraryNewFolderSheet`** mounted on **`LibraryClient`** so it works on every view tab. See **`docs/library-hub-header-pattern.md`** and **`.cursor/rules/exxat-library-hub-header.mdc`**.
|
|
6
6
|
|
|
7
7
|
## When to use
|
|
8
8
|
|
|
@@ -33,11 +33,11 @@ Shared UI for **who can access a hub** (face stack in the header) and **inviting
|
|
|
33
33
|
|
|
34
34
|
```tsx
|
|
35
35
|
<CollaborationAccessFlow
|
|
36
|
-
initialCollaborators={
|
|
36
|
+
initialCollaborators={LIBRARY_HEADER_COLLABORATORS}
|
|
37
37
|
resourceLabel={hubHeader.title}
|
|
38
38
|
>
|
|
39
39
|
{({ collaborators, openInvite }) => (
|
|
40
|
-
<
|
|
40
|
+
<LibraryPageHeader
|
|
41
41
|
variant="collaboration"
|
|
42
42
|
title={hubHeader.title}
|
|
43
43
|
questionCount={count}
|
|
@@ -100,9 +100,9 @@ Row order:
|
|
|
100
100
|
| Hub flow | `components/collaboration-access-flow.tsx` |
|
|
101
101
|
| Collaborator type | `components/page-header.tsx` (`PageHeaderCollaborator`) |
|
|
102
102
|
| Invite sheet | `components/invite-collaborators-drawer.tsx` |
|
|
103
|
-
| Entity header | `components/
|
|
104
|
-
| Hub wiring | `components/
|
|
105
|
-
| Demo roster | `lib/mock/
|
|
103
|
+
| Entity header | `components/library-page-header.tsx` |
|
|
104
|
+
| Hub wiring | `components/library-client.tsx` |
|
|
105
|
+
| Demo roster | `lib/mock/library-header-collaborators.ts` |
|
|
106
106
|
|
|
107
107
|
## Checklist (new hub)
|
|
108
108
|
|
|
@@ -42,4 +42,4 @@ The command menu is the app’s **global search and AI entry**—one place to ju
|
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
-
Keep this document aligned with **`
|
|
45
|
+
Keep this document aligned with **`apps/web/AGENTS.md` §7.1** when behavior or copy changes.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Exxat DS — Component Selection Guide
|
|
2
|
+
|
|
3
|
+
**Audience:** humans + AI agents. **Companion to:** [`token-taxonomy.md`](./token-taxonomy.md), [`blueprints/`](./blueprints/).
|
|
4
|
+
|
|
5
|
+
When you're about to build a UI, **start here**. Follow the decision tree
|
|
6
|
+
to find the right composition before you write any markup. The rule is
|
|
7
|
+
always: **compose existing components first**; only create a new shared
|
|
8
|
+
primitive after asking the user
|
|
9
|
+
([`exxat-reuse-before-custom.mdc`](../../.cursor/rules/exxat-reuse-before-custom.mdc)).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. Quick chart
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
┌─────────────────────────────────────┐
|
|
17
|
+
│ What is the surface? │
|
|
18
|
+
└──┬──────────────────────────────────┘
|
|
19
|
+
│
|
|
20
|
+
┌───────────┴────────────────────────────┐
|
|
21
|
+
│ │
|
|
22
|
+
PRIMARY HUB OVERLAY / SECONDARY
|
|
23
|
+
(route w/ many records, (on top of a hub,
|
|
24
|
+
filters, properties) modal task, side panel)
|
|
25
|
+
│ │
|
|
26
|
+
│ ▼
|
|
27
|
+
│ See § 3
|
|
28
|
+
▼
|
|
29
|
+
See § 1
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. Building a primary hub (route with records)
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Q: Is the data > ~10 comparable records?
|
|
38
|
+
─────────────────────────────────────────
|
|
39
|
+
│ yes ──────────────────────────────► DataTable inside ListPageTemplate (§1.1)
|
|
40
|
+
│ no ──┬─ all rows shown at once?
|
|
41
|
+
│ │ yes ── simple `<dl>` / card list (no Properties / Filters needed)
|
|
42
|
+
│ │ no ── still use DataTable — future growth is expected
|
|
43
|
+
└─────►
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 1.1 DataTable hub (canonical)
|
|
47
|
+
|
|
48
|
+
| Need | Use |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Browsable grid | **`DataTable`** + **`useTableState`** ([blueprint](./blueprints/data-table.md)) |
|
|
51
|
+
| View tabs (table/list/board/dashboard) | **`ListPageTemplate`** + connected views ([`exxat-list-page-connected-views.mdc`](../../.cursor/rules/exxat-list-page-connected-views.mdc)) |
|
|
52
|
+
| Column/density/properties | **`TablePropertiesDrawer`** (pass `currentView` + `onViewChange`) |
|
|
53
|
+
| Filters | Shared `FilterFieldDef` chips |
|
|
54
|
+
| Find-in-list | Toolbar search (`⌘K`) |
|
|
55
|
+
| Metrics strip | **`KeyMetrics`** `variant="flat"` ([`kpi-flat-band-pattern.md`](./kpi-flat-band-pattern.md)) — **max 4 tiles** ([`exxat-kpi-max-four.mdc`](../../.cursor/rules/exxat-kpi-max-four.mdc)) |
|
|
56
|
+
| Export | Filled primary CTA + `⋯` → `ExportDrawer` |
|
|
57
|
+
| Kanban view body | **`ListPageBoardCard`** + `ListPageBoardTemplate` ([`exxat-board-cards.mdc`](../../.cursor/rules/exxat-board-cards.mdc)) |
|
|
58
|
+
| Folder / panel view body | **`FolderGridView`** / **`FinderPanelView`** wrapped in **`ListPageViewFrame`** ([`exxat-list-page-view-shells.mdc`](../../.cursor/rules/exxat-list-page-view-shells.mdc)) |
|
|
59
|
+
| Dashboard view body | **`KeyMetrics variant="card"`** + a hub-specific chart section (reference: `library-dashboard-charts.tsx`) |
|
|
60
|
+
| Nested scope nav (All / Mine / tree) | **`secondaryPanel`** + `PANELS` + `useAutoPanel` ([`exxat-primary-nav-secondary-panel.mdc`](../../.cursor/rules/exxat-primary-nav-secondary-panel.mdc)) |
|
|
61
|
+
| Shared hub w/ invite | **`PageHeader` `variant="collaboration"`** + `InviteCollaboratorsDrawer` |
|
|
62
|
+
| Dedicated search (empty `?q=` vs results) | **`DedicatedSearchLandingTemplate`** + **`DedicatedSearchResultsHeaderChrome`** |
|
|
63
|
+
|
|
64
|
+
**Reference:** `PlacementsClient` (Placements) is the most complete example.
|
|
65
|
+
|
|
66
|
+
### 1.2 Visual-browse hub (kanban / gallery)
|
|
67
|
+
|
|
68
|
+
If the product wants a **kanban-first** experience and the table is the
|
|
69
|
+
fallback rather than primary:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
ListPageTemplate
|
|
73
|
+
├── PageHeader
|
|
74
|
+
├── KeyMetrics (optional, ≤4)
|
|
75
|
+
└── viewType="board" → ListPageBoardTemplate + ListPageBoardCard
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Even here, **back the board with `useTableState`** so switching to the table
|
|
79
|
+
tab is consistent. Don't fork the data.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. Naming a card / row / list
|
|
84
|
+
|
|
85
|
+
| Pattern | What to reach for |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Dense comparable rows | `DataTable` row (don't card-wall it — see [`card-vs-rows-pattern.md`](./card-vs-rows-pattern.md)) |
|
|
88
|
+
| Kanban column card | `ListPageBoardCard` + `BoardCardTwoLineBlock` + `BoardCardIconRow` |
|
|
89
|
+
| OS-folder grid | `FolderGridView` in `ListPageViewFrame` |
|
|
90
|
+
| Finder split (list + preview) | `FinderPanelView` |
|
|
91
|
+
| Sidebar nav row | `SidebarMenuButton` (do not roll your own) |
|
|
92
|
+
| KPI tile | `KeyMetrics` `MetricItem` — never a custom `Card` w/ number |
|
|
93
|
+
| Coach mark tile | `CoachMark` step — never an ad-hoc onboarding popover |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 3. Same-route overlay vs new route
|
|
98
|
+
|
|
99
|
+
Always ask: **does the user need the hub visible behind them?**
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
┌────────────────────────────┐
|
|
103
|
+
│ Does the user need the hub │
|
|
104
|
+
│ visible behind them? │
|
|
105
|
+
└─────────────┬──────────────┘
|
|
106
|
+
│
|
|
107
|
+
┌───── YES ─────┴───── NO ─────┐
|
|
108
|
+
▼ ▼
|
|
109
|
+
Same route New route
|
|
110
|
+
(overlay) (own URL)
|
|
111
|
+
│ │
|
|
112
|
+
┌─────┴──────┐ │
|
|
113
|
+
│ Is the task│ │
|
|
114
|
+
│ short + │ │
|
|
115
|
+
│ blocking? │ │
|
|
116
|
+
└─────┬──────┘ │
|
|
117
|
+
│ │
|
|
118
|
+
┌─ YES ┴ NO ──┐ │
|
|
119
|
+
▼ ▼ ▼
|
|
120
|
+
Dialog Drawer / Sheet Page route
|
|
121
|
+
(AlertDialog, (TablePropertiesDrawer, (full create/edit
|
|
122
|
+
delete confirm) ExportDrawer, wizard, deep detail)
|
|
123
|
+
InviteCollaboratorsDrawer)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
See [`drawer-vs-dialog-pattern.md`](./drawer-vs-dialog-pattern.md) and
|
|
127
|
+
[`exxat-page-vs-drawer.mdc`](../../.cursor/rules/exxat-page-vs-drawer.mdc).
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 4. Search / Find / Command
|
|
132
|
+
|
|
133
|
+
| Need | Use | Shortcut |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| Find inside a table | `DataTableToolbar` search | `⌘K` / `Ctrl K` (no Alt) |
|
|
136
|
+
| Find inside a hub (across tabs/views) | Same `⌘K` while focus is on the hub | `⌘K` |
|
|
137
|
+
| Global navigation + AI starter | `CommandMenu` ([`command-menu-pattern.md`](./command-menu-pattern.md)) | `⌘K` while no input has focus |
|
|
138
|
+
| Long AI / chat | `AskLeoSidebar` | `⌘⌥K` |
|
|
139
|
+
| Dedicated search page (results view) | `DedicatedSearchLandingTemplate` + `DedicatedSearchResultsHeaderChrome` | — |
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 5. Feedback / messaging
|
|
144
|
+
|
|
145
|
+
| Need | Use |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Persistent banner ("system maintenance") | `SystemBanner` |
|
|
148
|
+
| Per-page contextual info | `LocalBanner` |
|
|
149
|
+
| Per-control success/error | Inline text next to the field |
|
|
150
|
+
| Confirm a destructive action | `AlertDialog` |
|
|
151
|
+
| **Never** | `toast()` / Sonner / snackbars ([`exxat-no-toast.mdc`](../../.cursor/rules/exxat-no-toast.mdc)) |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 6. Icons
|
|
156
|
+
|
|
157
|
+
| Use case | Pattern |
|
|
158
|
+
|---|---|
|
|
159
|
+
| Icon next to a label | FA glyph + `aria-hidden` (Case A) |
|
|
160
|
+
| Icon standing alone (meaning-bearing) | `<span role="img" aria-label="…" tabIndex={0}>` + `Tooltip` (Case B) |
|
|
161
|
+
| Icon-only button / link | `<button aria-label="…">` wrapped in `Tooltip` (Case C) |
|
|
162
|
+
| Product mark | `ExxatProductLogo` |
|
|
163
|
+
| School / org mark | `logoDevUrl()` |
|
|
164
|
+
|
|
165
|
+
Source: `apps/web/AGENTS.md` §8.6.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 7. KPIs / metrics
|
|
170
|
+
|
|
171
|
+
| Need | Use |
|
|
172
|
+
|---|---|
|
|
173
|
+
| Hub metric strip on top of `ListPageTemplate` | `KeyMetrics variant="flat"` |
|
|
174
|
+
| Dashboard view tab key-metrics card | `KeyMetrics variant="card"` (1–4 tiles) |
|
|
175
|
+
| Chart + mini-metric next to it | `ChartCard` + chart's own KPI helpers |
|
|
176
|
+
| Trend arrow on a metric | Set `MetricItem.trend` to match delta sign; set `trendPolarity` when "up" is bad |
|
|
177
|
+
|
|
178
|
+
Cap visible KPIs at **4** ([`exxat-kpi-max-four.mdc`](../../.cursor/rules/exxat-kpi-max-four.mdc)).
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 8. Identifiers and typography
|
|
183
|
+
|
|
184
|
+
| Carries | Use |
|
|
185
|
+
|---|---|
|
|
186
|
+
| System ID (`questionId`, record key) | `font-mono tabular-nums` ([`exxat-mono-ids.mdc`](../../.cursor/rules/exxat-mono-ids.mdc)) |
|
|
187
|
+
| Page title | `<h1>` with `font-heading` (Ivy Presto) inside `PageHeader` |
|
|
188
|
+
| Body | Default Inter, ≥ 11px (`text-xs` minimum) |
|
|
189
|
+
| Status label | `ListHubStatusBadge` from `lib/list-status-badges.ts` — never raw text |
|
|
190
|
+
| Currency / counts | `tabular-nums` (no `font-mono`) |
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 9. When NOTHING here fits
|
|
195
|
+
|
|
196
|
+
You are now in the territory covered by
|
|
197
|
+
[`exxat-reuse-before-custom.mdc`](../../.cursor/rules/exxat-reuse-before-custom.mdc):
|
|
198
|
+
|
|
199
|
+
1. Re-scan `apps/web/components/`, `packages/ui/src/components/`, and `apps/web/components/data-views/`.
|
|
200
|
+
2. Check `AGENTS.md` §9 architecture table.
|
|
201
|
+
3. If still no fit, **ask the user** with a short option list:
|
|
202
|
+
- extend an existing primitive (preferred),
|
|
203
|
+
- add a new component under `components/data-views/` or `components/templates/`,
|
|
204
|
+
- or open a packaged shared primitive in `packages/ui`.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 10. Cheat sheet — one-line rules
|
|
209
|
+
|
|
210
|
+
- **Data list, > 10 rows** → `DataTable` + `ListPageTemplate`.
|
|
211
|
+
- **Visual browse / kanban** → `ListPageBoardCard`.
|
|
212
|
+
- **Folder / panel / OS-folder view** → `data-views/` primitive in `ListPageViewFrame`.
|
|
213
|
+
- **Quick auxiliary task with hub behind** → drawer.
|
|
214
|
+
- **Blocking short confirm** → dialog.
|
|
215
|
+
- **Primary / long / own-URL flow** → new route.
|
|
216
|
+
- **Global ⌘K** → `CommandMenu` (search + quick AI).
|
|
217
|
+
- **Long AI** → Ask Leo (`⌘⌥K`).
|
|
218
|
+
- **Feedback** → banner / inline / dialog — **never** toast.
|
|
219
|
+
- **Icon-only button** → `aria-label` + `Tooltip` (Case C).
|
|
220
|
+
- **System ID** → `font-mono tabular-nums`.
|
|
221
|
+
- **KPI strip** → ≤ 4 tiles, `variant="flat"` on hubs.
|
|
222
|
+
- **Hex color in code** → no. Use a token.
|
|
223
|
+
|
|
224
|
+
See also: [`AGENTS.md` §13 checklist](../AGENTS.md) — run it before shipping a hub.
|