basalt-ui 1.38.1 → 1.40.1

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.
Files changed (41) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +27 -0
  3. package/MIGRATING.md +42 -13
  4. package/configs/oxlint-plugin.js +6 -0
  5. package/configs/oxlint-plugin.test.ts +2 -1
  6. package/dist/forms/index.d.ts +3 -36
  7. package/dist/forms/index.d.ts.map +1 -1
  8. package/dist/forms/index.js +0 -16
  9. package/dist/provider/index.d.ts +1 -1
  10. package/dist/provider/index.d.ts.map +1 -1
  11. package/dist/provider/index.js +14 -4
  12. package/dist/shell/app-sidebar-account.d.ts.map +1 -1
  13. package/dist/shell/app-sidebar-account.js +4 -3
  14. package/dist/shell/app-sidebar.module.css +3 -4
  15. package/dist/shell/index.d.ts +11 -0
  16. package/dist/shell/index.d.ts.map +1 -1
  17. package/dist/shell/index.js +2 -1
  18. package/dist/styles.css +6 -2
  19. package/dist/surfaces.d.ts +1 -1
  20. package/dist/surfaces.js +1 -1
  21. package/dist/theme/index.d.ts +15 -0
  22. package/dist/theme/index.d.ts.map +1 -1
  23. package/dist/theme/index.js +23 -4
  24. package/dist/theme/segmented-control.module.css +16 -0
  25. package/dist/theme/segmented-control.module.css.d.ts +1 -0
  26. package/dist/tokens/palette.d.ts +2 -0
  27. package/dist/tokens/palette.d.ts.map +1 -1
  28. package/dist/tokens/palette.js +2 -0
  29. package/llms.txt +3 -3
  30. package/package.json +1 -1
  31. package/src/forms/index.ts +3 -44
  32. package/src/provider/index.tsx +15 -3
  33. package/src/shell/app-sidebar-account.tsx +8 -3
  34. package/src/shell/app-sidebar.module.css +3 -4
  35. package/src/shell/index.tsx +13 -1
  36. package/src/styles.css +6 -2
  37. package/src/surfaces.ts +1 -1
  38. package/src/theme/index.ts +41 -3
  39. package/src/theme/segmented-control.module.css +16 -0
  40. package/src/theme/segmented-control.module.css.d.ts +1 -0
  41. package/src/tokens/palette.ts +2 -0
