basalt-ui 2.6.0 → 2.6.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [2.6.1](https://github.com/jkrumm/basalt-ui/compare/v2.6.0...v2.6.1) (2026-10-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * answer DX trial 2 in the shipped layer and the trace docs ([2f6bd57](https://github.com/jkrumm/basalt-ui/commit/2f6bd5791a4023b82453b3a6cbe51140de4d9601))
7
+ * give per-bar shades their own legend swatches ([9840cd4](https://github.com/jkrumm/basalt-ui/commit/9840cd4d5ed48e9f5b11e06cbf2b34470093ffc9))
8
+
1
9
  # [2.6.0](https://github.com/jkrumm/basalt-ui/compare/v2.5.0...v2.6.0) (2026-10-14)
2
10
 
3
11
 
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 | 1.39.0 | 1.40.0 | 1.40.1 | 1.40.2 | 1.40.3 | 1.41.0 | 2.0.0 | 2.0.1 | 2.0.2 | 2.0.3 | 2.0.4 | 2.0.5 | 2.1.0 | 2.2.0 | 2.3.0 | 2.4.0 | 2.5.0 | 2.6.0 | 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) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | the managed block moves `CLAUDE.md` → `AGENTS.md` (§ 1.41.0) | — | — | — | — | — | — | — | — | — | — | — | — | — |
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 | 1.40.2 | 1.40.3 | 1.41.0 | 2.0.0 | 2.0.1 | 2.0.2 | 2.0.3 | 2.0.4 | 2.0.5 | 2.1.0 | 2.2.0 | 2.3.0 | 2.4.0 | 2.5.0 | 2.6.0 | 2.6.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) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | the managed block moves `CLAUDE.md` → `AGENTS.md` (§ 1.41.0) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
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
 
@@ -992,6 +992,18 @@ optional, subpath-required peers.
992
992
  _Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
993
993
  release renames it and opens a new one here._
994
994
 
995
+ ## 2.6.1 — per-bar legend shades
996
+
997
+ - `Bars`: a legend swatch now wears the shade its bars draw. It samples `barOpacity(firstRow, key)`,
998
+ else the bar's `fillOpacity`, else the 0.85 default, so a per-series shade ladder (Warm-up / Work /
999
+ Drop in one colour) no longer collapses to one flat swatch. The `dots` legend mode honours the
1000
+ opacity too. Visible change: default-opacity bars now show a 0.85 swatch instead of a solid one.
1001
+ - `EnumFilter` stays internal to `basalt-ui/controls` (no export added): `SelectFilter` is the public
1002
+ single-choice filter and `DataTable` facets render `EnumFilter` themselves. No consumer needs the
1003
+ bare body (argo's DX trial reached for it from a task prompt, not from an app), so per the
1004
+ adopt-or-delete doctrine it is not exported. Its `.d.ts` still ships because `DataTable`'s
1005
+ declarations import it.
1006
+
995
1007
  ## 2.6.0 — external-store fields, a live query-fn-unwrap, page shape
996
1008
 
997
1009
  - `externalField({ values, fallback, labels, store })` (`basalt-ui/state`) returns a `FieldHandle`
@@ -18,7 +18,7 @@ paths:
18
18
 
19
19
  ## Query
20
20
 
21
- - Wrap every API-client `queryFn` response in `unwrap()` (it throws on the error branch and on `null` data); a mock returning plain data needs none, and the lint sees only an inline `queryFn` calling `fetch(`. [basalt/query-fn-unwrap]
21
+ - Wrap every API-client `queryFn` response in `unwrap()` from `basalt-ui` (it throws on the error branch and on `null` data); a mock returning plain data needs none, and the lint sees only an inline `queryFn` calling `fetch(`. [basalt/query-fn-unwrap]
22
22
  - The client comes from `createBasaltRouter`; extend it via its `query:` option. [type createBasaltRouter]
23
23
 
24
24
  ## Forms
@@ -29,7 +29,7 @@ createRoot(document.getElementById('root')!).render(<BasaltProvider router={rout
29
29
  3. Import extension layer CSS (`@mantine/dates` for `basalt-ui/controls-dates`, `@mantine/schedule`) after `basalt-ui/styles.css` (core must precede them in `@layer mantine`).
30
30
  4. Install the peers of each subpath you import: read its `Install: bun add …` line in `node_modules/basalt-ui/llms.txt`; a subpath with no `Install:` line needs only the required peers listed at the top of that file.
31
31
  5. In `vite.config.ts` spread `...basaltViteConfig({ port, apiTarget })` and register, in this order, `plugins: [tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ...basaltAppPlugin({ name, description })]`. Run `bun add -d @tanstack/router-plugin` and import `tanstackRouter` from `@tanstack/router-plugin/vite`.
32
- 6. Run `vite build` once so the plugin writes `src/routeTree.gen.ts`; commit it (`tsc -b` fails without it).
32
+ 6. Run `vite build` once so the router plugin writes `src/routeTree.gen.ts` (`tsc -b` fails without it). Follow the repo's own convention for that file: commit it or gitignore it, never both.
33
33
  7. In `src/routes/__root.tsx`: `<BasaltShell brand={{ name }} nav={NAV}><Outlet /></BasaltShell>`; build `NAV` with `defineNav` in `src/lib/nav.tsx`.
34
34
  8. Add a page as a file route, and link to it with `navTarget`:
35
35
 
@@ -237,8 +237,7 @@ export function Chat() {
237
237
 
238
238
  1. `./node_modules/.bin/basalt-ui doctor`; read to the last line. `SKIPPED` exits non-zero.
239
239
  2. Fix every finding doctor prints, then rerun until it is clean.
240
- 3. `bun run lint:basalt` (`oxlint . && basalt-ui check-theme`); fix every finding at its source.
241
- 4. `bunx tsc --noEmit`; fix every error without `as never` or `any`.
240
+ 3. Run the repo's own gate (e.g. `make check`), which runs lint, the theme guard (`basalt-ui check-theme`) and typecheck; fix every finding at its source, and every type error without `as never` or `any`.
242
241
 
243
242
  ## Refresh after any upgrade
244
243
 
@@ -36,5 +36,5 @@ import { lineY } from '@tanstack/charts/line'
36
36
  ```
37
37
 
38
38
  5. Wrap it in `ChartCard`; pass `state={{ pending, error, empty }}` from the query.
39
- 6. Run `bun run lint:basalt` and `bunx tsc --noEmit`; fix every finding at its source.
39
+ 6. Run the repo's own gate (e.g. `make check`), which runs lint, the theme guard and typecheck; fix every finding at its source.
40
40
  7. Check both color schemes and a pending query.
@@ -14,5 +14,5 @@ Method only; the law is `.claude/rules/basalt-*.md` and `./DESIGN.md`.
14
14
  4. Build with Mantine primitives and the composites; take every color from `VX.*` or a series token.
15
15
  5. Tune by eye in the running app: open the theme lab with the `dev.theme` Spotlight command (dev only) and adjust in both color schemes.
16
16
  6. Bake the values back: identity changes go into the `derive` knobs of `createBasaltTheme`, series colors into `src/lib/series.ts` as `{ light, dark }` pairs. Clear the lab overrides and confirm the baked result matches.
17
- 7. Run `bun run lint:basalt`; fix every finding at its source.
17
+ 7. Run the repo's own gate (e.g. `make check`), which runs lint, the theme guard and typecheck; fix every finding at its source.
18
18
  8. Check both schemes, and below and above the `sm` breakpoint.
@@ -12,7 +12,7 @@ export type BarsProps<T, X extends ChartX = ChartX> = Omit<CartesianChartProps<T
12
12
  lines?: readonly BarsLine<T>[] | undefined;
13
13
  /** Default `'stacked'`. `'normalized'` stacks each x to its share of the total. */
14
14
  layout?: 'stacked' | 'grouped' | 'normalized' | undefined;
15
- /** Per-bar opacity (a partial week, an estimate). Overrides the series' `fillOpacity`. */
15
+ /** Per-bar opacity (a partial week, an estimate, a shade per series). Overrides the series' `fillOpacity`; the legend swatch samples it on the first row. */
16
16
  barOpacity?: ((d: T, key: string) => number) | undefined;
17
17
  };
18
18
  export declare function Bars<T, X extends ChartX = ChartX>(props: BarsProps<T, X>): ReactElement;
@@ -1 +1 @@
1
- {"version":3,"file":"Bars.d.ts","sourceRoot":"","sources":["../../src/charts/Bars.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAIzC,OAAO,KAAK,EACV,mBAAmB,EAEnB,WAAW,EACX,MAAM,EAGP,MAAM,SAAS,CAAA;AAEhB,oDAAoD;AACpD,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,IAAI,CAC3B,WAAW,CAAC,CAAC,CAAC,EACd,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAChG,GAAG;IACF,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,CAAA;AAED,8DAA8D;AAC9D,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,IAAI,CAC5B,WAAW,CAAC,CAAC,CAAC,EACZ,KAAK,GACL,OAAO,GACP,OAAO,GACP,UAAU,GACV,aAAa,GACb,SAAS,GACT,QAAQ,GACR,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,aAAa,GACb,eAAe,CAClB,CAAA;AAED,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,CACxD,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,EACzB,OAAO,GAAG,QAAQ,CACnB,GAAG;IACF,IAAI,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3B,KAAK,CAAC,EAAE,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAA;IAC1C,mFAAmF;IACnF,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAA;IACzD,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAA;CACzD,CAAA;AAoBD,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,YAAY,CA2DvF"}
1
+ {"version":3,"file":"Bars.d.ts","sourceRoot":"","sources":["../../src/charts/Bars.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAIzC,OAAO,KAAK,EACV,mBAAmB,EAEnB,WAAW,EACX,MAAM,EAGP,MAAM,SAAS,CAAA;AAEhB,oDAAoD;AACpD,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,IAAI,CAC3B,WAAW,CAAC,CAAC,CAAC,EACd,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAChG,GAAG;IACF,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,CAAA;AAED,8DAA8D;AAC9D,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,IAAI,CAC5B,WAAW,CAAC,CAAC,CAAC,EACZ,KAAK,GACL,OAAO,GACP,OAAO,GACP,UAAU,GACV,aAAa,GACb,SAAS,GACT,QAAQ,GACR,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,aAAa,GACb,eAAe,CAClB,CAAA;AAED,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,CACxD,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,EACzB,OAAO,GAAG,QAAQ,CACnB,GAAG;IACF,IAAI,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3B,KAAK,CAAC,EAAE,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAA;IAC1C,mFAAmF;IACnF,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAA;IACzD,6JAA6J;IAC7J,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAA;CACzD,CAAA;AAoBD,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,YAAY,CAqEvF"}
@@ -19,12 +19,19 @@ function guardLogStack(layout, onLog) {
19
19
  function Bars(props) {
20
20
  const { bars, lines, layout = "stacked", barOpacity, ...rest } = props;
21
21
  guardLogStack(layout, bars.length > 0 && rest.y?.scale === "log");
22
+ const sample = rest.data[0];
22
23
  const series = useMemo(
23
24
  () => [
24
- ...bars.map((b) => ({ ...b, mark: "bar" })),
25
+ // The legend has no datum: its swatch wears the shade the bars draw on the first row, so
26
+ // per-bar shades (`barOpacity`) read the same in the legend as on the plot.
27
+ ...bars.map((b) => ({
28
+ ...b,
29
+ mark: "bar",
30
+ fillOpacity: (sample !== void 0 ? barOpacity?.(sample, b.key) : void 0) ?? b.fillOpacity ?? DEFAULT_BAR_OPACITY
31
+ })),
25
32
  ...(lines ?? []).map((l) => ({ ...l, mark: "line" }))
26
33
  ],
27
- [bars, lines]
34
+ [bars, lines, barOpacity, sample]
28
35
  );
29
36
  const marks = useCallback(
30
37
  (plot) => {
@@ -1 +1 @@
1
- {"version":3,"file":"legend.d.ts","sourceRoot":"","sources":["../../src/charts/legend.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAA;AAGxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C,6FAA6F;AAC7F,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AAUlD,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,CAAC,EAC7B,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,EACjC,MAAM,EAAE,OAAO,GACd,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAMpB;AA8FD,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,IAAI,CAmE9E"}
1
+ {"version":3,"file":"legend.d.ts","sourceRoot":"","sources":["../../src/charts/legend.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAA;AAGxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C,6FAA6F;AAC7F,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AAUlD,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,CAAC,EAC7B,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,EACjC,MAAM,EAAE,OAAO,GACd,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAMpB;AAqGD,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,IAAI,CAmE9E"}
@@ -55,7 +55,15 @@ function Swatch({ s, mode }) {
55
55
  {
56
56
  "aria-hidden": true,
57
57
  className: classes.dot,
58
- style: { width: 8, height: 8, borderRadius: "50%", background: s.color, flex: "none" }
58
+ style: {
59
+ width: 8,
60
+ height: 8,
61
+ // theme-allow raw-surface — a legend dot is a circle, not a surface corner
62
+ borderRadius: "50%",
63
+ background: s.color,
64
+ opacity: s.fillOpacity ?? 1,
65
+ flex: "none"
66
+ }
59
67
  }
60
68
  );
61
69
  if ((s.mark ?? "line") === "line")
@@ -90,6 +90,11 @@ export type ChatTurnTrace = {
90
90
  * else. A sink without the hook, or no sink, changes nothing on the wire. basalt has no OTel
91
91
  * dependency; the hook is where the consumer's SDK does the work.
92
92
  *
93
+ * A fetch instrumentation (OTel web, HyperDX) overwrites the returned `traceparent` on same-origin
94
+ * requests with its own fetch span, so the API span lands in a separate trace. Either exclude the
95
+ * chat URL from the instrumentation (`ignoreUrls` in HyperDX and in OTel's fetch instrumentation),
96
+ * or make the turn span the active context around the request.
97
+ *
93
98
  * @example
94
99
  * export const telemetry: Telemetry = Object.assign(onEvent, {
95
100
  * startChatTurn({ threadId }) {
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # basalt-ui v2.6.0
1
+ # basalt-ui v2.6.1
2
2
  # Opinionated framework for Mantine-based React apps — theme, app shell, TanStack Charts, toolchain presets
3
3
  #
4
4
  # Entry points: use the exact import specifier below; do not guess.
@@ -13,13 +13,39 @@
13
13
  # A subpath's `Install:` line is its required peers; `OptionalPeers:` are import()-only, install on use.
14
14
 
15
15
  Package: basalt-ui
16
- Version: 2.6.0
16
+ Version: 2.6.1
17
17
 
18
18
  ## basalt-ui
19
19
  Import: import { ... } from 'basalt-ui'
20
20
  Description: Wiring (`BasaltProvider`, `createBasaltTheme`, `createBasaltRouter`, `unwrap`), shell + nav (`BasaltShell`, `PageBar`, `PageAside`, `PageTitle`, `ThemeToggle`, `defineNav`/`navGroup`/`navTarget`/`flattenNav`, `useBasaltNav`, `useSizeClass`, `useCoarsePointer`), dashboard (`Section`, `WidgetHeader`, `StatCard`, `StatGroup`, `DeltaBadge`, `EmptyState`, `SettingsSection`/`SettingsRow`/`DangerZone`). Reaches no subpath-required peer.
21
21
  Layer: mantine-coupled
22
22
  Rule: basalt-mantine
23
+ Signature: BasaltProvider(props: BasaltProviderProps): JSX.Element
24
+ Signature: BasaltShell(props: BasaltShellProps<G, T>): JSX.Element
25
+ Signature: DangerZone(props: SettingsSectionProps): JSX.Element
26
+ Signature: DeltaBadge(props: DeltaBadgeProps): JSX.Element
27
+ Signature: EmptyState(props: EmptyStateProps): JSX.Element
28
+ Signature: PageAside(props: PageAsideProps): ReactNode
29
+ Signature: PageBar(props: PageBarProps): ReactNode
30
+ Signature: PageTitle(props: PageTitleProps): ReactNode
31
+ Signature: Section(props: SectionProps): JSX.Element
32
+ Signature: SettingsRow(props: SettingsRowProps): JSX.Element
33
+ Signature: SettingsSection(props: SettingsSectionProps): JSX.Element
34
+ Signature: StatCard(props: StatCardProps): JSX.Element
35
+ Signature: StatGroup(props: StatGroupProps): JSX.Element
36
+ Signature: ThemeToggle(props: ThemeToggleProps): JSX.Element
37
+ Signature: WidgetHeader(props: WidgetHeaderProps): JSX.Element
38
+ Signature: createBasaltRouter(options: { routeTree: TRouteTree; context?: TContext; query?: QueryClientConfi…): BasaltRouter<TRouteTree>
39
+ Signature: createBasaltTheme(overrides: Omit<PartialObjectDeep<MantineTheme, { recurseIntoArrays: false; allo…, options: CreateBasaltThemeOptions | undefined): PartialObjectDeep<Ma…
40
+ Signature: defineNav(config: "basalt: declare Register { router }"): NavConfig<G, T>
41
+ Signature: flattenNav(config: { groups: ReadonlyArray<AnyNavGroup>; }): FlatNavItem[]
42
+ Signature: navGroup(meta: Exact<M, NavGroupMeta>, items: NavItemsInput<T>): M & { items: T; }
43
+ Signature: navTarget(config: C, id: K): NavIndex<C["groups"]>[K]
44
+ Signature: scrollParentOf(el: Element | null): HTMLElement | null
45
+ Signature: unwrap(response: R): UnwrapResult<R>
46
+ Signature: useBasaltNav(): { currentPath: string; isActive: (href: string, opts?: { exact?: bool…
47
+ Signature: useCoarsePointer(): boolean
48
+ Signature: useSizeClass(): "compact" | "medium" | "expanded"
23
49
  OptionalPeers: remark-gfm@^4.0.1, rehype-sanitize@^6.0.0, remend@1.4.0, shiki@^4.5.0, beautiful-mermaid@^1.1.0, @tanstack/react-router-devtools@^1.166.13
24
50
 
25
51
  ## basalt-ui/charts
@@ -27,6 +53,19 @@ Import: import { ... } from 'basalt-ui/charts'
27
53
  Description: CartesianChart (the TanStack Charts rung), the Lines and Bars kinds, ChartCard and the shared chartCursor (Mantine-free; @tanstack/charts + d3-scale peers)
28
54
  Layer: headless
29
55
  Rule: basalt-charts
56
+ Signature: BandStrip(props: BandStripProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
57
+ Signature: Bars(props: BarsProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
58
+ Signature: CartesianChart(props: CartesianChartProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
59
+ Signature: ChartCard(props: ChartCardProps): ReactElement<unknown, string | JSXElementConstructor<any>>
60
+ Signature: Donut(props: DonutProps<K>): ReactElement<unknown, string | JSXElementConstructor<any>>
61
+ Signature: DualPanel(props: DualPanelProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
62
+ Signature: Heatmap(props: HeatmapProps<T>): ReactElement<unknown, string | JSXElementConstructor<any>>
63
+ Signature: Lines(props: LinesProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
64
+ Signature: MirroredBars(props: MirroredBarsProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
65
+ Signature: Sparkline(props: SparklineProps): ReactElement<unknown, string | JSXElementConstructor<any>>
66
+ Signature: StackedArea(props: StackedAreaProps<T, X>): ReactElement<unknown, string | JSXElementConstructor<any>>
67
+ Signature: chartCursor(group: string): ChartCursorController<ChartValue, ChartValue>
68
+ Signature: chartCurve(name: CurveName): ChartCurve
30
69
  Install: bun add @tanstack/charts@1.1.0 d3-scale@4.0.2
31
70
 
32
71
  ## basalt-ui/tokens
@@ -34,11 +73,24 @@ Import: import { ... } from 'basalt-ui/tokens'
34
73
  Description: VX token refs, buildPaletteCss, defineSeries, seriesTokens, groupTokens, alpha (Mantine-free)
35
74
  Layer: headless
36
75
  Rule: basalt-tokens
76
+ Signature: BP: { black, white, darkGray, gray, lightGray, blue, green, orange, red, vermilion, rose, violet, indigo, cerulean, turquoise, forest, lime, gold, sepia }
77
+ Signature: CONTAINER_CLASSES: { micro, compact, regular, wide }
78
+ Signature: CONTAINER_GRID_BREAKPOINTS: { xs, sm, md, lg, xl }
79
+ Signature: CONTAINER_KEYS: { compact, regular, wide }
80
+ Signature: VX: { lineWidth, line2Width, axisFont, dotR, dashArray, legendGap, legendFontSize, text, radiusCard, radiusCtrl, radiusPill, hit, space, line2Dark, good, goodSoft, bad, …
81
+ Signature: alpha(token: string, a: number): string
82
+ Signature: buildPaletteCss(opts: BuildPaletteOpts, data: { ACCENT: { readonly accent: ColorPair; readonly accentHover: ColorPa…): string
83
+ Signature: defineSeries(map: T): T
84
+ Signature: groupTokens(name: string, map: T): { readonly [K in keyof T]: GroupRef; }
85
+ Signature: p(fam: readonly string[], light: number, dark: number): ColorPair
86
+ Signature: seriesTokens(map: T, prefix: string): { [K in keyof T]: string; }
37
87
 
38
88
  ## basalt-ui/vite
39
89
  Import: import { ... } from 'basalt-ui/vite'
40
90
  Description: basaltViteConfig(opts) — Vite preset for basalt-ui consumer apps; basaltAppPlugin(opts) — PWA head, manifest, and icon metadata derived from the token palette
41
91
  Layer: build-tooling
92
+ Signature: basaltAppPlugin(options: BasaltAppOptions): PluginOption[]
93
+ Signature: basaltViteConfig(opts: BasaltViteOptions): UserConfig
42
94
  Install: bun add 'vite@^7 || ^8'
43
95
  OptionalPeers: vite-plugin-pwa@^1.3.0
44
96
 
@@ -46,20 +98,23 @@ OptionalPeers: vite-plugin-pwa@^1.3.0
46
98
  Import: import { ... } from 'basalt-ui/format'
47
99
  Description: integer/money/percent/durationClock/relativeTime/weekday/km/kcal — Intl-backed, Mantine-free, React-free formatting; the chart layer formats through the same implementation
48
100
  Layer: headless
49
- Signature: integer(value: number, { locale? }) => string
50
- Signature: money(value: number, { currency: string, compact?, digits?, locale? }) => string
51
- Signature: percent(value: number, { input?: 'ratio' | 'percent', digits?, locale? }) => string
52
- Signature: km(meters: number, { digits? }) => string
53
- Signature: kcal(value: number, { digits? }) => string
54
- Signature: durationClock(seconds: number) => string
55
- Signature: relativeTime(value: number | Date | string, { now?, locale? }) => string
56
- Signature: weekday(value: Date | number | string, { format?: 'short' | 'long' | 'narrow', locale? }) => string
101
+ Signature: durationClock(seconds: number): string
102
+ Signature: integer(value: number, options: LocaleOption): string
103
+ Signature: kcal(value: number, options: KcalOptions): string
104
+ Signature: km(meters: number, options: KmOptions): string
105
+ Signature: money(value: number, options: FmtCurrencyOptions): string
106
+ Signature: percent(value: number, options: FmtPercentOptions): string
107
+ Signature: relativeTime(value: string | number | Date, options: RelativeTimeOptions): string
108
+ Signature: weekday(value: string | number | Date, options: WeekdayOptions): string
57
109
 
58
110
  ## basalt-ui/forms
59
111
  Import: import { ... } from 'basalt-ui/forms'
60
112
  Description: Mantine form layer: useBasaltForm + inputProps/fieldKey (two calls — a spread `key` is a React 19 warning), on @mantine/form
61
113
  Layer: mantine-coupled
62
114
  Rule: basalt-batteries
115
+ Signature: fieldKey(form: UseFormReturnType<Values>, path: Path): string
116
+ Signature: inputProps(form: UseFormReturnType<Values>, path: Path): GetInputPropsReturnType
117
+ Signature: useBasaltForm(opts: UseBasaltFormOptions<Values>): UseFormReturnType<Values>
63
118
  Install: bun add @mantine/form@^9.7.0
64
119
 
65
120
  ## basalt-ui/commands
@@ -67,6 +122,15 @@ Import: import { ... } from 'basalt-ui/commands'
67
122
  Description: defineCommands (typed command bus), defineOverlays/overlays, setColorScheme, toggleSidebar, ShortcutsHelp, defineNotifications/emit/NotificationBell (folded in from ./notifications); BasaltProvider mounts Spotlight, Modals and Notifications
68
123
  Layer: mantine-coupled
69
124
  Rule: basalt-batteries
125
+ Signature: NotificationBell(props: NotificationBellProps): JSX.Element
126
+ Signature: ShortcutsHelp(props: ShortcutsHelpProps): JSX.Element | null
127
+ Signature: defineCommands(spec: T): T
128
+ Signature: defineNotifications(spec: T): T
129
+ Signature: defineOverlays(spec: T): T
130
+ Signature: emit(kind: K, args: EmitArgs<K>): string
131
+ Signature: overlays: { open, confirm, confirmDelete, close }
132
+ Signature: setColorScheme(scheme: ColorScheme): void
133
+ Signature: toggleSidebar(): void
70
134
  Install: bun add @tanstack/react-hotkeys@0.13.0
71
135
 
72
136
  ## basalt-ui/table
@@ -74,6 +138,8 @@ Import: import { ... } from 'basalt-ui/table'
74
138
  Description: BasaltDataTable and createColumnHelper: a data table over TanStack Table v9, rendered with Mantine (renamed from ./data/table)
75
139
  Layer: mantine-coupled
76
140
  Rule: basalt-batteries
141
+ Signature: BasaltDataTable(props: BasaltDataTableProps<T>): JSX.Element
142
+ Signature: createColumnHelper(): ColumnHelper<{ rowSortingFeature: TableFeature; columnFilteringFeatur…
77
143
  Install: bun add @tanstack/react-table@9.2.8
78
144
 
79
145
  ## basalt-ui/agent
@@ -81,6 +147,14 @@ Import: import { ... } from 'basalt-ui/agent'
81
147
  Description: Streaming-chat surface: aiSdkTransport, useAgentThreadRuns, parseAgentPart, the open part-registry types, the consumer-owned thread contracts (AgentThread/ThreadsStore/ChatMessage), and the Mantine chat UI folded in from ./agent-chat (ThreadFeed, ThreadFeedRow, Composer, ToolChip). motion is subpath-required: the chat UI imports it eagerly
82
148
  Layer: mantine-coupled
83
149
  Rule: basalt-batteries
150
+ Signature: Composer(props: ComposerProps): JSX.Element
151
+ Signature: ThreadFeed(props: ThreadFeedProps): JSX.Element
152
+ Signature: ThreadFeedRow(props: ThreadFeedRowProps): JSX.Element
153
+ Signature: ToolChip(props: ToolChipProps): JSX.Element
154
+ Signature: aiSdkTransport(options: AiSdkTransportOptions): AiSdkTransport<TPart>
155
+ Signature: parseAgentPart(raw: unknown): AgentPart | null
156
+ Signature: toAgentError(error: unknown): AgentError
157
+ Signature: useAgentThreadRuns(props: UseAgentThreadRunsArgs<TPart>): UseAgentThreadRunsReturn<TPart>
84
158
  Install: bun add ai@^7.0.137 @ai-sdk/provider@^4.0.26 motion@14.1.0
85
159
  OptionalPeers: use-stick-to-bottom@^1.1.6, @tanstack/react-virtual@>=3.14.0 <4
86
160
 
@@ -89,6 +163,14 @@ Import: import { ... } from 'basalt-ui/content'
89
163
  Description: Prose (article/chat typography), Callout, TableOfContents, Markdown (react-markdown + remark-gfm, optional peers; `streaming` is a rendering mode ONLY — `contentTrust` is the independent security input, and any surface rendering agent/model output must pin `contentTrust="untrusted"`, the sole input to the image-origin allowlist; `fenceRenderers` extends fenced-block rendering — settledOnly/FenceRenderer/FenceRenderers; `sanitizeSchema` is an additions-only SanitizeSchemaExtension merged over the default via mergeSanitizeSchema; shiki code blocks, beautiful-mermaid diagrams and the remend streaming repair load lazily from optional peers), ArticleLayout (docs-page frame), GuideLink (contextual-help link) — the content/prose surface
90
164
  Layer: mantine-coupled
91
165
  Rule: basalt-batteries
166
+ Signature: ArticleLayout(props: ArticleLayoutProps): JSX.Element
167
+ Signature: Callout(props: CalloutProps): JSX.Element
168
+ Signature: GuideLink(props: GuideLinkProps): JSX.Element
169
+ Signature: Markdown(props: MarkdownProps): JSX.Element
170
+ Signature: Prose(props: ProseProps): JSX.Element
171
+ Signature: TableOfContents(props: TableOfContentsProps): JSX.Element | null
172
+ Signature: mergeSanitizeSchema(base: SanitizeSchemaInput, extensions: readonly (SanitizeSchemaExtension | undefined)[]): SanitizeSchema
173
+ Signature: settledOnly(render: FenceRenderer): FenceRenderer
92
174
  Install: bun add react-markdown@^10.1.0
93
175
  OptionalPeers: shiki@^4.5.0, @shikijs/langs@^4.5.0, @shikijs/themes@^4.5.0, beautiful-mermaid@^1.1.0, remark-gfm@^4.0.1, rehype-sanitize@^6.0.0, remend@1.4.0
94
176
 
@@ -97,12 +179,24 @@ Import: import { ... } from 'basalt-ui/controls'
97
179
  Description: The control tier (docs/CONTROLS-SPEC.md §3): FilterSet (nowrap row + measured +N fold + the mobile Filters (n) sheet), RangeFilter/CompareFilter/SelectFilter/MultiSelectFilter/NumberFilter/SearchFilter/ToggleFilter (each bound to a FieldHandle — no value/onChange/size, law C2/C5; NumberFilter is the field.number lane, a radio list over `options` or a stepper without), ViewTabs, the action/sync family (ActionGroup, OverflowMenu, SyncButton, BarAction/GlobalAction), and the form layout FormSection/FormRow/FormGroup/FormActions (moved here from ./forms in 1.36.0 — FormRow is law C1’s form row and needs no @mantine/form). THREE surfaces, picked by the home and never by a prop (useFilterSurface): pill in a PageBar row, sheet in the mobile Filters (n) drawer, panel in a PageAside body — where every control renders an inspector/facet ROW instead of a chip (docs/ASIDE-SPEC.md §3). PanelRow is that row primitive (label above, hint, mono readout, an `end` control on the label line) and SliderControl is the one bound control with no pill form at all; the counts/max props on MultiSelectFilter render the Foundry facet list there. Every control owns its own desktop/mobile swap in CSS (C9) and renders size="ctl" internally. Resolves and renders with NO @mantine/dates installed — the custom date picker is injected through RangeFilter.customPicker from ./controls-dates.
98
180
  Layer: mantine-coupled
99
181
  Rule: basalt-controls
182
+ Signature: FilterSet(props: FilterSetProps): ReactNode
183
+ Signature: FormGroup(props: FormGroupProps): JSX.Element
184
+ Signature: FormRow(props: FormRowProps): JSX.Element
185
+ Signature: MultiSelectFilter(props: MultiSelectFilterProps<T>): ReactNode
186
+ Signature: NumberFilter(props: NumberFilterProps): ReactNode
187
+ Signature: RangeFilter(props: RangeFilterProps<P, C>): ReactNode
188
+ Signature: SearchFilter(props: SearchFilterProps): ReactNode
189
+ Signature: SelectFilter(props: SelectFilterEnumProps<T>): ReactNode
190
+ Signature: SyncButton(props: SyncButtonProps): ReactNode
191
+ Signature: ToggleFilter(props: ToggleFilterProps): ReactNode
192
+ Signature: ViewTabs(props: ViewTabsProps<T>): ReactNode
100
193
 
101
194
  ## basalt-ui/controls-dates
102
195
  Import: import { ... } from 'basalt-ui/controls-dates'
103
196
  Description: DateRangePicker — the @mantine/dates implementation of RangeFilter's customPicker seam. Its own subpath because @mantine/dates is an optional peer and basaltViteConfig pre-bundles the whole @mantine scope, so a consumer without the peer (linewatch) must never resolve it: nothing under src/controls may import it, statically or lazily (docs/CONTROLS-SPEC.md §3).
104
197
  Layer: mantine-coupled
105
198
  Rule: basalt-controls
199
+ Signature: DateRangePicker(props: RangeCustomPickerProps): ReactNode
106
200
  Install: bun add @mantine/dates@^9.7.0 dayjs@^1.11.0
107
201
 
108
202
  ## basalt-ui/state
@@ -110,6 +204,11 @@ Import: import { ... } from 'basalt-ui/state'
110
204
  Description: field.enum/multi/range/number/boolean/string (the store field vocabulary), createSearchStore (typed URL > localStorage > fallback store), createLocalStore (the router-free store), createPersistedState (versioned localStorage)
111
205
  Layer: headless
112
206
  Rule: basalt-state
207
+ Signature: createLocalStore(o: { key: string; fields: S; version?: number; }): LocalStore<S>
208
+ Signature: createPersistedState(opts: PersistedStateOptions<T>): () => readonly [T, (next: T) => void]
209
+ Signature: createSearchStore(o: CreateSearchStoreOptions<S>): SearchStore<S>
210
+ Signature: externalField(o: { values: readonly T[]; fallback: NoInfer<T>; labels?: Partial<Record…): FieldHandle<EnumField<T, ResolvedLane>>
211
+ Signature: field: { enum, multi, range, number, boolean, string }
113
212
 
114
213
  ## basalt-ui/styles.css
115
214
  Asset: basalt-ui/styles.css
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basalt-ui",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "Opinionated framework for Mantine-based React apps — theme, app shell, TanStack Charts, toolchain presets",
5
5
  "keywords": [
6
6
  "charts",
@@ -57,7 +57,7 @@ export type BarsProps<T, X extends ChartX = ChartX> = Omit<
57
57
  lines?: readonly BarsLine<T>[] | undefined
58
58
  /** Default `'stacked'`. `'normalized'` stacks each x to its share of the total. */
59
59
  layout?: 'stacked' | 'grouped' | 'normalized' | undefined
60
- /** Per-bar opacity (a partial week, an estimate). Overrides the series' `fillOpacity`. */
60
+ /** Per-bar opacity (a partial week, an estimate, a shade per series). Overrides the series' `fillOpacity`; the legend swatch samples it on the first row. */
61
61
  barOpacity?: ((d: T, key: string) => number) | undefined
62
62
  }
63
63
 
@@ -82,12 +82,22 @@ function guardLogStack(layout: string, onLog: boolean): void {
82
82
  export function Bars<T, X extends ChartX = ChartX>(props: BarsProps<T, X>): ReactElement {
83
83
  const { bars, lines, layout = 'stacked', barOpacity, ...rest } = props
84
84
  guardLogStack(layout, bars.length > 0 && rest.y?.scale === 'log')
85
+ const sample = rest.data[0]
85
86
  const series = useMemo<ChartSeries<T>[]>(
86
87
  () => [
87
- ...bars.map((b) => ({ ...b, mark: 'bar' as const })),
88
+ // The legend has no datum: its swatch wears the shade the bars draw on the first row, so
89
+ // per-bar shades (`barOpacity`) read the same in the legend as on the plot.
90
+ ...bars.map((b) => ({
91
+ ...b,
92
+ mark: 'bar' as const,
93
+ fillOpacity:
94
+ (sample !== undefined ? barOpacity?.(sample, b.key) : undefined) ??
95
+ b.fillOpacity ??
96
+ DEFAULT_BAR_OPACITY,
97
+ })),
88
98
  ...(lines ?? []).map((l) => ({ ...l, mark: 'line' as const })),
89
99
  ],
90
- [bars, lines],
100
+ [bars, lines, barOpacity, sample],
91
101
  )
92
102
 
93
103
  const marks = useCallback(
@@ -87,8 +87,15 @@ function Swatch({ s, mode }: { s: SwatchStyle; mode: LegendMode }): ReactElement
87
87
  <span
88
88
  aria-hidden
89
89
  className={classes.dot}
90
- // theme-allow raw-surface — a legend dot is a circle, not a surface corner
91
- style={{ width: 8, height: 8, borderRadius: '50%', background: s.color, flex: 'none' }}
90
+ style={{
91
+ width: 8,
92
+ height: 8,
93
+ // theme-allow raw-surface — a legend dot is a circle, not a surface corner
94
+ borderRadius: '50%',
95
+ background: s.color,
96
+ opacity: s.fillOpacity ?? 1,
97
+ flex: 'none',
98
+ }}
92
99
  />
93
100
  )
94
101
  if ((s.mark ?? 'line') === 'line')
package/src/telemetry.ts CHANGED
@@ -99,6 +99,11 @@ export type ChatTurnTrace = {
99
99
  * else. A sink without the hook, or no sink, changes nothing on the wire. basalt has no OTel
100
100
  * dependency; the hook is where the consumer's SDK does the work.
101
101
  *
102
+ * A fetch instrumentation (OTel web, HyperDX) overwrites the returned `traceparent` on same-origin
103
+ * requests with its own fetch span, so the API span lands in a separate trace. Either exclude the
104
+ * chat URL from the instrumentation (`ignoreUrls` in HyperDX and in OTel's fetch instrumentation),
105
+ * or make the turn span the active context around the request.
106
+ *
102
107
  * @example
103
108
  * export const telemetry: Telemetry = Object.assign(onEvent, {
104
109
  * startChatTurn({ threadId }) {