cursedbelt 5.40.0 → 5.45.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/dist/react/Toast.d.ts +12 -2
- package/dist/react/Toast.d.ts.map +1 -1
- package/dist/react/Toast.js +32 -3
- package/dist/react/Toast.js.map +1 -1
- package/dist/react/analytics/MetricDrilldown.js +1 -1
- package/dist/react/charts/AreaChart.d.ts.map +1 -1
- package/dist/react/charts/AreaChart.js +5 -5
- package/dist/react/charts/AreaChart.js.map +1 -1
- package/dist/react/charts/BarChart.d.ts.map +1 -1
- package/dist/react/charts/BarChart.js +3 -3
- package/dist/react/charts/BarChart.js.map +1 -1
- package/dist/react/charts/ChartCard.d.ts +53 -0
- package/dist/react/charts/ChartCard.d.ts.map +1 -0
- package/dist/react/charts/ChartCard.js +46 -0
- package/dist/react/charts/ChartCard.js.map +1 -0
- package/dist/react/charts/ChartFrame.d.ts +12 -5
- package/dist/react/charts/ChartFrame.d.ts.map +1 -1
- package/dist/react/charts/ChartFrame.js +12 -5
- package/dist/react/charts/ChartFrame.js.map +1 -1
- package/dist/react/charts/ChartLegend.js +1 -1
- package/dist/react/charts/ChartLegend.js.map +1 -1
- package/dist/react/charts/HeatmapChart.js +3 -3
- package/dist/react/charts/HeatmapChart.js.map +1 -1
- package/dist/react/charts/IntervalTimeline.js +1 -1
- package/dist/react/charts/IntervalTimeline.js.map +1 -1
- package/dist/react/charts/LineChart.d.ts.map +1 -1
- package/dist/react/charts/LineChart.js +3 -3
- package/dist/react/charts/LineChart.js.map +1 -1
- package/dist/react/charts/TimeSeriesChart.d.ts.map +1 -1
- package/dist/react/charts/TimeSeriesChart.js +6 -6
- package/dist/react/charts/TimeSeriesChart.js.map +1 -1
- package/dist/react/charts/chartBox.d.ts +46 -0
- package/dist/react/charts/chartBox.d.ts.map +1 -0
- package/dist/react/charts/chartBox.js +45 -0
- package/dist/react/charts/chartBox.js.map +1 -0
- package/dist/react/charts/index.d.ts +2 -0
- package/dist/react/charts/index.d.ts.map +1 -1
- package/dist/react/charts/index.js +2 -0
- package/dist/react/charts/index.js.map +1 -1
- package/dist/react/charts/shared.d.ts +13 -2
- package/dist/react/charts/shared.d.ts.map +1 -1
- package/dist/react/charts/shared.js +14 -3
- package/dist/react/charts/shared.js.map +1 -1
- package/dist/react/chat/Bubble.js +4 -4
- package/dist/react/chat/Bubble.js.map +1 -1
- package/dist/react/chat/MessageScroller.js +1 -1
- package/dist/react/chat/MessageScroller.js.map +1 -1
- package/dist/react/components/ActionBar.d.ts.map +1 -1
- package/dist/react/components/ActionBar.js +63 -1
- package/dist/react/components/ActionBar.js.map +1 -1
- package/dist/react/components/AddItemsMenu.js +1 -1
- package/dist/react/components/AddItemsMenu.js.map +1 -1
- package/dist/react/components/Alert.d.ts +16 -2
- package/dist/react/components/Alert.d.ts.map +1 -1
- package/dist/react/components/Alert.js +35 -2
- package/dist/react/components/Alert.js.map +1 -1
- package/dist/react/components/AppShell.d.ts +55 -33
- package/dist/react/components/AppShell.d.ts.map +1 -1
- package/dist/react/components/AppShell.js +121 -31
- package/dist/react/components/AppShell.js.map +1 -1
- package/dist/react/components/AsyncPanel.d.ts +21 -3
- package/dist/react/components/AsyncPanel.d.ts.map +1 -1
- package/dist/react/components/AsyncPanel.js +49 -5
- package/dist/react/components/AsyncPanel.js.map +1 -1
- package/dist/react/components/BannerLane.d.ts +32 -0
- package/dist/react/components/BannerLane.d.ts.map +1 -0
- package/dist/react/components/BannerLane.js +41 -0
- package/dist/react/components/BannerLane.js.map +1 -0
- package/dist/react/components/Button.d.ts.map +1 -1
- package/dist/react/components/Button.js +2 -1
- package/dist/react/components/Button.js.map +1 -1
- package/dist/react/components/ChipFilterStrip.js +1 -1
- package/dist/react/components/ChipFilterStrip.js.map +1 -1
- package/dist/react/components/ComboboxField.d.ts.map +1 -1
- package/dist/react/components/ComboboxField.js +14 -4
- package/dist/react/components/ComboboxField.js.map +1 -1
- package/dist/react/components/CommentThread.js +2 -2
- package/dist/react/components/CommentThread.js.map +1 -1
- package/dist/react/components/ConfirmDialog.js +1 -1
- package/dist/react/components/ConfirmDialog.js.map +1 -1
- package/dist/react/components/DataTable/DataTable.d.ts +18 -2
- package/dist/react/components/DataTable/DataTable.d.ts.map +1 -1
- package/dist/react/components/DataTable/DataTable.js +51 -12
- package/dist/react/components/DataTable/DataTable.js.map +1 -1
- package/dist/react/components/DataTable/Pagination.js +1 -1
- package/dist/react/components/DataTable/Pagination.js.map +1 -1
- package/dist/react/components/DataTable/RowActions.d.ts +7 -1
- package/dist/react/components/DataTable/RowActions.d.ts.map +1 -1
- package/dist/react/components/DataTable/RowActions.js +10 -3
- package/dist/react/components/DataTable/RowActions.js.map +1 -1
- package/dist/react/components/DataTable/TableFilterBuilder.js +1 -1
- package/dist/react/components/DataTable/TableFilterBuilder.js.map +1 -1
- package/dist/react/components/DataTable/cells/CodeCell.js +1 -1
- package/dist/react/components/DataTable/cells/CodeCell.js.map +1 -1
- package/dist/react/components/DataTable/cells/LinkCell.js +1 -1
- package/dist/react/components/DataTable/cells/LinkCell.js.map +1 -1
- package/dist/react/components/DataTable/index.d.ts +1 -1
- package/dist/react/components/DataTable/index.d.ts.map +1 -1
- package/dist/react/components/DataTable/index.js.map +1 -1
- package/dist/react/components/DataTable/types.d.ts +20 -0
- package/dist/react/components/DataTable/types.d.ts.map +1 -1
- package/dist/react/components/DataTable/types.js +22 -0
- package/dist/react/components/DataTable/types.js.map +1 -1
- package/dist/react/components/DateTimeField.d.ts.map +1 -1
- package/dist/react/components/DateTimeField.js +4 -1
- package/dist/react/components/DateTimeField.js.map +1 -1
- package/dist/react/components/DeleteButton.js +2 -0
- package/dist/react/components/DeleteButton.js.map +1 -1
- package/dist/react/components/Drawer.js +3 -3
- package/dist/react/components/Drawer.js.map +1 -1
- package/dist/react/components/DropdownMenu.d.ts +16 -0
- package/dist/react/components/DropdownMenu.d.ts.map +1 -1
- package/dist/react/components/DropdownMenu.js +22 -6
- package/dist/react/components/DropdownMenu.js.map +1 -1
- package/dist/react/components/EmptyState.d.ts +10 -2
- package/dist/react/components/EmptyState.d.ts.map +1 -1
- package/dist/react/components/EmptyState.js +10 -5
- package/dist/react/components/EmptyState.js.map +1 -1
- package/dist/react/components/EventTimeline.js +1 -1
- package/dist/react/components/EventTimeline.js.map +1 -1
- package/dist/react/components/FileDropZone.js +1 -1
- package/dist/react/components/FileDropZone.js.map +1 -1
- package/dist/react/components/Grid.d.ts +9 -1
- package/dist/react/components/Grid.d.ts.map +1 -1
- package/dist/react/components/Grid.js +20 -2
- package/dist/react/components/Grid.js.map +1 -1
- package/dist/react/components/Guide.d.ts +31 -0
- package/dist/react/components/Guide.d.ts.map +1 -0
- package/dist/react/components/Guide.js +18 -0
- package/dist/react/components/Guide.js.map +1 -0
- package/dist/react/components/InfoHintImpl.d.ts +0 -13
- package/dist/react/components/InfoHintImpl.d.ts.map +1 -1
- package/dist/react/components/InfoHintImpl.js +17 -1
- package/dist/react/components/InfoHintImpl.js.map +1 -1
- package/dist/react/components/InlineEditableText.js +1 -1
- package/dist/react/components/InlineEditableText.js.map +1 -1
- package/dist/react/components/IsolatedFrame.js +1 -1
- package/dist/react/components/IsolatedFrame.js.map +1 -1
- package/dist/react/components/ListToolbar.d.ts.map +1 -1
- package/dist/react/components/ListToolbar.js +2 -2
- package/dist/react/components/ListToolbar.js.map +1 -1
- package/dist/react/components/LogViewer.d.ts +26 -2
- package/dist/react/components/LogViewer.d.ts.map +1 -1
- package/dist/react/components/LogViewer.js +41 -26
- package/dist/react/components/LogViewer.js.map +1 -1
- package/dist/react/components/Modal.d.ts +5 -1
- package/dist/react/components/Modal.d.ts.map +1 -1
- package/dist/react/components/Modal.js +18 -8
- package/dist/react/components/Modal.js.map +1 -1
- package/dist/react/components/Page.d.ts +51 -7
- package/dist/react/components/Page.d.ts.map +1 -1
- package/dist/react/components/Page.js +53 -8
- package/dist/react/components/Page.js.map +1 -1
- package/dist/react/components/PageGuideButton.d.ts +11 -0
- package/dist/react/components/PageGuideButton.d.ts.map +1 -0
- package/dist/react/components/PageGuideButton.js +13 -0
- package/dist/react/components/PageGuideButton.js.map +1 -0
- package/dist/react/components/PanelSeparator.js +1 -1
- package/dist/react/components/PanelSeparator.js.map +1 -1
- package/dist/react/components/Popover.d.ts.map +1 -1
- package/dist/react/components/Popover.js +2 -1
- package/dist/react/components/Popover.js.map +1 -1
- package/dist/react/components/PromptDialog.js +1 -1
- package/dist/react/components/PromptDialog.js.map +1 -1
- package/dist/react/components/ScrollArea.d.ts +9 -1
- package/dist/react/components/ScrollArea.d.ts.map +1 -1
- package/dist/react/components/ScrollArea.js +9 -3
- package/dist/react/components/ScrollArea.js.map +1 -1
- package/dist/react/components/Section.d.ts +5 -2
- package/dist/react/components/Section.d.ts.map +1 -1
- package/dist/react/components/Section.js +5 -2
- package/dist/react/components/Section.js.map +1 -1
- package/dist/react/components/Skeleton.d.ts +19 -1
- package/dist/react/components/Skeleton.d.ts.map +1 -1
- package/dist/react/components/Skeleton.js +24 -2
- package/dist/react/components/Skeleton.js.map +1 -1
- package/dist/react/components/StatStrip.js +1 -1
- package/dist/react/components/StatStrip.js.map +1 -1
- package/dist/react/components/StatTile.d.ts +30 -3
- package/dist/react/components/StatTile.d.ts.map +1 -1
- package/dist/react/components/StatTile.js +35 -9
- package/dist/react/components/StatTile.js.map +1 -1
- package/dist/react/components/StatTileGrid.d.ts +10 -1
- package/dist/react/components/StatTileGrid.d.ts.map +1 -1
- package/dist/react/components/StatTileGrid.js +50 -33
- package/dist/react/components/StatTileGrid.js.map +1 -1
- package/dist/react/components/StatusPill.d.ts.map +1 -1
- package/dist/react/components/StatusPill.js +26 -1
- package/dist/react/components/StatusPill.js.map +1 -1
- package/dist/react/components/Surface.d.ts +1 -1
- package/dist/react/components/Surface.d.ts.map +1 -1
- package/dist/react/components/Surface.js +20 -11
- package/dist/react/components/Surface.js.map +1 -1
- package/dist/react/components/SwatchPicker.d.ts.map +1 -1
- package/dist/react/components/SwatchPicker.js +5 -1
- package/dist/react/components/SwatchPicker.js.map +1 -1
- package/dist/react/components/Switch.js +1 -1
- package/dist/react/components/Switch.js.map +1 -1
- package/dist/react/components/WidgetHeader.js +1 -1
- package/dist/react/components/WidgetHeader.js.map +1 -1
- package/dist/react/components/calendar/CalendarLegend.js +1 -1
- package/dist/react/components/calendar/CalendarLegend.js.map +1 -1
- package/dist/react/components/calendar/DayAgenda.js +1 -1
- package/dist/react/components/calendar/DayAgenda.js.map +1 -1
- package/dist/react/components/calendar/EventChip.js +1 -1
- package/dist/react/components/calendar/EventChip.js.map +1 -1
- package/dist/react/components/calendar/MonthGrid.js +1 -1
- package/dist/react/components/calendar/MonthGrid.js.map +1 -1
- package/dist/react/components/calendar/WeekView.js +2 -2
- package/dist/react/components/calendar/WeekView.js.map +1 -1
- package/dist/react/components/cardFrame.d.ts +16 -0
- package/dist/react/components/cardFrame.d.ts.map +1 -0
- package/dist/react/components/cardFrame.js +24 -0
- package/dist/react/components/cardFrame.js.map +1 -0
- package/dist/react/components/dialog.d.ts.map +1 -1
- package/dist/react/components/dialog.js +2 -1
- package/dist/react/components/dialog.js.map +1 -1
- package/dist/react/dashboard-grid/WidgetFrame.js +2 -2
- package/dist/react/dashboard-grid/WidgetFrame.js.map +1 -1
- package/dist/react/emoji/EmojiPicker.js +1 -1
- package/dist/react/emoji/EmojiPicker.js.map +1 -1
- package/dist/react/file-tree/FileTree.d.ts +8 -1
- package/dist/react/file-tree/FileTree.d.ts.map +1 -1
- package/dist/react/file-tree/FileTree.js +29 -4
- package/dist/react/file-tree/FileTree.js.map +1 -1
- package/dist/react/filter-rail/FilterRail.js +1 -1
- package/dist/react/filter-rail/FilterRail.js.map +1 -1
- package/dist/react/icons.js +1 -1
- package/dist/react/icons.js.map +1 -1
- package/dist/react/index.d.ts +8 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -2
- package/dist/react/index.js.map +1 -1
- package/dist/react/lib/menuSections.d.ts +8 -0
- package/dist/react/lib/menuSections.d.ts.map +1 -0
- package/dist/react/lib/menuSections.js +37 -0
- package/dist/react/lib/menuSections.js.map +1 -0
- package/dist/react/markdown/Markdown.js +2 -2
- package/dist/react/markdown/Markdown.js.map +1 -1
- package/dist/react/media/HoverScrubVideoThumb.js +1 -1
- package/dist/react/media/HoverScrubVideoThumb.js.map +1 -1
- package/dist/react/media/MaskPainter.js +1 -1
- package/dist/react/media/MediaUploadControl.js +1 -1
- package/dist/react/media/MediaUploadControl.js.map +1 -1
- package/dist/react/media/VideoTrimmer.js +1 -1
- package/dist/react/media/VideoTrimmer.js.map +1 -1
- package/dist/react/media/denseGallery.css +5 -1
- package/dist/react/namespace/NamespaceTargetCapsule.js +1 -1
- package/dist/react/namespace/NamespaceTargetCapsule.js.map +1 -1
- package/dist/react/nav/BreadcrumbTrail.js +1 -1
- package/dist/react/nav/BreadcrumbTrail.js.map +1 -1
- package/dist/react/nav/CommandBar.d.ts +7 -1
- package/dist/react/nav/CommandBar.d.ts.map +1 -1
- package/dist/react/nav/CommandBar.js +5 -3
- package/dist/react/nav/CommandBar.js.map +1 -1
- package/dist/react/nav/PlaceBar.d.ts.map +1 -1
- package/dist/react/nav/PlaceBar.js +7 -9
- package/dist/react/nav/PlaceBar.js.map +1 -1
- package/dist/react/nav/SideNav.d.ts +12 -2
- package/dist/react/nav/SideNav.d.ts.map +1 -1
- package/dist/react/nav/SideNav.js +42 -22
- package/dist/react/nav/SideNav.js.map +1 -1
- package/dist/react/nav/TopBar.d.ts +65 -31
- package/dist/react/nav/TopBar.d.ts.map +1 -1
- package/dist/react/nav/TopBar.js +59 -24
- package/dist/react/nav/TopBar.js.map +1 -1
- package/dist/react/nav/index.d.ts +1 -1
- package/dist/react/nav/index.d.ts.map +1 -1
- package/dist/react/nav/index.js +1 -1
- package/dist/react/nav/index.js.map +1 -1
- package/dist/react/nav/navShared.d.ts +10 -1
- package/dist/react/nav/navShared.d.ts.map +1 -1
- package/dist/react/nav/navShared.js +23 -0
- package/dist/react/nav/navShared.js.map +1 -1
- package/dist/react/notifications/NotificationFeed.js +2 -2
- package/dist/react/notifications/NotificationFeed.js.map +1 -1
- package/dist/react/palette/Command.d.ts.map +1 -1
- package/dist/react/palette/Command.js +1 -1
- package/dist/react/palette/Command.js.map +1 -1
- package/dist/react/palette/CommandPalette.d.ts +13 -1
- package/dist/react/palette/CommandPalette.d.ts.map +1 -1
- package/dist/react/palette/CommandPalette.js +44 -8
- package/dist/react/palette/CommandPalette.js.map +1 -1
- package/dist/react/palette/commandSources.d.ts +57 -0
- package/dist/react/palette/commandSources.d.ts.map +1 -0
- package/dist/react/palette/commandSources.js +129 -0
- package/dist/react/palette/commandSources.js.map +1 -0
- package/dist/react/palette/index.d.ts +1 -0
- package/dist/react/palette/index.d.ts.map +1 -1
- package/dist/react/palette/index.js +1 -0
- package/dist/react/palette/index.js.map +1 -1
- package/dist/react/rich-text/RichTextEditor.js +1 -1
- package/dist/react/rich-text/RichTextEditor.js.map +1 -1
- package/dist/react/rich-text/RichTextToolbar.js +1 -1
- package/dist/react/rich-text/RichTextToolbar.js.map +1 -1
- package/dist/scripts/guardrailsEnforce.d.ts.map +1 -1
- package/dist/styles-areas/analytics.css +16 -16
- package/dist/styles-areas/auth.css +3 -3
- package/dist/styles-areas/calendar.css +6 -6
- package/dist/styles-areas/chart-table.css +1 -1
- package/dist/styles-areas/charts.css +3 -3
- package/dist/styles-areas/chat.css +7 -6
- package/dist/styles-areas/companion-link.css +2 -2
- package/dist/styles-areas/core.css +98 -89
- package/dist/styles-areas/dashboard-grid.css +4 -4
- package/dist/styles-areas/data-table.css +16 -16
- package/dist/styles-areas/disk-usage.css +5 -5
- package/dist/styles-areas/emoji.css +2 -2
- package/dist/styles-areas/fields.css +13 -14
- package/dist/styles-areas/filter-rail.css +4 -4
- package/dist/styles-areas/folder-tree.css +3 -3
- package/dist/styles-areas/markdown.css +2 -1
- package/dist/styles-areas/master-detail.css +3 -3
- package/dist/styles-areas/media-gallery.css +8 -8
- package/dist/styles-areas/media.css +12 -13
- package/dist/styles-areas/nav.css +28 -14
- package/dist/styles-areas/notifications.css +4 -4
- package/dist/styles-areas/overlays.css +4 -4
- package/dist/styles-areas/palette.css +4 -3
- package/dist/styles-areas/rich-text.css +3 -3
- package/dist/styles-areas/sharing.css +4 -3
- package/dist/styles-areas/stats.css +9 -8
- package/dist/styles-areas/test-report.css +3 -3
- package/dist/styles-areas/wizard.css +6 -5
- package/dist/styles-areas/workbench.css +10 -9
- package/dist/styles-areas/workbook-viewer.css +2 -2
- package/dist/styles-utilities.css +272 -187
- package/dist/testing/designAudit.d.ts.map +1 -1
- package/dist/testing/designAudit.js +4 -0
- package/dist/testing/designAudit.js.map +1 -1
- package/dist/testing/designBaseline.d.ts.map +1 -1
- package/dist/testing/designBaseline.js +4 -0
- package/dist/testing/designBaseline.js.map +1 -1
- package/dist/theme.css +103 -2
- package/package.json +3 -2
- package/scripts/guardrails-baseline.json +2 -1
- package/scripts/guardrailsEnforce.spec.ts +64 -0
- package/scripts/guardrailsEnforce.ts +65 -8
- package/scripts/styleAreas.ts +1 -0
- package/src/nodeTypesDeclared.spec.ts +47 -0
- package/src/react/Toast.spec.tsx +43 -0
- package/src/react/Toast.tsx +45 -2
- package/src/react/analytics/MetricDrilldown.tsx +1 -1
- package/src/react/charts/AreaChart.tsx +9 -8
- package/src/react/charts/BarChart.tsx +11 -10
- package/src/react/charts/ChartCard.tsx +146 -0
- package/src/react/charts/ChartFrame.tsx +28 -10
- package/src/react/charts/ChartLegend.tsx +1 -1
- package/src/react/charts/HeatmapChart.tsx +5 -5
- package/src/react/charts/IntervalTimeline.tsx +2 -2
- package/src/react/charts/LineChart.tsx +9 -8
- package/src/react/charts/TimeSeriesChart.tsx +11 -10
- package/src/react/charts/chartBox.spec.ts +40 -0
- package/src/react/charts/chartBox.ts +75 -0
- package/src/react/charts/index.ts +2 -0
- package/src/react/charts/shared.ts +16 -3
- package/src/react/chat/Bubble.tsx +5 -5
- package/src/react/chat/MessageScroller.tsx +1 -1
- package/src/react/components/ActionBar.spec.tsx +90 -0
- package/src/react/components/ActionBar.tsx +82 -2
- package/src/react/components/AddItemsMenu.tsx +1 -1
- package/src/react/components/Alert.spec.tsx +32 -2
- package/src/react/components/Alert.tsx +47 -3
- package/src/react/components/AppShell.spec.tsx +199 -13
- package/src/react/components/AppShell.tsx +235 -92
- package/src/react/components/AsyncPanel.spec.tsx +7 -1
- package/src/react/components/AsyncPanel.tsx +85 -5
- package/src/react/components/BannerLane.tsx +128 -0
- package/src/react/components/Button.tsx +2 -0
- package/src/react/components/ChipFilterStrip.tsx +1 -1
- package/src/react/components/ComboboxField.tsx +20 -3
- package/src/react/components/CommentThread.tsx +2 -2
- package/src/react/components/ConfirmDialog.tsx +1 -1
- package/src/react/components/DataTable/DataTable.tsx +80 -8
- package/src/react/components/DataTable/Pagination.tsx +1 -1
- package/src/react/components/DataTable/RowActions.tsx +55 -2
- package/src/react/components/DataTable/TableFilterBuilder.tsx +1 -1
- package/src/react/components/DataTable/cells/CodeCell.tsx +1 -1
- package/src/react/components/DataTable/cells/LinkCell.tsx +1 -1
- package/src/react/components/DataTable/index.ts +1 -0
- package/src/react/components/DataTable/numericColumn.spec.ts +19 -0
- package/src/react/components/DataTable/types.ts +36 -0
- package/src/react/components/DateTimeField.tsx +3 -1
- package/src/react/components/DeleteButton.tsx +3 -0
- package/src/react/components/Drawer.tsx +3 -3
- package/src/react/components/DropdownMenu.spec.tsx +55 -0
- package/src/react/components/DropdownMenu.tsx +73 -20
- package/src/react/components/EmptyState.tsx +26 -7
- package/src/react/components/EventTimeline.tsx +1 -1
- package/src/react/components/Field.width.spec.tsx +11 -0
- package/src/react/components/FileDropZone.tsx +1 -1
- package/src/react/components/Grid.spec.tsx +44 -0
- package/src/react/components/Grid.tsx +41 -11
- package/src/react/components/Guide.tsx +77 -0
- package/src/react/components/InfoHint.spec.tsx +21 -0
- package/src/react/components/InfoHintImpl.tsx +22 -1
- package/src/react/components/InlineEditableText.tsx +1 -1
- package/src/react/components/IsolatedFrame.tsx +1 -1
- package/src/react/components/ListToolbar.spec.tsx +12 -0
- package/src/react/components/ListToolbar.tsx +8 -5
- package/src/react/components/LogViewer.tsx +118 -18
- package/src/react/components/Modal.spec.tsx +17 -2
- package/src/react/components/Modal.tsx +25 -10
- package/src/react/components/MultiSelectField.spec.tsx +6 -0
- package/src/react/components/Page.spec.tsx +89 -5
- package/src/react/components/Page.tsx +100 -16
- package/src/react/components/PageGuideButton.tsx +42 -0
- package/src/react/components/PanelSeparator.tsx +1 -1
- package/src/react/components/Popover.tsx +3 -1
- package/src/react/components/PromptDialog.tsx +1 -1
- package/src/react/components/ScrollArea.spec.tsx +20 -0
- package/src/react/components/ScrollArea.tsx +19 -0
- package/src/react/components/Section.spec.tsx +82 -1
- package/src/react/components/Section.tsx +10 -4
- package/src/react/components/Skeleton.tsx +50 -2
- package/src/react/components/StatStrip.tsx +1 -1
- package/src/react/components/StatTile.tsx +84 -11
- package/src/react/components/StatTileGrid.spec.tsx +6 -1
- package/src/react/components/StatTileGrid.tsx +25 -0
- package/src/react/components/StatusPill.tsx +26 -1
- package/src/react/components/Surface.tsx +22 -14
- package/src/react/components/SwatchPicker.tsx +4 -0
- package/src/react/components/Switch.tsx +1 -1
- package/src/react/components/WidgetHeader.tsx +1 -1
- package/src/react/components/calendar/CalendarLegend.tsx +1 -1
- package/src/react/components/calendar/DayAgenda.tsx +1 -1
- package/src/react/components/calendar/EventChip.tsx +1 -1
- package/src/react/components/calendar/MonthGrid.tsx +1 -1
- package/src/react/components/calendar/WeekView.tsx +2 -2
- package/src/react/components/cardFrame.ts +28 -0
- package/src/react/components/dataDisplay.spec.tsx +176 -0
- package/src/react/components/dialog.tsx +4 -1
- package/src/react/dashboard-grid/WidgetFrame.tsx +2 -2
- package/src/react/emoji/EmojiPicker.tsx +1 -1
- package/src/react/file-tree/FileTree.spec.tsx +49 -0
- package/src/react/file-tree/FileTree.tsx +37 -4
- package/src/react/filter-rail/FilterRail.tsx +1 -1
- package/src/react/icons.tsx +1 -1
- package/src/react/index.ts +28 -3
- package/src/react/lib/menuSections.ts +33 -0
- package/src/react/markdown/Markdown.tsx +2 -2
- package/src/react/media/HoverScrubVideoThumb.tsx +2 -2
- package/src/react/media/MaskPainter.tsx +1 -1
- package/src/react/media/MediaUploadControl.tsx +1 -1
- package/src/react/media/VideoTrimmer.tsx +1 -1
- package/src/react/media/denseGallery.css +5 -1
- package/src/react/namespace/NamespaceTargetCapsule.tsx +1 -1
- package/src/react/nav/BreadcrumbTrail.tsx +2 -2
- package/src/react/nav/CommandBar.tsx +14 -3
- package/src/react/nav/PlaceBar.tsx +18 -8
- package/src/react/nav/SideNav.tsx +99 -17
- package/src/react/nav/TopBar.spec.tsx +78 -21
- package/src/react/nav/TopBar.tsx +270 -98
- package/src/react/nav/index.ts +8 -1
- package/src/react/nav/nav.spec.tsx +46 -2
- package/src/react/nav/navShared.tsx +23 -2
- package/src/react/notifications/NotificationFeed.tsx +2 -2
- package/src/react/palette/Command.tsx +1 -1
- package/src/react/palette/CommandPalette.spec.tsx +31 -0
- package/src/react/palette/CommandPalette.tsx +108 -11
- package/src/react/palette/commandSources.tsx +186 -0
- package/src/react/palette/index.ts +7 -0
- package/src/react/rich-text/RichTextEditor.tsx +1 -1
- package/src/react/rich-text/RichTextToolbar.tsx +1 -1
- package/src/styles-areas/analytics.css +16 -16
- package/src/styles-areas/auth.css +3 -3
- package/src/styles-areas/calendar.css +6 -6
- package/src/styles-areas/chart-table.css +1 -1
- package/src/styles-areas/charts.css +3 -3
- package/src/styles-areas/chat.css +7 -6
- package/src/styles-areas/companion-link.css +2 -2
- package/src/styles-areas/core.css +98 -89
- package/src/styles-areas/dashboard-grid.css +4 -4
- package/src/styles-areas/data-table.css +16 -16
- package/src/styles-areas/disk-usage.css +5 -5
- package/src/styles-areas/emoji.css +2 -2
- package/src/styles-areas/fields.css +13 -14
- package/src/styles-areas/filter-rail.css +4 -4
- package/src/styles-areas/folder-tree.css +3 -3
- package/src/styles-areas/markdown.css +2 -1
- package/src/styles-areas/master-detail.css +3 -3
- package/src/styles-areas/media-gallery.css +8 -8
- package/src/styles-areas/media.css +12 -13
- package/src/styles-areas/nav.css +28 -14
- package/src/styles-areas/notifications.css +4 -4
- package/src/styles-areas/overlays.css +4 -4
- package/src/styles-areas/palette.css +4 -3
- package/src/styles-areas/rich-text.css +3 -3
- package/src/styles-areas/sharing.css +4 -3
- package/src/styles-areas/stats.css +9 -8
- package/src/styles-areas/test-report.css +3 -3
- package/src/styles-areas/wizard.css +6 -5
- package/src/styles-areas/workbench.css +10 -9
- package/src/styles-areas/workbook-viewer.css +2 -2
- package/src/styles-utilities.css +272 -187
- package/src/testing/designAudit.ts +3 -0
- package/src/testing/designBaseline.ts +4 -0
- package/src/theme.css +103 -2
- package/src/themeDarkScopeAliases.spec.ts +65 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { AlertTriangle, Info, XCircle } from 'lucide-react';
|
|
2
|
+
import { type ReactNode, useId, useState } from 'react';
|
|
3
|
+
import { cn } from '../lib/cn.js';
|
|
4
|
+
import { Button } from './Button.js';
|
|
5
|
+
import { ButtonLink } from './ButtonLink.js';
|
|
6
|
+
|
|
7
|
+
export interface ShellBanner {
|
|
8
|
+
/** Stable key. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** ONE sentence — what is wrong, in the owner's words. Never a paragraph (CPY-1). */
|
|
11
|
+
message: ReactNode;
|
|
12
|
+
/** `warning` (default) for a degraded app, `error` for a broken one, `info` for a plain fact. */
|
|
13
|
+
tone?: 'info' | 'warning' | 'error';
|
|
14
|
+
/** Leading icon. Omit for the tone's own. */
|
|
15
|
+
icon?: ReactNode;
|
|
16
|
+
/** The ONE thing to do about it — "Reconnect", "Wake the Mac". */
|
|
17
|
+
action?: { label: string; onClick?: () => void; href?: string };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface BannerLaneProps {
|
|
21
|
+
banners: readonly ShellBanner[];
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TONE = {
|
|
26
|
+
info: 'bg-accent/10 [&_[data-cb-banner-icon]]:text-accent',
|
|
27
|
+
warning: 'bg-warning/10 [&_[data-cb-banner-icon]]:text-warning',
|
|
28
|
+
error: 'bg-destructive/10 [&_[data-cb-banner-icon]]:text-destructive',
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
const ICON = { info: <Info />, warning: <AlertTriangle />, error: <XCircle /> } as const;
|
|
32
|
+
|
|
33
|
+
/** The worst tone in a set: an error outranks a warning outranks a fact. */
|
|
34
|
+
const worst = (banners: readonly ShellBanner[]): keyof typeof TONE =>
|
|
35
|
+
banners.some((b) => b.tone === 'error')
|
|
36
|
+
? 'error'
|
|
37
|
+
: banners.some((b) => (b.tone ?? 'warning') === 'warning')
|
|
38
|
+
? 'warning'
|
|
39
|
+
: 'info';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The shell's ONE banner lane (NAV-10): app-wide conditions — a sign-in broke, the Mac is
|
|
43
|
+
* asleep, the app is offline — as full-width, one-line ribbons between the header and the
|
|
44
|
+
* page. Icon, sentence, one action. Two or more collapse into "N problems · View", so a bad
|
|
45
|
+
* morning is one line tall until the reader asks for the list.
|
|
46
|
+
*
|
|
47
|
+
* A banner is never a card inside the page, and never repeated on the page it links to.
|
|
48
|
+
* `AppShell banners` renders this; a shell of an app's own can render it directly.
|
|
49
|
+
*/
|
|
50
|
+
export function BannerLane({ banners, className }: BannerLaneProps) {
|
|
51
|
+
const [open, setOpen] = useState(false);
|
|
52
|
+
const listId = useId();
|
|
53
|
+
if (banners.length === 0) return null;
|
|
54
|
+
|
|
55
|
+
const only = banners.length === 1 ? banners[0] : undefined;
|
|
56
|
+
return (
|
|
57
|
+
<section
|
|
58
|
+
aria-label='App alerts'
|
|
59
|
+
data-cb-banner-lane=''
|
|
60
|
+
className={cn('shrink-0 border-b border-border', className)}
|
|
61
|
+
>
|
|
62
|
+
{only ? (
|
|
63
|
+
<BannerLine banner={only} />
|
|
64
|
+
) : (
|
|
65
|
+
<>
|
|
66
|
+
<div
|
|
67
|
+
data-cb-banner=''
|
|
68
|
+
className={cn('flex min-h-10 items-center gap-3 px-3 py-1.5 text-sm md:px-6', TONE[worst(banners)])}
|
|
69
|
+
>
|
|
70
|
+
<span data-cb-banner-icon='' aria-hidden='true' className='grid size-5 shrink-0 place-items-center [&_svg]:size-4'>
|
|
71
|
+
{ICON[worst(banners)]}
|
|
72
|
+
</span>
|
|
73
|
+
<span className='min-w-0 flex-1 truncate font-medium text-foreground'>{banners.length} problems</span>
|
|
74
|
+
<Button
|
|
75
|
+
variant='ghost'
|
|
76
|
+
size='sm'
|
|
77
|
+
aria-expanded={open}
|
|
78
|
+
aria-controls={listId}
|
|
79
|
+
onClick={() => setOpen((o) => !o)}
|
|
80
|
+
tooltip={open ? 'Hide the list' : `Show all ${banners.length}`}
|
|
81
|
+
tooltipMobile='off'
|
|
82
|
+
>
|
|
83
|
+
{open ? 'Hide' : 'View'}
|
|
84
|
+
</Button>
|
|
85
|
+
</div>
|
|
86
|
+
{open ? (
|
|
87
|
+
<ul id={listId} className='divide-y divide-border border-t border-border'>
|
|
88
|
+
{banners.map((banner) => (
|
|
89
|
+
<li key={banner.id}>
|
|
90
|
+
<BannerLine banner={banner} />
|
|
91
|
+
</li>
|
|
92
|
+
))}
|
|
93
|
+
</ul>
|
|
94
|
+
) : null}
|
|
95
|
+
</>
|
|
96
|
+
)}
|
|
97
|
+
</section>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function BannerLine({ banner }: { banner: ShellBanner }) {
|
|
102
|
+
const tone = banner.tone ?? 'warning';
|
|
103
|
+
const { action } = banner;
|
|
104
|
+
return (
|
|
105
|
+
<div
|
|
106
|
+
data-cb-banner=''
|
|
107
|
+
role={tone === 'error' ? 'alert' : 'status'}
|
|
108
|
+
className={cn('flex min-h-10 items-center gap-3 px-3 py-1.5 text-sm md:px-6', TONE[tone])}
|
|
109
|
+
>
|
|
110
|
+
<span data-cb-banner-icon='' aria-hidden='true' className='grid size-5 shrink-0 place-items-center [&_svg]:size-4'>
|
|
111
|
+
{banner.icon ?? ICON[tone]}
|
|
112
|
+
</span>
|
|
113
|
+
{/* One line: a long sentence truncates rather than growing the lane (NAV-10). */}
|
|
114
|
+
<span className='min-w-0 flex-1 truncate text-foreground'>{banner.message}</span>
|
|
115
|
+
{action ? (
|
|
116
|
+
action.href ? (
|
|
117
|
+
<ButtonLink to={action.href} variant='ghost' size='sm' onClick={action.onClick} tooltip={action.label}>
|
|
118
|
+
{action.label} →
|
|
119
|
+
</ButtonLink>
|
|
120
|
+
) : (
|
|
121
|
+
<Button variant='ghost' size='sm' onClick={action.onClick} tooltip={action.label} tooltipMobile='off'>
|
|
122
|
+
{action.label} →
|
|
123
|
+
</Button>
|
|
124
|
+
)
|
|
125
|
+
) : null}
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -242,8 +242,10 @@ export function Button({
|
|
|
242
242
|
resetTimer.current = setTimeout(() => setJustSucceeded(false), resetMs);
|
|
243
243
|
} catch (err) {
|
|
244
244
|
if (errorMessage !== false) {
|
|
245
|
+
// OVL-9: an error toast carries the action that resolves it.
|
|
245
246
|
toast.error(
|
|
246
247
|
typeof errorMessage === 'string' ? errorMessage : err instanceof Error ? err.message : String(err),
|
|
248
|
+
{ action: { label: 'Retry', onClick: () => void handleClick?.(e) } },
|
|
247
249
|
);
|
|
248
250
|
}
|
|
249
251
|
} finally {
|
|
@@ -121,7 +121,7 @@ function Chip({ active, onClick, children }: ChipProps) {
|
|
|
121
121
|
className={cn(
|
|
122
122
|
// 44 px min tap target height via py + min-h (STANDARDS §4a). px-4 keeps every
|
|
123
123
|
// pill's internal padding identical regardless of label length.
|
|
124
|
-
'inline-flex min-h-
|
|
124
|
+
'inline-flex min-h-11 shrink-0 cursor-pointer items-center rounded-full px-4 text-sm font-medium transition-colors',
|
|
125
125
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
126
126
|
// Soft active state — an accent tint + accent text (the standardized active
|
|
127
127
|
// treatment shared with nav items and the `accent` Badge tone), not a stark
|
|
@@ -4,7 +4,13 @@ import { Combobox } from '@base-ui/react/combobox';
|
|
|
4
4
|
import { Check, ChevronDown, Loader2, Plus, X } from 'lucide-react';
|
|
5
5
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
6
6
|
import { cn } from '../lib/cn.js';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
CONTROL_HEIGHT_CLASS,
|
|
9
|
+
CONTROL_MIN_HEIGHT_CLASS,
|
|
10
|
+
type ControlSize,
|
|
11
|
+
choiceFieldWidth,
|
|
12
|
+
declareFieldWidth,
|
|
13
|
+
} from '../lib/field.js';
|
|
8
14
|
import { FLOATING_COLLISION_PADDING,
|
|
9
15
|
FLOATING_CONTENT_BASE, FLOATING_ITEM_BASE } from '../lib/floatingStyles.js';
|
|
10
16
|
import { TAP_TARGET } from '../lib/tapTarget.js';
|
|
@@ -242,6 +248,10 @@ export function ComboboxField(props: ComboboxFieldProps) {
|
|
|
242
248
|
value={(multiple ? multiValue : singleValue) as never}
|
|
243
249
|
onValueChange={handleValueChange as never}
|
|
244
250
|
onInputValueChange={(v) => setQuery(v)}
|
|
251
|
+
// The value is the option's `value` string, the items are option objects: without this
|
|
252
|
+
// Base UI writes `String(value)` into the closed input — "electric", not "Electric"
|
|
253
|
+
// (forge task 2514). Called with both shapes.
|
|
254
|
+
itemToStringLabel={((v: string | ComboboxOption) => (typeof v === 'string' ? labelForValue(v) : v.label)) as never}
|
|
245
255
|
>
|
|
246
256
|
<Combobox.InputGroup className={inputGroupClass}>
|
|
247
257
|
{multiple && (
|
|
@@ -269,7 +279,9 @@ export function ComboboxField(props: ComboboxFieldProps) {
|
|
|
269
279
|
id={id}
|
|
270
280
|
aria-describedby={ariaDescribedBy}
|
|
271
281
|
aria-invalid={ariaInvalid}
|
|
272
|
-
|
|
282
|
+
// Once a chip is chosen the prompt has done its job: "Select…" beside "Idea ×" reads
|
|
283
|
+
// as if nothing were selected (forge task 2514).
|
|
284
|
+
placeholder={multiple && (multiValue?.length ?? 0) > 0 ? undefined : placeholder}
|
|
273
285
|
className={cn(
|
|
274
286
|
'min-w-24 flex-1 bg-transparent px-3 text-base text-field-fg outline-none placeholder:text-field-placeholder sm:text-sm',
|
|
275
287
|
multiple && 'py-1.5',
|
|
@@ -320,4 +332,9 @@ export function ComboboxField(props: ComboboxFieldProps) {
|
|
|
320
332
|
);
|
|
321
333
|
}
|
|
322
334
|
|
|
323
|
-
|
|
335
|
+
// FRM-3: a closed list is sized by its longest option, as SelectField is. A list that can hold
|
|
336
|
+
// a value nobody has seen yet — fetched (`loadOptions`) or typed (`creatable`) — keeps a
|
|
337
|
+
// name-length `md`; a chip row (`multiple`) keeps the whole row.
|
|
338
|
+
declareFieldWidth(ComboboxField, (props) =>
|
|
339
|
+
props.multiple ? 'full' : props.loadOptions || props.creatable ? 'md' : choiceFieldWidth(props),
|
|
340
|
+
);
|
|
@@ -108,7 +108,7 @@ function Composer({
|
|
|
108
108
|
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) submit();
|
|
109
109
|
if (e.key === 'Escape') onCancel?.();
|
|
110
110
|
}}
|
|
111
|
-
className={cn(FIELD_CLASS, 'min-h-
|
|
111
|
+
className={cn(FIELD_CLASS, 'min-h-9 flex-1')}
|
|
112
112
|
/>
|
|
113
113
|
<Button
|
|
114
114
|
variant='primary'
|
|
@@ -177,7 +177,7 @@ function CommentItem({
|
|
|
177
177
|
value={draft}
|
|
178
178
|
rows={1}
|
|
179
179
|
onChange={(e) => setDraft(e.target.value)}
|
|
180
|
-
className={cn(FIELD_CLASS, 'min-h-
|
|
180
|
+
className={cn(FIELD_CLASS, 'min-h-9 flex-1')}
|
|
181
181
|
/>
|
|
182
182
|
<Button
|
|
183
183
|
variant='primary'
|
|
@@ -53,7 +53,7 @@ export function ConfirmDialog({
|
|
|
53
53
|
<DialogContent
|
|
54
54
|
ref={contentRef}
|
|
55
55
|
className={cn(
|
|
56
|
-
'fixed top-1/2 left-1/2 flex w-[calc(100vw-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 flex-col gap-4',
|
|
56
|
+
'fixed top-1/2 left-1/2 flex w-[calc(100vw-2rem)] max-w-[var(--modal-w-sm)] -translate-x-1/2 -translate-y-1/2 flex-col gap-4',
|
|
57
57
|
'rounded-xl border border-border bg-popover p-6 text-popover-foreground shadow-overlay',
|
|
58
58
|
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
59
59
|
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
@@ -50,12 +50,14 @@ import { SortHeader } from './SortHeader.js';
|
|
|
50
50
|
import type {
|
|
51
51
|
ColDef,
|
|
52
52
|
DataTableHandle,
|
|
53
|
+
DataTableRowAction,
|
|
53
54
|
DataTableRowProps,
|
|
54
55
|
DataTableSelectAll,
|
|
55
56
|
DataTableServerWindow,
|
|
56
57
|
TableViewMode,
|
|
57
58
|
} from './types.js';
|
|
58
|
-
import { resolveColumnAlign, SELECT_COLUMN_ID } from './types.js';
|
|
59
|
+
import { isNumericColumn, resolveColumnAlign, SELECT_COLUMN_ID, untypedNumericColumn } from './types.js';
|
|
60
|
+
import { devWarnOnce } from '../../lib/devWarn.js';
|
|
59
61
|
import { AUTO_TRACK_FLOOR_PX, columnFloor, columnsDroppedForWidth } from './columnPriority.js';
|
|
60
62
|
import { lazyPart } from './lazyPart.js';
|
|
61
63
|
import type { TablePaginationProps } from './Pagination.js';
|
|
@@ -105,7 +107,7 @@ function ToolbarPlaceholder() {
|
|
|
105
107
|
/** Where the pager will be, the height it will be. */
|
|
106
108
|
function PaginationPlaceholder() {
|
|
107
109
|
return (
|
|
108
|
-
<div data-cb-table-pagination-pending='' aria-hidden className='border-t border-border px-4 py-2
|
|
110
|
+
<div data-cb-table-pagination-pending='' aria-hidden className='border-t border-border px-4 py-2'>
|
|
109
111
|
<div className={cn('h-8', TAP_TARGET_HEIGHT)} />
|
|
110
112
|
</div>
|
|
111
113
|
);
|
|
@@ -143,6 +145,8 @@ declare module '@tanstack/react-table' {
|
|
|
143
145
|
minWidth?: number;
|
|
144
146
|
hideBelow?: 'sm' | 'md' | 'lg';
|
|
145
147
|
leading?: boolean;
|
|
148
|
+
/** The column's values are numbers — its header and cells set `tabular-nums` (DAT-1). */
|
|
149
|
+
numeric?: boolean;
|
|
146
150
|
}
|
|
147
151
|
interface TableMeta<TData extends RowData> {
|
|
148
152
|
/** {@link DataTableControls} — see its doc for why it rides on the table. */
|
|
@@ -229,6 +233,12 @@ export interface DataTableProps<TRow extends Record<string, unknown>> {
|
|
|
229
233
|
/** The kebab's accessible name for one row — `(row) => \`More for ${row.title}\``. Default
|
|
230
234
|
* `Row actions`, identical on every row. */
|
|
231
235
|
rowMenuLabel?: (row: TRow) => string;
|
|
236
|
+
/**
|
|
237
|
+
* The row's ONE optional inline action, beside its `⋯` (DAT-5) — only when it is the row's
|
|
238
|
+
* reason to exist ("Play", "Retry"). Return `null` for a row that has none. Everything else
|
|
239
|
+
* goes in {@link rowMenu}. Renders the actions column.
|
|
240
|
+
*/
|
|
241
|
+
rowAction?: (row: TRow) => DataTableRowAction | null;
|
|
232
242
|
loading?: boolean;
|
|
233
243
|
/** Shown when there are no rows (default: a plain "No results"). */
|
|
234
244
|
emptyState?: ReactNode;
|
|
@@ -290,6 +300,14 @@ export interface DataTableProps<TRow extends Record<string, unknown>> {
|
|
|
290
300
|
* cells vary wildly and that never claimed fixed lanes.
|
|
291
301
|
*/
|
|
292
302
|
fixedLayout?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Keep the table's MEASURE (DAT-3, LAY-2): it takes its columns' natural content width, up
|
|
305
|
+
* to its container, instead of stretching every column across a 1536px page. A dense table
|
|
306
|
+
* spread over a 2,560px monitor is a row nobody can track from its name to its numbers. The
|
|
307
|
+
* table hugs the left edge and the toolbar keeps the container's width. Off by default,
|
|
308
|
+
* because a fixed-layout table's proportional tracks need the full width to mean anything.
|
|
309
|
+
*/
|
|
310
|
+
fit?: boolean;
|
|
293
311
|
/**
|
|
294
312
|
* EXTRA freeze floor for the wide grid (px): below this the columns stop
|
|
295
313
|
* compressing and the wrapper scrolls horizontally instead — the design
|
|
@@ -910,6 +928,7 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
910
928
|
onRowDelete,
|
|
911
929
|
rowMenu,
|
|
912
930
|
rowMenuLabel,
|
|
931
|
+
rowAction,
|
|
913
932
|
loading,
|
|
914
933
|
emptyState,
|
|
915
934
|
toolbar,
|
|
@@ -925,6 +944,7 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
925
944
|
rowClassName,
|
|
926
945
|
hideEmptyColumns,
|
|
927
946
|
fixedLayout,
|
|
947
|
+
fit = false,
|
|
928
948
|
minTableWidth,
|
|
929
949
|
scrollBody,
|
|
930
950
|
virtualize,
|
|
@@ -1048,6 +1068,18 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
1048
1068
|
[columns, data, hideEmptyColumns],
|
|
1049
1069
|
);
|
|
1050
1070
|
|
|
1071
|
+
// DAT-1: a plain-text column of numbers left-aligns them in proportional digits, which is
|
|
1072
|
+
// the misalignment the type system exists to prevent. Warn the author (dev only, once per
|
|
1073
|
+
// column) instead of guessing — a column of zip codes or years is "numeric" and is not.
|
|
1074
|
+
useEffect(() => {
|
|
1075
|
+
if (data.length === 0) return;
|
|
1076
|
+
const sample = data.slice(0, 50);
|
|
1077
|
+
for (const col of columns) {
|
|
1078
|
+
const warning = untypedNumericColumn(col, sample.map((row) => readPath(row, col.key)));
|
|
1079
|
+
if (warning) devWarnOnce(`datatable-untyped-numeric:${col.key}`, warning);
|
|
1080
|
+
}
|
|
1081
|
+
}, [columns, data]);
|
|
1082
|
+
|
|
1051
1083
|
/**
|
|
1052
1084
|
* The filter BUILDER is applied to the rows before TanStack ever sees them,
|
|
1053
1085
|
* and that is deliberate: it is what makes the builder AND with the search box
|
|
@@ -1109,6 +1141,7 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
1109
1141
|
label: col.label,
|
|
1110
1142
|
menuLabel: col.menuLabel,
|
|
1111
1143
|
align: resolveColumnAlign(col),
|
|
1144
|
+
numeric: isNumericColumn(col),
|
|
1112
1145
|
width: col.width,
|
|
1113
1146
|
minWidth: col.minWidth,
|
|
1114
1147
|
hideBelow: col.hideBelow,
|
|
@@ -1558,7 +1591,10 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
1558
1591
|
/** The spacers belong to the tier on screen; the hidden ones hold no rows and no padding. */
|
|
1559
1592
|
const tierPad = (t: TableTier) =>
|
|
1560
1593
|
virtualEnabled && activeTier === t ? { paddingTop: padTop, paddingBottom: padBottom } : undefined;
|
|
1561
|
-
const hasActions = !!(onRowEdit || onRowDelete || rowMenu);
|
|
1594
|
+
const hasActions = !!(onRowEdit || onRowDelete || rowMenu || rowAction);
|
|
1595
|
+
// DAT-5: right-click opens the SAME menu the row's `⋯` opens — a desktop accelerator, never
|
|
1596
|
+
// the only way in. Held by row id so the menu stays anchored to that row's kebab.
|
|
1597
|
+
const [contextMenuRowId, setContextMenuRowId] = useState<string | null>(null);
|
|
1562
1598
|
|
|
1563
1599
|
// ── Row selection (see the `selectedIds` prop doc) ──────────────────────────
|
|
1564
1600
|
const canSelect = (row: TRow) => isRowSelectable?.(row) ?? true;
|
|
@@ -1769,7 +1805,23 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
1769
1805
|
))}
|
|
1770
1806
|
</div>
|
|
1771
1807
|
) : rows.length === 0 && windowTotal === 0 ? (
|
|
1772
|
-
<div className='p-2'>
|
|
1808
|
+
<div className='p-2'>
|
|
1809
|
+
{emptyState ??
|
|
1810
|
+
// STA-3: rows exist and the reader's search or filters hid them all — say so, and
|
|
1811
|
+
// offer the one action that undoes it. A table with no data says "No results".
|
|
1812
|
+
(data.length > 0 && !serverWindow ? (
|
|
1813
|
+
<EmptyState
|
|
1814
|
+
compact
|
|
1815
|
+
onClearFilters={() => {
|
|
1816
|
+
setSearchText('');
|
|
1817
|
+
setFilterQuery(EMPTY_FILTER_QUERY);
|
|
1818
|
+
setColumnFilters([]);
|
|
1819
|
+
}}
|
|
1820
|
+
/>
|
|
1821
|
+
) : (
|
|
1822
|
+
<EmptyState title='No results' />
|
|
1823
|
+
))}
|
|
1824
|
+
</div>
|
|
1773
1825
|
) : (
|
|
1774
1826
|
// scrollBody makes the table body the one scroll container for BOTH axes —
|
|
1775
1827
|
// required for stickyHeader to pin (see the prop doc); ScrollArea's
|
|
@@ -1859,7 +1911,8 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
1859
1911
|
onEdit={onRowEdit}
|
|
1860
1912
|
onDelete={onRowDelete}
|
|
1861
1913
|
menu={rowMenu?.(row.original)}
|
|
1862
|
-
|
|
1914
|
+
menuLabel={rowMenuLabel?.(row.original)}
|
|
1915
|
+
action={rowAction?.(row.original) ?? undefined}
|
|
1863
1916
|
/>
|
|
1864
1917
|
) : null
|
|
1865
1918
|
}
|
|
@@ -1998,6 +2051,7 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
1998
2051
|
onDelete={onRowDelete}
|
|
1999
2052
|
menu={rowMenu?.(row.original)}
|
|
2000
2053
|
menuLabel={rowMenuLabel?.(row.original)}
|
|
2054
|
+
action={rowAction?.(row.original) ?? undefined}
|
|
2001
2055
|
/>
|
|
2002
2056
|
) : null}
|
|
2003
2057
|
</div>
|
|
@@ -2057,7 +2111,8 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
2057
2111
|
aria-rowcount={
|
|
2058
2112
|
virtualEnabled ? (serverWindow ? windowTotal + 1 : onNearEnd ? -1 : rows.length + 1) : undefined
|
|
2059
2113
|
}
|
|
2060
|
-
|
|
2114
|
+
data-cb-table-fit={fit || undefined}
|
|
2115
|
+
className={cn('border-collapse text-sm', fit ? 'w-auto max-w-full' : 'w-full', fixedLayout && 'table-fixed')}
|
|
2061
2116
|
style={tableMinWidth != null ? { minWidth: tableMinWidth } : undefined}
|
|
2062
2117
|
>
|
|
2063
2118
|
{caption ? <caption className='sr-only'>{caption}</caption> : null}
|
|
@@ -2097,6 +2152,11 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
2097
2152
|
'border-b border-border px-4 text-caption font-bold uppercase tracking-wider text-muted-foreground',
|
|
2098
2153
|
cellPadY,
|
|
2099
2154
|
align === 'right' ? 'text-right' : 'text-left',
|
|
2155
|
+
meta?.numeric && 'tabular-nums',
|
|
2156
|
+
// Under `fit` the column takes its CONTENT's width, and a truncating
|
|
2157
|
+
// label contributes none — "RUNS" read "R…" over a column of 2,472s.
|
|
2158
|
+
// The header's own width is the column's floor instead.
|
|
2159
|
+
fit && 'min-w-max [&>*]:max-w-none',
|
|
2100
2160
|
// Sticky pins per-<th> (a <tr> can't stick); needs its own
|
|
2101
2161
|
// near-opaque bg so rows scrolling beneath never bleed through.
|
|
2102
2162
|
stickyHeader &&
|
|
@@ -2143,7 +2203,8 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
2143
2203
|
{hasActions ? (
|
|
2144
2204
|
<th
|
|
2145
2205
|
className={cn(
|
|
2146
|
-
|
|
2206
|
+
// A fixed trailing track (DAT-12): the ⋯ lines up down the list.
|
|
2207
|
+
rowAction ? 'w-32 border-b border-border px-2' : 'w-20 border-b border-border px-2',
|
|
2147
2208
|
stickyHeader && 'sticky top-0 z-10 bg-card/95 backdrop-blur-sm',
|
|
2148
2209
|
)}
|
|
2149
2210
|
aria-label='Row actions'
|
|
@@ -2220,6 +2281,13 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
2220
2281
|
),
|
|
2221
2282
|
tabIndex: onRowClick ? 0 : undefined,
|
|
2222
2283
|
onClick: onRowClick ? (event: MouseEvent<HTMLElement>) => onRowClick(row.original, event) : undefined,
|
|
2284
|
+
onContextMenu: rowMenu
|
|
2285
|
+
? (event: MouseEvent<HTMLElement>) => {
|
|
2286
|
+
if (rowMenu(row.original).length === 0) return;
|
|
2287
|
+
event.preventDefault();
|
|
2288
|
+
setContextMenuRowId(row.id);
|
|
2289
|
+
}
|
|
2290
|
+
: undefined,
|
|
2223
2291
|
onKeyDown: onRowClick
|
|
2224
2292
|
? (e: KeyboardEvent<HTMLElement>) => {
|
|
2225
2293
|
if (e.key === 'Enter') onRowClick(row.original);
|
|
@@ -2266,6 +2334,7 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
2266
2334
|
// has to escape its bounds.
|
|
2267
2335
|
fixedLayout && '[overflow-wrap:anywhere]',
|
|
2268
2336
|
cell.column.columnDef.meta?.align === 'right' && 'text-right',
|
|
2337
|
+
cell.column.columnDef.meta?.numeric && 'tabular-nums',
|
|
2269
2338
|
cell.column.columnDef.meta?.hideBelow &&
|
|
2270
2339
|
HIDE_BELOW_CLASS[cell.column.columnDef.meta.hideBelow],
|
|
2271
2340
|
droppedByWidth.has(cell.column.id) && COLLAPSED_CLASS,
|
|
@@ -2310,7 +2379,10 @@ export function DataTable<TRow extends Record<string, unknown>>({
|
|
|
2310
2379
|
onEdit={onRowEdit}
|
|
2311
2380
|
onDelete={onRowDelete}
|
|
2312
2381
|
menu={rowMenu?.(row.original)}
|
|
2313
|
-
|
|
2382
|
+
menuLabel={rowMenuLabel?.(row.original)}
|
|
2383
|
+
action={rowAction?.(row.original) ?? undefined}
|
|
2384
|
+
menuOpen={contextMenuRowId === row.id}
|
|
2385
|
+
onMenuOpenChange={(open) => setContextMenuRowId(open ? row.id : null)}
|
|
2314
2386
|
/>
|
|
2315
2387
|
</td>
|
|
2316
2388
|
) : null}
|
|
@@ -25,7 +25,7 @@ export function TablePagination<TRow>({ table, pageSizeOptions }: TablePaginatio
|
|
|
25
25
|
const end = Math.min((pageIndex + 1) * pageSize, total);
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
|
-
<div className='flex flex-wrap items-center justify-between gap-3 border-t border-border px-4 py-2
|
|
28
|
+
<div className='flex flex-wrap items-center justify-between gap-3 border-t border-border px-4 py-2 text-sm text-muted-foreground'>
|
|
29
29
|
<div className='flex items-center gap-3'>
|
|
30
30
|
<span>{total === 0 ? 'No results' : `${start}–${end} of ${total}`}</span>
|
|
31
31
|
{pageSizeOptions?.length ? (
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { EllipsisVertical, Pencil, Trash2 } from 'lucide-react';
|
|
2
|
+
import { Button } from '../Button.js';
|
|
2
3
|
import type { DropdownMenuItem } from '../DropdownMenu.js';
|
|
3
4
|
import { IconButton } from '../IconButton.js';
|
|
5
|
+
import type { DataTableRowAction } from './types.js';
|
|
4
6
|
import { lazyPart } from './lazyPart.js';
|
|
5
7
|
|
|
6
8
|
// The kebab's menu is Radix's Menu, and most tables never draw a kebab — so it loads
|
|
@@ -21,6 +23,11 @@ export interface RowActionsProps<TRow> {
|
|
|
21
23
|
/** The kebab's accessible name and tooltip — say WHOSE actions (`More for Alien`). Default
|
|
22
24
|
* `Row actions`, which a screen reader repeats identically on every row. */
|
|
23
25
|
menuLabel?: string;
|
|
26
|
+
/** The row's ONE inline action (DAT-5) — a quiet button before the kebab. */
|
|
27
|
+
action?: DataTableRowAction;
|
|
28
|
+
/** Controlled open state of the kebab's menu — how a right-click on the row opens it. */
|
|
29
|
+
menuOpen?: boolean;
|
|
30
|
+
onMenuOpenChange?: (open: boolean) => void;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
/**
|
|
@@ -30,7 +37,16 @@ export interface RowActionsProps<TRow> {
|
|
|
30
37
|
* caller's call (wrap `onDelete` with `confirm()` from task 10) — this primitive just
|
|
31
38
|
* surfaces the intent.
|
|
32
39
|
*/
|
|
33
|
-
export function RowActions<TRow>({
|
|
40
|
+
export function RowActions<TRow>({
|
|
41
|
+
row,
|
|
42
|
+
onEdit,
|
|
43
|
+
onDelete,
|
|
44
|
+
menu,
|
|
45
|
+
menuLabel = 'Row actions',
|
|
46
|
+
action,
|
|
47
|
+
menuOpen,
|
|
48
|
+
onMenuOpenChange,
|
|
49
|
+
}: RowActionsProps<TRow>) {
|
|
34
50
|
const kebab = (
|
|
35
51
|
<IconButton label={menuLabel} className='size-8 pointer-coarse:min-w-11 [&_svg]:size-4'>
|
|
36
52
|
<EllipsisVertical />
|
|
@@ -46,6 +62,37 @@ export function RowActions<TRow>({ row, onEdit, onDelete, menu, menuLabel = 'Row
|
|
|
46
62
|
onClick={(e) => e.stopPropagation()}
|
|
47
63
|
onPointerDown={(e) => e.stopPropagation()}
|
|
48
64
|
>
|
|
65
|
+
{action ? (
|
|
66
|
+
action.icon ? (
|
|
67
|
+
<IconButton
|
|
68
|
+
label={action.label}
|
|
69
|
+
className='size-8 pointer-coarse:min-w-11 [&_svg]:size-4'
|
|
70
|
+
disabled={action.disabled && !action.disabledReason}
|
|
71
|
+
unavailableReason={action.disabled ? action.disabledReason : undefined}
|
|
72
|
+
onClick={(e) => {
|
|
73
|
+
e.stopPropagation();
|
|
74
|
+
action.onClick();
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{action.icon}
|
|
78
|
+
</IconButton>
|
|
79
|
+
) : (
|
|
80
|
+
<Button
|
|
81
|
+
variant='ghost'
|
|
82
|
+
size='sm'
|
|
83
|
+
tooltip={action.label}
|
|
84
|
+
tooltipMobile='off'
|
|
85
|
+
disabled={action.disabled && !action.disabledReason}
|
|
86
|
+
unavailableReason={action.disabled ? action.disabledReason : undefined}
|
|
87
|
+
onClick={(e) => {
|
|
88
|
+
e.stopPropagation();
|
|
89
|
+
action.onClick();
|
|
90
|
+
}}
|
|
91
|
+
>
|
|
92
|
+
{action.label}
|
|
93
|
+
</Button>
|
|
94
|
+
)
|
|
95
|
+
) : null}
|
|
49
96
|
{onEdit ? (
|
|
50
97
|
<IconButton
|
|
51
98
|
label='Edit row'
|
|
@@ -73,7 +120,13 @@ export function RowActions<TRow>({ row, onEdit, onDelete, menu, menuLabel = 'Row
|
|
|
73
120
|
{menu && menu.length > 0 ? (
|
|
74
121
|
// Until the menu arrives the kebab is already there, the same button in the same
|
|
75
122
|
// place — so nothing shifts and nothing flashes; a click in those milliseconds opens nothing.
|
|
76
|
-
<MenuPart
|
|
123
|
+
<MenuPart
|
|
124
|
+
align='end'
|
|
125
|
+
trigger={kebab}
|
|
126
|
+
items={menu}
|
|
127
|
+
fallback={kebab}
|
|
128
|
+
{...(onMenuOpenChange ? { open: menuOpen ?? false, onOpenChange: onMenuOpenChange } : {})}
|
|
129
|
+
/>
|
|
77
130
|
) : null}
|
|
78
131
|
</div>
|
|
79
132
|
);
|
|
@@ -152,7 +152,7 @@ export function TableFilterBuilder({
|
|
|
152
152
|
) : null}
|
|
153
153
|
|
|
154
154
|
{/* guardrails-ignore no-raw-overflow: bounded builder body inside a portal panel. */}
|
|
155
|
-
<div className='flex max-h-
|
|
155
|
+
<div className='flex max-h-88 flex-col gap-2 overflow-y-auto'>
|
|
156
156
|
{value.groups.map((group, groupIndex) => (
|
|
157
157
|
<div key={group.id}>
|
|
158
158
|
{groupIndex > 0 ? (
|
|
@@ -17,7 +17,7 @@ export function CodeCell({ value, language }: CodeCellProps) {
|
|
|
17
17
|
<TruncatedText
|
|
18
18
|
as='code'
|
|
19
19
|
data-language={language}
|
|
20
|
-
className='block max-w-
|
|
20
|
+
className='block max-w-60 rounded bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground'
|
|
21
21
|
>
|
|
22
22
|
{value}
|
|
23
23
|
</TruncatedText>
|
|
@@ -25,7 +25,7 @@ export function LinkCell({ href, label }: LinkCellProps): JSX.Element | null {
|
|
|
25
25
|
url={href}
|
|
26
26
|
{...(label === undefined ? {} : { display: label })}
|
|
27
27
|
stopPropagation
|
|
28
|
-
className={`max-w-
|
|
28
|
+
className={`max-w-45 truncate font-sans not-italic ${TAP_TARGET_HEIGHT}`}
|
|
29
29
|
/>
|
|
30
30
|
);
|
|
31
31
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { isNumericColumn, untypedNumericColumn } from './types.js';
|
|
3
|
+
|
|
4
|
+
describe('DAT-1 · what counts as a numeric column', () => {
|
|
5
|
+
test('money counts as numeric, text does not', () => {
|
|
6
|
+
expect(isNumericColumn({ key: 'a', label: 'A', type: 'money' })).toBe(true);
|
|
7
|
+
expect(isNumericColumn({ key: 'a', label: 'A', type: 'text' })).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('a text column holding only numbers is named; a rendered or aligned one is left alone', () => {
|
|
11
|
+
const col = { key: 'code', label: 'Code', type: 'text' } as const;
|
|
12
|
+
expect(untypedNumericColumn(col, ['41', '7', '1,204'])).toContain("type 'number'");
|
|
13
|
+
expect(untypedNumericColumn(col, ['41', 'x'])).toBeNull();
|
|
14
|
+
expect(untypedNumericColumn(col, ['41'])).toBeNull();
|
|
15
|
+
expect(untypedNumericColumn({ ...col, align: 'left' }, ['41', '7'])).toBeNull();
|
|
16
|
+
expect(untypedNumericColumn({ ...col, render: () => null }, ['41', '7'])).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
});
|