package/AGENTS.md CHANGED
@@ -15,7 +15,7 @@ Toolchain: Bun runtime, oxlint + oxfmt, conventional commits (empty scope), `mas
15
15
  | `basalt-ui/vite` | build-tooling | basaltViteConfig(opts) — Vite preset for basalt-ui consumer apps; basaltAppPlugin(opts) — PWA head, manifest, and icon metadata derived from the token palette |
16
16
  | `basalt-ui/guard` | headless | checkSource, GUARD_RULES, Finding types — the headless theme-guard core |
17
17
  | `basalt-ui/router-tanstack` | headless | TanStack Router bridge: defineNav/navGroup/navTarget (one typed nav definition) + useNav (sections + mobileNav, spread onto BasaltShell) + useBasaltNav (active route) + useRouterBreadcrumbs + createSearchStore (typed URL > localStorage > fallback store over field.enum/multi/range/number/boolean/string; the deprecated createSearchParamStore/createMultiSearchParamStore wrappers were removed in 1.29.0, C1 consolidation) |
18
- | `basalt-ui/forms` | mantine-coupled | Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout moved to ./controls in 1.36.0 and the useForm/schemaResolver re-exports are deprecated (import from @mantine/form); all six stay here until 1.37.0 |
18
+ | `basalt-ui/forms` | mantine-coupled | Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout lives in ./controls (moved in 1.36.0) and useForm/schemaResolver come from @mantine/form; the six re-exports here were removed in 1.39.0 |
19
19
  | `basalt-ui/notifications` | mantine-coupled | Mantine notifications: notify helpers, typed registry, persisted history, NotificationBell, NotificationCenter |
20
20
  | `basalt-ui/commands` | mantine-coupled | typed command bus + overlay controller, toSpotlightActions, ShortcutsHelp, BasaltOverlays |
21
21
  | `basalt-ui/data/table` | mantine-coupled | BasaltDataTable: a sortable data table over TanStack Table, rendered with Mantine (Mantine-rendered) |
package/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ ## [1.40.1](https://github.com/jkrumm/basalt-ui/compare/v1.40.0...v1.40.1) (2026-10-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * lift the selected segment above the track in dark mode ([a8315a9](https://github.com/jkrumm/basalt-ui/commit/a8315a90b9b067470f9d6ae3a0005117e713934b))
7
+
8
+ # [1.40.0](https://github.com/jkrumm/basalt-ui/compare/v1.39.0...v1.40.0) (2026-10-05)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * raised segmented indicator, nav-row geometry for the sidebar account row ([d800ea1](https://github.com/jkrumm/basalt-ui/commit/d800ea1dad17091aa558c05d33117adc7cf31310))
14
+
15
+
16
+ ### Features
17
+
18
+ * createBasaltTheme inputs option for desktop-sized inputs ([51a3d7f](https://github.com/jkrumm/basalt-ui/commit/51a3d7f023a5379c9c55f226c1671d83e732ea59))
19
+
20
+ # [1.39.0](https://github.com/jkrumm/basalt-ui/compare/v1.38.1...v1.39.0) (2026-10-04)
21
+
22
+
23
+ ### Features
24
+
25
+ * add BasaltShell headerHeight for a deliberate, consumer-set header row ([3561361](https://github.com/jkrumm/basalt-ui/commit/3561361279664d3ee51d245586331e057dd62844))
26
+ * remove the deprecated forms layout and useForm re-exports ([9e8b8c6](https://github.com/jkrumm/basalt-ui/commit/9e8b8c69241ea33d8bdf47532358166a809eb4ce))
27
+
1
28
  ## [1.38.1](https://github.com/jkrumm/basalt-ui/compare/v1.38.0...v1.38.1) (2026-10-04)
2
29
 
3
30
 
package/MIGRATING.md CHANGED
@@ -66,18 +66,18 @@ There is one row per SURFACE, not per export, and a surface earns a row once any
66
66
  shipped lefthook preset both changed in 1.30.0 with no row that owned them — which is how a
67
67
  consumer read this index, found nothing, and diffed a KPI row that had silently gone 4-up → 2-up.
68
68
 
69
- | Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | Unreleased |
70
- | ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | --- |
71
- | **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — |
72
- | **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — |
73
- | **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — |
74
- | **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — |
75
- | **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — |
76
- | **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — |
77
- | **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
78
- | **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
79
- | **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
80
- | **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — |
69
+ | Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | 1.39.0 | 1.40.0 | 1.40.1 | Unreleased |
70
+ | ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | ------ | ------ | ---------- | --- |
71
+ | **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — | — | — | — |
72
+ | **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
73
+ | **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — | — | — | — |
74
+ | **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — | — | — | — |
75
+ | **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — | — | — | — |
76
+ | **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
77
+ | **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
78
+ | **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
79
+ | **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
80
+ | **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — | — | — | — |
81
81
 
82
82
  ---
83
83
 
@@ -86,6 +86,33 @@ consumer read this index, found nothing, and diffed a KPI row that had silently
86
86
  _Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
87
87
  release renames it and opens a new one here._
88
88
 
89
+ ## 1.40.1
90
+
91
+ _Nothing to migrate in this release._
92
+
93
+ ## 1.40.0
94
+
95
+ _Nothing to migrate in this release._
96
+
97
+ ## 1.39.0 — the forms aliases leave
98
+
99
+ **Added: `BasaltShell headerHeight?: number`** (px, default unchanged — the density-tracking
100
+ `appShellHeaderHeight`, 44). One value for both sidebar forms and every width; the navbar and aside
101
+ tops, the page-bar band and Main follow it. A native unified-toolbar title bar sets ~52.
102
+
103
+ **Removed (grace ended — deprecated in 1.36.0, re-dated twice):** the six `basalt-ui/forms`
104
+ re-exports below. No autofix: move the import by hand.
105
+
106
+ | Was (`basalt-ui/forms`) | Now |
107
+ | ------------------------------------------------------------------------------------- | ---------------------------------------- |
108
+ | `FormSection`, `FormRow`, `FormGroup`, `FormActions` (+ their `*Props`/`*Slot` types) | the same names from `basalt-ui/controls` |
109
+ | `useForm`, `schemaResolver`, `UseFormReturnType`, `UseFormInput` | `@mantine/form` directly |
110
+
111
+ `basalt/deprecated-export` keeps the rows as `removed: true`, so an old import still gets a finding
112
+ that names the new home. `useBasaltForm`, `inputProps`, `fieldKey`, `useFormSubmit`,
113
+ `FormStateProvider`, `useFieldArray`, `FormErrorSummary` and `useFormDraft` are unchanged.
114
+ The `public symbols` budget is back to 400.
115
+
89
116
  ## 1.38.1 — the content inset
90
117
 
91
118
  No export changed. Two default numbers moved, both from `sm` up (the phone gutter is untouched):
@@ -100,7 +127,9 @@ No export changed. Two default numbers moved, both from `sm` up (the phone gutte
100
127
  The block inset is `stack-sm` from `sm` up and stays `stack-md` (12) on a phone. The breadcrumb
101
128
  now sits exactly on Main's content edge (it was 7px short of it); the brand mark no longer borrows
102
129
  the page gutter for its x — it is the nav-icon column (`row-inset-x` twice) on its own, so it stays
103
- at 20 while the gutter is 16. A consumer that wants the old numbers has no knob for them: the gutter
130
+ at 20 while the gutter is 16.
131
+
132
+ A consumer that wants the old numbers has no knob for them: the gutter
104
133
  is a `SPACE_STEP` entry, so retune it through the density level or accept the new default.
105
134
 
106
135
  ## 1.38.0
@@ -3672,6 +3672,7 @@ export const DEPRECATED_EXPORTS = [
3672
3672
  name: 'FormSection',
3673
3673
  replacement: "FormSection from 'basalt-ui/controls'",
3674
3674
  removeIn: '1.39.0',
3675
+ removed: true,
3675
3676
  fix: false,
3676
3677
  },
3677
3678
  {
@@ -3679,6 +3680,7 @@ export const DEPRECATED_EXPORTS = [
3679
3680
  name: 'FormRow',
3680
3681
  replacement: "FormRow from 'basalt-ui/controls'",
3681
3682
  removeIn: '1.39.0',
3683
+ removed: true,
3682
3684
  fix: false,
3683
3685
  },
3684
3686
  {
@@ -3686,6 +3688,7 @@ export const DEPRECATED_EXPORTS = [
3686
3688
  name: 'FormGroup',
3687
3689
  replacement: "FormGroup from 'basalt-ui/controls'",
3688
3690
  removeIn: '1.39.0',
3691
+ removed: true,
3689
3692
  fix: false,
3690
3693
  },
3691
3694
  {
@@ -3693,6 +3696,7 @@ export const DEPRECATED_EXPORTS = [
3693
3696
  name: 'FormActions',
3694
3697
  replacement: "FormActions from 'basalt-ui/controls'",
3695
3698
  removeIn: '1.39.0',
3699
+ removed: true,
3696
3700
  fix: false,
3697
3701
  },
3698
3702
  {
@@ -3700,6 +3704,7 @@ export const DEPRECATED_EXPORTS = [
3700
3704
  name: 'useForm',
3701
3705
  replacement: "useForm from '@mantine/form'",
3702
3706
  removeIn: '1.39.0',
3707
+ removed: true,
3703
3708
  fix: false,
3704
3709
  },
3705
3710
  {
@@ -3707,6 +3712,7 @@ export const DEPRECATED_EXPORTS = [
3707
3712
  name: 'schemaResolver',
3708
3713
  replacement: "schemaResolver from '@mantine/form'",
3709
3714
  removeIn: '1.39.0',
3715
+ removed: true,
3710
3716
  fix: false,
3711
3717
  },
3712
3718
  {
@@ -3393,7 +3393,7 @@ describe('basalt/deprecated-export — the form layout move', () => {
3393
3393
  )
3394
3394
  expect(rules).toContain('deprecated-export')
3395
3395
  expect(output).toContain(`'basalt-ui/controls'`)
3396
- expect(output).toContain('removed in 1.39.0')
3396
+ expect(output).toContain('was removed in 1.39.0')
3397
3397
  },
3398
3398
  )
3399
3399
 
@@ -3403,6 +3403,7 @@ describe('basalt/deprecated-export — the form layout move', () => {
3403
3403
  )
3404
3404
  expect(rules).toContain('deprecated-export')
3405
3405
  expect(output).toContain(`'@mantine/form'`)
3406
+ expect(output).toContain('was removed in 1.39.0')
3406
3407
  })
3407
3408
 
3408
3409
  it('does NOT report FormRow imported from basalt-ui/controls', () => {
@@ -8,38 +8,15 @@
8
8
  *
9
9
  * Four pieces: the form (`useBasaltForm` + `inputProps`/`fieldKey`), the submit lifecycle
10
10
  * (`useFormSubmit` + `FormStateProvider`), the list field (`useFieldArray`) and the draft
11
- * (`useFormDraft`). The layout (`FormSection` / `FormRow` / `FormGroup` / `FormActions`) moved to
12
- * `basalt-ui/controls` in 1.36.0 — it needs no `@mantine/form` — and stays here as deprecated
13
- * aliases until 1.39.0, as do the `useForm`/`schemaResolver` re-exports (import from
14
- * `@mantine/form`).
11
+ * (`useFormDraft`). The layout (`FormSection` / `FormRow` / `FormGroup` / `FormActions`) lives in
12
+ * `basalt-ui/controls` (it needs no `@mantine/form`); `useForm`/`schemaResolver` come from
13
+ * `@mantine/form` directly. Both stopped being re-exported here in 1.39.0.
15
14
  *
16
15
  * Optional peer: @mantine/form ^9.3.0 — install with: bun add @mantine/form
17
16
  */
18
17
  export { useBasaltForm } from './create-form.js';
19
18
  export type { UseBasaltFormOptions } from './create-form.js';
20
19
  export { inputProps, fieldKey } from './field.js';
21
- export {
22
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
23
- FormSection,
24
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
25
- FormRow,
26
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
27
- FormGroup,
28
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
29
- FormActions, } from '../controls/form-layout.js';
30
- export type {
31
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
32
- FormSectionProps,
33
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
34
- FormSectionSlot,
35
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
36
- FormRowProps,
37
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
38
- FormRowSlot,
39
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
40
- FormGroupProps,
41
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
42
- FormActionsProps, } from '../controls/form-layout.js';
43
20
  export { useFormSubmit, isFieldErrorEnvelope } from './use-form-submit.js';
44
21
  export type { FormFieldErrors, UseFormSubmitOptions, UseFormSubmitReturn } from './use-form-submit.js';
45
22
  export { FormStateProvider, useFormState } from './form-state.js';
@@ -50,14 +27,4 @@ export { FormErrorSummary } from './FormErrorSummary.js';
50
27
  export type { FormErrorSummaryProps } from './FormErrorSummary.js';
51
28
  export { useFormDraft, DEFAULT_AUTOSAVE_DEBOUNCE_MS } from './use-form-draft.js';
52
29
  export type { UseFormDraftOptions, UseFormDraftReturn } from './use-form-draft.js';
53
- export {
54
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
55
- useForm,
56
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
57
- schemaResolver, } from '@mantine/form';
58
- export type {
59
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
60
- UseFormReturnType,
61
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
62
- UseFormInput, } from '@mantine/form';
63
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAIzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAG9C,OAAO;AACL,wEAAwE;AACxE,WAAW;AACX,wEAAwE;AACxE,OAAO;AACP,wEAAwE;AACxE,SAAS;AACT,wEAAwE;AACxE,WAAW,GACZ,MAAM,yBAAyB,CAAA;AAChC,YAAY;AACV,wEAAwE;AACxE,gBAAgB;AAChB,wEAAwE;AACxE,eAAe;AACf,wEAAwE;AACxE,YAAY;AACZ,wEAAwE;AACxE,WAAW;AACX,wEAAwE;AACxE,cAAc;AACd,wEAAwE;AACxE,gBAAgB,GACjB,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACvE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACnG,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9D,YAAY,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAGrE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAG5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAG/D,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAA;AAC7E,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAG/E,OAAO;AACL,mEAAmE;AACnE,OAAO;AACP,mEAAmE;AACnE,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,YAAY;AACV,mEAAmE;AACnE,iBAAiB;AACjB,mEAAmE;AACnE,YAAY,GACb,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAIzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAG9C,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACvE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACnG,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9D,YAAY,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAGrE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAG5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAG/D,OAAO,EAAE,YAAY,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAA;AAC7E,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -1,35 +1,19 @@
1
1
  import { useBasaltForm } from "./create-form.js";
2
2
  import { inputProps, fieldKey } from "./field.js";
3
- import {
4
- FormSection,
5
- FormRow,
6
- FormGroup,
7
- FormActions
8
- } from "../controls/form-layout.js";
9
3
  import { useFormSubmit, isFieldErrorEnvelope } from "./use-form-submit.js";
10
4
  import { FormStateProvider, useFormState } from "./form-state.js";
11
5
  import { useFieldArray } from "./use-field-array.js";
12
6
  import { FormErrorSummary } from "./FormErrorSummary.js";
13
7
  import { useFormDraft, DEFAULT_AUTOSAVE_DEBOUNCE_MS } from "./use-form-draft.js";
14
- import {
15
- useForm,
16
- schemaResolver
17
- } from "@mantine/form";
18
8
  export {
19
9
  DEFAULT_AUTOSAVE_DEBOUNCE_MS,
20
- FormActions,
21
10
  FormErrorSummary,
22
- FormGroup,
23
- FormRow,
24
- FormSection,
25
11
  FormStateProvider,
26
12
  fieldKey,
27
13
  inputProps,
28
14
  isFieldErrorEnvelope,
29
- schemaResolver,
30
15
  useBasaltForm,
31
16
  useFieldArray,
32
- useForm,
33
17
  useFormDraft,
34
18
  useFormState,
35
19
  useFormSubmit
@@ -142,7 +142,7 @@ export declare class BasaltErrorBoundary extends Component<BasaltErrorBoundaryPr
142
142
  * `BasaltBridge`'s `useMemo`) purely so `provider/index.test.ts` can assert the ORDER holds without
143
143
  * rendering a React tree.
144
144
  */
145
- export declare function composeInjectedCss(base: string, fontsCss: string, radiusCss: string, densityCss: string): string;
145
+ export declare function composeInjectedCss(base: string, fontsCss: string, radiusCss: string, densityCss: string, inputsCss?: string): string;
146
146
  /**
147
147
  * `data-basalt-host` on `<html>` — the one place a `display-mode` query is read; CSS keys off it.
148
148
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.tsx"],"names":[],"mappings":"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"}
@@ -66,8 +66,8 @@ class BasaltErrorBoundary extends Component {
66
66
  return this.props.children;
67
67
  }
68
68
  }
69
- function composeInjectedCss(base, fontsCss, radiusCss, densityCss) {
70
- return [base, fontsCss, radiusCss, densityCss].filter(Boolean).join("\n");
69
+ function composeInjectedCss(base, fontsCss, radiusCss, densityCss, inputsCss = "") {
70
+ return [base, fontsCss, radiusCss, densityCss, inputsCss].filter(Boolean).join("\n");
71
71
  }
72
72
  function createMountCounter() {
73
73
  let count = 0;
@@ -106,6 +106,7 @@ function BasaltBridge({
106
106
  const fontsConfig = theme.other?.basaltFonts;
107
107
  const radiusConfig = theme.other?.basaltRadius;
108
108
  const densityConfig = theme.other?.basaltDensity;
109
+ const desktopInputs = theme.other?.["basaltInputs"] === "desktop";
109
110
  const paletteCss = useMemo(() => {
110
111
  if (!injectPalette) return "";
111
112
  const base = deriveConfig === void 0 || isDefaultDeriveConfig(deriveConfig) ? buildPaletteCss(paletteOptions) : (
@@ -116,8 +117,17 @@ function BasaltBridge({
116
117
  const fontsCss = buildFontsCss(fontsConfig);
117
118
  const radiusCss = buildRadiusCss(radiusConfig);
118
119
  const densityCss = buildDensityCss(densityConfig);
119
- return composeInjectedCss(base, fontsCss, radiusCss, densityCss);
120
- }, [injectPalette, deriveConfig, fontsConfig, radiusConfig, densityConfig, paletteOptions]);
120
+ const inputsCss = desktopInputs ? ":root {\n--basalt-input-fz-floor: 0px;\n}" : "";
121
+ return composeInjectedCss(base, fontsCss, radiusCss, densityCss, inputsCss);
122
+ }, [
123
+ injectPalette,
124
+ deriveConfig,
125
+ fontsConfig,
126
+ radiusConfig,
127
+ densityConfig,
128
+ desktopInputs,
129
+ paletteOptions
130
+ ]);
121
131
  useEffect(() => {
122
132
  if (typeof window === "undefined") return;
123
133
  const handleError = (e) => {
@@ -1 +1 @@
1
- {"version":3,"file":"app-sidebar-account.d.ts","sourceRoot":"","sources":["../../src/shell/app-sidebar-account.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AA0DzD,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,GAAG,WAAW,+BA6FrE"}
1
+ {"version":3,"file":"app-sidebar-account.d.ts","sourceRoot":"","sources":["../../src/shell/app-sidebar-account.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AA0DzD,wBAAgB,cAAc,CAAC,KAAK,EAAE,kBAAkB,GAAG,WAAW,+BAiGrE"}
@@ -1,6 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Group, Menu, Skeleton, Stack, Text, UnstyledButton } from "@mantine/core";
3
3
  import { useBasaltSpacing } from "../theme/index.js";
4
+ import { VX } from "../tokens/index.js";
4
5
  import { cx } from "../common/props.js";
5
6
  import { assertRequiredProps } from "../common/validate.js";
6
7
  import classes from "./app-sidebar.module.css";
@@ -68,13 +69,13 @@ function SidebarAccount(props) {
68
69
  return /* @__PURE__ */ jsxs(
69
70
  UnstyledButton,
70
71
  {
71
- className: cx(classes.accountRow, className),
72
+ className: cx(classes.footerBtn, className),
72
73
  "aria-label": "Sign in",
73
74
  onClick: actions?.onSignIn,
74
75
  ...style !== void 0 && { style },
75
76
  children: [
76
- /* @__PURE__ */ jsx(IconUser, {}),
77
- /* @__PURE__ */ jsx(Text, { className: classes.accountText, size: "sm", fw: 500, children: "Sign in" })
77
+ /* @__PURE__ */ jsx("span", { className: classes.footerIconSlot, children: /* @__PURE__ */ jsx(IconUser, {}) }),
78
+ /* @__PURE__ */ jsx(Text, { className: classes.accountText, fz: VX.text.md, children: "Sign in" })
78
79
  ]
79
80
  }
80
81
  );
@@ -275,8 +275,8 @@
275
275
  }
276
276
 
277
277
  /*
278
- * Sidebar account row (SidebarAccount) — mock footer geometry: padding 11px 8px 3px, gap 10, NO
279
- * border; hover = the same ink-6% tint as every other row, rounded 6.
278
+ * Sidebar account row (SidebarAccount, authenticated) — a nav row's padding and gap, so its leading
279
+ * block starts on the nav icon column; NO border; hover = the same ink-6% tint as every other row.
280
280
  */
281
281
  .accountRow {
282
282
  flex: 1;
@@ -284,8 +284,7 @@
284
284
  display: flex;
285
285
  align-items: center;
286
286
  gap: var(--vx-space-nav-icon-gap);
287
- padding: var(--vx-space-sidebar-account-inset-top) var(--vx-space-sidebar-account-inset-x)
288
- var(--vx-space-sidebar-account-inset-bottom);
287
+ padding: var(--vx-space-row-inset-y) var(--vx-space-row-inset-x);
289
288
  border-radius: var(--vx-radius-ctrl);
290
289
  }
291
290
 
@@ -144,6 +144,17 @@ export type BasaltShellProps = BasaltProps & {
144
144
  * a no-op when omitted.
145
145
  */
146
146
  onCollapsedChange?: (collapsed: boolean) => void;
147
+ /**
148
+ * The header row's height in px — default `SPACE_STEP.appShellHeaderHeight` (44, tracking the
149
+ * density level). ONE number at every width and in both sidebar forms (law C14): the navbar's and
150
+ * aside's top, the page-bar band, the aside's shell header and Main all derive from Mantine's
151
+ * `--app-shell-header-height`, so they follow it with no second value to keep in step. Brand,
152
+ * breadcrumb, page actions and globals centre vertically in the row. For a host that draws its
153
+ * own chrome into the header, e.g. a native macOS unified-toolbar title bar (~52): pair it with
154
+ * `--basalt-shell-lead-inset`. Keep it at or above the `ctl` control height (32) — the row holds
155
+ * one `ctl`-tier control.
156
+ */
157
+ headerHeight?: number;
147
158
  /** Page content. */
148
159
  children?: ReactNode;
149
160
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.tsx"],"names":[],"mappings":"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"}
@@ -87,6 +87,7 @@ function ShellFrame({
87
87
  storageKey = "basalt-sidebar-collapsed",
88
88
  collapsed: collapsedProp,
89
89
  onCollapsedChange,
90
+ headerHeight,
90
91
  account,
91
92
  search,
92
93
  children,
@@ -146,7 +147,7 @@ function ShellFrame({
146
147
  h: "100dvh",
147
148
  header: {
148
149
  // ONE height at every width (law C14): nothing reserves a second mobile row any more.
149
- height: step.appShellHeaderHeight
150
+ height: headerHeight ?? step.appShellHeaderHeight
150
151
  },
151
152
  navbar: {
152
153
  width: { base: step.appShellNavbarWidth, sm: navbarWidth },
package/dist/styles.css CHANGED
@@ -97,11 +97,15 @@
97
97
  and re-opens the zoom bug — a floor a `style` prop can override is not a floor, it's a
98
98
  suggestion. `check-theme`'s `raw-form-control` + `sub-16-input-font` guard kinds catch the
99
99
  authoring mistake at build time; this `!important` is the runtime backstop that makes it
100
- un-defeatable even when a violation slips through. */
100
+ un-defeatable even when a violation slips through.
101
+
102
+ `--basalt-input-fz-floor` is the one knob: `createBasaltTheme(…, { inputs: 'desktop' })` has the
103
+ provider set it to 0px for an app that never runs on iOS Safari (a Tauri/desktop shell), where
104
+ the 16px floor is only visual weight. Default stays 16px. */
101
105
  input,
102
106
  select,
103
107
  textarea {
104
- font-size: max(16px, var(--input-fz, 1rem)) !important;
108
+ font-size: max(var(--basalt-input-fz-floor, 16px), var(--input-fz, 1rem)) !important;
105
109
  }
106
110
 
107
111
  /* `data-numeric` — one typographic law, every element. A number read as a MEASUREMENT (a preset
@@ -267,7 +267,7 @@ export declare const SURFACES: {
267
267
  readonly skill: readonly ["basalt-design"];
268
268
  readonly guardKinds: readonly [];
269
269
  readonly pluginRules: readonly ["forms-field-key"];
270
- readonly description: "Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout moved to ./controls in 1.36.0 and the useForm/schemaResolver re-exports are deprecated (import from @mantine/form); all six stay here until 1.37.0";
270
+ readonly description: "Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout lives in ./controls (moved in 1.36.0) and useForm/schemaResolver come from @mantine/form; the six re-exports here were removed in 1.39.0";
271
271
  readonly optionalPeers: readonly ["@mantine/form"];
272
272
  readonly forbiddenImports: readonly [];
273
273
  };
package/dist/surfaces.js CHANGED
@@ -243,7 +243,7 @@ const SURFACES = {
243
243
  // only stops resetting. `warn` through the 1.30.0 grace because it fires on what every
244
244
  // consumer ships today (`PLUGIN_RULE_GRACE`).
245
245
  pluginRules: ["forms-field-key"],
246
- description: "Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls \u2014 a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout moved to ./controls in 1.36.0 and the useForm/schemaResolver re-exports are deprecated (import from @mantine/form); all six stay here until 1.37.0",
246
+ description: "Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls \u2014 a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout lives in ./controls (moved in 1.36.0) and useForm/schemaResolver come from @mantine/form; the six re-exports here were removed in 1.39.0",
247
247
  optionalPeers: ["@mantine/form"],
248
248
  forbiddenImports: []
249
249
  },
@@ -99,6 +99,21 @@ export type CreateBasaltThemeOptions = {
99
99
  * createBasaltTheme(undefined, { density: -2 })
100
100
  */
101
101
  density?: number;
102
+ /**
103
+ * Input sizing for the platform the app runs on. `'touch'` (default) keeps the shipped identity:
104
+ * `md` inputs (42px) with the 16px font floor that stops iOS Safari's focus-zoom. `'desktop'` is
105
+ * for an app that never runs in a mobile browser (a Tauri/Electron shell): the Input family
106
+ * (`TextInput`, `NumberInput`, `PasswordInput`, `Select`, `Textarea`, `Input`) defaults to
107
+ * Mantine's `sm` (36px, `--vx-text-sm` font) and the provider drops the 16px floor, so every
108
+ * input Mantine ships — `MultiSelect`/`TagsInput`/pills included, they already default to `sm` —
109
+ * renders at its own size. An explicit `size` prop still wins. Stashed on
110
+ * `theme.other.basaltInputs` (only when non-default); `BasaltProvider` emits the floor override,
111
+ * so `injectPalette={false}` also opts it out.
112
+ *
113
+ * @example
114
+ * createBasaltTheme(undefined, { inputs: 'desktop' })
115
+ */
116
+ inputs?: 'touch' | 'desktop';
102
117
  };
103
118
  /**
104
119
  * Build the Basalt theme, optionally merged with consumer overrides. Overrides win on conflict
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EACV,oBAAoB,EAGpB,oBAAoB,EAErB,MAAM,eAAe,CAAA;AAStB,OAAO,KAAK,EAAe,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQlD;;;;;GAKG;AACH,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAIlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAgBnE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,aAAa,CAAC,EAAE,WAAW,CAAA;KAC5B;CACF;AA0hCD;+EAC+E;AAC/E,eAAO,MAAM,SAAS,EAAE,oBAAuD,CAAA;AAyT/E;;8FAE8F;AAC9F,eAAO,MAAM,oBAAoB,EAAE,oBACc,CAAA;AAEjD,kEAAkE;AAClE,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAE9B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAA;IAEzB;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAYD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,aAAa,CAAC,EACrD,OAAO,CAAC,EAAE,wBAAwB,GACjC,oBAAoB,CAiCtB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EACV,oBAAoB,EAGpB,oBAAoB,EAErB,MAAM,eAAe,CAAA;AAStB,OAAO,KAAK,EAAe,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQlD;;;;;GAKG;AACH,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAIlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAgBnE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,aAAa,CAAC,EAAE,WAAW,CAAA;KAC5B;CACF;AAgiCD;+EAC+E;AAC/E,eAAO,MAAM,SAAS,EAAE,oBAAuD,CAAA;AAyT/E;;8FAE8F;AAC9F,eAAO,MAAM,oBAAoB,EAAE,oBACc,CAAA;AAEjD,kEAAkE;AAClE,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAE9B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAA;IAEzB;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC7B,CAAA;AA0BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,aAAa,CAAC,EACrD,OAAO,CAAC,EAAE,wBAAwB,GACjC,oBAAoB,CAmCtB"}
@@ -530,7 +530,8 @@ function buildTheme(data, options = {}) {
530
530
  defaultProps: { radius: radius.card },
531
531
  classNames: {
532
532
  label: segmentedControlClasses.label,
533
- control: segmentedControlClasses.control
533
+ control: segmentedControlClasses.control,
534
+ indicator: segmentedControlClasses.indicator
534
535
  },
535
536
  // `label` gets a `ctl`-only min-height (function-form `styles`, same `props.size === …` gate
536
537
  // as Button/ActionIcon/Input's `vars` overrides above) so a `size="ctl"` SegmentedControl
@@ -539,7 +540,7 @@ function buildTheme(data, options = {}) {
539
540
  // density. `sm`/`md` SegmentedControls (forms) are untouched, keeping Mantine's own sizing.
540
541
  styles: (_theme, props) => ({
541
542
  root: {
542
- backgroundColor: "color-mix(in srgb, var(--vx-ink) 6%, transparent)",
543
+ backgroundColor: "color-mix(in srgb, var(--vx-ink) 8%, transparent)",
543
544
  padding: `${SPACE_FIXED.segmentedTrackInset}px`,
544
545
  // The OUTER safety net a `.control`'s own `min-width: 0` (`segmented-control.module.css`)
545
546
  // cannot provide by itself: that rule only lets each SEGMENT shrink below its own label's
@@ -556,8 +557,13 @@ function buildTheme(data, options = {}) {
556
557
  minWidth: "max-content"
557
558
  },
558
559
  indicator: {
559
- backgroundColor: "color-mix(in srgb, var(--vx-ink) 12%, var(--vx-surface-panel))",
560
- boxShadow: "var(--vx-shadow-ctrl)",
560
+ // A RAISED pill, not a darker one: its fill (`segmented-control.module.css`, per scheme) is
561
+ // lighter than the ink-tinted track in both schemes, + the shared raised shadow + a 1px ink outline.
562
+ // Same model as Mantine's default (white indicator, shadow, on a grey track) and
563
+ // shadcn's Tabs/ToggleGroup (`bg-background` + shadow on a `bg-muted` track). The old
564
+ // ink-12% fill sat one shade from the track and read as a hover state.
565
+ boxShadow: "var(--vx-shadow-raised)",
566
+ outline: "1px solid color-mix(in srgb, var(--vx-ink) 14%, transparent)",
561
567
  borderRadius: "var(--vx-radius-tight)"
562
568
  },
563
569
  // Conditionally spread the WHOLE key (never a present `label: undefined`) — the package
@@ -1037,6 +1043,17 @@ const cssVariablesResolver = buildCssVariablesResolver(DEFAULT_PALETTE_DATA);
1037
1043
  function hasFontsConfig(fonts) {
1038
1044
  return fonts !== void 0 && Object.values(fonts).some((value) => value !== void 0);
1039
1045
  }
1046
+ const DESKTOP_INPUTS_THEME = {
1047
+ components: {
1048
+ Input: Input.extend({ defaultProps: { size: "sm" } }),
1049
+ TextInput: TextInput.extend({ defaultProps: { size: "sm" } }),
1050
+ NumberInput: NumberInput.extend({ defaultProps: { size: "sm" } }),
1051
+ PasswordInput: PasswordInput.extend({ defaultProps: { size: "sm" } }),
1052
+ Select: Select.extend({ defaultProps: { size: "sm" } }),
1053
+ Textarea: Textarea.extend({ defaultProps: { size: "sm" } })
1054
+ },
1055
+ other: { basaltInputs: "desktop" }
1056
+ };
1040
1057
  function createBasaltTheme(overrides, options) {
1041
1058
  const resolvedConfig = resolveDeriveConfig(options?.derive);
1042
1059
  const radiusLevel = options?.radius ?? 0;
@@ -1046,6 +1063,7 @@ function createBasaltTheme(overrides, options) {
1046
1063
  const spaceValues = deriveSpacing(densityLevel);
1047
1064
  const isDefaultDensity = densityLevel === 0;
1048
1065
  const isDefaultDerive = isDefaultDeriveConfig(resolvedConfig);
1066
+ const desktopInputs = options?.inputs === "desktop";
1049
1067
  let theme;
1050
1068
  if (isDefaultDerive && isDefaultRadius && isDefaultDensity) {
1051
1069
  theme = baseTheme;
@@ -1066,6 +1084,7 @@ function createBasaltTheme(overrides, options) {
1066
1084
  if (hasFontsConfig(fontsConfig)) {
1067
1085
  theme = mergeThemeOverrides(theme, { other: { basaltFonts: fontsConfig } });
1068
1086
  }
1087
+ if (desktopInputs) theme = mergeThemeOverrides(theme, DESKTOP_INPUTS_THEME);
1069
1088
  if (!overrides) return theme;
1070
1089
  return { ...mergeThemeOverrides(theme, overrides), breakpoints: SIZE_CLASS_BREAKPOINTS };
1071
1090
  }
@@ -54,3 +54,19 @@
54
54
  font-family: var(--basalt-font-mono);
55
55
  font-size: var(--vx-text-xs);
56
56
  }
57
+
58
+ /*
59
+ * Selected-segment fill — LIGHTER than the ink-8% track in both schemes, which is what reads as
60
+ * raised. The two schemes need different recipes: the track is an ink tint, so on light it is
61
+ * darker than the page (the panel surface sits above it) while on dark it is LIGHTER than the page,
62
+ * and the same panel surface would then sink below it. Dark therefore lifts the elevated surface
63
+ * with ink. In the module (not the theme's inline `styles`) so the scheme can be selected on —
64
+ * same ancestor-attribute pattern as `controls.module.css`.
65
+ */
66
+ .indicator {
67
+ background-color: var(--vx-surface-elevated);
68
+ }
69
+
70
+ html[data-mantine-color-scheme='dark'] .indicator {
71
+ background-color: color-mix(in srgb, var(--vx-ink) 14%, var(--vx-surface-elevated));
72
+ }
@@ -5,5 +5,6 @@
5
5
  declare const classes: {
6
6
  readonly label: string
7
7
  readonly control: string
8
+ readonly indicator: string
8
9
  }
9
10
  export default classes
@@ -502,6 +502,8 @@ declare const SPACE_STEP_BASE: {
502
502
  * folds that row's overflow into a kebab and moves its filters/tabs into the page flow, so the
503
503
  * bar is one row on a phone too and there is no sum to keep in step any more.
504
504
  *
505
+ * Consumer-settable per shell through `BasaltShell`'s `headerHeight` (px); this is its default.
506
+ *
505
507
  * 44, down from 48. The band holds ONE `ctl`-tier row (32 since this pass), so 48 left 8px of
506
508
  * dead air above and below it — the "too much spacing at the top bar" the header reads as. 44
507
509
  * keeps 6px of breathing room a side, still clears `controlHeight` (42) for a `size="md"`
@@ -1 +1 @@
1
- {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/tokens/palette.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/tokens/palette.ts"],"names":[],"mappings":"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"}
@@ -414,6 +414,8 @@ const SPACE_STEP_BASE = {
414
414
  * folds that row's overflow into a kebab and moves its filters/tabs into the page flow, so the
415
415
  * bar is one row on a phone too and there is no sum to keep in step any more.
416
416
  *
417
+ * Consumer-settable per shell through `BasaltShell`'s `headerHeight` (px); this is its default.
418
+ *
417
419
  * 44, down from 48. The band holds ONE `ctl`-tier row (32 since this pass), so 48 left 8px of
418
420
  * dead air above and below it — the "too much spacing at the top bar" the header reads as. 44
419
421
  * keeps 6px of breathing room a side, still clears `controlHeight` (42) for a `size="md"`
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # basalt-ui v1.38.1
1
+ # basalt-ui v1.40.1
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,7 +19,7 @@
19
19
  # ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
20
20
 
21
21
  Package: basalt-ui
22
- Version: 1.38.1
22
+ Version: 1.40.1
23
23
 
24
24
  ## basalt-ui
25
25
  Import: import { ... } from 'basalt-ui'
@@ -70,7 +70,7 @@ OptionalPeers: @tanstack/react-router@^1.170.0
70
70
 
71
71
  ## basalt-ui/forms
72
72
  Import: import { ... } from 'basalt-ui/forms'
73
- Description: Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout moved to ./controls in 1.36.0 and the useForm/schemaResolver re-exports are deprecated (import from @mantine/form); all six stay here until 1.37.0
73
+ Description: Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout lives in ./controls (moved in 1.36.0) and useForm/schemaResolver come from @mantine/form; the six re-exports here were removed in 1.39.0
74
74
  Layer: mantine-coupled
75
75
  Rule: basalt-batteries
76
76
  OptionalPeers: @mantine/form@^9.3.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basalt-ui",
3
- "version": "1.38.1",
3
+ "version": "1.40.1",
4
4
  "description": "Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets",
5
5
  "keywords": [
6
6
  "charts",
@@ -8,10 +8,9 @@
8
8
  *
9
9
  * Four pieces: the form (`useBasaltForm` + `inputProps`/`fieldKey`), the submit lifecycle
10
10
  * (`useFormSubmit` + `FormStateProvider`), the list field (`useFieldArray`) and the draft
11
- * (`useFormDraft`). The layout (`FormSection` / `FormRow` / `FormGroup` / `FormActions`) moved to
12
- * `basalt-ui/controls` in 1.36.0 — it needs no `@mantine/form` — and stays here as deprecated
13
- * aliases until 1.39.0, as do the `useForm`/`schemaResolver` re-exports (import from
14
- * `@mantine/form`).
11
+ * (`useFormDraft`). The layout (`FormSection` / `FormRow` / `FormGroup` / `FormActions`) lives in
12
+ * `basalt-ui/controls` (it needs no `@mantine/form`); `useForm`/`schemaResolver` come from
13
+ * `@mantine/form` directly. Both stopped being re-exported here in 1.39.0.
15
14
  *
16
15
  * Optional peer: @mantine/form ^9.3.0 — install with: bun add @mantine/form
17
16
  */
@@ -24,32 +23,6 @@ export type { UseBasaltFormOptions } from './create-form'
24
23
  // Two calls, never one object: `key` inside a spread is a React 19 warning. See field.ts.
25
24
  export { inputProps, fieldKey } from './field'
26
25
 
27
- // ── layout — moved to ./controls (1.36.0), deprecated aliases until 1.39.0 ─────
28
- export {
29
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
30
- FormSection,
31
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
32
- FormRow,
33
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
34
- FormGroup,
35
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
36
- FormActions,
37
- } from '../controls/form-layout'
38
- export type {
39
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
40
- FormSectionProps,
41
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
42
- FormSectionSlot,
43
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
44
- FormRowProps,
45
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
46
- FormRowSlot,
47
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
48
- FormGroupProps,
49
- /** @deprecated Import from 'basalt-ui/controls' — removed in 1.39.0. */
50
- FormActionsProps,
51
- } from '../controls/form-layout'
52
-
53
26
  // ── submit lifecycle ──────────────────────────────────────────────────────────
54
27
  export { useFormSubmit, isFieldErrorEnvelope } from './use-form-submit'
55
28
  export type { FormFieldErrors, UseFormSubmitOptions, UseFormSubmitReturn } from './use-form-submit'
@@ -67,17 +40,3 @@ export type { FormErrorSummaryProps } from './FormErrorSummary'
67
40
  // ── useFormDraft ──────────────────────────────────────────────────────────────
68
41
  export { useFormDraft, DEFAULT_AUTOSAVE_DEBOUNCE_MS } from './use-form-draft'
69
42
  export type { UseFormDraftOptions, UseFormDraftReturn } from './use-form-draft'
70
-
71
- // ── @mantine/form re-exports — deprecated, zero consumers import them from here ──
72
- export {
73
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
74
- useForm,
75
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
76
- schemaResolver,
77
- } from '@mantine/form'
78
- export type {
79
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
80
- UseFormReturnType,
81
- /** @deprecated Import from '@mantine/form' — removed in 1.39.0. */
82
- UseFormInput,
83
- } from '@mantine/form'
@@ -236,8 +236,9 @@ export function composeInjectedCss(
236
236
  fontsCss: string,
237
237
  radiusCss: string,
238
238
  densityCss: string,
239
+ inputsCss = '',
239
240
  ): string {
240
- return [base, fontsCss, radiusCss, densityCss].filter(Boolean).join('\n')
241
+ return [base, fontsCss, radiusCss, densityCss, inputsCss].filter(Boolean).join('\n')
241
242
  }
242
243
 
243
244
  // ── Host attribute ────────────────────────────────────────────────────────────────────────────────
@@ -325,6 +326,7 @@ function BasaltBridge({
325
326
  const fontsConfig = theme.other?.basaltFonts
326
327
  const radiusConfig = theme.other?.basaltRadius
327
328
  const densityConfig = theme.other?.basaltDensity
329
+ const desktopInputs = theme.other?.['basaltInputs'] === 'desktop'
328
330
  const paletteCss = useMemo(() => {
329
331
  if (!injectPalette) return ''
330
332
  const base =
@@ -336,8 +338,18 @@ function BasaltBridge({
336
338
  const fontsCss = buildFontsCss(fontsConfig)
337
339
  const radiusCss = buildRadiusCss(radiusConfig)
338
340
  const densityCss = buildDensityCss(densityConfig)
339
- return composeInjectedCss(base, fontsCss, radiusCss, densityCss)
340
- }, [injectPalette, deriveConfig, fontsConfig, radiusConfig, densityConfig, paletteOptions])
341
+ // `createBasaltTheme({ inputs: 'desktop' })` — lifts the iOS 16px input-font floor (`styles.css`).
342
+ const inputsCss = desktopInputs ? ':root {\n--basalt-input-fz-floor: 0px;\n}' : ''
343
+ return composeInjectedCss(base, fontsCss, radiusCss, densityCss, inputsCss)
344
+ }, [
345
+ injectPalette,
346
+ deriveConfig,
347
+ fontsConfig,
348
+ radiusConfig,
349
+ densityConfig,
350
+ desktopInputs,
351
+ paletteOptions,
352
+ ])
341
353
 
342
354
  useEffect(() => {
343
355
  // SSR guard — window is not available in server contexts
@@ -18,6 +18,7 @@
18
18
  */
19
19
  import { Group, Menu, Skeleton, Stack, Text, UnstyledButton } from '@mantine/core'
20
20
  import { useBasaltSpacing } from '../theme'
21
+ import { VX } from '../tokens'
21
22
  import { cx } from '../common/props'
22
23
  import type { BasaltProps } from '../common/props'
23
24
  import { assertRequiredProps } from '../common/validate'
@@ -100,15 +101,19 @@ export function SidebarAccount(props: BasaltAccountProps & BasaltProps) {
100
101
  if (state.status === 'unauthenticated') {
101
102
  return (
102
103
  <UnstyledButton
103
- className={cx(classes.accountRow, className)}
104
+ // A footer row IS a nav row's geometry (`.footerBtn`) — same padding, icon column, muted
105
+ // rest state and hover as the Settings row above it, so the footer reads as one cluster.
106
+ className={cx(classes.footerBtn, className)}
104
107
  // The collapsed rail hides `.accountText` (display:none), which drops "Sign in" from the
105
108
  // accessibility tree — the label keeps the button nameable with only the glyph showing.
106
109
  aria-label="Sign in"
107
110
  onClick={actions?.onSignIn}
108
111
  {...(style !== undefined && { style })}
109
112
  >
110
- <IconUser />
111
- <Text className={classes.accountText} size="sm" fw={500}>
113
+ <span className={classes.footerIconSlot}>
114
+ <IconUser />
115
+ </span>
116
+ <Text className={classes.accountText} fz={VX.text.md}>
112
117
  Sign in
113
118
  </Text>
114
119
  </UnstyledButton>
@@ -275,8 +275,8 @@
275
275
  }
276
276
 
277
277
  /*
278
- * Sidebar account row (SidebarAccount) — mock footer geometry: padding 11px 8px 3px, gap 10, NO
279
- * border; hover = the same ink-6% tint as every other row, rounded 6.
278
+ * Sidebar account row (SidebarAccount, authenticated) — a nav row's padding and gap, so its leading
279
+ * block starts on the nav icon column; NO border; hover = the same ink-6% tint as every other row.
280
280
  */
281
281
  .accountRow {
282
282
  flex: 1;
@@ -284,8 +284,7 @@
284
284
  display: flex;
285
285
  align-items: center;
286
286
  gap: var(--vx-space-nav-icon-gap);
287
- padding: var(--vx-space-sidebar-account-inset-top) var(--vx-space-sidebar-account-inset-x)
288
- var(--vx-space-sidebar-account-inset-bottom);
287
+ padding: var(--vx-space-row-inset-y) var(--vx-space-row-inset-x);
289
288
  border-radius: var(--vx-radius-ctrl);
290
289
  }
291
290
 
@@ -232,6 +232,17 @@ export type BasaltShellProps = BasaltProps & {
232
232
  * a no-op when omitted.
233
233
  */
234
234
  onCollapsedChange?: (collapsed: boolean) => void
235
+ /**
236
+ * The header row's height in px — default `SPACE_STEP.appShellHeaderHeight` (44, tracking the
237
+ * density level). ONE number at every width and in both sidebar forms (law C14): the navbar's and
238
+ * aside's top, the page-bar band, the aside's shell header and Main all derive from Mantine's
239
+ * `--app-shell-header-height`, so they follow it with no second value to keep in step. Brand,
240
+ * breadcrumb, page actions and globals centre vertically in the row. For a host that draws its
241
+ * own chrome into the header, e.g. a native macOS unified-toolbar title bar (~52): pair it with
242
+ * `--basalt-shell-lead-inset`. Keep it at or above the `ctl` control height (32) — the row holds
243
+ * one `ctl`-tier control.
244
+ */
245
+ headerHeight?: number
235
246
  /** Page content. */
236
247
  children?: ReactNode
237
248
  }
@@ -349,6 +360,7 @@ function ShellFrame({
349
360
  storageKey = 'basalt-sidebar-collapsed',
350
361
  collapsed: collapsedProp,
351
362
  onCollapsedChange,
363
+ headerHeight,
352
364
  account,
353
365
  search,
354
366
  children,
@@ -466,7 +478,7 @@ function ShellFrame({
466
478
  // bar to the RIGHT of the sidebar instead of above it.
467
479
  header={{
468
480
  // ONE height at every width (law C14): nothing reserves a second mobile row any more.
469
- height: step.appShellHeaderHeight,
481
+ height: headerHeight ?? step.appShellHeaderHeight,
470
482
  }}
471
483
  navbar={{
472
484
  width: { base: step.appShellNavbarWidth, sm: navbarWidth },
package/src/styles.css CHANGED
@@ -97,11 +97,15 @@
97
97
  and re-opens the zoom bug — a floor a `style` prop can override is not a floor, it's a
98
98
  suggestion. `check-theme`'s `raw-form-control` + `sub-16-input-font` guard kinds catch the
99
99
  authoring mistake at build time; this `!important` is the runtime backstop that makes it
100
- un-defeatable even when a violation slips through. */
100
+ un-defeatable even when a violation slips through.
101
+
102
+ `--basalt-input-fz-floor` is the one knob: `createBasaltTheme(…, { inputs: 'desktop' })` has the
103
+ provider set it to 0px for an app that never runs on iOS Safari (a Tauri/desktop shell), where
104
+ the 16px floor is only visual weight. Default stays 16px. */
101
105
  input,
102
106
  select,
103
107
  textarea {
104
- font-size: max(16px, var(--input-fz, 1rem)) !important;
108
+ font-size: max(var(--basalt-input-fz-floor, 16px), var(--input-fz, 1rem)) !important;
105
109
  }
106
110
 
107
111
  /* `data-numeric` — one typographic law, every element. A number read as a MEASUREMENT (a preset
package/src/surfaces.ts CHANGED
@@ -443,7 +443,7 @@ export const SURFACES = {
443
443
  // consumer ships today (`PLUGIN_RULE_GRACE`).
444
444
  pluginRules: ['forms-field-key'],
445
445
  description:
446
- 'Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout moved to ./controls in 1.36.0 and the useForm/schemaResolver re-exports are deprecated (import from @mantine/form); all six stay here until 1.37.0',
446
+ 'Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning; the deprecated `field` alias for `inputProps` was removed in 1.29.0, C1 consolidation), useFormSubmit (submit state, decoded errors, server fieldErrors, focus-first-error, validateAsync), FormStateProvider disable propagation, useFieldArray, FormErrorSummary, useFormDraft with autosave (Standard Schema). The FormSection/FormRow/FormGroup/FormActions layout lives in ./controls (moved in 1.36.0) and useForm/schemaResolver come from @mantine/form; the six re-exports here were removed in 1.39.0',
447
447
  optionalPeers: ['@mantine/form'],
448
448
  forbiddenImports: [],
449
449
  },
@@ -810,6 +810,7 @@ function buildTheme(data: PaletteData, options: BuildThemeOptions = {}): Mantine
810
810
  classNames: {
811
811
  label: segmentedControlClasses.label,
812
812
  control: segmentedControlClasses.control,
813
+ indicator: segmentedControlClasses.indicator,
813
814
  },
814
815
  // `label` gets a `ctl`-only min-height (function-form `styles`, same `props.size === …` gate
815
816
  // as Button/ActionIcon/Input's `vars` overrides above) so a `size="ctl"` SegmentedControl
@@ -818,7 +819,7 @@ function buildTheme(data: PaletteData, options: BuildThemeOptions = {}): Mantine
818
819
  // density. `sm`/`md` SegmentedControls (forms) are untouched, keeping Mantine's own sizing.
819
820
  styles: (_theme, props) => ({
820
821
  root: {
821
- backgroundColor: 'color-mix(in srgb, var(--vx-ink) 6%, transparent)',
822
+ backgroundColor: 'color-mix(in srgb, var(--vx-ink) 8%, transparent)',
822
823
  padding: `${SPACE_FIXED.segmentedTrackInset}px`,
823
824
  // The OUTER safety net a `.control`'s own `min-width: 0` (`segmented-control.module.css`)
824
825
  // cannot provide by itself: that rule only lets each SEGMENT shrink below its own label's
@@ -835,8 +836,13 @@ function buildTheme(data: PaletteData, options: BuildThemeOptions = {}): Mantine
835
836
  minWidth: 'max-content',
836
837
  },
837
838
  indicator: {
838
- backgroundColor: 'color-mix(in srgb, var(--vx-ink) 12%, var(--vx-surface-panel))',
839
- boxShadow: 'var(--vx-shadow-ctrl)',
839
+ // A RAISED pill, not a darker one: its fill (`segmented-control.module.css`, per scheme) is
840
+ // lighter than the ink-tinted track in both schemes, + the shared raised shadow + a 1px ink outline.
841
+ // Same model as Mantine's default (white indicator, shadow, on a grey track) and
842
+ // shadcn's Tabs/ToggleGroup (`bg-background` + shadow on a `bg-muted` track). The old
843
+ // ink-12% fill sat one shade from the track and read as a hover state.
844
+ boxShadow: 'var(--vx-shadow-raised)',
845
+ outline: '1px solid color-mix(in srgb, var(--vx-ink) 14%, transparent)',
840
846
  borderRadius: 'var(--vx-radius-tight)',
841
847
  },
842
848
  // Conditionally spread the WHOLE key (never a present `label: undefined`) — the package
@@ -1577,6 +1583,22 @@ export type CreateBasaltThemeOptions = {
1577
1583
  * createBasaltTheme(undefined, { density: -2 })
1578
1584
  */
1579
1585
  density?: number
1586
+
1587
+ /**
1588
+ * Input sizing for the platform the app runs on. `'touch'` (default) keeps the shipped identity:
1589
+ * `md` inputs (42px) with the 16px font floor that stops iOS Safari's focus-zoom. `'desktop'` is
1590
+ * for an app that never runs in a mobile browser (a Tauri/Electron shell): the Input family
1591
+ * (`TextInput`, `NumberInput`, `PasswordInput`, `Select`, `Textarea`, `Input`) defaults to
1592
+ * Mantine's `sm` (36px, `--vx-text-sm` font) and the provider drops the 16px floor, so every
1593
+ * input Mantine ships — `MultiSelect`/`TagsInput`/pills included, they already default to `sm` —
1594
+ * renders at its own size. An explicit `size` prop still wins. Stashed on
1595
+ * `theme.other.basaltInputs` (only when non-default); `BasaltProvider` emits the floor override,
1596
+ * so `injectPalette={false}` also opts it out.
1597
+ *
1598
+ * @example
1599
+ * createBasaltTheme(undefined, { inputs: 'desktop' })
1600
+ */
1601
+ inputs?: 'touch' | 'desktop'
1580
1602
  }
1581
1603
 
1582
1604
  /**
@@ -1589,6 +1611,20 @@ function hasFontsConfig(fonts: BasaltFontsConfig | undefined): fonts is BasaltFo
1589
1611
  return fonts !== undefined && Object.values(fonts).some((value) => value !== undefined)
1590
1612
  }
1591
1613
 
1614
+ /** `{ inputs: 'desktop' }` — see {@link CreateBasaltThemeOptions.inputs}. Merged AFTER the base
1615
+ * theme, so `defaultProps.size: 'sm'` replaces the base's `'md'` and `other` deep-merges. */
1616
+ const DESKTOP_INPUTS_THEME: MantineThemeOverride = {
1617
+ components: {
1618
+ Input: Input.extend({ defaultProps: { size: 'sm' } }),
1619
+ TextInput: TextInput.extend({ defaultProps: { size: 'sm' } }),
1620
+ NumberInput: NumberInput.extend({ defaultProps: { size: 'sm' } }),
1621
+ PasswordInput: PasswordInput.extend({ defaultProps: { size: 'sm' } }),
1622
+ Select: Select.extend({ defaultProps: { size: 'sm' } }),
1623
+ Textarea: Textarea.extend({ defaultProps: { size: 'sm' } }),
1624
+ },
1625
+ other: { basaltInputs: 'desktop' },
1626
+ }
1627
+
1592
1628
  /**
1593
1629
  * Build the Basalt theme, optionally merged with consumer overrides. Overrides win on conflict
1594
1630
  * (Mantine `mergeThemeOverrides` is last-wins), so a consumer can retune any field without
@@ -1625,6 +1661,7 @@ export function createBasaltTheme(
1625
1661
  const spaceValues = deriveSpacing(densityLevel)
1626
1662
  const isDefaultDensity = densityLevel === 0
1627
1663
  const isDefaultDerive = isDefaultDeriveConfig(resolvedConfig)
1664
+ const desktopInputs = options?.inputs === 'desktop'
1628
1665
 
1629
1666
  let theme: MantineThemeOverride
1630
1667
  if (isDefaultDerive && isDefaultRadius && isDefaultDensity) {
@@ -1646,6 +1683,7 @@ export function createBasaltTheme(
1646
1683
  if (hasFontsConfig(fontsConfig)) {
1647
1684
  theme = mergeThemeOverrides(theme, { other: { basaltFonts: fontsConfig } })
1648
1685
  }
1686
+ if (desktopInputs) theme = mergeThemeOverrides(theme, DESKTOP_INPUTS_THEME)
1649
1687
  if (!overrides) return theme
1650
1688
  // `theme.breakpoints` is derived from `SIZE_CLASSES` — a JS caller's override is dropped.
1651
1689
  return { ...mergeThemeOverrides(theme, overrides), breakpoints: SIZE_CLASS_BREAKPOINTS }
@@ -54,3 +54,19 @@
54
54
  font-family: var(--basalt-font-mono);
55
55
  font-size: var(--vx-text-xs);
56
56
  }
57
+
58
+ /*
59
+ * Selected-segment fill — LIGHTER than the ink-8% track in both schemes, which is what reads as
60
+ * raised. The two schemes need different recipes: the track is an ink tint, so on light it is
61
+ * darker than the page (the panel surface sits above it) while on dark it is LIGHTER than the page,
62
+ * and the same panel surface would then sink below it. Dark therefore lifts the elevated surface
63
+ * with ink. In the module (not the theme's inline `styles`) so the scheme can be selected on —
64
+ * same ancestor-attribute pattern as `controls.module.css`.
65
+ */
66
+ .indicator {
67
+ background-color: var(--vx-surface-elevated);
68
+ }
69
+
70
+ html[data-mantine-color-scheme='dark'] .indicator {
71
+ background-color: color-mix(in srgb, var(--vx-ink) 14%, var(--vx-surface-elevated));
72
+ }
@@ -5,5 +5,6 @@
5
5
  declare const classes: {
6
6
  readonly label: string
7
7
  readonly control: string
8
+ readonly indicator: string
8
9
  }
9
10
  export default classes
@@ -611,6 +611,8 @@ const SPACE_STEP_BASE = {
611
611
  * folds that row's overflow into a kebab and moves its filters/tabs into the page flow, so the
612
612
  * bar is one row on a phone too and there is no sum to keep in step any more.
613
613
  *
614
+ * Consumer-settable per shell through `BasaltShell`'s `headerHeight` (px); this is its default.
615
+ *
614
616
  * 44, down from 48. The band holds ONE `ctl`-tier row (32 since this pass), so 48 left 8px of
615
617
  * dead air above and below it — the "too much spacing at the top bar" the header reads as. 44
616
618
  * keeps 6px of breathing room a side, still clears `controlHeight` (42) for a `size="md"`