basalt-ui 1.30.2 → 1.32.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/AGENTS.md +1 -1
- package/CHANGELOG.md +54 -0
- package/MIGRATING.md +256 -12
- package/agent/rules/basalt-controls.md +19 -19
- package/agent/rules/basalt-mantine.md +5 -5
- package/configs/oxlint-plugin.js +371 -4
- package/configs/oxlint-plugin.test.ts +327 -2
- package/configs/oxlint.json +2 -1
- package/dist/agent-chat/composer.d.ts.map +1 -1
- package/dist/agent-chat/composer.js +41 -43
- package/dist/agent-chat/thread-workspace.d.ts +2 -2
- package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
- package/dist/agent-chat/thread-workspace.js +3 -4
- package/dist/agent-chat/use-keyboard-inset.d.ts +2 -0
- package/dist/agent-chat/use-keyboard-inset.d.ts.map +1 -0
- package/dist/agent-chat/use-keyboard-inset.js +34 -0
- package/dist/charts/cursor/touch-pin.d.ts +45 -0
- package/dist/charts/cursor/touch-pin.d.ts.map +1 -0
- package/dist/charts/cursor/touch-pin.js +79 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts +66 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts.map +1 -0
- package/dist/charts/hooks/use-discrete-cursor.js +198 -0
- package/dist/charts/hooks/use-hysteresis.d.ts +18 -0
- package/dist/charts/hooks/use-hysteresis.d.ts.map +1 -0
- package/dist/charts/hooks/use-hysteresis.js +12 -0
- package/dist/charts/hooks/useBandPlot.d.ts +7 -0
- package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
- package/dist/charts/hooks/useBandPlot.js +62 -18
- package/dist/charts/hooks/useChartCursor.d.ts +40 -11
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
- package/dist/charts/hooks/useChartCursor.js +102 -11
- package/dist/charts/index.d.ts +0 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +0 -10
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +47 -82
- package/dist/charts/kinds/Donut.d.ts +9 -3
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +110 -48
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +138 -145
- package/dist/charts/kinds/Heatmap.d.ts +7 -0
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +37 -16
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
- package/dist/charts/kinds/MirroredBars.js +68 -111
- package/dist/charts/kinds/band-chrome.d.ts +31 -0
- package/dist/charts/kinds/band-chrome.d.ts.map +1 -0
- package/dist/charts/kinds/band-chrome.js +71 -0
- package/dist/charts/kinds/donut-layout.d.ts +47 -0
- package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
- package/dist/charts/kinds/donut-layout.js +52 -0
- package/dist/charts/layout/auto-margin.d.ts +7 -2
- package/dist/charts/layout/auto-margin.d.ts.map +1 -1
- package/dist/charts/layout/auto-margin.js +12 -3
- package/dist/charts/layout/end-labels.d.ts +64 -0
- package/dist/charts/layout/end-labels.d.ts.map +1 -0
- package/dist/charts/layout/end-labels.js +76 -0
- package/dist/charts/primitives/Axes.d.ts +32 -4
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +62 -16
- package/dist/charts/primitives/CartesianChart.d.ts +7 -6
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +264 -145
- package/dist/charts/primitives/ChartCard.d.ts +0 -14
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +56 -21
- package/dist/charts/primitives/ChartFrame.d.ts +28 -22
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +116 -34
- package/dist/charts/primitives/ChartLegend.d.ts +19 -15
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +86 -73
- package/dist/charts/primitives/ChartTooltip.d.ts +5 -0
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +20 -4
- package/dist/charts/primitives/Crosshair.js +2 -2
- package/dist/charts/primitives/HoverOverlay.d.ts +29 -9
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +54 -27
- package/dist/charts/primitives/HoverOverlay.module.css +13 -0
- package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/dist/charts/primitives/chart-card-context.d.ts +33 -0
- package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
- package/dist/charts/primitives/chart-card-context.js +18 -0
- package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
- package/dist/charts/primitives/chart-frame-layout.js +75 -34
- package/dist/charts/primitives/chart-layout.d.ts +112 -0
- package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
- package/dist/charts/primitives/chart-layout.js +175 -0
- package/dist/charts/primitives/chart-tier.d.ts +13 -11
- package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
- package/dist/charts/primitives/chart-tier.js +42 -13
- package/dist/charts/primitives/legend-disclosure.d.ts +27 -0
- package/dist/charts/primitives/legend-disclosure.d.ts.map +1 -0
- package/dist/charts/primitives/legend-disclosure.js +153 -0
- package/dist/charts/series.d.ts +4 -1
- package/dist/charts/series.d.ts.map +1 -1
- package/dist/charts/utils/ticks.d.ts +27 -8
- package/dist/charts/utils/ticks.d.ts.map +1 -1
- package/dist/charts/utils/ticks.js +35 -11
- package/dist/common/errors.d.ts +11 -1
- package/dist/common/errors.d.ts.map +1 -1
- package/dist/common/errors.js +16 -2
- package/dist/common/hit-floor.d.ts +10 -0
- package/dist/common/hit-floor.d.ts.map +1 -0
- package/dist/common/hit-floor.js +6 -0
- package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
- package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/common/use-measured-widths.d.ts +37 -0
- package/dist/common/use-measured-widths.d.ts.map +1 -0
- package/dist/common/use-measured-widths.js +51 -0
- package/dist/common/use-media-query.d.ts +6 -0
- package/dist/common/use-media-query.d.ts.map +1 -0
- package/dist/common/use-media-query.js +40 -0
- package/dist/common/validate.d.ts +9 -0
- package/dist/common/validate.d.ts.map +1 -1
- package/dist/common/validate.js +9 -4
- package/dist/content/article-layout.d.ts +4 -2
- package/dist/content/article-layout.d.ts.map +1 -1
- package/dist/content/article-layout.js +43 -3
- package/dist/content/article-layout.module.css +45 -4
- package/dist/content/article-layout.module.css.d.ts +3 -0
- package/dist/content/code-block.d.ts.map +1 -1
- package/dist/content/code-block.js +40 -2
- package/dist/content/code-block.module.css +32 -2
- package/dist/content/prose.module.css +13 -8
- package/dist/controls/actions.d.ts +29 -6
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/actions.js +158 -27
- package/dist/controls/actions.module.css +14 -1
- package/dist/controls/actions.module.css.d.ts +1 -0
- package/dist/controls/controls.module.css +13 -31
- package/dist/controls/enum-filter.js +2 -2
- package/dist/controls/filter-context.d.ts +10 -0
- package/dist/controls/filter-context.d.ts.map +1 -1
- package/dist/controls/filter-context.js +2 -0
- package/dist/controls/filter-pill.d.ts.map +1 -1
- package/dist/controls/filter-pill.js +1 -0
- package/dist/controls/index.d.ts +1 -1
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +0 -2
- package/dist/controls/multi-select-filter.js +2 -2
- package/dist/controls/sync-button.module.css +2 -1
- package/dist/dashboard/section.d.ts.map +1 -1
- package/dist/dashboard/section.js +1 -0
- package/dist/dashboard/section.module.css +1 -26
- package/dist/dashboard/stat-card.d.ts +1 -1
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +4 -1
- package/dist/dashboard/stat-card.module.css +6 -9
- package/dist/dashboard/stat-group.module.css +33 -66
- package/dist/dashboard/widget-grid.d.ts.map +1 -1
- package/dist/dashboard/widget-grid.module.css +11 -38
- package/dist/dashboard/widget-header.d.ts +14 -4
- package/dist/dashboard/widget-header.d.ts.map +1 -1
- package/dist/dashboard/widget-header.js +23 -6
- package/dist/dashboard/widget-header.module.css +145 -133
- package/dist/dashboard/widget-header.module.css.d.ts +2 -0
- package/dist/data/data-table-state.d.ts +83 -0
- package/dist/data/data-table-state.d.ts.map +1 -0
- package/dist/data/data-table-state.js +139 -0
- package/dist/data/data-table.d.ts +56 -2
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +436 -336
- package/dist/data/data-table.module.css +94 -0
- package/dist/data/data-table.module.css.d.ts +11 -0
- package/dist/data/virtual-list.d.ts.map +1 -1
- package/dist/data/virtual-list.js +10 -0
- package/dist/forms/form-layout.d.ts.map +1 -1
- package/dist/forms/form-layout.js +3 -3
- package/dist/forms/form-layout.module.css +20 -5
- package/dist/forms/form-layout.module.css.d.ts +1 -0
- package/dist/guard/index.d.ts +8 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +68 -2
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/notifications/center.d.ts.map +1 -1
- package/dist/provider/index.d.ts +20 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +30 -8
- package/dist/shell/app-brand.d.ts.map +1 -1
- package/dist/shell/app-brand.js +1 -0
- package/dist/shell/app-brand.module.css +2 -2
- package/dist/shell/app-header.module.css +18 -8
- package/dist/shell/app-main.module.css +54 -3
- package/dist/shell/app-main.module.css.d.ts +1 -0
- package/dist/shell/app-mobile-nav.module.css +16 -4
- package/dist/shell/app-sidebar.module.css +4 -6
- package/dist/shell/aside-docking.d.ts +31 -0
- package/dist/shell/aside-docking.d.ts.map +1 -0
- package/dist/shell/aside-docking.js +19 -0
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +56 -16
- package/dist/shell/mobile-nav-model.d.ts +1 -1
- package/dist/shell/page-aside.d.ts +22 -3
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +27 -13
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +10 -5
- package/dist/shell/page-bar.module.css +10 -34
- package/dist/shell/use-breakpoint.d.ts +3 -4
- package/dist/shell/use-breakpoint.d.ts.map +1 -1
- package/dist/shell/use-breakpoint.js +3 -25
- package/dist/shell/use-size-class.d.ts +6 -0
- package/dist/shell/use-size-class.d.ts.map +1 -0
- package/dist/shell/use-size-class.js +19 -0
- package/dist/state/persisted-or-local.d.ts +4 -1
- package/dist/state/persisted-or-local.d.ts.map +1 -1
- package/dist/state/persisted-or-local.js +4 -3
- package/dist/state/persisted.d.ts +10 -0
- package/dist/state/persisted.d.ts.map +1 -1
- package/dist/state/persisted.js +44 -14
- package/dist/styles.css +41 -0
- package/dist/surfaces.d.ts +4 -4
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +11 -3
- package/dist/theme/controls.module.css +7 -0
- package/dist/theme/ctl-theme.d.ts +1 -0
- package/dist/theme/ctl-theme.d.ts.map +1 -1
- package/dist/theme/ctl-theme.js +12 -4
- package/dist/theme/floating.module.css +37 -0
- package/dist/theme/floating.module.css.d.ts +3 -0
- package/dist/theme/index.d.ts +2 -2
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +34 -5
- package/dist/theme/nav-link.module.css +7 -0
- package/dist/theme-lab/derive-controls.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +7 -16
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +23 -28
- package/dist/tokens/palette.d.ts +5 -27
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +8 -30
- package/dist/tokens/size-classes.d.ts +40 -0
- package/dist/tokens/size-classes.d.ts.map +1 -0
- package/dist/tokens/size-classes.js +29 -0
- package/dist/tokens.css +8 -4
- package/llms.txt +3 -3
- package/package.json +18 -17
- package/src/agent-chat/composer.tsx +74 -47
- package/src/agent-chat/thread-workspace.tsx +8 -11
- package/src/agent-chat/use-keyboard-inset.ts +68 -0
- package/src/charts/cursor/touch-pin.ts +138 -0
- package/src/charts/hooks/use-discrete-cursor.ts +335 -0
- package/src/charts/hooks/use-hysteresis.ts +26 -0
- package/src/charts/hooks/useBandPlot.ts +90 -27
- package/src/charts/hooks/useChartCursor.ts +211 -26
- package/src/charts/index.ts +0 -8
- package/src/charts/kinds/BandStrip.tsx +25 -61
- package/src/charts/kinds/Donut.tsx +153 -62
- package/src/charts/kinds/DualPanel.tsx +21 -26
- package/src/charts/kinds/Heatmap.tsx +61 -22
- package/src/charts/kinds/MirroredBars.tsx +23 -65
- package/src/charts/kinds/band-chrome.tsx +91 -0
- package/src/charts/kinds/donut-layout.ts +82 -0
- package/src/charts/layout/auto-margin.ts +24 -5
- package/src/charts/layout/end-labels.ts +135 -0
- package/src/charts/primitives/Axes.tsx +112 -21
- package/src/charts/primitives/CartesianChart.tsx +282 -111
- package/src/charts/primitives/ChartCard.tsx +119 -48
- package/src/charts/primitives/ChartFrame.tsx +204 -60
- package/src/charts/primitives/ChartLegend.tsx +115 -78
- package/src/charts/primitives/ChartTooltip.tsx +24 -3
- package/src/charts/primitives/Crosshair.tsx +2 -2
- package/src/charts/primitives/HoverOverlay.module.css +13 -0
- package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/src/charts/primitives/HoverOverlay.tsx +62 -20
- package/src/charts/primitives/chart-card-context.ts +46 -0
- package/src/charts/primitives/chart-frame-layout.ts +207 -182
- package/src/charts/primitives/chart-layout.ts +318 -0
- package/src/charts/primitives/chart-tier.tsx +66 -21
- package/src/charts/primitives/legend-disclosure.tsx +177 -0
- package/src/charts/series.ts +4 -1
- package/src/charts/utils/ticks.ts +95 -19
- package/src/common/errors.ts +25 -1
- package/src/common/hit-floor.ts +9 -0
- package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
- package/src/common/use-measured-widths.ts +88 -0
- package/src/common/use-media-query.ts +56 -0
- package/src/common/validate.ts +17 -4
- package/src/content/article-layout.module.css +45 -4
- package/src/content/article-layout.module.css.d.ts +3 -0
- package/src/content/article-layout.tsx +60 -5
- package/src/content/code-block.module.css +32 -2
- package/src/content/code-block.tsx +47 -3
- package/src/content/prose.module.css +13 -8
- package/src/controls/actions.module.css +14 -1
- package/src/controls/actions.module.css.d.ts +1 -0
- package/src/controls/actions.tsx +223 -75
- package/src/controls/controls.module.css +13 -31
- package/src/controls/enum-filter.tsx +2 -2
- package/src/controls/filter-context.tsx +11 -0
- package/src/controls/filter-pill.tsx +1 -0
- package/src/controls/index.ts +0 -1
- package/src/controls/multi-select-filter.tsx +2 -2
- package/src/controls/sync-button.module.css +2 -1
- package/src/dashboard/section.module.css +1 -26
- package/src/dashboard/section.tsx +1 -0
- package/src/dashboard/stat-card.module.css +6 -9
- package/src/dashboard/stat-card.tsx +6 -3
- package/src/dashboard/stat-group.module.css +33 -66
- package/src/dashboard/widget-grid.module.css +11 -38
- package/src/dashboard/widget-grid.tsx +7 -6
- package/src/dashboard/widget-header.module.css +145 -133
- package/src/dashboard/widget-header.module.css.d.ts +2 -0
- package/src/dashboard/widget-header.tsx +45 -11
- package/src/data/data-table-state.ts +218 -0
- package/src/data/data-table.module.css +94 -0
- package/src/data/data-table.module.css.d.ts +11 -0
- package/src/data/data-table.tsx +547 -299
- package/src/data/virtual-list.tsx +31 -0
- package/src/forms/form-layout.module.css +20 -5
- package/src/forms/form-layout.module.css.d.ts +1 -0
- package/src/forms/form-layout.tsx +12 -10
- package/src/guard/index.ts +188 -3
- package/src/guard/types.ts +3 -2
- package/src/index.ts +2 -0
- package/src/notifications/center.tsx +3 -0
- package/src/provider/index.tsx +60 -7
- package/src/shell/app-brand.module.css +2 -2
- package/src/shell/app-brand.tsx +1 -0
- package/src/shell/app-header.module.css +18 -8
- package/src/shell/app-main.module.css +54 -3
- package/src/shell/app-main.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.module.css +16 -4
- package/src/shell/app-sidebar.module.css +4 -6
- package/src/shell/aside-docking.ts +54 -0
- package/src/shell/index.tsx +178 -129
- package/src/shell/mobile-nav-model.ts +1 -1
- package/src/shell/page-aside.tsx +70 -21
- package/src/shell/page-bar.module.css +10 -34
- package/src/shell/page-bar.tsx +10 -5
- package/src/shell/use-breakpoint.ts +9 -45
- package/src/shell/use-size-class.ts +31 -0
- package/src/state/persisted-or-local.ts +10 -4
- package/src/state/persisted.ts +76 -17
- package/src/styles.css +41 -0
- package/src/surfaces.ts +9 -1
- package/src/theme/controls.module.css +7 -0
- package/src/theme/ctl-theme.tsx +15 -3
- package/src/theme/floating.module.css +37 -0
- package/src/theme/floating.module.css.d.ts +3 -0
- package/src/theme/index.ts +46 -8
- package/src/theme/nav-link.module.css +7 -0
- package/src/theme-lab/derive-controls.tsx +2 -0
- package/src/tokens/index.ts +20 -30
- package/src/tokens/palette.ts +6 -28
- package/src/tokens/size-classes.ts +46 -0
- package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
- /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
package/dist/tokens/palette.js
CHANGED
|
@@ -177,12 +177,7 @@ const SPACE_ANCHORS_BASE = {
|
|
|
177
177
|
* rowLineHeight * text.md`) — so a `size="ctl"` button sitting beside any of them read 2px short
|
|
178
178
|
* and the whole band looked unresolved. 32 lands the entire chrome tier on ONE number, which is
|
|
179
179
|
* also the smallest square that still holds a 16px icon with a 8px surround. */
|
|
180
|
-
controlHeightCtl: 32
|
|
181
|
-
/** The touch hit-area size (`::before`) every home control expands to below `sm` (C15,
|
|
182
|
-
* `docs/CONTROLS-SPEC.md` §5) — independent of the visible `controlHeightCtl` box, same shape as
|
|
183
|
-
* `mobileNavBarHeight`/`mobileNavRowHeight`'s Apple HIG 44pt / WCAG 2.5.5 floors elsewhere in this
|
|
184
|
-
* table. Floored at 30px in {@link deriveSpacing} (C15's "floor 30 at density −3"). */
|
|
185
|
-
touchControlHeight: 36
|
|
180
|
+
controlHeightCtl: 32
|
|
186
181
|
};
|
|
187
182
|
const SPACE_SCALE_BASE = {
|
|
188
183
|
xs: 11,
|
|
@@ -421,9 +416,8 @@ const SPACE_STEP_BASE = {
|
|
|
421
416
|
*
|
|
422
417
|
* 44, down from 48. The band holds ONE `ctl`-tier row (32 since this pass), so 48 left 8px of
|
|
423
418
|
* dead air above and below it — the "too much spacing at the top bar" the header reads as. 44
|
|
424
|
-
* keeps 6px of breathing room a side, still clears `
|
|
425
|
-
*
|
|
426
|
-
* this table already floors its touch targets at. */
|
|
419
|
+
* keeps 6px of breathing room a side, still clears `controlHeight` (42) for a `size="md"`
|
|
420
|
+
* control, and is the 44px touch floor (WCAG 2.5.5). */
|
|
427
421
|
appShellHeaderHeight: 44,
|
|
428
422
|
/** AppShell navbar width, expanded — ONE entry for both the `base` (mobile, where the navbar is
|
|
429
423
|
* permanently collapsed and unused — see `MobileNav`) and the expanded `sm` value: the same
|
|
@@ -498,12 +492,9 @@ const SPACE_STEP_BASE = {
|
|
|
498
492
|
mobileNavTabInsetY: 2,
|
|
499
493
|
/** Active-pill inset around the slot icon, horizontal. */
|
|
500
494
|
mobileNavTabInsetX: 12,
|
|
501
|
-
/** Menu/sheet row height.
|
|
502
|
-
*
|
|
503
|
-
|
|
504
|
-
* `sheetRowHeight` still hold to) — the shortest box that still reads as ONE row vocabulary with
|
|
505
|
-
* the sidebar instead of a bespoke touch size. */
|
|
506
|
-
mobileNavRowHeight: 40,
|
|
495
|
+
/** Menu/sheet row height — the WCAG 2.5.5 44px target, floored at 44 in `deriveSpacing` (the
|
|
496
|
+
* pointer tier's `--vx-hit` is the same number under `(pointer: coarse)`). */
|
|
497
|
+
mobileNavRowHeight: 44,
|
|
507
498
|
/** More/group `<Menu width={…}>`. JS-consumed, no var — same rationale as
|
|
508
499
|
* `sidebarSettingsMenuWidth` directly above. */
|
|
509
500
|
mobileNavMenuWidth: 232,
|
|
@@ -643,19 +634,7 @@ const SPACE_FIXED = {
|
|
|
643
634
|
* to 1 at density's floor level -3 and 3 at its ceiling level +3 — the widest swing `deriveSpacing`'s
|
|
644
635
|
* `[-3, 3]` range can produce) for no compensating benefit, since the two radii it sits between
|
|
645
636
|
* never move independently of each other. */
|
|
646
|
-
segmentedTrackInset: 2
|
|
647
|
-
/**
|
|
648
|
-
* The WCAG 2.5.5/2.5.8 touch-target floor (44px) for a hit area that has no `ctl`-tier home to
|
|
649
|
-
* size it — a raw CSS-module rule bumping a control's hit area under `@media (pointer: coarse)`
|
|
650
|
-
* (C5 consolidation: argo carried three such rules with a hand-picked 44/46px literal apiece).
|
|
651
|
-
* Density-exempt for the same reason `touchControlHeight`'s FLOOR is: a target this small must
|
|
652
|
-
* never shrink further, whatever the density knob says elsewhere. Unlike the rest of this
|
|
653
|
-
* object, this ONE key IS emitted as a `--vx-*` var (`tokens/index.ts`'s `space-touch-target`) —
|
|
654
|
-
* the others stay JS-only because nothing outside the framework's own components reads them, but
|
|
655
|
-
* this floor's whole purpose is being read by a CONSUMER's own `.module.css`, which cannot
|
|
656
|
-
* import a JS ref at all.
|
|
657
|
-
*/
|
|
658
|
-
spaceTouchTarget: 44
|
|
637
|
+
segmentedTrackInset: 2
|
|
659
638
|
};
|
|
660
639
|
function scaleSpace(value, level, multiplier) {
|
|
661
640
|
if (level === 0) return value;
|
|
@@ -687,11 +666,10 @@ function deriveSpacing(level) {
|
|
|
687
666
|
anchors.controlHeightTag = Math.max(18, anchors.controlHeightTag);
|
|
688
667
|
anchors.controlHeightWidget = Math.max(22, anchors.controlHeightWidget);
|
|
689
668
|
anchors.controlHeightCtl = Math.max(28, anchors.controlHeightCtl);
|
|
690
|
-
anchors.touchControlHeight = Math.max(30, anchors.touchControlHeight);
|
|
691
669
|
const mappedStep = mapSpaceGroup(SPACE_STEP_BASE, level, multiplier);
|
|
692
670
|
mappedStep.sidebarSearchTriggerHeight = Math.max(24, mappedStep.sidebarSearchTriggerHeight);
|
|
693
671
|
mappedStep.mobileNavBarHeight = Math.max(49, mappedStep.mobileNavBarHeight);
|
|
694
|
-
mappedStep.mobileNavRowHeight = Math.max(
|
|
672
|
+
mappedStep.mobileNavRowHeight = Math.max(44, mappedStep.mobileNavRowHeight);
|
|
695
673
|
mappedStep.sheetRowHeight = Math.max(44, mappedStep.sheetRowHeight);
|
|
696
674
|
const step = {
|
|
697
675
|
...mappedStep,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two responsive tables (`docs/DESIGN-CORE.md` § Layout, elevation, shapes) — pure data, Mantine-free. Each
|
|
3
|
+
* value is the class's minimum width in px.
|
|
4
|
+
*
|
|
5
|
+
* A `@media`/`@container` condition cannot read a custom property, so CSS writes the literal and
|
|
6
|
+
* `breakpoint-literals.test.ts` pins every literal to these tables.
|
|
7
|
+
*/
|
|
8
|
+
/** Viewport classes — shell chrome only (bottom bar / rail / sidebar, aside docking). */
|
|
9
|
+
export declare const SIZE_CLASSES: {
|
|
10
|
+
readonly compact: 0;
|
|
11
|
+
readonly medium: 840;
|
|
12
|
+
readonly expanded: 1200;
|
|
13
|
+
};
|
|
14
|
+
/** A component's own inline size — card chrome, chart tier, forms. No CSS reads it yet. */
|
|
15
|
+
export declare const CONTAINER_CLASSES: {
|
|
16
|
+
readonly micro: 0;
|
|
17
|
+
readonly compact: 240;
|
|
18
|
+
readonly regular: 480;
|
|
19
|
+
readonly wide: 800;
|
|
20
|
+
};
|
|
21
|
+
export type ContainerClass = keyof typeof CONTAINER_CLASSES;
|
|
22
|
+
/** The class a MEASURED inline size falls in (`px` is a min-width boundary, so 240 is `compact`). */
|
|
23
|
+
export declare function resolveContainerClass(px: number): ContainerClass;
|
|
24
|
+
/**
|
|
25
|
+
* `theme.breakpoints`, derived — a consumer cannot retune it. Mantine needs all five keys:
|
|
26
|
+
* `base` (no key) is compact, `xs`/`sm` open the medium class, `md`/`lg`/`xl` the expanded one, so
|
|
27
|
+
* every `visibleFrom`/`hiddenFrom` in the package stays "desktop chrome" from `sm` up.
|
|
28
|
+
*/
|
|
29
|
+
export declare const SIZE_CLASS_BREAKPOINTS: {
|
|
30
|
+
readonly xs: `${number}em`;
|
|
31
|
+
readonly sm: `${number}em`;
|
|
32
|
+
readonly md: `${number}em`;
|
|
33
|
+
readonly lg: `${number}em`;
|
|
34
|
+
readonly xl: `${number}em`;
|
|
35
|
+
};
|
|
36
|
+
/** A px width as the `em` length media queries use (16px root). */
|
|
37
|
+
export declare function toEm(px: number): string;
|
|
38
|
+
/** The `max-width` complement of a class boundary — 0.1px under it, Mantine's own convention. */
|
|
39
|
+
export declare function sizeClassMaxEm(minPx: number): string;
|
|
40
|
+
//# sourceMappingURL=size-classes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size-classes.d.ts","sourceRoot":"","sources":["../../src/tokens/size-classes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yFAAyF;AACzF,eAAO,MAAM,YAAY;;;;CAAuD,CAAA;AAEhF,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB;;;;;CAA+D,CAAA;AAE7F,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,iBAAiB,CAAA;AAE3D,qGAAqG;AACrG,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,CAKhE;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;CAMzB,CAAA;AAEV,mEAAmE;AACnE,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const SIZE_CLASSES = { compact: 0, medium: 840, expanded: 1200 };
|
|
2
|
+
const CONTAINER_CLASSES = { micro: 0, compact: 240, regular: 480, wide: 800 };
|
|
3
|
+
function resolveContainerClass(px) {
|
|
4
|
+
if (px >= CONTAINER_CLASSES.wide) return "wide";
|
|
5
|
+
if (px >= CONTAINER_CLASSES.regular) return "regular";
|
|
6
|
+
if (px >= CONTAINER_CLASSES.compact) return "compact";
|
|
7
|
+
return "micro";
|
|
8
|
+
}
|
|
9
|
+
const SIZE_CLASS_BREAKPOINTS = {
|
|
10
|
+
xs: `${SIZE_CLASSES.medium / 16}em`,
|
|
11
|
+
sm: `${SIZE_CLASSES.medium / 16}em`,
|
|
12
|
+
md: `${SIZE_CLASSES.expanded / 16}em`,
|
|
13
|
+
lg: `${SIZE_CLASSES.expanded / 16}em`,
|
|
14
|
+
xl: `${SIZE_CLASSES.expanded / 16}em`
|
|
15
|
+
};
|
|
16
|
+
function toEm(px) {
|
|
17
|
+
return `${Number((px / 16).toFixed(5))}em`;
|
|
18
|
+
}
|
|
19
|
+
function sizeClassMaxEm(minPx) {
|
|
20
|
+
return toEm(minPx - 0.1);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
CONTAINER_CLASSES,
|
|
24
|
+
SIZE_CLASSES,
|
|
25
|
+
SIZE_CLASS_BREAKPOINTS,
|
|
26
|
+
resolveContainerClass,
|
|
27
|
+
sizeClassMaxEm,
|
|
28
|
+
toEm
|
|
29
|
+
};
|
package/dist/tokens.css
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
--vx-radius-fine: 4px;
|
|
6
6
|
--vx-radius-floating: 8px;
|
|
7
7
|
--vx-radius-pill: 9999px;
|
|
8
|
-
--vx-
|
|
8
|
+
--vx-hit: 24px;
|
|
9
9
|
--vx-space-row-inset-x: 10px;
|
|
10
10
|
--vx-space-row-inset-y: 6px;
|
|
11
11
|
--vx-space-row-line-height: 1.35;
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
--vx-space-control-height-tag: 1.25rem;
|
|
15
15
|
--vx-space-control-height-widget: 1.5rem;
|
|
16
16
|
--vx-space-control-height-ctl: 2rem;
|
|
17
|
-
--vx-space-touch-control-height: 2.25rem;
|
|
18
17
|
--vx-space-stack-xs: 4px;
|
|
19
18
|
--vx-space-stack-sm: 8px;
|
|
20
19
|
--vx-space-stack-md: 12px;
|
|
@@ -103,7 +102,7 @@
|
|
|
103
102
|
--vx-space-mobile-nav-icon-size: 24px;
|
|
104
103
|
--vx-space-mobile-nav-tab-inset-y: 2px;
|
|
105
104
|
--vx-space-mobile-nav-tab-inset-x: 12px;
|
|
106
|
-
--vx-space-mobile-nav-row-height:
|
|
105
|
+
--vx-space-mobile-nav-row-height: 44px;
|
|
107
106
|
--vx-space-agent-rail-inset-x: 10px;
|
|
108
107
|
--vx-space-agent-part-gap-top: 6px;
|
|
109
108
|
--vx-space-agent-code-inset: 8px;
|
|
@@ -190,12 +189,17 @@
|
|
|
190
189
|
--vx-badRef: var(--vx-bad-ref);
|
|
191
190
|
--vx-warnRef: var(--vx-warn-ref);
|
|
192
191
|
}
|
|
193
|
-
@media (max-width:
|
|
192
|
+
@media (max-width: 52.49375em) {
|
|
194
193
|
:root {
|
|
195
194
|
--vx-space-card-inset-x: 11px;
|
|
196
195
|
--vx-space-section-gap: 8px;
|
|
197
196
|
}
|
|
198
197
|
}
|
|
198
|
+
@media (pointer: coarse) {
|
|
199
|
+
:root {
|
|
200
|
+
--vx-hit: 44px;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
199
203
|
:root,
|
|
200
204
|
html[data-mantine-color-scheme='dark'] {
|
|
201
205
|
--vx-status-excellent: #43bf4d;
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v1.
|
|
1
|
+
# basalt-ui v1.32.0
|
|
2
2
|
# Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets
|
|
3
3
|
#
|
|
4
4
|
# basalt-ui is an opinionated framework for Mantine-based React apps.
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
# ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
|
|
20
20
|
|
|
21
21
|
Package: basalt-ui
|
|
22
|
-
Version: 1.
|
|
22
|
+
Version: 1.32.0
|
|
23
23
|
|
|
24
24
|
## basalt-ui
|
|
25
25
|
Import: import { ... } from 'basalt-ui'
|
|
26
|
-
Description: BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useBreakpoint, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)
|
|
26
|
+
Description: BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass (useBreakpoint on notice), NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)
|
|
27
27
|
Layer: mantine-coupled
|
|
28
28
|
Rule: basalt-mantine
|
|
29
29
|
OptionalPeers: react-markdown@^10.1.0, remark-gfm@^4.0.1, rehype-sanitize@^6.0.0, remend@1.3.0, shiki@^4.3.0, beautiful-mermaid@^1.1.0, @tanstack/react-router-devtools@^1.166.13
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "basalt-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"charts",
|
|
@@ -162,19 +162,20 @@
|
|
|
162
162
|
"clean": "rm -rf dist"
|
|
163
163
|
},
|
|
164
164
|
"devDependencies": {
|
|
165
|
-
"@arethetypeswrong/cli": "0.18.
|
|
166
|
-
"@fontsource-variable/hubot-sans": "5.
|
|
167
|
-
"@fontsource-variable/jetbrains-mono": "5.
|
|
168
|
-
"@fontsource-variable/nunito-sans": "5.
|
|
165
|
+
"@arethetypeswrong/cli": "0.18.5",
|
|
166
|
+
"@fontsource-variable/hubot-sans": "5.3.0",
|
|
167
|
+
"@fontsource-variable/jetbrains-mono": "5.3.0",
|
|
168
|
+
"@fontsource-variable/nunito-sans": "5.3.0",
|
|
169
169
|
"@mantine/dates": "9.3.0",
|
|
170
|
-
"@shikijs/langs": "^4.3
|
|
171
|
-
"@shikijs/themes": "^4.3
|
|
170
|
+
"@shikijs/langs": "^4.4.3",
|
|
171
|
+
"@shikijs/themes": "^4.4.3",
|
|
172
172
|
"@tanstack/react-hotkeys": "0.10.0",
|
|
173
|
-
"@tanstack/react-router-devtools": "^1.
|
|
174
|
-
"@
|
|
175
|
-
"@types/
|
|
176
|
-
"@types/
|
|
177
|
-
"@types/react
|
|
173
|
+
"@tanstack/react-router-devtools": "^1.167.2",
|
|
174
|
+
"@testing-library/react": "16.3.3",
|
|
175
|
+
"@types/bun": "^1.4.2",
|
|
176
|
+
"@types/hast": "^3.0.5",
|
|
177
|
+
"@types/react": "^19.3.0",
|
|
178
|
+
"@types/react-dom": "^19.3.0",
|
|
178
179
|
"@visx/axis": "4.0.0",
|
|
179
180
|
"@visx/curve": "4.0.0",
|
|
180
181
|
"@visx/event": "4.0.0",
|
|
@@ -184,19 +185,19 @@
|
|
|
184
185
|
"@visx/scale": "4.0.0",
|
|
185
186
|
"@visx/shape": "4.0.0",
|
|
186
187
|
"@visx/threshold": "4.0.0",
|
|
187
|
-
"ai": "^7.0.
|
|
188
|
+
"ai": "^7.0.107",
|
|
188
189
|
"beautiful-mermaid": "^1.1.3",
|
|
189
190
|
"motion": "12.42.0",
|
|
190
|
-
"publint": "0.3.
|
|
191
|
+
"publint": "0.3.24",
|
|
191
192
|
"react-markdown": "^10.1.0",
|
|
192
193
|
"rehype-sanitize": "6.0.0",
|
|
193
194
|
"remark-gfm": "^4.0.1",
|
|
194
|
-
"remend": "1.3.
|
|
195
|
-
"shiki": "^4.3
|
|
195
|
+
"remend": "1.3.1",
|
|
196
|
+
"shiki": "^4.4.3",
|
|
196
197
|
"tsup": "^8.5.1",
|
|
197
198
|
"typescript": "^6.0.3",
|
|
198
199
|
"use-stick-to-bottom": "^1.1.6",
|
|
199
|
-
"vite": "^8.0
|
|
200
|
+
"vite": "^8.3.0",
|
|
200
201
|
"vite-plugin-pwa": "^1.3.0"
|
|
201
202
|
},
|
|
202
203
|
"peerDependencies": {
|
|
@@ -36,13 +36,14 @@
|
|
|
36
36
|
* onSubmit={({ text, attachments }) => send(text, attachments)}
|
|
37
37
|
* />
|
|
38
38
|
*/
|
|
39
|
-
import { ActionIcon, Group, Kbd, Stack, Text, Textarea } from '@mantine/core'
|
|
39
|
+
import { ActionIcon, Box, Group, Kbd, Stack, Text, Textarea } from '@mantine/core'
|
|
40
40
|
import type { ClipboardEvent, ComponentProps, JSX, KeyboardEvent, ReactNode, Ref } from 'react'
|
|
41
41
|
import { useImperativeHandle, useLayoutEffect, useRef, useSyncExternalStore } from 'react'
|
|
42
42
|
import { cx } from '../common/props'
|
|
43
43
|
import type { BasaltProps, SlotStylesProps } from '../common/props'
|
|
44
44
|
import { readPersistedValue } from '../state'
|
|
45
45
|
import { VX } from '../tokens'
|
|
46
|
+
import { useKeyboardInsetRef } from './use-keyboard-inset'
|
|
46
47
|
|
|
47
48
|
/** A minimal, dependency-free send-arrow glyph (icons are passed in as ReactNode elsewhere; this
|
|
48
49
|
* one is inline since Composer has no icon prop in its contract). */
|
|
@@ -202,6 +203,14 @@ export type ComposerSubmit = {
|
|
|
202
203
|
/** Stable empty list — keeps the submit payload's `attachments` referentially constant. */
|
|
203
204
|
const NO_ATTACHMENTS: readonly ComposerAttachment[] = []
|
|
204
205
|
|
|
206
|
+
/**
|
|
207
|
+
* The gap between the textarea/actions row and the hint row, inside the inner `Stack` the render
|
|
208
|
+
* below owns exclusively — the keyboard-inset spacer is deliberately NOT one of that Stack's flex
|
|
209
|
+
* children (see the render's own comment), so this value never has to be cancelled back out of
|
|
210
|
+
* anything the spacer contributes.
|
|
211
|
+
*/
|
|
212
|
+
const ROOT_GAP = 6
|
|
213
|
+
|
|
205
214
|
/**
|
|
206
215
|
* Imperative escape hatch for slot content that must write into the composer from OUTSIDE the
|
|
207
216
|
* render tree — a voice recorder streaming transcript chunks, a suggestion chip inserting at the
|
|
@@ -471,6 +480,13 @@ export function Composer({
|
|
|
471
480
|
|
|
472
481
|
useImperativeHandle(ref, () => ({ insertText, setValue, focus: focusTextarea }))
|
|
473
482
|
|
|
483
|
+
// Pins the composer above a coarse-pointer on-screen keyboard — see use-keyboard-inset.ts. The
|
|
484
|
+
// published custom property defaults to 0px via CSS, so a Composer with no `visualViewport`
|
|
485
|
+
// support (SSR, an unsupporting engine) pays for exactly one no-op custom property on a trailing
|
|
486
|
+
// spacer (see the render below) rather than an inline `paddingBottom` that could ever beat a
|
|
487
|
+
// consumer's own `className`/`classNames.root` padding.
|
|
488
|
+
const keyboardInsetRef = useKeyboardInsetRef()
|
|
489
|
+
|
|
474
490
|
const submit = (): void => {
|
|
475
491
|
if (inputDisabled || !hasPayload) return
|
|
476
492
|
const submittedText = trimmed
|
|
@@ -572,51 +588,62 @@ export function Composer({
|
|
|
572
588
|
const showActions = showStop || showSend
|
|
573
589
|
|
|
574
590
|
return (
|
|
575
|
-
<
|
|
576
|
-
gap={
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
591
|
+
<Box ref={keyboardInsetRef} className={cx(classNames?.root, className)} style={style}>
|
|
592
|
+
<Stack gap={ROOT_GAP}>
|
|
593
|
+
<Group gap="xs" align="flex-end" wrap="nowrap">
|
|
594
|
+
{leftSection}
|
|
595
|
+
<Textarea {...textareaProps} ref={textareaRef} />
|
|
596
|
+
{rightSection}
|
|
597
|
+
{showActions && (
|
|
598
|
+
<Group gap="xs" wrap="nowrap" className={cx(classNames?.actions)}>
|
|
599
|
+
{showStop ? (
|
|
600
|
+
<ActionIcon
|
|
601
|
+
size={42}
|
|
602
|
+
radius="md"
|
|
603
|
+
variant="filled"
|
|
604
|
+
color="red"
|
|
605
|
+
onClick={onStop}
|
|
606
|
+
aria-label="Stop generating"
|
|
607
|
+
>
|
|
608
|
+
<StopGlyph />
|
|
609
|
+
</ActionIcon>
|
|
610
|
+
) : null}
|
|
611
|
+
{showSend ? (
|
|
612
|
+
<ActionIcon
|
|
613
|
+
size={42}
|
|
614
|
+
radius="md"
|
|
615
|
+
variant="filled"
|
|
616
|
+
onClick={submit}
|
|
617
|
+
disabled={inputDisabled || !hasPayload}
|
|
618
|
+
aria-label="Send message"
|
|
619
|
+
// Send action (docs/DESIGN-SPEC.md §5): the one accent-filled control. It needs
|
|
620
|
+
// no color override — `filled` resolves through the theme to `--vx-accent-fill`
|
|
621
|
+
// / `--vx-on-accent`. (It used to hand-wire those two vars inline, which is why
|
|
622
|
+
// this was the ONLY filled control that stayed legible while the rest of the
|
|
623
|
+
// chrome went through Mantine's scheme-blind autoContrast. The theme owns it
|
|
624
|
+
// now, and hover works again — an inline style can't express a `:hover` state.)
|
|
625
|
+
>
|
|
626
|
+
<SendGlyph />
|
|
627
|
+
</ActionIcon>
|
|
628
|
+
) : null}
|
|
629
|
+
</Group>
|
|
630
|
+
)}
|
|
631
|
+
</Group>
|
|
632
|
+
{hint === undefined ? <DefaultHint /> : hint}
|
|
633
|
+
</Stack>
|
|
634
|
+
{/* Pins the composer above a coarse-pointer on-screen keyboard by growing THIS spacer, not
|
|
635
|
+
by padding the root — so a consumer's own `className`/`classNames.root` padding-bottom is
|
|
636
|
+
never overridden (see use-keyboard-inset.ts). It is a SIBLING of the gapped Stack above,
|
|
637
|
+
not one of its flex children, precisely so it never has to cancel that Stack's `gap`
|
|
638
|
+
back out: a consumer's own `style` (which lands on this outer, non-flex root, not on the
|
|
639
|
+
inner Stack) can carry an unrelated `gap` without ever touching what this spacer
|
|
640
|
+
contributes. A closed keyboard (the var's `0px` fallback) then really is 0 extra height,
|
|
641
|
+
regardless of anything the caller's `style`/`className` does to the root. (This used to
|
|
642
|
+
be the Stack's own trailing child, cancelled via a negative `margin-top` reading
|
|
643
|
+
`--stack-gap` back — exact against Stack's OWN `gap` prop, but blind to a `gap` a
|
|
644
|
+
consumer added on top through `style`, which changes the rendered gap without moving that
|
|
645
|
+
var.) */}
|
|
646
|
+
<Box aria-hidden style={{ height: 'var(--vx-keyboard-inset, 0px)' }} />
|
|
647
|
+
</Box>
|
|
621
648
|
)
|
|
622
649
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Composes `ThreadFeed` + a new-thread `Composer` (left/main pane) with `ThreadDetailPanel`
|
|
5
5
|
* (right pane) over `useAgentThreadRuns`, so a consumer wires one component instead of hand-
|
|
6
6
|
* assembling the pieces. Responsive: wide viewports show both panes side by side; narrow
|
|
7
|
-
* viewports (
|
|
7
|
+
* viewports (the `compact` size class, < 840px) show exactly one — the feed when no thread is open, a full-screen
|
|
8
8
|
* detail panel once one is.
|
|
9
9
|
*
|
|
10
10
|
* `useThreads` is a prop, not called internally, because `createThreadsStore` must be invoked
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
* )
|
|
33
33
|
* }
|
|
34
34
|
*/
|
|
35
|
-
import { Box, Divider, Flex, Skeleton, Stack, Text
|
|
36
|
-
import { useMediaQuery } from '@mantine/hooks'
|
|
35
|
+
import { Box, Divider, Flex, Skeleton, Stack, Text } from '@mantine/core'
|
|
37
36
|
import type { JSX, ReactNode } from 'react'
|
|
38
37
|
import type { AgentPart, AgentTransport, OutcomeResolver, ThreadsStore } from '../agent'
|
|
39
38
|
import { useAgentThreadRuns } from '../agent'
|
|
40
39
|
import { cx } from '../common/props'
|
|
41
40
|
import type { BasaltProps, SlotStylesProps } from '../common/props'
|
|
42
41
|
import { assertRequiredProps } from '../common/validate'
|
|
42
|
+
import { useSizeClass } from '../shell/use-size-class'
|
|
43
43
|
import { VX } from '../tokens'
|
|
44
44
|
import { Composer } from './composer'
|
|
45
45
|
import { ThreadDetailPanel } from './thread-detail-panel'
|
|
@@ -53,7 +53,7 @@ const FULL_HEIGHT_STYLE = { height: '100%' } as const
|
|
|
53
53
|
|
|
54
54
|
/** The four boxes `ThreadWorkspace` paints: `root` is the outermost pane split, `feed` is the
|
|
55
55
|
* thread-list pane, `composer` is the new-thread composer pinned under the feed, `detail` is the
|
|
56
|
-
* right-hand (or,
|
|
56
|
+
* right-hand (or, in the `compact` size class, full-screen) open-thread pane. */
|
|
57
57
|
export type ThreadWorkspaceSlot = 'root' | 'feed' | 'composer' | 'detail'
|
|
58
58
|
|
|
59
59
|
export type ThreadWorkspaceProps = BasaltProps &
|
|
@@ -146,7 +146,7 @@ function FeedErrorState(): JSX.Element {
|
|
|
146
146
|
/**
|
|
147
147
|
* A two-pane master-detail thread workspace: a scrollable feed of threads with an anchored
|
|
148
148
|
* new-thread composer, and a detail panel for the open thread's live transcript. Collapses to a
|
|
149
|
-
* single pane
|
|
149
|
+
* single pane in the `compact` size class (< 840px).
|
|
150
150
|
*
|
|
151
151
|
* @example
|
|
152
152
|
* <ThreadWorkspace useThreads={useThreads} transport={transport} resolveOutcome={heuristicOutcome} />
|
|
@@ -165,12 +165,9 @@ export function ThreadWorkspace({
|
|
|
165
165
|
assertRequiredProps('ThreadWorkspace', { useThreads }, ['useThreads'])
|
|
166
166
|
const store = useThreads()
|
|
167
167
|
const runs = useAgentThreadRuns({ transport, store, resolveOutcome })
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
// Mantine's own CSS breakpoints use), so the two checks never straddle the same pixel.
|
|
172
|
-
const theme = useMantineTheme()
|
|
173
|
-
const narrow = useMediaQuery(`(max-width: calc(${theme.breakpoints.sm} - 0.00625em))`)
|
|
168
|
+
// Narrow = the compact size class — the same viewport axis as the shell, and SSR/first-frame
|
|
169
|
+
// correct (the provider's `sizeClassHint` is the server snapshot, no post-mount flip).
|
|
170
|
+
const narrow = useSizeClass() === 'compact'
|
|
174
171
|
|
|
175
172
|
const threads = store.threads
|
|
176
173
|
const activeThread = threads.find((thread) => thread.id === store.activeId) ?? null
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useKeyboardInsetRef` — publishes the live on-screen-keyboard inset as `--vx-keyboard-inset` on
|
|
3
|
+
* a ref'd root element, so `Composer` can stay pinned above a coarse-pointer on-screen keyboard
|
|
4
|
+
* without the consumer hand-rolling a `dvh` clamp (`docs/MATURATION-LEDGER.md`, the wave 10
|
|
5
|
+
* agent-chat finding). Internal — not exported from the package.
|
|
6
|
+
*
|
|
7
|
+
* Reads `window.visualViewport`, guarded exactly like `useSizeClass`'s `matchMedia` guard
|
|
8
|
+
* (`shell/use-size-class.ts`): absent in SSR and in an engine with no `visualViewport` support
|
|
9
|
+
* (older Safari, and happy-dom/jsdom in tests), where the property is simply never published and
|
|
10
|
+
* CSS's `var(--vx-keyboard-inset, 0px)` fallback carries the zero.
|
|
11
|
+
*
|
|
12
|
+
* The inset is `document.documentElement.clientHeight - visualViewport.height -
|
|
13
|
+
* visualViewport.offsetTop`, floored at 0 — the slice of the LAYOUT viewport's bottom edge the
|
|
14
|
+
* visual viewport no longer covers. `clientHeight` (not `window.innerHeight`) is the layout
|
|
15
|
+
* viewport's height on every engine that also implements `visualViewport`. Both `resize` (fires
|
|
16
|
+
* when the on-screen keyboard opens/closes and shrinks `visualViewport.height`) and `scroll`
|
|
17
|
+
* (fires when the visual viewport's origin moves with no size change — iOS Safari scrolling the
|
|
18
|
+
* page to keep a focused field in view) are subscribed, because either can move the inset on its
|
|
19
|
+
* own.
|
|
20
|
+
*
|
|
21
|
+
* The state-node + layout-effect shape mirrors `shell/page-bar.tsx`'s `useMeasuredHeightVar`: a
|
|
22
|
+
* callback ref stored in state (so the effect re-runs once the node actually mounts) rather than a
|
|
23
|
+
* plain `RefObject` (which is not itself a dependency).
|
|
24
|
+
*
|
|
25
|
+
* Returns the callback ref only. It intentionally does NOT track the live inset (open/closed) —
|
|
26
|
+
* that stays an imperative, no-re-render style write, which is the entire point of publishing it
|
|
27
|
+
* outside React state.
|
|
28
|
+
*/
|
|
29
|
+
import { useCallback, useState } from 'react'
|
|
30
|
+
import { useIsomorphicLayoutEffect } from '../common/isomorphic-layout-effect'
|
|
31
|
+
|
|
32
|
+
const KEYBOARD_INSET_VAR = '--vx-keyboard-inset'
|
|
33
|
+
|
|
34
|
+
export function useKeyboardInsetRef(): (el: HTMLElement | null) => void {
|
|
35
|
+
const [node, setNode] = useState<HTMLElement | null>(null)
|
|
36
|
+
|
|
37
|
+
const attach = useCallback((el: HTMLElement | null) => {
|
|
38
|
+
setNode(el)
|
|
39
|
+
}, [])
|
|
40
|
+
|
|
41
|
+
useIsomorphicLayoutEffect(() => {
|
|
42
|
+
if (node === null) return
|
|
43
|
+
if (typeof window === 'undefined') return
|
|
44
|
+
const viewport = window.visualViewport
|
|
45
|
+
// `undefined`, not the typed `null`, is what an engine with no support actually returns
|
|
46
|
+
// (confirmed: happy-dom — this package's test DOM — has no `visualViewport` property at all).
|
|
47
|
+
if (viewport === null || viewport === undefined) return
|
|
48
|
+
|
|
49
|
+
const publish = (): void => {
|
|
50
|
+
const inset = Math.max(
|
|
51
|
+
0,
|
|
52
|
+
document.documentElement.clientHeight - viewport.height - viewport.offsetTop,
|
|
53
|
+
)
|
|
54
|
+
node.style.setProperty(KEYBOARD_INSET_VAR, `${inset}px`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
publish()
|
|
58
|
+
viewport.addEventListener('resize', publish)
|
|
59
|
+
viewport.addEventListener('scroll', publish)
|
|
60
|
+
return () => {
|
|
61
|
+
viewport.removeEventListener('resize', publish)
|
|
62
|
+
viewport.removeEventListener('scroll', publish)
|
|
63
|
+
node.style.removeProperty(KEYBOARD_INSET_VAR)
|
|
64
|
+
}
|
|
65
|
+
}, [node])
|
|
66
|
+
|
|
67
|
+
return attach
|
|
68
|
+
}
|