basalt-ui 1.35.0 → 1.36.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/AGENTS.md +21 -21
- package/CHANGELOG.md +16 -0
- package/MIGRATING.md +85 -14
- package/agent/rules/basalt-controls.md +1 -1
- package/agent/rules/basalt-mantine.md +1 -1
- package/configs/oxlint-plugin.js +51 -4
- package/configs/oxlint-plugin.test.ts +58 -15
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +2 -1
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +2 -1
- package/dist/charts/primitives/chart-tier.d.ts +0 -2
- package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
- package/dist/charts/primitives/chart-tier.js +0 -5
- package/dist/common/index.d.ts +1 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +2 -0
- package/dist/common/use-media-query.d.ts +7 -0
- package/dist/common/use-media-query.d.ts.map +1 -1
- package/dist/common/use-media-query.js +4 -0
- package/dist/common/vx-families.d.ts +1 -1
- package/dist/{forms → controls}/form-layout.d.ts +1 -1
- package/dist/controls/form-layout.d.ts.map +1 -0
- package/dist/{forms → controls}/form-layout.js +2 -2
- package/dist/controls/index.d.ts +1 -0
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +10 -0
- package/dist/forms/index.d.ts +37 -7
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +10 -2
- package/dist/guard/index.d.ts +3 -1
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +2 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/provider/index.d.ts +5 -4
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/shell/use-size-class.d.ts.map +1 -1
- package/dist/surfaces.d.ts +4 -4
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +11 -3
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +5 -7
- package/llms.txt +5 -5
- package/package.json +1 -1
- package/src/charts/primitives/ChartFrame.tsx +2 -1
- package/src/charts/primitives/ChartLegend.tsx +2 -1
- package/src/charts/primitives/chart-tier.tsx +0 -6
- package/src/common/index.ts +1 -0
- package/src/common/use-media-query.ts +10 -0
- package/src/common/vx-families.ts +1 -1
- package/src/{forms → controls}/form-layout.tsx +7 -5
- package/src/controls/index.ts +16 -0
- package/src/forms/index.ts +36 -9
- package/src/guard/index.ts +5 -15
- package/src/index.ts +1 -0
- package/src/provider/index.tsx +5 -4
- package/src/shell/use-size-class.ts +6 -4
- package/src/surfaces.ts +11 -3
- package/src/tokens/index.ts +12 -15
- package/dist/forms/form-layout.d.ts.map +0 -1
- /package/dist/{forms → controls}/form-layout.module.css +0 -0
- /package/dist/{forms → controls}/form-layout.module.css.d.ts +0 -0
- /package/src/{forms → controls}/form-layout.module.css +0 -0
- /package/src/{forms → controls}/form-layout.module.css.d.ts +0 -0
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v1.
|
|
1
|
+
# basalt-ui v1.36.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,11 +19,11 @@
|
|
|
19
19
|
# ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
|
|
20
20
|
|
|
21
21
|
Package: basalt-ui
|
|
22
|
-
Version: 1.
|
|
22
|
+
Version: 1.36.1
|
|
23
23
|
|
|
24
24
|
## basalt-ui
|
|
25
25
|
Import: import { ... } from 'basalt-ui'
|
|
26
|
-
Description: BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)
|
|
26
|
+
Description: BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass, useCoarsePointer, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)
|
|
27
27
|
Layer: mantine-coupled
|
|
28
28
|
Rule: basalt-mantine
|
|
29
29
|
OptionalPeers: react-markdown@^10.1.0, remark-gfm@^4.0.1, rehype-sanitize@^6.0.0, remend@1.3.0, shiki@^4.3.0, beautiful-mermaid@^1.1.0, @tanstack/react-router-devtools@^1.166.13
|
|
@@ -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),
|
|
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
|
|
74
74
|
Layer: mantine-coupled
|
|
75
75
|
Rule: basalt-batteries
|
|
76
76
|
OptionalPeers: @mantine/form@^9.3.0
|
|
@@ -126,7 +126,7 @@ OptionalPeers: shiki@^4.3.0, @shikijs/langs@^4.3.1, @shikijs/themes@^4.3.1, beau
|
|
|
126
126
|
|
|
127
127
|
## basalt-ui/controls
|
|
128
128
|
Import: import { ... } from 'basalt-ui/controls'
|
|
129
|
-
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,
|
|
129
|
+
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.
|
|
130
130
|
Layer: mantine-coupled
|
|
131
131
|
Rule: basalt-controls
|
|
132
132
|
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
legendSlotContention,
|
|
9
9
|
plotBelowFloor,
|
|
10
10
|
} from '../../common/errors'
|
|
11
|
+
import { useCoarsePointer } from '../../common/use-media-query'
|
|
11
12
|
import { reportOnce, useValidateProps } from '../../common/validate'
|
|
12
13
|
import { SizeClassHintContext, useSizeClass } from '../../shell/use-size-class'
|
|
13
14
|
import { VX } from '../../tokens'
|
|
@@ -18,7 +19,7 @@ import { ChartCardContext } from './chart-card-context'
|
|
|
18
19
|
import { resolveChartLayout, resolveFrameClass } from './chart-layout'
|
|
19
20
|
import { resolveFrameHeight, resolveLegendRollup, resolvePlotRect } from './chart-frame-layout'
|
|
20
21
|
import type { ResponsiveChartHeight } from './chart-frame-layout'
|
|
21
|
-
import { ChartTierProvider,
|
|
22
|
+
import { ChartTierProvider, useViewportHeight } from './chart-tier'
|
|
22
23
|
import { ChartLegend } from './ChartLegend'
|
|
23
24
|
import { ChartEmpty, ChartError, ChartPending, resolveChartState } from './ChartPending'
|
|
24
25
|
import type { ChartState } from './ChartPending'
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { CSSProperties, MouseEvent, ReactNode } from 'react'
|
|
2
2
|
import type { BasaltProps } from '../../common/props'
|
|
3
|
+
import { useCoarsePointer } from '../../common/use-media-query'
|
|
3
4
|
import { alpha, VX } from '../../tokens'
|
|
4
5
|
import type { SeriesRole, LegendPlacement } from '../series'
|
|
5
6
|
import { DOTS_HIT_GAP, LEGEND_DOT_SIZE, LEGEND_ROW_GAP, orderEntries } from './chart-frame-layout'
|
|
6
|
-
import { useChartMetrics
|
|
7
|
+
import { useChartMetrics } from './chart-tier'
|
|
7
8
|
import { LegendDisclosure, useLegendDisclosure } from './legend-disclosure'
|
|
8
9
|
|
|
9
10
|
export type LegendEntry = {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createContext, useContext, useSyncExternalStore } from 'react'
|
|
2
2
|
import type { ReactNode } from 'react'
|
|
3
|
-
import { useMediaQuery } from '../../common/use-media-query'
|
|
4
3
|
import type { ContainerClass } from '../../tokens/size-classes'
|
|
5
4
|
import { chartMetrics } from './chart-frame-layout'
|
|
6
5
|
import type { ChartTierMetrics } from './chart-frame-layout'
|
|
@@ -42,11 +41,6 @@ export function useChartMetrics(): ChartTierMetrics {
|
|
|
42
41
|
|
|
43
42
|
const subscribeNothing = (): (() => void) => () => {}
|
|
44
43
|
|
|
45
|
-
/** Whether the primary pointer is coarse. Server snapshot `false`: hydration agrees, then updates. */
|
|
46
|
-
export function useCoarsePointer(): boolean {
|
|
47
|
-
return useMediaQuery('(pointer: coarse)', false)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
44
|
/** Viewport height is quantized so a mobile URL bar collapsing does not re-lay-out every chart. */
|
|
51
45
|
const VIEWPORT_H_STEP = 50
|
|
52
46
|
|
package/src/common/index.ts
CHANGED
|
@@ -19,4 +19,5 @@ export {
|
|
|
19
19
|
} from './errors'
|
|
20
20
|
export { useValidateProps, assertRequiredProps, resetValidatedProps } from './validate'
|
|
21
21
|
export { scrollParentOf, SCROLLPORT_ATTRIBUTE } from './scroll-parent'
|
|
22
|
+
export { useCoarsePointer } from './use-media-query'
|
|
22
23
|
export { MOTION_DURATION, MOTION_EASE_STANDARD, MOTION_SPRING } from './motion'
|
|
@@ -54,3 +54,13 @@ export function useMediaQuery(query: string, serverFallback: boolean): boolean {
|
|
|
54
54
|
const getServerSnapshot = useCallback(() => serverFallback, [serverFallback])
|
|
55
55
|
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Whether the primary pointer is coarse — the JS twin of `--vx-hit`'s `(pointer: coarse)` query.
|
|
60
|
+
* For a branch CSS cannot express (mount one of two components, attach a keydown listener); styling
|
|
61
|
+
* stays `@media (pointer: coarse)` in a CSS module. Server and hydration snapshot is `false`; a
|
|
62
|
+
* `createRoot` app reads the real pointer on its first render.
|
|
63
|
+
*/
|
|
64
|
+
export function useCoarsePointer(): boolean {
|
|
65
|
+
return useMediaQuery('(pointer: coarse)', false)
|
|
66
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The families every emitted `--vx-*` name lives in (`basaltVxFamilies`) — basalt-owned:
|
|
5
|
-
* `unknown-vx-token` judges every name inside one, and `groupTokens`/`seriesTokens`
|
|
5
|
+
* `unknown-vx-token` judges every name inside one, and `groupTokens`/`seriesTokens` throw on a
|
|
6
6
|
* consumer ref there.
|
|
7
7
|
*/
|
|
8
8
|
export const BASALT_VX_FAMILIES: readonly string[] = [
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ./
|
|
3
|
-
* Mantine-coupled.
|
|
2
|
+
* ./controls — the form layout primitives: `FormSection`, `FormRow`, `FormGroup`, `FormActions`.
|
|
3
|
+
* Mantine-coupled. They need no `@mantine/form` (layout only), which is why they live here and not
|
|
4
|
+
* in `./forms`, whose barrel value-imports it: importing a row from there made a consumer install a
|
|
5
|
+
* peer it never used. `./forms` re-exports them as deprecated aliases until 1.37.0.
|
|
4
6
|
*
|
|
5
7
|
* The gap they close (audit B #5 / §4): `./forms` shipped no layout at all, so the only row
|
|
6
8
|
* primitive in the package was `SettingsRow` over in `./dashboard` — which is the SETTINGS-page
|
|
@@ -22,11 +24,11 @@ import type { ReactNode } from 'react'
|
|
|
22
24
|
import { cx } from '../common/props'
|
|
23
25
|
import type { BasaltProps, SlotStylesProps } from '../common/props'
|
|
24
26
|
import { assertRequiredProps } from '../common/validate'
|
|
25
|
-
import { BarActionSlot } from '
|
|
26
|
-
import type { SlotActions } from '
|
|
27
|
+
import { BarActionSlot } from './actions'
|
|
28
|
+
import type { SlotActions } from './actions'
|
|
27
29
|
import { WidgetHeader } from '../dashboard'
|
|
28
30
|
import type { WidgetHeaderTitleProps } from '../dashboard'
|
|
29
|
-
import { useFormState } from '
|
|
31
|
+
import { useFormState } from '../forms/form-state'
|
|
30
32
|
import classes from './form-layout.module.css'
|
|
31
33
|
|
|
32
34
|
// ── the two fragments FormRow and FormGroup both paint ────────────────────────
|
package/src/controls/index.ts
CHANGED
|
@@ -53,3 +53,19 @@ export { ViewTabs, type ViewTabsOption, type ViewTabsProps } from './view-tabs'
|
|
|
53
53
|
// docs. The filters above render their own panel forms; there is nothing extra to import for them.
|
|
54
54
|
export { PanelRow, type PanelRowProps } from './panel-row'
|
|
55
55
|
export { SliderControl, type SliderControlProps } from './slider-control'
|
|
56
|
+
|
|
57
|
+
// ── The form layout (moved from ./forms in 1.36.0) ────────────────────────────────────────────
|
|
58
|
+
// Layout needs no `@mantine/form`, and `./forms`' barrel value-imports it — so a consumer rendering
|
|
59
|
+
// a `FormRow` had to install a peer it never used. `./forms` re-exports these until 1.37.0.
|
|
60
|
+
export {
|
|
61
|
+
FormSection,
|
|
62
|
+
FormRow,
|
|
63
|
+
FormGroup,
|
|
64
|
+
FormActions,
|
|
65
|
+
type FormSectionProps,
|
|
66
|
+
type FormSectionSlot,
|
|
67
|
+
type FormRowProps,
|
|
68
|
+
type FormRowSlot,
|
|
69
|
+
type FormGroupProps,
|
|
70
|
+
type FormActionsProps,
|
|
71
|
+
} from './form-layout'
|
package/src/forms/index.ts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* `basalt-ui`. Same reason `./charts` and `./tokens` stay off the root barrel, one optional peer
|
|
7
7
|
* over. Import everything below from `basalt-ui/forms`.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* (`FormSection` / `FormRow` / `FormGroup` / `FormActions`), the submit lifecycle
|
|
9
|
+
* Four pieces: the form (`useBasaltForm` + `inputProps`/`fieldKey`), the submit lifecycle
|
|
11
10
|
* (`useFormSubmit` + `FormStateProvider`), the list field (`useFieldArray`) and the draft
|
|
12
|
-
* (`useFormDraft`).
|
|
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.37.0, as do the `useForm`/`schemaResolver` re-exports (import from
|
|
14
|
+
* `@mantine/form`).
|
|
13
15
|
*
|
|
14
16
|
* Optional peer: @mantine/form ^9.3.0 — install with: bun add @mantine/form
|
|
15
17
|
*/
|
|
@@ -22,16 +24,31 @@ export type { UseBasaltFormOptions } from './create-form'
|
|
|
22
24
|
// Two calls, never one object: `key` inside a spread is a React 19 warning. See field.ts.
|
|
23
25
|
export { inputProps, fieldKey } from './field'
|
|
24
26
|
|
|
25
|
-
// ── layout —
|
|
26
|
-
export {
|
|
27
|
+
// ── layout — moved to ./controls (1.36.0), deprecated aliases until 1.37.0 ─────
|
|
28
|
+
export {
|
|
29
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
30
|
+
FormSection,
|
|
31
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
32
|
+
FormRow,
|
|
33
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
34
|
+
FormGroup,
|
|
35
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
36
|
+
FormActions,
|
|
37
|
+
} from '../controls/form-layout'
|
|
27
38
|
export type {
|
|
39
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
28
40
|
FormSectionProps,
|
|
41
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
29
42
|
FormSectionSlot,
|
|
43
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
30
44
|
FormRowProps,
|
|
45
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
31
46
|
FormRowSlot,
|
|
47
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
32
48
|
FormGroupProps,
|
|
49
|
+
/** @deprecated Import from 'basalt-ui/controls' — removed in 1.37.0. */
|
|
33
50
|
FormActionsProps,
|
|
34
|
-
} from '
|
|
51
|
+
} from '../controls/form-layout'
|
|
35
52
|
|
|
36
53
|
// ── submit lifecycle ──────────────────────────────────────────────────────────
|
|
37
54
|
export { useFormSubmit, isFieldErrorEnvelope } from './use-form-submit'
|
|
@@ -51,6 +68,16 @@ export type { FormErrorSummaryProps } from './FormErrorSummary'
|
|
|
51
68
|
export { useFormDraft, DEFAULT_AUTOSAVE_DEBOUNCE_MS } from './use-form-draft'
|
|
52
69
|
export type { UseFormDraftOptions, UseFormDraftReturn } from './use-form-draft'
|
|
53
70
|
|
|
54
|
-
// ── @mantine/form re-exports
|
|
55
|
-
export {
|
|
56
|
-
|
|
71
|
+
// ── @mantine/form re-exports — deprecated, zero consumers import them from here ──
|
|
72
|
+
export {
|
|
73
|
+
/** @deprecated Import from '@mantine/form' — removed in 1.37.0. */
|
|
74
|
+
useForm,
|
|
75
|
+
/** @deprecated Import from '@mantine/form' — removed in 1.37.0. */
|
|
76
|
+
schemaResolver,
|
|
77
|
+
} from '@mantine/form'
|
|
78
|
+
export type {
|
|
79
|
+
/** @deprecated Import from '@mantine/form' — removed in 1.37.0. */
|
|
80
|
+
UseFormReturnType,
|
|
81
|
+
/** @deprecated Import from '@mantine/form' — removed in 1.37.0. */
|
|
82
|
+
UseFormInput,
|
|
83
|
+
} from '@mantine/form'
|
package/src/guard/index.ts
CHANGED
|
@@ -334,7 +334,7 @@ const KNOWN_VX_NAMES: ReadonlySet<string> = new Set(BASALT_VX_NAMES)
|
|
|
334
334
|
* emitted set, so `--vx-surface-2` and a bare root like `--vx-space` are both findings.
|
|
335
335
|
*
|
|
336
336
|
* That judgement is honest only because no consumer ref may point into these families:
|
|
337
|
-
* `groupTokens`/`seriesTokens`
|
|
337
|
+
* `groupTokens`/`seriesTokens` throw on a name inside one. A name in any OTHER family (argo's
|
|
338
338
|
* `--vx-activity-*`, rb's `--vx-confidence-*`) may be a consumer group declared in a file this scan
|
|
339
339
|
* cannot see, and is never judged.
|
|
340
340
|
*/
|
|
@@ -893,6 +893,8 @@ export type GraceEntry = { since: string; promote: string; why: string }
|
|
|
893
893
|
|
|
894
894
|
/**
|
|
895
895
|
* Kinds still inside their grace minor — reported, not fatal, until the next minor promotes them.
|
|
896
|
+
* Empty since 1.36.0: `unknown-vx-token`, the last tenant, promoted (its grace ran one minor past
|
|
897
|
+
* 1.35.0 to keep the factory throw out of the a11y release).
|
|
896
898
|
* See {@link GuardSeverity} for the doctrine and why basalt-ui in particular needs it.
|
|
897
899
|
*
|
|
898
900
|
* Adding a kind here is part of shipping it; removing the entry IS the promotion, and belongs in
|
|
@@ -929,19 +931,7 @@ export type GraceEntry = { since: string; promote: string; why: string }
|
|
|
929
931
|
* 'raw-font-family': { since: '1.4.0', promote: '1.5.0', why: 'introduced 1.4.0 — …' },
|
|
930
932
|
* }
|
|
931
933
|
*/
|
|
932
|
-
export const GRACE_PERIOD_KINDS: Partial<Record<GuardKind, GraceEntry>> = {
|
|
933
|
-
'unknown-vx-token': {
|
|
934
|
-
since: '1.34.0',
|
|
935
|
-
promote: '1.36.0',
|
|
936
|
-
why:
|
|
937
|
-
'New kind at 1.33.0 (consumer-loop r2 B3): obsidian lost its 44px touch floor to a removed ' +
|
|
938
|
-
'`var(--vx-space-touch-target)` that nothing reported. WIDENED at 1.34.0 (image-gen r4: ' +
|
|
939
|
-
'`var(--vx-surface-2)` rendered transparent, unreported) to every unemitted name inside a ' +
|
|
940
|
-
'basalt-owned family, so the grace restarts: warn through 1.34.x, error at 1.35.0. EXTENDED one minor at 1.35.0: that ' +
|
|
941
|
-
'minor ships the shell a11y fixes consumers are upgrading for, and the promotion also turns the ' +
|
|
942
|
-
'seriesTokens warning into a throw — not a change to bundle into that bump. Error at 1.36.0.',
|
|
943
|
-
},
|
|
944
|
-
}
|
|
934
|
+
export const GRACE_PERIOD_KINDS: Partial<Record<GuardKind, GraceEntry>> = {}
|
|
945
935
|
|
|
946
936
|
/** A kind's effective severity: consumer override first, then the grace table, then `error`. */
|
|
947
937
|
function severityOf(kind: GuardKind, cfg: GuardConfig): GuardSeverity {
|
|
@@ -2272,7 +2262,7 @@ export const GUARD_RULES = {
|
|
|
2272
2262
|
'unknown-vx-token': {
|
|
2273
2263
|
kind: 'unknown-vx-token',
|
|
2274
2264
|
pattern: VX_VAR_REF, // handled inline (basalt-owned families); entry keeps the registry complete
|
|
2275
|
-
message: `var() names a --vx-* token basalt does not emit, so it resolves to its fallback (or to nothing) with no error anywhere. Judged: every name inside a basalt-owned family (${[...BASALT_VX_FAMILY_SET].join(', ')}) — pick the token from basalt-ui/tokens.css; your own series belong in a family of their own (groupTokens
|
|
2265
|
+
message: `var() names a --vx-* token basalt does not emit, so it resolves to its fallback (or to nothing) with no error anywhere. Judged: every name inside a basalt-owned family (${[...BASALT_VX_FAMILY_SET].join(', ')}) — pick the token from basalt-ui/tokens.css; your own series belong in a family of their own (groupTokens throws on one inside basalt's, in dev builds). Removed names and their replacements: ${Object.entries(
|
|
2276
2266
|
REMOVED_VX_NAMES,
|
|
2277
2267
|
)
|
|
2278
2268
|
.map(([from, to]) => `${from} → ${to ?? '(deleted, no replacement)'}`)
|
package/src/index.ts
CHANGED
package/src/provider/index.tsx
CHANGED
|
@@ -113,10 +113,11 @@ export type BasaltProviderProps = {
|
|
|
113
113
|
connectivity?: Omit<ConnectivityProviderProps, 'children'>
|
|
114
114
|
/**
|
|
115
115
|
* The size class `useSizeClass()` reports on the server and during hydration, before `matchMedia`
|
|
116
|
-
* can answer. Default `'compact'` (mobile-first).
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
116
|
+
* can answer. Default `'compact'` (mobile-first). SSR only: a client-rendered (`createRoot`) app
|
|
117
|
+
* reads `matchMedia` on its first render and never sees this value. An SSR app that knows the
|
|
118
|
+
* device class (UA hint, cookie) passes it so the first frame already matches. An SSR desktop app
|
|
119
|
+
* SHOULD pass it: without it the first paint is `'compact'`, and `PageAside`/`ThreadWorkspace`
|
|
120
|
+
* remount after hydration when the real class lands.
|
|
120
121
|
*/
|
|
121
122
|
sizeClassHint?: SizeClass
|
|
122
123
|
} & Omit<MantineProviderProps, 'children' | 'theme' | 'defaultColorScheme' | 'cssVariablesResolver'>
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* `'compact' | 'medium' | 'expanded'`, for the JS reads CSS cannot express (portal targets,
|
|
5
5
|
* mount-one-of-two branches). Shell-only — components size by container, not by this.
|
|
6
6
|
*
|
|
7
|
-
* Built on `useMediaQuery` (`common/use-media-query`), one call per class boundary.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Built on `useMediaQuery` (`common/use-media-query`), one call per class boundary. A
|
|
8
|
+
* client-rendered app (`createRoot`) reads `matchMedia` on its FIRST render — no hint, no flash, so
|
|
9
|
+
* a mount-one-of-two branch on this hook is flash-free in a CSR SPA (`use-size-class.test.tsx`
|
|
10
|
+
* pins it). Only SSR and the `hydrateRoot` pass read the server snapshot,
|
|
11
|
+
* `<BasaltProvider sizeClassHint>` (default `'compact'`), so server HTML and hydration agree and the
|
|
12
|
+
* real class lands one commit later.
|
|
11
13
|
*/
|
|
12
14
|
import { createContext, useContext } from 'react'
|
|
13
15
|
import { useMediaQuery } from '../common/use-media-query'
|
package/src/surfaces.ts
CHANGED
|
@@ -299,7 +299,7 @@ export const SURFACES = {
|
|
|
299
299
|
"no second cssVariablesResolver — don't hand-build createTheme or re-add the resolver basalt already installs",
|
|
300
300
|
],
|
|
301
301
|
description:
|
|
302
|
-
'BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)',
|
|
302
|
+
'BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass, useCoarsePointer, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)',
|
|
303
303
|
optionalPeers: [
|
|
304
304
|
'react-markdown',
|
|
305
305
|
'remark-gfm',
|
|
@@ -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),
|
|
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',
|
|
447
447
|
optionalPeers: ['@mantine/form'],
|
|
448
448
|
forbiddenImports: [],
|
|
449
449
|
},
|
|
@@ -589,7 +589,7 @@ export const SURFACES = {
|
|
|
589
589
|
'C12 — one shape for refresh/sync (SyncButton); only the alias table sees a renamed copy',
|
|
590
590
|
],
|
|
591
591
|
description:
|
|
592
|
-
'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,
|
|
592
|
+
'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.',
|
|
593
593
|
optionalPeers: [],
|
|
594
594
|
// `@mantine/dates` is an optional peer basaltViteConfig pre-bundles the whole @mantine scope
|
|
595
595
|
// for — a consumer without the peer (linewatch) must never resolve it through this surface.
|
|
@@ -608,6 +608,14 @@ export const SURFACES = {
|
|
|
608
608
|
'@mantine/dates/*',
|
|
609
609
|
'@mantine/dates is an OPTIONAL peer (docs/CONTROLS-SPEC.md §3) — ./controls must resolve with no @mantine/dates installed. The one reach lives in src/controls-dates/, injected into range-filter.tsx’s customPicker seam.',
|
|
610
610
|
),
|
|
611
|
+
v(
|
|
612
|
+
'@mantine/form',
|
|
613
|
+
'@mantine/form is an OPTIONAL peer — ./controls (which owns the form layout since 1.36.0) must resolve with no @mantine/form installed. Only ./forms needs it.',
|
|
614
|
+
),
|
|
615
|
+
vg(
|
|
616
|
+
'@mantine/form/*',
|
|
617
|
+
'@mantine/form is an OPTIONAL peer — ./controls (which owns the form layout since 1.36.0) must resolve with no @mantine/form installed. Only ./forms needs it.',
|
|
618
|
+
),
|
|
611
619
|
],
|
|
612
620
|
},
|
|
613
621
|
'./controls-dates': {
|
package/src/tokens/index.ts
CHANGED
|
@@ -808,23 +808,20 @@ function frameworkDerived(data: PaletteData, only: 'core' | 'all', legacyAliases
|
|
|
808
808
|
return legacyAliases ? `${canonical}\n${frameworkDerivedAliases(data)}` : canonical
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
-
const warnedVxNames = new Set<string>()
|
|
812
|
-
|
|
813
811
|
/**
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
820
|
-
*
|
|
812
|
+
* Throw on a consumer series/group name inside a basalt-owned `--vx-*` family (`surface`, `space`,
|
|
813
|
+
* `ink`, …): `check-theme`'s `unknown-vx-token` judges every name there against what basalt emits,
|
|
814
|
+
* which is sound only while no consumer REF points there. Dev builds only (the call sits behind a
|
|
815
|
+
* literal NODE_ENV read); `unknown-vx-token` left the grace ledger at 1.36.0, which is when this
|
|
816
|
+
* went from a once-per-name warning to a throw. The families are the guard's own generated
|
|
817
|
+
* `BASALT_VX_FAMILIES`. Checked on the refs, not in `buildPaletteCss`, which runs on every first
|
|
818
|
+
* paint.
|
|
821
819
|
*/
|
|
822
|
-
function
|
|
820
|
+
function assertConsumerVxName(name: string): void {
|
|
823
821
|
const family = vxFamilyOf(name)
|
|
824
|
-
if (!BASALT_VX_FAMILIES.includes(family)
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
`[basalt] ${name} is inside basalt's own --vx-${family} family — name your series group something basalt does not own (groupTokens('app', …)). Throws from 1.36.0.`,
|
|
822
|
+
if (!BASALT_VX_FAMILIES.includes(family)) return
|
|
823
|
+
throw new Error(
|
|
824
|
+
`[basalt] ${name} is inside basalt's own --vx-${family} family — name your series group something basalt does not own (groupTokens('app', …)).`,
|
|
828
825
|
)
|
|
829
826
|
}
|
|
830
827
|
|
|
@@ -842,7 +839,7 @@ export function seriesTokens<const T extends SeriesMap>(
|
|
|
842
839
|
const out = {} as { [K in keyof T]: string }
|
|
843
840
|
for (const key of Object.keys(map) as (keyof T)[]) {
|
|
844
841
|
// Literal read at the branch, so a production bundle drops the check (common/dev-gate.test.ts).
|
|
845
|
-
if (process.env.NODE_ENV !== 'production')
|
|
842
|
+
if (process.env.NODE_ENV !== 'production') assertConsumerVxName(`--vx-${prefix}${String(key)}`)
|
|
846
843
|
out[key] = `var(--vx-${prefix}${String(key)})`
|
|
847
844
|
}
|
|
848
845
|
return out
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-layout.d.ts","sourceRoot":"","sources":["../../src/forms/form-layout.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAyC1D,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAExD;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,GACxC,eAAe,CAAC,eAAe,CAAC,GAChC,sBAAsB,GAAG;IACvB,0DAA0D;IAC1D,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAoBlD;AAID,4DAA4D;AAC5D,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;AAEtD,MAAM,MAAM,YAAY,GAAG,WAAW,GACpC,eAAe,CAAC,WAAW,CAAC,GAAG;IAC7B,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4FAA4F;IAC5F,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,+BA0B1C;AAID,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IACzC,qGAAqG;IACrG,KAAK,EAAE,MAAM,CAAA;IACb,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC5B,+CAA+C;IAC/C,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,+BAsB9C;AAID,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG;IAC3C;;;;;;;;OAQG;IACH,OAAO,EAAE,WAAW,CAAA;CACrB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAgBlD"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|