@exxatdesignux/ui 0.2.18 → 0.3.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 +69 -1
- package/bin/sync-extras.mjs +116 -29
- package/consumer-extras/README.md +43 -4
- 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 +41 -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-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-question-bank-hub-header.mdc +28 -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 +2 -2
- package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +1 -1
- package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +9 -9
- package/consumer-extras/cursor-skills/exxat-ds-skill/references/data-table-pattern.md +1 -1
- package/consumer-extras/handbook/HANDBOOK.md +185 -0
- package/consumer-extras/handbook/glossary.md +57 -0
- package/consumer-extras/handbook/reference-implementations.md +126 -0
- package/consumer-extras/handbook/voice-and-tone.md +262 -0
- package/consumer-extras/patterns/command-menu-pattern.md +1 -1
- package/consumer-extras/patterns/data-views-pattern.md +14 -14
- 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 +167 -0
- package/dist/components/data-views/hub-table.js +5561 -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 +6575 -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 +13324 -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 -18
- 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 +255 -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 +498 -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/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 +494 -151
- 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/.cursor/rules/exxat-command-menu.mdc +1 -1
- package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +3 -3
- package/template/.cursor/rules/exxat-data-tables.mdc +1 -1
- package/template/.cursor/rules/exxat-ds-agents.mdc +2 -2
- package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +2 -2
- package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
- package/template/AGENTS.md +84 -20
- package/template/app/(app)/examples/page.tsx +0 -1
- package/template/app/(app)/layout.tsx +17 -4
- package/template/app/(app)/question-bank/layout.tsx +1 -1
- package/template/app/(app)/question-bank/new/page.tsx +11 -24
- package/template/app/globals.css +13 -1972
- 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/compliance-table.tsx +240 -384
- 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-view-dashboard-charts-compliance.tsx +2 -2
- package/template/components/data-view-dashboard-charts-team.tsx +2 -2
- package/template/components/data-view-dashboard-charts.tsx +2 -2
- 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 +42 -1
- 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 -0
- 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 -60
- 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/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/hub-tree-panel-view.tsx +2 -2
- 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/new-placement-back-btn.tsx +1 -1
- package/template/components/new-placement-form.tsx +63 -189
- package/template/components/new-question-composer.tsx +432 -402
- 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/placement-board-card.tsx +71 -83
- package/template/components/placements-board-view.tsx +3 -10
- package/template/components/placements-client.tsx +10 -42
- package/template/components/placements-list-view.tsx +22 -69
- package/template/components/placements-table-columns.tsx +8 -438
- package/template/components/placements-table.tsx +588 -1296
- package/template/components/product-switcher.tsx +1 -1
- package/template/components/product-wordmark.tsx +2 -1
- package/template/components/question-bank-client.tsx +4 -1
- package/template/components/question-bank-hub-client.tsx +1 -1
- package/template/components/question-bank-new-folder-sheet.tsx +2 -2
- package/template/components/question-bank-secondary-nav.tsx +3 -3
- package/template/components/question-bank-table.tsx +294 -526
- package/template/components/rotations-empty-state.tsx +1 -1
- package/template/components/rotations-panel-activator.tsx +1 -1
- package/template/components/settings-appearance-card.tsx +1 -1
- package/template/components/{app-sidebar-dynamic.tsx → sidebar/app-sidebar-dynamic.tsx} +1 -1
- package/template/components/{app-sidebar.tsx → sidebar/app-sidebar.tsx} +4 -4
- package/template/components/sidebar/index.ts +16 -0
- package/template/components/{secondary-nav.tsx → sidebar/secondary-nav.tsx} +2 -2
- package/template/components/{secondary-panel.tsx → sidebar/secondary-panel.tsx} +6 -3
- package/template/components/{sidebar-auto-collapse.tsx → sidebar/sidebar-auto-collapse.tsx} +6 -2
- package/template/components/{sidebar-shell.tsx → sidebar/sidebar-shell.tsx} +1 -1
- package/template/components/site-header.tsx +1 -1
- package/template/components/{sites-all-client.tsx → sites-client.tsx} +1 -1
- package/template/components/sites-table.tsx +124 -257
- 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 -249
- package/template/components/table-properties/drawer.tsx +1 -1105
- 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/team-table.tsx +242 -382
- 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/list-page.tsx +1 -584
- package/template/components/templates/nested-secondary-panel-shell.tsx +1 -62
- package/template/components/templates/new-focus-template.tsx +659 -0
- package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
- 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/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/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 +14 -14
- 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/token-taxonomy.md +416 -0
- package/template/eslint.config.mjs +27 -0
- package/template/hooks/use-secondary-panel-hub-nav.ts +1 -1
- package/template/lib/command-menu-config.ts +0 -1
- package/template/lib/compliance-supported-views.ts +10 -0
- package/template/lib/conditional-rule-match.ts +6 -97
- package/template/lib/data-list-display-options.ts +1 -35
- package/template/lib/data-list-view-registry.ts +1 -0
- package/template/lib/data-list-view-surface.ts +1 -69
- package/template/lib/data-list-view.ts +1 -38
- package/template/lib/dev-log.ts +1 -8
- package/template/lib/editable-target.ts +1 -10
- package/template/lib/hub-connected-view-renderers.ts +58 -0
- package/template/lib/list-hub-supported-views.ts +10 -0
- package/template/lib/list-page-table-properties.ts +1 -52
- package/template/lib/mock/navigation.tsx +0 -8
- package/template/lib/mock/placements.ts +0 -7
- package/template/lib/placement-board-card-layout.ts +41 -41
- package/template/lib/placements-supported-views.ts +12 -0
- package/template/lib/question-bank-supported-views.ts +12 -0
- 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/sites-supported-views.ts +10 -0
- package/template/lib/team-supported-views.ts +10 -0
- package/template/package.json +1 -0
- package/template/tests/setup.ts +25 -0
- package/src/theme.css +0 -1132
- package/template/app/(app)/data-list/[id]/page.tsx +0 -44
- package/template/app/(app)/data-list/new/page.tsx +0 -34
- package/template/app/(app)/data-list/page.tsx +0 -10
- package/template/components/compliance-list-view.tsx +0 -54
- package/template/components/dashboard-onboarding-gallery.tsx +0 -13
- package/template/components/dashboard-onboarding.tsx +0 -21
- package/template/components/question-bank-list-view.tsx +0 -53
- package/template/components/section-cards.tsx +0 -106
- package/template/components/sites-list-view.tsx +0 -42
- package/template/components/team-list-view.tsx +0 -59
- package/template/lib/placement-lifecycle.ts +0 -5
- /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
- /package/template/components/{sidebar-auto-open.tsx → sidebar/sidebar-auto-open.tsx} +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types + design-system constants for the Table Properties drawer
|
|
3
|
+
* and related data-table primitives (filter chips, sort cards,
|
|
4
|
+
* conditional formatting rules).
|
|
5
|
+
*
|
|
6
|
+
* Product-specific seed data (`FILTER_FIELDS` and `COLUMNS` arrays
|
|
7
|
+
* tailored to the Placements hub) intentionally stays in
|
|
8
|
+
* `apps/web/components/table-properties/types.ts` — those values are
|
|
9
|
+
* **product data**, not design-system primitives, and the package must
|
|
10
|
+
* not know about Placement specializations, supervisor labels, etc.
|
|
11
|
+
*
|
|
12
|
+
* Consumers compose their own `FilterFieldDef[]` / `ColDef[]` arrays
|
|
13
|
+
* tailored to their entity (Team members, Compliance items, Question
|
|
14
|
+
* bank rows, …) and pass them into the drawer through props.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Comparison operator vocabulary used by every filter row + conditional rule. */
|
|
18
|
+
export type FilterOperator = "is" | "is_not" | "contains" | "not_contains"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Input mask for `type: "text"` filters. Maps to a
|
|
22
|
+
* [Shadcn Studio input-mask](https://shadcnstudio.com/docs/components/input-mask)
|
|
23
|
+
* pattern key. Add new keys here (and in your concrete `exxatMaskPatterns`
|
|
24
|
+
* map) when a new column needs a structured text format.
|
|
25
|
+
*/
|
|
26
|
+
export type FilterTextMask = "phone" | "zip" | "dateMDY"
|
|
27
|
+
|
|
28
|
+
export interface FilterFieldDef {
|
|
29
|
+
key: string
|
|
30
|
+
label: string
|
|
31
|
+
icon: string
|
|
32
|
+
type: "select" | "text" | "date"
|
|
33
|
+
operators: FilterOperator[]
|
|
34
|
+
/** Select options, or for `date` fields used by conditional rules (exact row strings). */
|
|
35
|
+
options?: { value: string; label: string }[]
|
|
36
|
+
/** When `type` is `text`, optional `use-mask-input` pattern for the value field. */
|
|
37
|
+
textMask?: FilterTextMask
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ActiveFilter {
|
|
41
|
+
id: string
|
|
42
|
+
fieldKey: string
|
|
43
|
+
operator: FilterOperator
|
|
44
|
+
values: string[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface SortRule {
|
|
48
|
+
id: string
|
|
49
|
+
fieldKey: string
|
|
50
|
+
direction: "asc" | "desc"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Operator → human-readable label map (centralized so chips, drawer, and CSV exports stay aligned). */
|
|
54
|
+
export const OPERATOR_LABELS: Record<FilterOperator, string> = {
|
|
55
|
+
is: "is",
|
|
56
|
+
is_not: "is not",
|
|
57
|
+
contains: "contains",
|
|
58
|
+
not_contains: "does not contain",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Column descriptor for `TableProperties` views (Columns / Sort / Group panels). */
|
|
62
|
+
export interface ColDef {
|
|
63
|
+
key: string
|
|
64
|
+
label: string
|
|
65
|
+
sortable: boolean
|
|
66
|
+
sortKey?: string
|
|
67
|
+
minWidth: number
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ─── Conditional formatting ──────────────────────────────────────────── */
|
|
71
|
+
|
|
72
|
+
export interface ConditionalRule {
|
|
73
|
+
id: string
|
|
74
|
+
/** Column key to evaluate */
|
|
75
|
+
fieldKey: string
|
|
76
|
+
operator: FilterOperator
|
|
77
|
+
/** Selected option values (select) or text (single entry) when operator needs values */
|
|
78
|
+
values: string[]
|
|
79
|
+
/** Resolved CSS background color string */
|
|
80
|
+
bgColor: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Predefined palette for conditional rule backgrounds.
|
|
85
|
+
*
|
|
86
|
+
* Backgrounds are exposed as CSS custom properties so theming swaps the
|
|
87
|
+
* palette per brand without code edits (`--conditional-rule-green`,
|
|
88
|
+
* `--conditional-rule-yellow`, etc., declared in
|
|
89
|
+
* `packages/ui/src/globals.css`).
|
|
90
|
+
*/
|
|
91
|
+
export const RULE_COLORS: { name: string; bg: string }[] = [
|
|
92
|
+
{ name: "Green", bg: "var(--conditional-rule-green)" },
|
|
93
|
+
{ name: "Yellow", bg: "var(--conditional-rule-yellow)" },
|
|
94
|
+
{ name: "Blue", bg: "var(--conditional-rule-blue)" },
|
|
95
|
+
{ name: "Red", bg: "var(--conditional-rule-red)" },
|
|
96
|
+
{ name: "Purple", bg: "var(--conditional-rule-purple)" },
|
|
97
|
+
{ name: "Orange", bg: "var(--conditional-rule-orange)" },
|
|
98
|
+
]
|
|
@@ -5,14 +5,14 @@ alwaysApply: true
|
|
|
5
5
|
|
|
6
6
|
# Exxat DS — Data view dashboard (list hubs)
|
|
7
7
|
|
|
8
|
-
**Authoritative detail:** **`
|
|
8
|
+
**Authoritative detail:** **`apps/web/AGENTS.md` §4.3** and **`exxat-dashboard-view-charts`** (this rule).
|
|
9
9
|
|
|
10
10
|
## Two dashboard surfaces (do not fork chart engines)
|
|
11
11
|
|
|
12
12
|
| Surface | Entry | Shared building blocks |
|
|
13
13
|
|--------|--------|-------------------------|
|
|
14
14
|
| **Full-page dashboard** | `app/(app)/dashboard/page.tsx` | `DashboardTabs`, `ChartsOverview` / gallery demos in `charts-overview.tsx` |
|
|
15
|
-
| **Data tab** on Placements / Team / Compliance | `
|
|
15
|
+
| **Data tab** on Placements / Team / Compliance | `PlacementsTable`, `TeamTable`, `ComplianceTable` → `*DashboardChartsSection` | `ChartFigure`, `ChartCard`, `useChartVariant()`, `data-view-dashboard-charts*.tsx` |
|
|
16
16
|
|
|
17
17
|
**MUST NOT** duplicate “another” chart system for Data view — extend **`charts-overview`** patterns and **`lib/chart-keyboard-selection`**.
|
|
18
18
|
|
|
@@ -49,5 +49,5 @@ alwaysApply: true
|
|
|
49
49
|
|
|
50
50
|
- `components/data-view-dashboard-charts.tsx` (Placements)
|
|
51
51
|
- `components/data-view-dashboard-charts-team.tsx`, `data-view-dashboard-charts-compliance.tsx`
|
|
52
|
-
- `components/
|
|
52
|
+
- `components/placements-table.tsx` — dashboard tab body wires `PlacementsDashboardChartsSection` + layout-edit toolbar inline (no separate `DashboardShell` component)
|
|
53
53
|
- `lib/chart-keyboard-selection.ts`, `lib/data-view-dashboard-storage.ts`, `lib/dashboard-customize-coach-mark.ts`
|
|
@@ -16,7 +16,7 @@ For **any app screen that shows a browsable, filterable grid of records** (lists
|
|
|
16
16
|
5. **Active view:** On **`ListPageTemplate`** pages with **table / list / board / dashboard** tabs, **`TablePropertiesDrawer`** **MUST** receive **`currentView`** and **`onViewChange`** (see **`./AGENTS.md` §4.2** and **`.cursor/rules/exxat-table-properties-drawer.mdc`**) so Properties matches the selected view (not table-only copy on Board).
|
|
17
17
|
6. **Dropdown menus:** **`DropdownMenuContent`** uses the shared **`@exxatdesignux/ui`** default (**intrinsic `w-max`**, **`min-w-52`**, capped **`max-w`**) for view settings, row ⋯, column menus, and filter pickers — **pure CSS**, no **`ResizeObserver`**. Override only for deliberate narrow/wide rails (e.g. pagination **`w-20`**, account trigger-width, school switcher **`!w-max min-w-72 …`**). See **`docs/data-views-pattern.md`** (“Dropdown menus”).
|
|
18
18
|
|
|
19
|
-
**Reference implementation:** `components/
|
|
19
|
+
**Reference implementation:** `components/placements-table.tsx` (placements) shows how `DataTable`, filters, and `TablePropertiesDrawer` compose together.
|
|
20
20
|
|
|
21
21
|
## Do not
|
|
22
22
|
|
|
@@ -10,9 +10,9 @@ alwaysApply: true
|
|
|
10
10
|
## Non‑negotiables (if anything conflicts, open AGENTS.md §12–§13)
|
|
11
11
|
|
|
12
12
|
1. **Product data lists** → `DataTable` + search + shared filters + `TablePropertiesDrawer` — not raw `<table>` / ui `Table` alone / ad-hoc grids. With **`ListPageTemplate`** view tabs, pass **`currentView`** + **`onViewChange`** into **`TablePropertiesDrawer`** (**`AGENTS.md` §4.2**, **`.cursor/rules/exxat-table-properties-drawer.mdc`**).
|
|
13
|
-
2. **Main `DataTable` surface** → wrapped in **`ListPageTemplate`** (view tabs). All tab view types share **`useTableState`**; list/board/dashboard read **`tableState.rows`**. Reference: `
|
|
13
|
+
2. **Main `DataTable` surface** → wrapped in **`ListPageTemplate`** (view tabs). All tab view types share **`useTableState`**; list/board/dashboard read **`tableState.rows`**. Reference: `PlacementsClient`, `TeamClient`, `TeamTable`.
|
|
14
14
|
3. **Do not double-indent** the toolbar/table — avoid extra `px`/`mx` wrappers around `DataTable` when it already applies horizontal inset.
|
|
15
|
-
4. **Primary hub + large/complex data** → same composition as Placements/Team: `ListPageTemplate` + metrics/export pattern as in `
|
|
15
|
+
4. **Primary hub + large/complex data** → same composition as Placements/Team: `ListPageTemplate` + metrics/export pattern as in `PlacementsClient` / `TeamClient`, not `PageHeader`-only.
|
|
16
16
|
5. **Exportable pages** → filled primary CTA; **⋯** menu with Export → `ExportDrawer` pattern (see `PlacementsPageHeader`).
|
|
17
17
|
6. **Keyboard hints** → `.cursor/rules/exxat-kbd-shortcuts.mdc`; pair hints with behavior.
|
|
18
18
|
7. **Accessibility** → `.cursor/rules/exxat-accessibility.mdc` + **`AGENTS.md` §8** + `.cursor/skills/exxat-accessibility/SKILL.md` when present in your workspace.
|
|
@@ -96,5 +96,5 @@ Adjust this table when adding new global shortcuts.
|
|
|
96
96
|
|
|
97
97
|
## See also
|
|
98
98
|
|
|
99
|
-
- **`
|
|
100
|
-
- **`
|
|
99
|
+
- **`apps/web/AGENTS.md`** §7 — keyboard rules in project context.
|
|
100
|
+
- **`apps/web/AGENTS.md`** §7.1 — global command palette (⌘K) vs **Ask Leo** (**⌘⌥K**); **`apps/web/docs/command-menu-pattern.md`**.
|
|
@@ -28,7 +28,7 @@ When **`ListPageTemplate`** drives **`tab.viewType`** and the page renders **`Ta
|
|
|
28
28
|
|
|
29
29
|
3. Thread **`view`** and **`onViewChange`** through: **client → table component → drawer toolbar → `TablePropertiesDrawer`**.
|
|
30
30
|
|
|
31
|
-
**Reference implementations:** `components/
|
|
31
|
+
**Reference implementations:** `components/placements-table.tsx` (`PlacementsTable`), `components/team-client.tsx` + `team-table.tsx`, `components/compliance-client.tsx` + `compliance-table.tsx`.
|
|
32
32
|
|
|
33
33
|
## MUST NOT
|
|
34
34
|
|
package/template/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Purpose:** One place for product patterns so tools (Cursor, Codex, etc.) and contributors apply the same rules. **Imperative sections** use MUST / MUST NOT / SHOULD so they are easy to parse.
|
|
4
4
|
|
|
5
|
-
**Scope:** The Next.js app in this directory. **Path:** If your workspace root is only this folder, use **`./AGENTS.md`**. If the workspace is the parent
|
|
5
|
+
**Scope:** The Next.js app in this directory. **Path:** If your workspace root is only this folder, use **`./AGENTS.md`**. If the workspace is the parent monorepo, use **`apps/web/AGENTS.md`** (this file).
|
|
6
6
|
|
|
7
7
|
Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tables, keyboard hints, accessibility) when the parent repo is open.
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tab
|
|
|
14
14
|
2. **Before** changing **keyboard hints or shortcuts**, read **§7** and root `.cursor/rules/exxat-kbd-shortcuts.mdc`.
|
|
15
15
|
3. **Before** changing **table behavior**, read **§3** and root `.cursor/rules/exxat-data-tables.mdc`. **Before** wiring **`TablePropertiesDrawer`** on **`ListPageTemplate`** (view tabs), read **§4.2** and **`.cursor/rules/exxat-table-properties-drawer.mdc`**.
|
|
16
16
|
4. **Before** building or changing **tabs, nav, dialogs, icon-only controls, or color/contrast**, read **§8** and **`.cursor/skills/exxat-accessibility/SKILL.md`** (from monorepo root when the parent repo is open).
|
|
17
|
-
5. **Before** adding or changing **Data view charts** (dashboard tab on list hubs) or **graph keyboard styling**, read **§4.3** and **`
|
|
17
|
+
5. **Before** adding or changing **Data view charts** (dashboard tab on list hubs) or **graph keyboard styling**, read **§4.3** and **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`**.
|
|
18
18
|
6. **Before** adding or changing **board (kanban) cards** on list hubs, read **§4.4** and the **`exxat-board-cards`** skill (**`.cursor/skills/`** or **`.claude/skills/`** at repo root — same content).
|
|
19
19
|
7. **Before** adding **folder, panel, or other non-table view bodies** (centered grids, reusable shells), read **§4.5** and **`.cursor/rules/exxat-list-page-view-shells.mdc`** / **`.cursor/skills/exxat-list-page-view-shells/SKILL.md`**.
|
|
20
20
|
8. **Before** adding or changing **Font Awesome** icons in app UI, read **`.cursor/rules/exxat-fontawesome-icons.mdc`** (Kit subsetting, weights, **`aria-hidden`** on **`<i>`**).
|
|
@@ -36,6 +36,8 @@ Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tab
|
|
|
36
36
|
21. **Before** styling **`KeyMetrics variant="flat"`** (list hub metrics strip, dashboard mix KPI band), read **`docs/kpi-flat-band-pattern.md`** and **`.cursor/rules/exxat-kpi-flat-band.mdc`** / **`.cursor/skills/exxat-kpi-flat-band/SKILL.md`** (transparent band, OKLCH glow, border hairlines only).
|
|
37
37
|
22. **Before** changing **secondary panel** or **sidebar** brand chrome, read **`docs/shell-surface-elevation-pattern.md`** and **§4.6** ( **`--secondary-panel-bg`**, active product theme).
|
|
38
38
|
23. **Before** adding **new shared UI primitives** or bespoke widgets when nothing in **`components/`** fits after scanning, follow **`.cursor/rules/exxat-reuse-before-custom.mdc`** — **ask the user** for direction unless the task already approved a greenfield build.
|
|
39
|
+
24. **Before** introducing a **color, spacing, radius, or shadow value** in JSX `className`, inline `style`, CSS, or a `cn()` / `clsx()` argument, read **`docs/token-taxonomy.md`** and **`.cursor/rules/exxat-token-discipline.mdc`**. **New code SHOULD reach for the L0 Exxat namespace first** (`var(--exxat-color-surface-1)`, `bg-surface-1`, `bg-brand-1`, `rounded-2`, …) — the older shadcn-style names (`--background`, `bg-brand`, `rounded-md`, …) remain as L1 aliases and continue to work. No hex literals in app code; check `packages/ui/tokens/hooks-index.json` for available tokens + deprecations (163 tokens · 36 namespaces). ESLint catches violations via `exxat-ds/no-hex-color` + `exxat-ds/no-deprecated-tokens` (plugin: **`@exxatdesignux/eslint-plugin`**).
|
|
40
|
+
25. **Before** adopting any pattern from a **sibling Salesforce / SLDS / LWC** repo (e.g. `design-system-2-starter-kit`), read **`.cursor/rules/exxat-no-slds-leakage.mdc`**. **No** `slds-*` classes, **no** `<lightning-*>` markup, **no** synthetic-shadow assumptions, **no** SLDS token names (`--slds-g-color-*`). Document architectural ideas as Exxat blueprints (`docs/blueprints/`) instead of copying SLDS code.
|
|
39
41
|
|
|
40
42
|
**Longer narrative and architecture:** `docs/data-views-pattern.md`, `docs/drawer-vs-dialog-pattern.md`, `docs/card-vs-rows-pattern.md`, `docs/kpi-strip-max-four-pattern.md`, **`docs/kpi-flat-band-pattern.md`**, **`docs/shell-surface-elevation-pattern.md`**, `docs/command-menu-pattern.md`, `docs/collaboration-access-pattern.md` (keep in sync with this handbook for big refactors).
|
|
41
43
|
|
|
@@ -45,7 +47,7 @@ Cross-cutting Cursor rules also live in the repo root `.cursor/rules/` (data tab
|
|
|
45
47
|
|
|
46
48
|
1. **User / task instructions** in the current session (highest).
|
|
47
49
|
2. This **`AGENTS.md`** for Exxat DS product patterns.
|
|
48
|
-
3. **`.cursor/rules/*.mdc`** at repo root (`exxat-data-tables`, `exxat-list-page-connected-views`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-table-properties-drawer`, `exxat-board-cards`, `exxat-page-vs-drawer`, `exxat-drawer-vs-dialog`, `exxat-card-vs-list-rows`, `exxat-kpi-max-four`, `exxat-reuse-before-custom`, `exxat-no-toast`, `exxat-kbd-shortcuts`, `exxat-accessibility`, `exxat-fontawesome-icons`, **`exxat-mono-ids`**, `exxat-primary-nav-secondary-panel`, `exxat-collaboration-access`, `exxat-ds-agents`) and any rules under **`
|
|
50
|
+
3. **`.cursor/rules/*.mdc`** at repo root (`exxat-data-tables`, `exxat-list-page-connected-views`, `exxat-centralized-list-dataset`, `exxat-list-page-view-shells`, `exxat-table-properties-drawer`, `exxat-board-cards`, `exxat-page-vs-drawer`, `exxat-drawer-vs-dialog`, `exxat-card-vs-list-rows`, `exxat-kpi-max-four`, `exxat-reuse-before-custom`, `exxat-no-toast`, `exxat-kbd-shortcuts`, `exxat-accessibility`, `exxat-fontawesome-icons`, **`exxat-mono-ids`**, `exxat-primary-nav-secondary-panel`, `exxat-collaboration-access`, `exxat-ds-agents`) and any rules under **`apps/web/.cursor/rules/`** (including **`exxat-dashboard-view-charts`** for Data view charts).
|
|
49
51
|
4. Project **skills** under `.cursor/skills/` when relevant — e.g. **shadcn**, **exxat-accessibility** (WCAG / ARIA / touch / contrast), **exxat-board-cards** (kanban card shell, status badges, primitives), **exxat-list-page-view-shells** (centered view bodies, **`ListPageViewFrame`**), **exxat-centralized-list-dataset** (one **`useTableState`** row bag + shared maps across all list-hub views and **`TablePropertiesDrawer`**), **exxat-collaboration-access** (face rail + invite sheet + library access), **exxat-dedicated-search-surfaces** (landing vs results split, **`DedicatedSearch*`** templates + recents without hydration drift), **exxat-drawer-vs-dialog**, **exxat-card-vs-list-rows**, **exxat-kpi-max-four**, **`exxat-mono-ids`** (monospace system identifiers).
|
|
50
52
|
|
|
51
53
|
If two documents conflict, prefer the **more specific** rule for the file type, then **newer** team decisions captured in `AGENTS.md`.
|
|
@@ -63,7 +65,7 @@ If two documents conflict, prefer the **more specific** rule for the file type,
|
|
|
63
65
|
| Filters | Use the **shared filter model** (`FilterFieldDef`, operators, chips) consistent with existing list pages. |
|
|
64
66
|
| Table properties | Expose **Table properties** via **`TablePropertiesDrawer`** (`@/components/table-properties`) — columns, density, related options — same pattern as Placements / data list. |
|
|
65
67
|
|
|
66
|
-
**Reference:** `components/
|
|
68
|
+
**Reference:** `components/placements-table.tsx`, `components/data-table/`.
|
|
67
69
|
|
|
68
70
|
**MUST NOT:** Build product list pages with only `@/components/ui/table`, raw `<table>`, or a third-party grid that bypasses this stack.
|
|
69
71
|
|
|
@@ -75,7 +77,7 @@ If two documents conflict, prefer the **more specific** rule for the file type,
|
|
|
75
77
|
|
|
76
78
|
**MUST:** If the main surface is a **`DataTable`** (or equivalent data grid), wrap it in **`ListPageTemplate`** so the **views toolbar** exists (tabs, add view, per-tab settings). Do **not** place `DataTable` only under `PageHeader` without the tab shell.
|
|
77
79
|
|
|
78
|
-
**Reference implementations:** `components/
|
|
80
|
+
**Reference implementations:** `components/placements-client.tsx` (Placements), `components/team-client.tsx` (Team).
|
|
79
81
|
|
|
80
82
|
**Rationale:** Consistent navigation, saved views, per-tab view type (table / list / board / dashboard), export at template level.
|
|
81
83
|
|
|
@@ -104,7 +106,38 @@ If two documents conflict, prefer the **more specific** rule for the file type,
|
|
|
104
106
|
|
|
105
107
|
Thread **`view`** and **`onViewChange`** from the **client** → **table / toolbar wrapper** → **`TablePropertiesDrawer`**. If **`currentView`** is omitted, the drawer defaults to **table** labels and controls even on **Board**, which is incorrect.
|
|
106
108
|
|
|
107
|
-
**Reference:** `components/
|
|
109
|
+
**Reference:** `components/placements-table.tsx`, `components/team-table.tsx`, `components/compliance-table.tsx`. Root **`.cursor/rules/exxat-table-properties-drawer.mdc`**.
|
|
110
|
+
|
|
111
|
+
#### Deep-linking the drawer to a specific panel
|
|
112
|
+
|
|
113
|
+
`TablePropertiesDrawer` accepts an optional **`initialPanel`** prop so callsites can open the drawer focused on a named panel — `"main"` (default), `"table-display"`, `"filter"`, `"sort"`, `"group"`, `"columns"`, or `"conditional-rules"`. The current built-in use is the **Add Conditional Rule** item in every column header menu, which deep-links to the **Conditional rules** panel.
|
|
114
|
+
|
|
115
|
+
**MUST**:
|
|
116
|
+
|
|
117
|
+
1. `useTableState` exposes **`sheetInitialPanel`** + **`setSheetInitialPanel`** alongside `sheetOpen` / `setSheetOpen`. Pass **`initialPanel={sheetInitialPanel}`** to `TablePropertiesDrawer` from the toolbar / button wrapper. Reference: `packages/ui/src/components/table-properties/drawer-button.tsx`.
|
|
118
|
+
2. The toolbar **Properties** button MUST clear the deep-link before opening so a plain "open Properties" click always lands on the main index panel:
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
onClick={() => {
|
|
122
|
+
setSheetInitialPanel?.(null)
|
|
123
|
+
setSheetOpen(true)
|
|
124
|
+
}}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
3. Deep-link callsites MUST set panel + open in **the same batched setState call** so the drawer mounts with the right panel in one render:
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
setSheetInitialPanel("conditional-rules")
|
|
131
|
+
setSheetOpen(true)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
4. From inside a Radix `DropdownMenu`, queue the work into `onCloseAutoFocus` (see `columnMenuPendingActionRef` in `packages/ui/src/components/data-table/index.tsx`) — opening the non-modal Sheet synchronously from `onSelect` races with the menu close cycle.
|
|
135
|
+
|
|
136
|
+
**MUST NOT**: introduce a second source of truth for "which panel" — `sheetInitialPanel` is the only deep-link channel; the drawer's internal `sheetPanel` stays internal.
|
|
137
|
+
|
|
138
|
+
#### View-type tile grid
|
|
139
|
+
|
|
140
|
+
The drawer's "View type" tile grid (and the Export drawer's "File format" grid) renders through `SelectionTileGrid` with `interaction="button"` + `labelPlacement="inside"`. The shared `selectionTileClassNames` utility applies **`aspect-square`** + `leading-tight` so every tile is the same uniform square regardless of how many tiles populate the last row of the `grid-cols-N` track. **Prefer** the shared `SelectionTileGrid` (or `selectionTileClassNames` directly) instead of inventing flex/grid wrappers for tile-style pickers — that's the only way to keep the squares uniform across the system.
|
|
108
141
|
|
|
109
142
|
### 4.3 Data view dashboard — charts, customisation, and parity with the gallery
|
|
110
143
|
|
|
@@ -115,13 +148,13 @@ Thread **`view`** and **`onViewChange`** from the **client** → **table / toolb
|
|
|
115
148
|
| **Accessibility** | Each chart uses **`ChartFigure`** (keyboard + live region) and **`ChartDataTable`** (`sr-only` table fallback), inside **`ChartCard`** — same stack as **`charts-overview.tsx`**. **MUST NOT** ship bare Recharts-only charts on these surfaces. |
|
|
116
149
|
| **Two “dashboard” surfaces** | The **`/dashboard`** route uses **`DashboardTabs`** + **`ChartsOverview`** (gallery / demos). The **Data** tab on list hubs uses **`*DashboardChartsSection`** (`PlacementsDashboardChartsSection`, Team, Compliance) and **`data-view-dashboard-charts*.tsx`**. Both share **`ChartFigure`**, **`ChartCard`**, and **`useChartVariant()`**; they are **not** duplicate chart engines — product charts belong in the shared components above. |
|
|
117
150
|
| **Keyboard selection (bars & pies)** | Match the **`/dashboard` gallery**: use **`CHART_KBD_ACTIVE_BAR`** and **`CHART_KBD_ACTIVE_PIE_SHAPE`** from **`@/lib/chart-keyboard-selection`** with Recharts **`activeBar` + `activeIndex`** on **`Bar`** and **`activeShape` + `activeIndex`** on **`Pie`**. **MUST NOT** rely on **`fillOpacity` dimming alone** on **`Cell`** as the only keyboard-selected state — it diverges from the gallery and from WCAG-aligned focus feedback. |
|
|
118
|
-
| **Customise UI** | Toggle **Edit layout** on the hub dashboard toolbar
|
|
151
|
+
| **Customise UI** | Toggle **Edit layout** on the hub dashboard toolbar inside **`PlacementsTable`** / **`TeamTable`** / **`ComplianceTable`** (the dashboard tab body renders `*DashboardChartsSection` directly — there is no shared `DashboardShell` wrapper). **`layoutEditMode`** shows on-canvas drag reorder, remove, width (half / full width), chart type, add chart, reset — **no** separate Sheet for layout. Target for coach marks: **`[aria-label='Edit dashboard layout']`**. |
|
|
119
152
|
| **Toolbar in edit mode** | Do **not** render **`DataTableToolbar`** while **`layoutEditMode`** — hides search, filters, **Properties**, and the edit affordance in one row. Canvas **Done** / **Cancel** / **Reset** stay on the charts section. |
|
|
120
153
|
| **Key metrics card** | Dashboard **`key-metrics`** uses **`KeyMetrics`** **`variant="card"`** (not **`flat`**). Users choose how many KPIs to show (**1–4**) via the canvas control in edit mode; persist **`keyMetricsKpiCount`** in the same layout object. Half-width (**span 1**) sets **`metricsHalfWidthLayout`**. |
|
|
121
154
|
| **Data wiring** | **`PlacementsDashboardChartsSection`** (and Team / Compliance equivalents) **MUST** receive **`cardSpans`** and **`cardChartTypes`** (or rely on defaults **inside** the component). **MUST NOT** omit them without defaults — runtime crash (`undefined[id]`). |
|
|
122
155
|
| **Persistence (centralized)** | Layout for all three hubs is stored in one bundle: **`lib/data-view-dashboard-storage.ts`** (`exxat-ds:data-view-dashboards:v1`, scopes **`placements` \| `team` \| `compliance`**). Placements wrappers: **`loadDashboardLayout`** / **`saveDashboardLayout`**; generic API: **`loadDataViewLayout`** / **`saveDataViewLayout`**. Legacy per-hub keys are migrated when a scope is missing. **MUST NOT** add a fourth localStorage key pattern for the same layout shape without extending this module. |
|
|
123
156
|
|
|
124
|
-
**Reference:** `components/data-view-dashboard-charts.tsx
|
|
157
|
+
**Reference:** `components/data-view-dashboard-charts.tsx` (`PlacementsDashboardChartsSection`), `data-view-dashboard-charts-team.tsx`, `data-view-dashboard-charts-compliance.tsx`, `components/placements-table.tsx` (dashboard tab body wires the section + edit toolbar inline), `lib/chart-keyboard-selection.ts`, `lib/data-view-dashboard-storage.ts`, **`apps/web/.cursor/rules/exxat-dashboard-view-charts.mdc`**.
|
|
125
158
|
|
|
126
159
|
### 4.4 Board cards (kanban)
|
|
127
160
|
|
|
@@ -133,8 +166,8 @@ Thread **`view`** and **`onViewChange`** from the **client** → **table / toolb
|
|
|
133
166
|
| **Information hierarchy** | **(1)** **`ListPageBoardCardTitleRow`** — title + optional **`ListPageBoardCardAvatar`** (`trailing`). **(2)** **`ListPageBoardCardBadgeRow`** — status / tags as **`Badge`** chips when the entity has a status (not raw body text for status). **(3)** **`ListPageBoardCardBody`** — facts via **`BoardCardTwoLineBlock`** and/or **`BoardCardIconRow`** from **`board-card-primitives.tsx`**. **(4)** Optional **`ListPageBoardCardSecondary`** for empty-state hints. |
|
|
134
167
|
| **Facts rows** | Prefer **`BoardCardTwoLineBlock`** (icon + primary line + optional secondary line) so rows match Placements. **`line2`** may be omitted for a single-line fact. Use **`BoardCardIconRow`** when the cell mirrors **`ColumnDef` cell renderers** (e.g. Placements). |
|
|
135
168
|
| **Avatar** | Use **`ListPageBoardCardAvatar`** with entity **`initials`** when present; otherwise derive with **`initialsFromDisplayName`** from **`lib/initials-from-name.ts`** (e.g. compliance owner name). |
|
|
136
|
-
| **Status labels + colors** | **All list hubs** (**Placements**, **Team**, **Compliance**, **Question bank**, …) **MUST** define status **labels**, **tint classes**, and **icons** in **`lib/list-status-badges.ts`**. Render with **`ListHubStatusBadge`**, or **`StatusBadge`** from **`components/
|
|
137
|
-
| **Placements-specific** | **`BoardPlacementCard`** may keep domain logic (lifecycle tabs, conditional row background, **`TablePropertiesDrawer`** column wiring); it still composes **`ListPageBoardCard`** parts and primitives. **Placements** status uses **`StatusBadge`** in **`components/
|
|
169
|
+
| **Status labels + colors** | **All list hubs** (**Placements**, **Team**, **Compliance**, **Question bank**, …) **MUST** define status **labels**, **tint classes**, and **icons** in **`lib/list-status-badges.ts`**. Render with **`ListHubStatusBadge`**, or **`StatusBadge`** from **`components/placements-table-cells.tsx`** for Placements (wrapper over **`ListHubStatusBadge`** + **`PLACEMENT_STATUS_*`**). **`surface="table"`** for **`DataTable`** / **list** rows; **`surface="board"`** in **`ListPageBoardCardBadgeRow`**. **SHOULD** map values onto **`LIST_HUB_STATUS_TINT_*`** (success / warning / neutral / danger / **info**) before inventing new palettes. **MUST NOT** duplicate maps in feature files or add **`uppercase`** / **`tracking-wide`**. |
|
|
170
|
+
| **Placements-specific** | **`BoardPlacementCard`** may keep domain logic (lifecycle tabs, conditional row background, **`TablePropertiesDrawer`** column wiring); it still composes **`ListPageBoardCard`** parts and primitives. **Placements** status uses **`StatusBadge`** in **`components/placements-table-cells.tsx`**, which wraps **`ListHubStatusBadge`** with **`PLACEMENT_STATUS_*`** maps in **`lib/list-status-badges.ts`** (same system as other hubs). |
|
|
138
171
|
|
|
139
172
|
**Reference:** **`components/data-views/placement-board-card.tsx`**, **`components/team-board-view.tsx`**, **`components/compliance-board-view.tsx`**, **`components/question-bank-board-view.tsx`**, **`components/list-hub-status-badge.tsx`**, **`lib/list-status-badges.ts`**, **`components/data-views/list-page-board-template.tsx`**. **Skill (Cursor + Claude):** **`.cursor/skills/exxat-board-cards/SKILL.md`** and **`.claude/skills/exxat-board-cards/SKILL.md`** (duplicate for Claude Code).
|
|
140
173
|
|
|
@@ -236,7 +269,7 @@ Match **Placements**:
|
|
|
236
269
|
|
|
237
270
|
**Primary nav destinations** that show **large or highly interactive** datasets **MUST** use the **primary page template**:
|
|
238
271
|
|
|
239
|
-
- **`ListPageTemplate`** + **`KeyMetrics`** (when metrics apply) + export wiring + the same **client composition** as **`
|
|
272
|
+
- **`ListPageTemplate`** + **`KeyMetrics`** (when metrics apply) + export wiring + the same **client composition** as **`PlacementsClient`** / **`TeamClient`** — not a minimal `PageHeader`-only layout for that hub.
|
|
240
273
|
|
|
241
274
|
**MUST NOT** treat a main hub table page as a “light” sub-section: use the same shell as Placements (tabs, optional metrics strip, template-level export).
|
|
242
275
|
|
|
@@ -428,18 +461,18 @@ Reference: `components/new-placement-form.tsx` (Next/Back buttons); full shortcu
|
|
|
428
461
|
| View tabs + shell | `ListPageTemplate` | `components/templates/list-page.tsx` |
|
|
429
462
|
| Table + toolbar | `DataTable`, `DataTableToolbar`, `useTableState` | `components/data-table/` |
|
|
430
463
|
| Properties | `TablePropertiesDrawer` (+ **`currentView`** / **`onViewChange`** when using view tabs — §4.2) | `@/components/table-properties` |
|
|
431
|
-
| Placements flow | `
|
|
464
|
+
| Placements flow | `PlacementsClient`, `PlacementsTable` | `components/placements-client.tsx`, `components/placements-table.tsx` |
|
|
432
465
|
| Team flow | `TeamClient`, `TeamTable`, `TeamPageHeader` | `components/team-client.tsx`, etc. |
|
|
433
|
-
| Dashboard view tab (KPIs + charts) | **`DashboardReportCharts`**; default **`ChartsOverview`** (placement demo). **Team** passes **`chartsSection`** (`TeamDashboardChartsSection`) so graphs match roster rows. KPIs from **`tableState.rows`** | `components/dashboard-report-charts.tsx`, `data-view-dashboard-charts-team.tsx`, `
|
|
466
|
+
| Dashboard view tab (KPIs + charts) | **`DashboardReportCharts`**; default **`ChartsOverview`** (placement demo). **Team** passes **`chartsSection`** (`TeamDashboardChartsSection`) so graphs match roster rows. KPIs from **`tableState.rows`** | `components/dashboard-report-charts.tsx`, `data-view-dashboard-charts-team.tsx`, `placements-table.tsx` |
|
|
434
467
|
| Data view layout + graph keyboard tokens | **`loadDataViewLayout` / `saveDataViewLayout`**, **`CHART_KBD_ACTIVE_BAR`**, **`CHART_KBD_ACTIVE_PIE_SHAPE`** | `lib/data-view-dashboard-storage.ts`, `lib/chart-keyboard-selection.ts` |
|
|
435
|
-
| Customize dashboard coach marks | Shared steps in **`lib/dashboard-customize-coach-mark.ts`**; flows **`placements-dashboard-customize`**, **`team-dashboard-customize`**, **`compliance-dashboard-customize`** | `hooks/use-coach-mark.ts` (`enabled`, `dependsOnDismissedFlowId`), `
|
|
468
|
+
| Customize dashboard coach marks | Shared steps in **`lib/dashboard-customize-coach-mark.ts`**; flows **`placements-dashboard-customize`**, **`team-dashboard-customize`**, **`compliance-dashboard-customize`** | `hooks/use-coach-mark.ts` (`enabled`, `dependsOnDismissedFlowId`), `placements-table.tsx`, `team-table.tsx`, `compliance-table.tsx` |
|
|
436
469
|
| Board columns (simple hubs) | **`ListPageBoardTemplate`** + **`ListPageBoardCard`** + primitives + **`lib/list-status-badges`** + **`ListHubStatusBadge`** (when applicable) | `components/data-views/list-page-board-template.tsx`, `list-hub-status-badge.tsx`, `team-board-view.tsx`, **`§4.4`** |
|
|
437
470
|
| Full dashboard route | `DashboardTabs`, `KeyMetrics`, `ChartsOverview` | `app/(app)/dashboard/page.tsx`, `components/dashboard-tabs.tsx` |
|
|
438
471
|
| Board cards | **`ListPageBoardCard`** + primitives + entity card (**§4.4**) | `components/data-views/list-page-board-card.tsx`, `board-card-primitives.tsx`, `placement-board-card.tsx` |
|
|
439
472
|
| **Application sidebar** (school/program, product, profile, child nav) | **`AppSidebar`**, **`TeamSwitcher`**, **`NavUser`**, collapsible + **popover** (icon rail) | `components/app-sidebar.tsx`, `nav-user.tsx`, `product-switcher.tsx`, `lib/mock/navigation.tsx`, `lib/logo-dev.ts`, `lib/stock-portrait.ts` — patterns in **exxat-ds-skill §3.1** |
|
|
440
473
|
| **Collaboration & access** (face rail + invite sheet) | **`PageHeader` `variant="collaboration"`**, **`InviteCollaboratorsDrawer`**, **`lib/collaborator-access.ts`** | `components/page-header.tsx`, `components/invite-collaborators-drawer.tsx`, `components/question-bank-page-header.tsx`, `components/question-bank-client.tsx`, **`§4.7`**, **`docs/collaboration-access-pattern.md`** |
|
|
441
474
|
| **Dedicated search** (empty `?q=` landing vs results) | **`DedicatedSearchLandingTemplate`**, **`DedicatedSearchUrlComposer`**, **`DedicatedSearchRecents`**, **`DedicatedSearchResultsHeaderChrome`**, **`lib/dedicated-search-recents.ts`** | **`§4.8`**, **`components/templates/dedicated-search-*`**, **`components/dedicated-search-*.tsx`** |
|
|
442
|
-
| Persistence (example) | Page + lifecycle keys | `lib/data-list-persistence.ts`, `
|
|
475
|
+
| Persistence (example) | Page + lifecycle keys | `lib/data-list-persistence.ts`, `PlacementsClient` / `PlacementsTable` |
|
|
443
476
|
| Coach marks / tours | `CoachMark`, `useCoachMark`, coach mark registry | `components/ui/coach-mark.tsx`, `hooks/use-coach-mark.ts`, `lib/coach-mark-registry.ts` |
|
|
444
477
|
| Settings page | Coach mark management | `app/(app)/settings/page.tsx`, `components/settings-client.tsx` |
|
|
445
478
|
|
|
@@ -464,8 +497,8 @@ Reference: `components/new-placement-form.tsx` (Next/Back buttons); full shortcu
|
|
|
464
497
|
|
|
465
498
|
## 10. Persistence (when copying Placements behavior)
|
|
466
499
|
|
|
467
|
-
- **Page-level:** tabs, `showMetrics`, `displayOptions`, `activeTabId` — see `lib/data-list-persistence.ts` and `
|
|
468
|
-
- **Per-lifecycle / tab:** sort, filters, columns, etc. — see `
|
|
500
|
+
- **Page-level:** tabs, `showMetrics`, `displayOptions`, `activeTabId` — see `lib/data-list-persistence.ts` and `PlacementsClient`.
|
|
501
|
+
- **Per-lifecycle / tab:** sort, filters, columns, etc. — see `PlacementsTable` and `scheduleLifecycleSave`.
|
|
469
502
|
|
|
470
503
|
New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrations.
|
|
471
504
|
|
|
@@ -504,7 +537,7 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
|
|
|
504
537
|
- **With image** — set `image` + `imageAlt` on the step
|
|
505
538
|
- **Without image** — text-only
|
|
506
539
|
|
|
507
|
-
**Reference:** `references/coach-marks.md` in the skill, `components/dashboard-tabs.tsx` (dashboard tour), `components/
|
|
540
|
+
**Reference:** `references/coach-marks.md` in the skill, `components/dashboard-tabs.tsx` (dashboard tour), `components/placements-client.tsx` (views tour).
|
|
508
541
|
|
|
509
542
|
---
|
|
510
543
|
|
|
@@ -519,7 +552,38 @@ New pages **SHOULD** namespace keys and version JSON (`v: 1`) for future migrati
|
|
|
519
552
|
- **KPI deltas & trend arrows:** `docs/kpi-trend-pattern.md` (`MetricItem.trendPolarity`, `KeyMetrics`, chart mini-metrics)
|
|
520
553
|
- **Global command palette (⌘K):** `docs/command-menu-pattern.md`
|
|
521
554
|
- **No toast / snackbars:** **§6.5**, root **`.cursor/rules/exxat-no-toast.mdc`**
|
|
522
|
-
- **
|
|
555
|
+
- **Token taxonomy:** `docs/token-taxonomy.md` — namespaces, layering (L0 / L1 / L2 / L3), naming, deprecation policy. Machine-readable index at `packages/ui/tokens/hooks-index.json` (163 tokens · 36 namespaces · regenerate via `pnpm --filter @exxatdesignux/ui tokens:index`).
|
|
556
|
+
- **Exxat L0 canonical namespace:** `--exxat-color-surface-*`, `--exxat-color-ink-*`, `--exxat-color-brand-*`, `--exxat-radius-*`, `--exxat-spacing-*`, … (taxonomy §2.0; rollout: `docs/migrations/0002-exxat-token-namespace.md`).
|
|
557
|
+
- **Component selection guide:** `docs/component-selection-guide.md` — decision tree across the whole DS.
|
|
558
|
+
- **Blueprints:** `docs/blueprints/` — framework-agnostic specs. Start with `page-header.md` and `data-table.md`; add new ones via `_template.md`.
|
|
559
|
+
- **Migrations:** `docs/migrations/` — token rename + removal history. Open a new entry alongside every breaking change.
|
|
560
|
+
- **Components audit:** `docs/components-audit-2026-05.md` — observation log; §2.1 (form-layout / section-cards) and §2.2 (onboarding consolidation) both resolved 2026-05-19.
|
|
561
|
+
- **This handbook:** `apps/web/AGENTS.md` (keep checklist sections updated when patterns change)
|
|
562
|
+
|
|
563
|
+
### 12.1 Design-system meta-rules
|
|
564
|
+
|
|
565
|
+
| Concern | Rule | Enforcement |
|
|
566
|
+
|---|---|---|
|
|
567
|
+
| Salesforce / SLDS / LWC cross-contamination | **`.cursor/rules/exxat-no-slds-leakage.mdc`** | ESLint: `exxat-ds/no-slds-classes`, `exxat-ds/no-lightning-elements` |
|
|
568
|
+
| Hex literals, deprecated tokens, wrong token family | **`.cursor/rules/exxat-token-discipline.mdc`** | ESLint: `exxat-ds/no-hex-color`, `exxat-ds/no-deprecated-tokens` |
|
|
569
|
+
| No-toast feedback policy | **`.cursor/rules/exxat-no-toast.mdc`** (§6.5) | ESLint: `exxat-ds/no-sonner-toast` |
|
|
570
|
+
|
|
571
|
+
The ESLint rules ship as a **workspace package**:
|
|
572
|
+
**`packages/eslint-plugin-exxat-ds/`** (published as `@exxatdesignux/eslint-plugin`).
|
|
573
|
+
`apps/web/eslint.config.mjs` imports it via `import exxatDs from "@exxatdesignux/eslint-plugin"`
|
|
574
|
+
and consumers of `@exxatdesignux/ui` can install the plugin from npm with the
|
|
575
|
+
same wiring. See [`packages/eslint-plugin-exxat-ds/README.md`](../../packages/eslint-plugin-exxat-ds/README.md)
|
|
576
|
+
for rule docs and authoring guidance.
|
|
577
|
+
|
|
578
|
+
When you **introduce** a new token in `packages/ui/src/globals.css` (the canonical CSS — app/template `globals.css` are thin `@import` shells):
|
|
579
|
+
|
|
580
|
+
1. **Prefer L0** — declare the canonical name in the `Exxat L0 — canonical namespace`
|
|
581
|
+
block (`--exxat-color-<bucket>-<slot>` / `--exxat-radius-N` / `--exxat-spacing-N`).
|
|
582
|
+
2. Add a row to `docs/token-taxonomy.md` in the right § (§2.0 if L0; §2.1–§2.17 for legacy L1 surfaces).
|
|
583
|
+
3. Run `pnpm --filter @exxatdesignux/ui tokens:index` and commit the
|
|
584
|
+
regenerated `packages/ui/tokens/hooks-index.json`.
|
|
585
|
+
4. If you are **deprecating** a token, also open a numbered entry under
|
|
586
|
+
`docs/migrations/` (see `docs/migrations/README.md` template).
|
|
523
587
|
|
|
524
588
|
---
|
|
525
589
|
|
|
@@ -562,7 +626,7 @@ Copy and complete when implementing or reviewing:
|
|
|
562
626
|
- [ ] **§4.5 View shells:** Folder / panel / icon views use **`ListPageViewFrame`** (or a **`data-views/`** component that uses it); no page-tied-only grid wrappers; **`DataTable`** not double-wrapped (**§5**).
|
|
563
627
|
- [ ] **> ~10 items:** Search, filter, sort, properties (per surface type in §6.1).
|
|
564
628
|
- [ ] **Exportable data:** Filled primary CTA; **⋯** menu with Export → `ExportDrawer`.
|
|
565
|
-
- [ ] **Primary hub + large data:** Same composition as `
|
|
629
|
+
- [ ] **Primary hub + large data:** Same composition as `PlacementsClient` / `TeamClient` (template + metrics when applicable).
|
|
566
630
|
- [ ] **All view tabs:** List/board/dashboard use **`tableState.rows`**; dashboard view uses **`KeyMetrics`** + shared KPI helpers — no “not wired” placeholders or duplicate metric cards.
|
|
567
631
|
- [ ] **Properties drawer:** **`TablePropertiesDrawer`** receives **`currentView`** and **`onViewChange`** from **`renderContent`** / **`updateTab`** + **`dataListViewIcon`** (§4.2) — not table-only copy on Board/List/Dashboard.
|
|
568
632
|
- [ ] **Data view dashboard (Placements / Team / Compliance):** Charts use **`ChartFigure`** + **`ChartDataTable`**; **Edit layout** on toolbar; **`activeBar` / `activeShape`** keyboard styling from **`lib/chart-keyboard-selection`** — not opacity-only **`Cell`** hacks (§4.3).
|
|
@@ -4,7 +4,6 @@ import { Button } from "@/components/ui/button"
|
|
|
4
4
|
|
|
5
5
|
const LINKS = [
|
|
6
6
|
{ href: "/dashboard", label: "Dashboard", description: "Metrics, charts, and layout patterns." },
|
|
7
|
-
{ href: "/data-list", label: "List hub", description: "Table, list, board, and dashboard views on shared state." },
|
|
8
7
|
{ href: "/question-bank", label: "Question bank", description: "Discovery hub for browsing folders, recents, and AI-assisted create/import flows." },
|
|
9
8
|
{ href: "/question-bank/library", label: "Question library", description: "Folders, OS folder view, panel, and tree demos on mock items." },
|
|
10
9
|
{ href: "/settings", label: "Settings", description: "Appearance, tours, and shell preferences." },
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { cookies } from "next/headers"
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
AppSidebar,
|
|
4
|
+
SidebarShell,
|
|
5
|
+
SecondaryPanelProvider,
|
|
6
|
+
SecondaryPanel,
|
|
7
|
+
} from "@/components/sidebar"
|
|
4
8
|
import {
|
|
5
9
|
SIDEBAR_STATE_COOKIE_NAME,
|
|
6
10
|
sidebarDefaultOpenFromCookie,
|
|
@@ -8,7 +12,7 @@ import {
|
|
|
8
12
|
import { DashboardViewProvider } from "@/contexts/dashboard-view-context"
|
|
9
13
|
import { ChartVariantProvider } from "@/contexts/chart-variant-context"
|
|
10
14
|
import { AskLeoProvider, AskLeoSidebar } from "@/components/ask-leo-sidebar"
|
|
11
|
-
import {
|
|
15
|
+
import { KeyMetricsAskLeoBridge } from "@/components/key-metrics-ask-leo-bridge"
|
|
12
16
|
import { SystemBannerProvider } from "@/contexts/system-banner-context"
|
|
13
17
|
import { SystemBannerSlot } from "@/components/system-banner-slot"
|
|
14
18
|
import { CommandMenu } from "@/components/command-menu"
|
|
@@ -37,6 +41,7 @@ export default async function AppLayout({ children }: { children: React.ReactNod
|
|
|
37
41
|
<DashboardViewProvider>
|
|
38
42
|
<ChartVariantProvider>
|
|
39
43
|
<AskLeoProvider>
|
|
44
|
+
<KeyMetricsAskLeoBridge>
|
|
40
45
|
<SystemBannerProvider>
|
|
41
46
|
<CommandMenuProvider value={commandMenuConfig}>
|
|
42
47
|
|
|
@@ -46,7 +51,14 @@ export default async function AppLayout({ children }: { children: React.ReactNod
|
|
|
46
51
|
<SystemBannerSlot />
|
|
47
52
|
|
|
48
53
|
{/* Sidebar + content row — flex-1 min-h-0 below min-h-svh shell; SidebarInset self-stretch + PrimaryPageTemplate flex-1 fills viewport when page body is short. */}
|
|
49
|
-
|
|
54
|
+
{/* suppressHydrationWarning: the Cursor IDE browser preview injects a
|
|
55
|
+
`data-cursor-ref` attribute on this layout root before React hydrates.
|
|
56
|
+
Scoped to this element's own attributes only. See companion comment
|
|
57
|
+
in components/templates/nested-secondary-panel-shell.tsx. */}
|
|
58
|
+
<div
|
|
59
|
+
className="flex min-h-0 w-full flex-1 items-stretch has-data-[variant=inset]:bg-sidebar"
|
|
60
|
+
suppressHydrationWarning
|
|
61
|
+
>
|
|
50
62
|
<SecondaryPanelProvider>
|
|
51
63
|
<AppSidebar variant="inset" />
|
|
52
64
|
<SecondaryPanel />
|
|
@@ -57,6 +69,7 @@ export default async function AppLayout({ children }: { children: React.ReactNod
|
|
|
57
69
|
</SidebarShell>
|
|
58
70
|
</CommandMenuProvider>
|
|
59
71
|
</SystemBannerProvider>
|
|
72
|
+
</KeyMetricsAskLeoBridge>
|
|
60
73
|
</AskLeoProvider>
|
|
61
74
|
</ChartVariantProvider>
|
|
62
75
|
</DashboardViewProvider>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import { usePathname } from "next/navigation"
|
|
5
5
|
|
|
6
|
-
import { useSecondaryPanel } from "@/components/
|
|
6
|
+
import { useSecondaryPanel } from "@/components/sidebar"
|
|
7
7
|
import {
|
|
8
8
|
QUESTION_BANK_ENTRY_PATH,
|
|
9
9
|
QUESTION_BANK_HUB_FIND_PATH,
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `/question-bank/new` —
|
|
2
|
+
* `/question-bank/new` — focused authoring page for a new question.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* • A wider max-width than the placement form (the composer carries a
|
|
8
|
-
* two-column document + metadata-rail layout)
|
|
9
|
-
*
|
|
10
|
-
* The body is `NewQuestionComposer` — see `components/new-question-composer.tsx`.
|
|
4
|
+
* The composer (`NewQuestionComposer`) owns the `NewFocusTemplate` (form-inspector
|
|
5
|
+
* variant) underneath. This route file is intentionally thin so the same composer
|
|
6
|
+
* can be mounted from other entry points (deep-link, command palette).
|
|
11
7
|
*
|
|
12
8
|
* Folder pre-selection: callers may pass `?folderId=<id>` so users dropped into
|
|
13
9
|
* the composer from a folder-scoped library land with that folder pre-selected
|
|
@@ -15,8 +11,6 @@
|
|
|
15
11
|
*/
|
|
16
12
|
|
|
17
13
|
import { NewQuestionComposer } from "@/components/new-question-composer"
|
|
18
|
-
import { SidebarAutoCollapse } from "@/components/sidebar-auto-collapse"
|
|
19
|
-
import { PrimaryPageTemplate } from "@/components/templates/primary-page-template"
|
|
20
14
|
import {
|
|
21
15
|
DEFAULT_QUESTION_BANK_FOLDERS,
|
|
22
16
|
type QuestionBankFolder,
|
|
@@ -40,19 +34,12 @@ export default async function NewQuestionPage({ searchParams }: NewQuestionPageP
|
|
|
40
34
|
const draftQuestionId = generateDraftQuestionId()
|
|
41
35
|
|
|
42
36
|
return (
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<NewQuestionComposer
|
|
51
|
-
draftQuestionId={draftQuestionId}
|
|
52
|
-
defaultFolderId={defaultFolderId}
|
|
53
|
-
backHref={back.href}
|
|
54
|
-
folders={folders}
|
|
55
|
-
/>
|
|
56
|
-
</PrimaryPageTemplate>
|
|
37
|
+
<NewQuestionComposer
|
|
38
|
+
draftQuestionId={draftQuestionId}
|
|
39
|
+
defaultFolderId={defaultFolderId}
|
|
40
|
+
backHref={back.href}
|
|
41
|
+
backLabel={back.label}
|
|
42
|
+
folders={folders}
|
|
43
|
+
/>
|
|
57
44
|
)
|
|
58
45
|
}
|