basalt-ui 1.23.0 → 1.23.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.
@@ -7,16 +7,29 @@ import type { ChartLegendConfig, SeriesStyle } from '../series.js';
7
7
  * numeric value to plot — `formatValue` reads the datum directly.
8
8
  */
9
9
  export type BandStripSeries<T> = SeriesStyle & {
10
- /** The derived tooltip row's value for a band in this state. Omit for a state whose NAME is the
11
- * whole reading ("Not measured"), which then renders as a label with an empty value. */
12
- formatValue?: (d: T) => string;
10
+ /**
11
+ * The derived tooltip row's value for a band in this state.
12
+ *
13
+ * Return `null` for a datum in this state whose reading is ABSENT — the row renders
14
+ * {@link NO_READING} instead, which is the escape `ChartSeries.getValue` has and this shape did
15
+ * not: with no value accessor, an absent reading had to come back as `''` and render as a label
16
+ * with an empty value, indistinguishable from a state whose name is the whole reading.
17
+ *
18
+ * Omit the function entirely for a state whose NAME *is* the whole reading ("Not measured").
19
+ */
20
+ formatValue?: (d: T) => string | null;
13
21
  };
14
22
  /** One drawn band — which state it is in, and the three ways a state can be qualified. */
15
23
  export type BandSpan = {
16
24
  /**
17
25
  * Series key naming this band's state: the tie to its legend entry, its fill, and its derived
18
- * tooltip row. A key not present in `series` draws nothing — the loud failure is deliberate,
19
- * since the alternative is a mark no legend entry accounts for.
26
+ * tooltip row.
27
+ *
28
+ * A key not present in `series` is a bug TypeScript cannot catch (this is a `string`), and it
29
+ * used to draw NOTHING — which on a strip whose vocabulary is measured/not-measured is
30
+ * indistinguishable from a real coverage gap, so a typo silently asserted "not measured". It now
31
+ * throws in development and draws an explicit unknown band in production; see
32
+ * {@link unknownStateError} for why the two differ.
20
33
  */
21
34
  state: string;
22
35
  /**
@@ -79,7 +92,8 @@ export type BandStripProps<T> = {
79
92
  legend?: ChartLegendConfig | false;
80
93
  /** Colour of the absence hatch. Names a `series` entry, so absence is legended like any other
81
94
  * state — a hatched band is the one mark a reader cannot decode from an axis. Default
82
- * `VX.neutral`, unnamed. */
95
+ * `VX.neutral`, unnamed. A key naming no `series` entry throws (a PROP, so a typo can only be a
96
+ * wiring error) rather than falling back to the unnamed default. */
83
97
  absentState?: string;
84
98
  /** Per-side overrides of the measured margins — applied last. */
85
99
  margin?: Partial<ChartMargin>;
@@ -1 +1 @@
1
- {"version":3,"file":"BandStrip.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/BandStrip.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAYvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG/D;;;GAGG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,WAAW,GAAG;IAC7C;4FACwF;IACxF,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;CAC/B,CAAA;AAED,0FAA0F;AAC1F,MAAM,MAAM,QAAQ,GAAG;IACrB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QACP,iFAAiF;QACjF,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,uEAAuE;QACvE,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;CACF,CAAA;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAA;IACf;yFACqF;IACrF,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;sCACkC;IAClC,MAAM,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAAA;IACrC,oCAAoC;IACpC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAA;IAC3B;kEAC8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,mDAAmD;IACnD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,CAAA;IAC/E,4EAA4E;IAC5E,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;IACtC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC;;gCAE4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B;iDAC6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAID;;;;;;;;;;;;;GAaG;AACH,iBAAS,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,+BAgBlD;AAuND;;;GAGG;AACH,eAAO,MAAM,SAAS,EAA2B,OAAO,cAAc,CAAA"}
1
+ {"version":3,"file":"BandStrip.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/BandStrip.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAYvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG/D;;;GAGG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,WAAW,GAAG;IAC7C;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,CAAA;CACtC,CAAA;AAED,0FAA0F;AAC1F,MAAM,MAAM,QAAQ,GAAG;IACrB;;;;;;;;;OASG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QACP,iFAAiF;QACjF,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,uEAAuE;QACvE,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;CACF,CAAA;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAA;IACf;yFACqF;IACrF,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;sCACkC;IAClC,MAAM,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAAA;IACrC,oCAAoC;IACpC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAA;IAC3B;kEAC8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,mDAAmD;IACnD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,CAAA;IAC/E,4EAA4E;IAC5E,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;IACtC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC;;;wEAGoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B;iDAC6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAkDD;;;;;;;;;;;;;GAaG;AACH,iBAAS,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,+BAgBlD;AAwPD;;;GAGG;AACH,eAAO,MAAM,SAAS,EAA2B,OAAO,cAAc,CAAA"}
@@ -16,6 +16,25 @@ import { HatchPattern, hatchFill, hatchSizeFor } from "../primitives/HatchPatter
16
16
  import { HoverOverlay } from "../primitives/HoverOverlay.js";
17
17
  import { fmtAxisDate } from "../utils/format.js";
18
18
  const DEFAULT_MARKER_INSET = 6;
19
+ const NO_READING = "\u2014";
20
+ const UNKNOWN_MARK = {
21
+ fill: alpha(VX.neutral, 0.2),
22
+ stroke: VX.neutral,
23
+ strokeWidth: 1,
24
+ strokeDasharray: "3 2"
25
+ };
26
+ function isDev() {
27
+ return process.env["NODE_ENV"] !== "production";
28
+ }
29
+ function unknownStateError(what, key, known) {
30
+ return new Error(
31
+ `BandStrip: ${what} "${key}" names no \`series\` entry (known: ${[...known].join(", ")}) \u2014 so it has no legend entry, no colour and no tooltip row. Add the state to \`series\`, or map the datum onto one that is there.`
32
+ );
33
+ }
34
+ function formatBandValue(style, datum) {
35
+ if (style.formatValue === void 0) return "";
36
+ return style.formatValue(datum) ?? NO_READING;
37
+ }
19
38
  function BandStripInner(props) {
20
39
  const { series, chartId, height, fill, legend, ariaLabel, isPending } = props;
21
40
  return /* @__PURE__ */ jsx(
@@ -66,19 +85,44 @@ function BandStripPlot(props) {
66
85
  const { bands, margin, plotWidth, scale, cursor, point, crosshairX, step, bandWidth } = band;
67
86
  const stripHeight = Math.max(plot.height - margin.top - margin.bottom, 1);
68
87
  const hatchId = `${chartId}-band-absent`;
88
+ if (absentState !== void 0 && !styleByKey.has(absentState)) {
89
+ throw unknownStateError("absentState", absentState, styleByKey.keys());
90
+ }
69
91
  const absentColor = (absentState === void 0 ? void 0 : styleByKey.get(absentState)?.color) ?? VX.neutral;
70
92
  const rects = useMemo(() => {
71
93
  const out = [];
72
94
  bands.forEach((d, i) => {
73
95
  const span = getBand(d);
74
96
  const style = styleByKey.get(span.state);
75
- if (style === void 0 || hidden.has(span.state)) return;
97
+ const x = i * step;
98
+ if (style === void 0) {
99
+ if (isDev()) throw unknownStateError("BandSpan.state", span.state, styleByKey.keys());
100
+ out.push(
101
+ /* @__PURE__ */ jsx(
102
+ "rect",
103
+ {
104
+ ...UNKNOWN_MARK,
105
+ x,
106
+ y: 0,
107
+ width: bandWidth,
108
+ height: stripHeight,
109
+ rx: 1,
110
+ pointerEvents: "none"
111
+ },
112
+ getX(d)
113
+ )
114
+ );
115
+ return;
116
+ }
117
+ if (hidden.has(span.state)) return;
76
118
  const absent = clampFraction(span.absentFraction);
77
119
  const measuredWidth = bandWidth * (1 - absent);
78
120
  const hatchWidth = bandWidth - measuredWidth;
79
- const x = i * step;
80
121
  const markerKey = span.marker?.state ?? span.state;
81
122
  const markerColor = styleByKey.get(markerKey)?.color;
123
+ if (span.marker !== void 0 && markerColor === void 0 && isDev()) {
124
+ throw unknownStateError("BandSpan.marker.state", markerKey, styleByKey.keys());
125
+ }
82
126
  const inset = span.marker?.inset ?? DEFAULT_MARKER_INSET;
83
127
  out.push(
84
128
  /* @__PURE__ */ jsxs("g", { children: [
@@ -106,15 +150,15 @@ function BandStripPlot(props) {
106
150
  pointerEvents: "none"
107
151
  }
108
152
  ),
109
- span.marker !== void 0 && markerColor !== void 0 && measuredWidth > 0 && /* @__PURE__ */ jsx(
153
+ span.marker !== void 0 && measuredWidth > 0 && /* @__PURE__ */ jsx(
110
154
  "rect",
111
155
  {
156
+ ...markerColor === void 0 ? UNKNOWN_MARK : { fill: markerColor },
112
157
  x,
113
158
  y: inset,
114
159
  width: measuredWidth,
115
160
  height: Math.max(stripHeight - 2 * inset, 2),
116
161
  rx: 1,
117
- fill: markerColor,
118
162
  pointerEvents: "none"
119
163
  }
120
164
  )
@@ -203,11 +247,20 @@ function clampFraction(value) {
203
247
  }
204
248
  function deriveBandRow(span, styleByKey, hidden, datum) {
205
249
  const style = styleByKey.get(span.state);
206
- if (style === void 0 || style.tooltip === false || hidden.has(span.state)) return null;
250
+ if (style === void 0) {
251
+ return {
252
+ color: VX.neutral,
253
+ label: "Unknown state",
254
+ value: span.state,
255
+ shape: "bar",
256
+ dashed: true
257
+ };
258
+ }
259
+ if (style.tooltip === false || hidden.has(span.state)) return null;
207
260
  return {
208
261
  color: style.color,
209
262
  label: style.label,
210
- value: style.formatValue?.(datum) ?? "",
263
+ value: formatBandValue(style, datum),
211
264
  shape: style.mark === "line" ? "line" : "bar",
212
265
  dashed: style.dash === "dashed"
213
266
  };
@@ -4,7 +4,8 @@ import type { BandFold, BandTooltipConfig } from '../hooks/useBandPlot.js';
4
4
  import type { ChartLegendConfig, ChartSeries } from '../series.js';
5
5
  /** One of the two panes. Each resolves its own domain — that is the whole point of the kind. */
6
6
  export type MirroredBarPane = {
7
- /** Key of the `series` entry this pane draws: its colour, its legend entry, its tooltip row. */
7
+ /** Key of the `series` entry this pane draws: its colour, its legend entry, its tooltip row.
8
+ * A key naming no entry throws — see {@link assertPaneKey}. */
8
9
  key: string;
9
10
  /**
10
11
  * The pane's upper bound. `'auto'` (default) is its own visible maximum; a number pins it.
@@ -63,7 +64,8 @@ export type MirroredBarsProps<T> = {
63
64
  cursorResolution?: CursorResolution;
64
65
  tooltip?: BandTooltipConfig<T> | false;
65
66
  legend?: ChartLegendConfig | false;
66
- /** Series key whose colour the absence hatch is drawn in. Default `VX.neutral`. */
67
+ /** Series key whose colour the absence hatch is drawn in. Default `VX.neutral`. A key naming no
68
+ * `series` entry throws rather than falling back to the unnamed default. */
67
69
  absentState?: string;
68
70
  margin?: Partial<ChartMargin>;
69
71
  ariaLabel?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"MirroredBars.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/MirroredBars.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAcvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG/D,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG;IAC5B,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB;sBACkB;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;oFACgF;IAChF,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;;;;;OAKG;IACH,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjC,yCAAyC;IACzC,EAAE,EAAE,eAAe,CAAA;IACnB,yCAAyC;IACzC,IAAI,EAAE,eAAe,CAAA;IACrB;8FAC0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACpC;kCAC8B;IAC9B,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAChC,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,CAAA;IAC/E,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;IACtC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAKD;;;;;;;;;;;;;GAaG;AACH,iBAAS,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BAgBxD;AAmUD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAA8B,OAAO,iBAAiB,CAAA"}
1
+ {"version":3,"file":"MirroredBars.d.ts","sourceRoot":"","sources":["../../../src/charts/kinds/MirroredBars.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAcvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG/D,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG;IAC5B;mEAC+D;IAC/D,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB;sBACkB;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;oFACgF;IAChF,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB;;;;;OAKG;IACH,MAAM,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACjC,yCAAyC;IACzC,EAAE,EAAE,eAAe,CAAA;IACnB,yCAAyC;IACzC,IAAI,EAAE,eAAe,CAAA;IACrB;8FAC0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACpC;kCAC8B;IAC9B,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAChC,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,CAAA;IAC/E,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;IACtC,MAAM,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAA;IAClC;gFAC4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AA8BD;;;;;;;;;;;;;GAaG;AACH,iBAAS,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BAgBxD;AA4UD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAA8B,OAAO,iBAAiB,CAAA"}
@@ -20,6 +20,12 @@ import { deriveTooltipRows } from "../series.js";
20
20
  import { fmtAxisDate } from "../utils/format.js";
21
21
  const DEFAULT_UP_FRACTION = 0.35;
22
22
  const DEFAULT_PANE_TICKS = 3;
23
+ function assertPaneKey(side, key, resolved, series) {
24
+ if (resolved !== void 0) return;
25
+ throw new Error(
26
+ `MirroredBars: ${side}.key "${key}" names no \`series\` entry (known: ${series.map((s) => s.key).join(", ")}) \u2014 the pane would silently vanish, which reads as a measured zero. Add the series, or point the pane at one that exists.`
27
+ );
28
+ }
23
29
  function MirroredBarsInner(props) {
24
30
  const { series, chartId, height, fill, legend, ariaLabel, isPending } = props;
25
31
  return /* @__PURE__ */ jsx(
@@ -61,6 +67,8 @@ function MirroredBarsPlot(props) {
61
67
  const seriesByKey = useMemo(() => new Map(series.map((s) => [s.key, s])), [series]);
62
68
  const upSeries = seriesByKey.get(up.key);
63
69
  const downSeries = seriesByKey.get(down.key);
70
+ assertPaneKey("up", up.key, upSeries, series);
71
+ assertPaneKey("down", down.key, downSeries, series);
64
72
  const upVisible = upSeries !== void 0 && !hidden.has(up.key);
65
73
  const downVisible = downSeries !== void 0 && !hidden.has(down.key);
66
74
  const upMax = usePaneMax(data, upSeries, up, upVisible);
@@ -112,6 +120,11 @@ function MirroredBarsPlot(props) {
112
120
  [upMax, upHeight]
113
121
  );
114
122
  const hatchId = `${chartId}-mirrored-absent`;
123
+ if (absentState !== void 0 && !seriesByKey.has(absentState)) {
124
+ throw new Error(
125
+ `MirroredBars: absentState "${absentState}" names no \`series\` entry (known: ${series.map((s) => s.key).join(", ")}) \u2014 the hatch would fall back to an unnamed neutral, and a hatched bar is the one mark a reader cannot decode from either axis.`
126
+ );
127
+ }
115
128
  const absentColor = (absentState === void 0 ? void 0 : seriesByKey.get(absentState)?.color) ?? VX.neutral;
116
129
  const drawnUp = upVisible ? upSeries : void 0;
117
130
  const drawnDown = downVisible ? downSeries : void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAwB,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE9E,OAAO,EAAE,UAAU,EAAE,WAAW,EAA2C,MAAM,aAAa,CAAA;AAI9F,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG;IACzB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IACnC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;wFACoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAA;IACpD,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,CAAA;IACzD;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;GAGG;AACH,KAAK,eAAe,GAAG,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAkdrE;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,aAAa,GAAE,MAAsB,EACrC,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,MAAM,CAqKR;AAwWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,KAAK,IAAI,GAAG,SAAS,GAAG,MAAM,CAAA;AAE9B,+DAA+D;AAC/D,KAAK,WAAW,GAAG;IACjB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB;IACtB,IAAI,EAAE,IAAI,CAAA;IACV;;;OAGG;IACH,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,MAAM,GAAG,IAAI,CAAA;CAC9C,CAAA;AAED,uEAAuE;AACvE,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,YAAY,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,uGAAuG;IACvG,WAAW,EAAE,MAAM,CAAA;IACnB,qGAAqG;IACrG,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mFAAmF;IACnF,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAMD,QAAA,MAAM,aAAa,0BAA0B,CAAA;AAmG7C;;;GAGG;AACH,KAAK,aAAa,GAAG;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sGAAsG;IACtG,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,4EAA4E;AAC5E,KAAK,SAAS,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAA;AAiC1D;;;;GAIG;AACH,KAAK,cAAc,GAAG;IACpB;;;;eAIW;IACX,iBAAiB,EAAE,OAAO,CAAA;IAC1B;iEAC6D;IAC7D,QAAQ,EAAE,MAAM,CAAA;IAChB;;;gFAG4E;IAC5E,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AA6ED,sGAAsG;AACtG,iBAAS,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,GAAE,cAA+B,GAAG,WAAW,EAAE,CA6JjG;AAED,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,CAAC,CAAA;IACV,gGAAgG;IAChG,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gGAAgG;IAChG,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtC,CAAA;AAwHD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iBAAS,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQhD;AAsfD,yGAAyG;AACzG,wBAAgB,IAAI,CAAC,GAAG,GAAE,MAAsB,EAAE,aAAa,GAAE,aAAkB,GAAG,MAAM,CA2L3F;AAcD,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mGAAmG;IACnG,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1B,CAAA;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,IAAI,GAAE,WAAgB,EAAE,aAAa,GAAE,MAAsB,GAAG,MAAM,CAoN1F;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,IAAI,MAAM,CA6JtC;AAMD,KAAK,YAAY,GAAG;IAClB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAgND;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,wBAAgB,MAAM,CAAC,aAAa,GAAE,MAAsB,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,CA0b1F;AAMD,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB,CAAA;AAED,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,WAAW,EAAE,CAAA;CACxB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CA8F5C;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3D;AAwDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CA4E9E;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CAa7E;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyF5E;AAqCD;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0CzF;AAKD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,CAAA;AACnF,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAwB,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE9E,OAAO,EAAE,UAAU,EAAE,WAAW,EAA2C,MAAM,aAAa,CAAA;AAI9F,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG;IACzB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IACnC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;wFACoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAA;IACpD,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,CAAA;IACzD;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;GAGG;AACH,KAAK,eAAe,GAAG,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAkdrE;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,aAAa,GAAE,MAAsB,EACrC,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,MAAM,CAqKR;AAwWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,KAAK,IAAI,GAAG,SAAS,GAAG,MAAM,CAAA;AAE9B,+DAA+D;AAC/D,KAAK,WAAW,GAAG;IACjB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB;IACtB,IAAI,EAAE,IAAI,CAAA;IACV;;;OAGG;IACH,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,MAAM,GAAG,IAAI,CAAA;CAC9C,CAAA;AAED,uEAAuE;AACvE,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,YAAY,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,uGAAuG;IACvG,WAAW,EAAE,MAAM,CAAA;IACnB,qGAAqG;IACrG,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mFAAmF;IACnF,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAMD,QAAA,MAAM,aAAa,0BAA0B,CAAA;AA+G7C;;;GAGG;AACH,KAAK,aAAa,GAAG;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sGAAsG;IACtG,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,4EAA4E;AAC5E,KAAK,SAAS,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAA;AAiC1D;;;;GAIG;AACH,KAAK,cAAc,GAAG;IACpB;;;;eAIW;IACX,iBAAiB,EAAE,OAAO,CAAA;IAC1B;iEAC6D;IAC7D,QAAQ,EAAE,MAAM,CAAA;IAChB;;;gFAG4E;IAC5E,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AA6ED,sGAAsG;AACtG,iBAAS,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,GAAE,cAA+B,GAAG,WAAW,EAAE,CA6JjG;AAED,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,CAAC,CAAA;IACV,gGAAgG;IAChG,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gGAAgG;IAChG,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtC,CAAA;AAwHD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iBAAS,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQhD;AAsfD,yGAAyG;AACzG,wBAAgB,IAAI,CAAC,GAAG,GAAE,MAAsB,EAAE,aAAa,GAAE,aAAkB,GAAG,MAAM,CA2L3F;AAcD,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mGAAmG;IACnG,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1B,CAAA;AAoCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,IAAI,GAAE,WAAgB,EAAE,aAAa,GAAE,MAAsB,GAAG,MAAM,CAmN1F;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,IAAI,MAAM,CA6JtC;AAMD,KAAK,YAAY,GAAG;IAClB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAgND;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,wBAAgB,MAAM,CAAC,aAAa,GAAE,MAAsB,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,CA6d1F;AAMD,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB,CAAA;AAED,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,WAAW,EAAE,CAAA;CACxB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CA8F5C;AAgJD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3D;AAgED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CA4E9E;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CAa7E;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyF5E;AAmGD;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoEzF;AAKD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,CAAA;AACnF,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA"}
package/dist/cli/index.js CHANGED
@@ -617,9 +617,13 @@ function readFrameworkVersion(pkgRoot) {
617
617
  return "0.0.0";
618
618
  }
619
619
  }
620
+ function basaltBinCommand(install, cwd) {
621
+ if (install.dir === null) return "bunx basalt-ui";
622
+ const binDir = resolve(install.dir, "..", ".bin");
623
+ return `${relativePosix(cwd, binDir).replace(/^\.\//, "")}/basalt-ui`;
624
+ }
620
625
  function buildTemplateVars(pkgRoot, cwd, cfg) {
621
626
  const install = findBasaltInstall(cwd);
622
- const binDir = install.dir === null ? null : resolve(install.dir, "..", ".bin");
623
627
  return {
624
628
  APP_NAME: readPackageName(cwd),
625
629
  BASALT_VERSION: readFrameworkVersion(pkgRoot),
@@ -628,7 +632,7 @@ function buildTemplateVars(pkgRoot, cwd, cfg) {
628
632
  ROOTS_GLOBS: resolveRoots(cfg).map(toRootGlob).join(" "),
629
633
  OXLINT_PRESET_PATH: shippedAssetPath(install, cwd, "configs/oxlint.json"),
630
634
  LEFTHOOK_PRESET_PATH: shippedAssetPath(install, cwd, "configs/lefthook.yml"),
631
- BASALT_BIN: binDir === null ? "bunx basalt-ui" : `${relativePosix(cwd, binDir).replace(/^\.\//, "")}/basalt-ui`
635
+ BASALT_BIN: basaltBinCommand(install, cwd)
632
636
  };
633
637
  }
634
638
  function fillTemplate(tpl, vars) {
@@ -1268,7 +1272,7 @@ Theme guard hook: add to .claude/settings.json \u2192 hooks.PreToolUse to catch
1268
1272
  "PreToolUse": [
1269
1273
  {
1270
1274
  "matcher": "Write|Edit|MultiEdit",
1271
- "hooks": [{ "type": "command", "command": "bunx basalt-ui guard-hook" }]
1275
+ "hooks": [{ "type": "command", "command": "${ctx.vars.BASALT_BIN} guard-hook" }]
1272
1276
  }
1273
1277
  ]
1274
1278
  }`
@@ -1299,6 +1303,9 @@ function readOxlintPresetPlugins(pkgRoot) {
1299
1303
  return [];
1300
1304
  }
1301
1305
  }
1306
+ function parentInstallAdvice(cwd, parent, verb) {
1307
+ return `This repo's install is at ${relativePosix(cwd, parent)} (${parent}) \u2014 run ${verb} there, or set BASALT_CWD to it.`;
1308
+ }
1302
1309
  function findManifestAbove(dir) {
1303
1310
  let current = resolve(dir, "..");
1304
1311
  for (; ; ) {
@@ -1337,7 +1344,7 @@ function sync(opts = {}, invocationCwd = process.cwd()) {
1337
1344
  const elsewhere = findManifestAbove(cwd);
1338
1345
  const wouldWrite = managedFiles(resolvePeerFlags(cwd, {}), resolvePlacement(cwd)).length;
1339
1346
  console.error(
1340
- `\u2716 basalt-ui sync: no ${MANIFEST_PATH} at ${cwd} \u2014 refusing to scaffold. \`sync\` refreshes an EXISTING basalt install; creating one is \`basalt-ui init\`'s decision, and continuing here would write ${wouldWrite} managed file(s) into this directory.` + (elsewhere === null ? " No manifest exists at any ancestor either \u2014 run `basalt-ui init` here if this package really is meant to be a consumer." : ` This repo's install is at ${relativePosix(cwd, elsewhere)} (${elsewhere}) \u2014 run sync there, or set BASALT_CWD to it.`)
1347
+ `\u2716 basalt-ui sync: no ${MANIFEST_PATH} at ${cwd} \u2014 refusing to scaffold. \`sync\` refreshes an EXISTING basalt install; creating one is \`basalt-ui init\`'s decision, and continuing here would write ${wouldWrite} managed file(s) into this directory.` + (elsewhere === null ? " No manifest exists at any ancestor either \u2014 run `basalt-ui init` here if this package really is meant to be a consumer." : ` ${parentInstallAdvice(cwd, elsewhere, "sync")}`)
1341
1348
  );
1342
1349
  return 1;
1343
1350
  }
@@ -1706,6 +1713,7 @@ basalt-ui doctor \u2014 ${cwd}
1706
1713
  }
1707
1714
  const manifestAbs = resolve(cwd, MANIFEST_PATH);
1708
1715
  const manifestExists = existsSync(manifestAbs);
1716
+ const parentInstall = manifestExists ? null : findManifestAbove(cwd);
1709
1717
  const profile = inferredProfile(cwd, cfg, flags);
1710
1718
  if (profile === "tokens-only") {
1711
1719
  lines.push(
@@ -1721,6 +1729,10 @@ basalt-ui doctor \u2014 ${cwd}
1721
1729
  pass(`${MANIFEST_PATH}: n/a \u2014 a tokens-only consumer has no scaffold to reconcile`);
1722
1730
  } else if (manifestExists) {
1723
1731
  pass(`${MANIFEST_PATH} exists`);
1732
+ } else if (parentInstall !== null) {
1733
+ fail(
1734
+ `${MANIFEST_PATH} missing here, but this is not an unscaffolded consumer. ${parentInstallAdvice(cwd, parentInstall, "doctor")} \`basalt-ui init\` is NOT the fix: it would scaffold a SECOND consumer beside the real one.`
1735
+ );
1724
1736
  } else {
1725
1737
  fail(`${MANIFEST_PATH} missing \u2014 run \`basalt-ui init\` to scaffold the consumer repo`);
1726
1738
  }
@@ -1816,7 +1828,7 @@ basalt-ui doctor \u2014 ${cwd}
1816
1828
  const oxlintrcRaw = readIfExists(resolve(cwd, ".oxlintrc.json"));
1817
1829
  if (oxlintrcRaw === null) {
1818
1830
  fail(
1819
- ".oxlintrc.json missing \u2014 the shipped oxlint preset (the basalt/* design rules) is not active. Run `basalt-ui init` to seed it."
1831
+ ".oxlintrc.json missing \u2014 the shipped oxlint preset (the basalt/* design rules) is not active. " + (parentInstall === null ? "Run `basalt-ui init` to seed it." : `${parentInstallAdvice(cwd, parentInstall, "doctor")} The preset is seeded once, at the install \u2014 not per package.`)
1820
1832
  );
1821
1833
  } else {
1822
1834
  const parsed = parseJsonc(oxlintrcRaw);
@@ -1864,30 +1876,43 @@ basalt-ui doctor \u2014 ${cwd}
1864
1876
  );
1865
1877
  } else if (lefthookGate.kind === "absent") {
1866
1878
  warn(
1867
- `${lefthookGate.file}: \`lefthook dump\` resolves the merged config and NO pre-commit command runs check-theme \u2014 the theme guard is not gating commits. Either add "extends: [${lefthookCorrect}]", or add your own command running \`bunx basalt-ui check-theme\` (with \`root:\` if it must run in a subdirectory).`
1879
+ `${lefthookGate.file}: \`lefthook dump\` resolves the merged config and NO pre-commit command runs check-theme \u2014 the theme guard is not gating commits. Either add "extends: [${lefthookCorrect}]", or add your own command running \`${basaltBinCommand(install, cwd)} check-theme\` (with \`root:\` if it must run in a subdirectory).`
1868
1880
  );
1869
1881
  } else {
1870
1882
  warn(
1871
- `${lefthookGate.file} names no basalt gate and \`lefthook dump\` could not be run here, so this check cannot tell a missing gate from one wired through an \`include:\` or a remote config it never read \u2014 treat it as advisory. If the guard really is unwired, add "extends: [${lefthookCorrect}]" or your own command running \`bunx basalt-ui check-theme\`.`
1883
+ `${lefthookGate.file} names no basalt gate and \`lefthook dump\` could not be run here, so this check cannot tell a missing gate from one wired through an \`include:\` or a remote config it never read \u2014 treat it as advisory. If the guard really is unwired, add "extends: [${lefthookCorrect}]" or your own command running \`${basaltBinCommand(install, cwd)} check-theme\`.`
1872
1884
  );
1873
1885
  }
1874
1886
  const publicDir = resolve(cwd, "public");
1875
1887
  if (profile === "framework" && existsSync(publicDir)) {
1876
- const iconFiles = [
1877
- "favicon.ico",
1878
- "favicon.svg",
1879
- "favicon-96x96.png",
1880
- "apple-touch-icon.png",
1881
- "web-app-manifest-192x192.png",
1882
- "web-app-manifest-512x512.png"
1883
- ];
1884
- const missingIcons = iconFiles.filter((f) => !existsSync(resolve(publicDir, f)));
1885
- if (missingIcons.length > 0) {
1886
- warn(
1887
- `public/ is missing basaltAppPlugin icon file(s): ${missingIcons.join(", ")} \u2014 generate them (e.g. via realfavicongenerator.net) and place them at the public/ root.`
1888
+ const icons = readAppIconsOption(cwd);
1889
+ if (icons.kind === "none") {
1890
+ pass("basaltAppPlugin is configured with no icons \u2014 nothing to check");
1891
+ } else if (icons.kind === "explicit") {
1892
+ const missing = icons.sources.filter(
1893
+ (src) => !existsSync(resolve(publicDir, src.replace(/^\//, "")))
1888
1894
  );
1895
+ if (missing.length > 0) {
1896
+ warn(
1897
+ `basaltAppPlugin declares icon(s) that are not in public/: ${missing.join(", ")} \u2014 the manifest and the head links will point at a 404. Place them, or drop them from the \`icons\` array.`
1898
+ );
1899
+ } else {
1900
+ pass(
1901
+ `public/ has all ${icons.sources.length} icon file(s) basaltAppPlugin's \`icons\` option names`
1902
+ );
1903
+ }
1889
1904
  } else {
1890
- pass("public/ has all of basaltAppPlugin's default icon files");
1905
+ const dir = icons.kind === "default" ? icons.dir : null;
1906
+ const iconRoot = dir === null ? publicDir : resolve(publicDir, dir.replace(/^\//, ""));
1907
+ const shown = dir === null ? "public/" : `public/${dir.replace(/^\//, "")}`;
1908
+ const missingIcons = DEFAULT_APP_ICON_FILES.filter((f) => !existsSync(resolve(iconRoot, f)));
1909
+ if (missingIcons.length > 0) {
1910
+ warn(
1911
+ `${shown} is missing basaltAppPlugin icon file(s): ${missingIcons.join(", ")} \u2014 generate them (e.g. via realfavicongenerator.net) and place them at the ${shown} root, or name the icons this app really has via the plugin's \`icons\` array.`
1912
+ );
1913
+ } else {
1914
+ pass(`${shown} has all of basaltAppPlugin's default icon files`);
1915
+ }
1891
1916
  }
1892
1917
  }
1893
1918
  const workspaceWalk = collectWorkspacePackages(cwd);
@@ -2008,6 +2033,68 @@ basalt-ui v${pkgVersion} \u2014 published surface
2008
2033
  console.log("");
2009
2034
  return 0;
2010
2035
  }
2036
+ const DEFAULT_APP_ICON_FILES = [
2037
+ "favicon.ico",
2038
+ "favicon.svg",
2039
+ "favicon-96x96.png",
2040
+ "apple-touch-icon.png",
2041
+ "web-app-manifest-192x192.png",
2042
+ "web-app-manifest-512x512.png"
2043
+ ];
2044
+ const VITE_CONFIG_FILES = [
2045
+ "vite.config.ts",
2046
+ "vite.config.mts",
2047
+ "vite.config.cts",
2048
+ "vite.config.js",
2049
+ "vite.config.mjs",
2050
+ "vite.config.cjs"
2051
+ ];
2052
+ function balancedSpan(text, open) {
2053
+ const pairs = { "(": ")", "{": "}", "[": "]" };
2054
+ const closer = pairs[text[open]];
2055
+ if (closer === void 0) return null;
2056
+ let depth = 0;
2057
+ for (let i = open; i < text.length; i++) {
2058
+ const ch = text[i];
2059
+ if (ch === text[open]) depth++;
2060
+ else if (ch === closer) {
2061
+ depth--;
2062
+ if (depth === 0) return text.slice(open, i + 1);
2063
+ }
2064
+ }
2065
+ return null;
2066
+ }
2067
+ function readAppIconsOption(cwd) {
2068
+ const configPath = VITE_CONFIG_FILES.map((f) => resolve(cwd, f)).find((f) => existsSync(f));
2069
+ if (configPath === void 0) return { kind: "unknown" };
2070
+ const text = readIfExists(configPath);
2071
+ if (text === null) return { kind: "unknown" };
2072
+ const call = text.indexOf("basaltAppPlugin(");
2073
+ if (call === -1) return { kind: "unknown" };
2074
+ const args = balancedSpan(text, call + "basaltAppPlugin".length);
2075
+ if (args === null) return { kind: "unknown" };
2076
+ const key = args.search(/\bicons\s*:/);
2077
+ if (key === -1) return { kind: "default", dir: null };
2078
+ const valueStart = args.indexOf(":", key) + 1;
2079
+ const rest = args.slice(valueStart).trimStart();
2080
+ if (rest.startsWith("false")) return { kind: "none" };
2081
+ const offset = args.length - rest.length;
2082
+ if (rest.startsWith("[")) {
2083
+ const list = balancedSpan(args, offset);
2084
+ if (list === null) return { kind: "unknown" };
2085
+ const sources = [...list.matchAll(/\bsrc\s*:\s*['"`]([^'"`]+)['"`]/g)].map(
2086
+ (m) => m[1]
2087
+ );
2088
+ return sources.length === 0 ? { kind: "none" } : { kind: "explicit", sources };
2089
+ }
2090
+ if (rest.startsWith("{")) {
2091
+ const obj = balancedSpan(args, offset);
2092
+ if (obj === null) return { kind: "unknown" };
2093
+ const dir = /\bdir\s*:\s*['"`]([^'"`]+)['"`]/.exec(obj);
2094
+ return { kind: "default", dir: dir === null ? null : dir[1] };
2095
+ }
2096
+ return { kind: "unknown" };
2097
+ }
2011
2098
  function flagValue(flags, name) {
2012
2099
  const i = flags.indexOf(name);
2013
2100
  if (i === -1) return void 0;
@@ -2021,6 +2108,12 @@ function generatedHeader(version, command, flags) {
2021
2108
  /* basalt-ui ${version} \u2014 \`basalt-ui ${invocation}\` */
2022
2109
  `;
2023
2110
  }
2111
+ function withoutProvenanceLine(css) {
2112
+ const lines = css.split("\n");
2113
+ if (lines.length < 2) return css;
2114
+ lines[1] = "";
2115
+ return lines.join("\n");
2116
+ }
2024
2117
  function normalizeColorFunctions(css) {
2025
2118
  return css.replace(/\b(rgba?|hsla?)\(([^()]*)\)/g, (_match, fn, args) => {
2026
2119
  const parts = args.split(",").map((part) => normalizeCssNumber(part.trim()));
@@ -2055,12 +2148,15 @@ function emitGeneratedCss(content, flags, cwd, command) {
2055
2148
  );
2056
2149
  return 1;
2057
2150
  }
2058
- if (onDisk === content) {
2059
- console.log(`\u2713 ${command} --check: ${shown} is up to date.`);
2151
+ if (withoutProvenanceLine(onDisk) === withoutProvenanceLine(content)) {
2152
+ const staleProvenance = onDisk.split("\n")[1] !== content.split("\n")[1];
2153
+ console.log(
2154
+ `\u2713 ${command} --check: ${shown} is up to date.` + (staleProvenance ? " (Its provenance line still names an older basalt-ui; that line is deliberately not gated \u2014 re-run without --check whenever you want it refreshed.)" : "")
2155
+ );
2060
2156
  return 0;
2061
2157
  }
2062
2158
  console.error(
2063
- `\u2716 ${command} --check: ${shown} differs from what \`basalt-ui ${command}\` emits today (on disk ${onDisk.split("\n").length} lines, emitted ${content.split("\n").length}) \u2014 re-run the same command without --check and commit the result.`
2159
+ `\u2716 ${command} --check: ${shown} differs from what \`basalt-ui ${command}\` emits today (on disk ${onDisk.split("\n").length} lines, emitted ${content.split("\n").length}) \u2014 re-run the same command without --check and commit the result. The \`@generated\` header's provenance line is excluded from this comparison, so a version bump alone never trips it.`
2064
2160
  );
2065
2161
  return 1;
2066
2162
  }
@@ -2241,13 +2337,71 @@ async function guardHook(cwd = process.cwd()) {
2241
2337
  }
2242
2338
  return 0;
2243
2339
  }
2244
- const USAGE = "Usage: basalt-ui <init [--with-router] [--with-query] [--merge-lint] |\n sync [--force] [--check] [--tokens-only|--framework] |\n check-theme [--audit-allows] | check-coverage | info [--json] |\n doctor [--tokens-only|--framework] | guard-hook | tokens:css | fonts:css | help>\n\ncheck-theme [--tokens-only|--framework] [--audit-allows]\n --audit-allows reports instead of scanning: every `theme-allow` annotation and every\n `basalt.exemptRules` entry, with what each one still suppresses \u2014 proved by re-running the\n guard with that one waiver neutralized, not by reading its text. Exits 1 on a waiver that\n suppresses nothing (dead), which is what makes it usable as a CI gate.\n\ntokens:css [--out <path>] [--check] [--selector-attribute <attr> | --selector-class <class>]\n [--light-class <class>] [--dark-value <v>] [--light-value <v>]\n [--default-scheme <dark|light|none>] [--media-fallback] [--only <core|all>]\n [--no-legacy-aliases]\n Emit the --vx-* stylesheet (stdout unless --out). Defaults reproduce basalt-ui/tokens.css.\n --selector-class emits `:root.dark` instead of an attribute selector (the Tailwind convention).\n --check writes nothing and exits 1 when --out differs from what would be emitted (a CI gate).\n --no-legacy-aliases drops the deprecated camelCase spellings (--vx-accentFill and friends),\n which are emitted by default as aliases of the canonical kebab-case names.\n\nfonts:css [--out <path>] [--check]\n Emit the shipped --basalt-font-* stacks as plain CSS \u2014 the typeface half of the token layer,\n otherwise reachable only by importing styles.css.\n\ndoctor [--tokens-only|--framework]\n Auto-detects a tokens-only consumer (no manifest + no @mantine/core) and checks only what\n applies. A check that cannot RUN is reported as SKIPPED and exits non-zero.\n\nsync [--force] [--check] [--tokens-only|--framework]\n Refreshes an EXISTING install; it never creates one (that is init). A tokens-only consumer\n has no scaffold to reconcile, so sync reports n/a and exits 0 there \u2014 as doctor does.\n\ncheck-theme / doctor / sync all resolve their project the same way: they honour BASALT_CWD, and\nrelocate to the single package below the cwd carrying a basalt config when invoked from a repo\nroot that has none \u2014 several carrying one is ambiguous and exits 1 in ALL THREE.\n--tokens-only and --framework are alternatives; passing both is an error.\n\nEvery subcommand accepts --help / -h to print this message and exit without running.";
2340
+ const COMMAND_FLAGS = {
2341
+ init: ["--with-router", "--with-query", "--merge-lint"],
2342
+ sync: ["--force", "--check", "--tokens-only", "--framework"],
2343
+ "check-theme": ["--audit-allows", "--tokens-only", "--framework"],
2344
+ "check-coverage": [],
2345
+ info: ["--json"],
2346
+ doctor: ["--tokens-only", "--framework"],
2347
+ "guard-hook": [],
2348
+ "tokens:css": [
2349
+ "--out",
2350
+ "--check",
2351
+ "--selector-attribute",
2352
+ "--selector-class",
2353
+ "--light-class",
2354
+ "--dark-value",
2355
+ "--light-value",
2356
+ "--default-scheme",
2357
+ "--media-fallback",
2358
+ "--only",
2359
+ "--no-legacy-aliases"
2360
+ ],
2361
+ "fonts:css": ["--out", "--check"]
2362
+ };
2363
+ const VALUE_FLAGS = /* @__PURE__ */ new Set([
2364
+ "--out",
2365
+ "--selector-attribute",
2366
+ "--selector-class",
2367
+ "--light-class",
2368
+ "--dark-value",
2369
+ "--light-value",
2370
+ "--default-scheme",
2371
+ "--only"
2372
+ ]);
2373
+ function unknownFlag(cmd, flags) {
2374
+ const allowed = COMMAND_FLAGS[cmd];
2375
+ if (allowed === void 0) return null;
2376
+ for (let i = 0; i < flags.length; i++) {
2377
+ const flag = flags[i];
2378
+ if (!flag.startsWith("-")) continue;
2379
+ if (!allowed.includes(flag)) return flag;
2380
+ if (VALUE_FLAGS.has(flag)) i++;
2381
+ }
2382
+ return null;
2383
+ }
2384
+ const USAGE = "Usage: basalt-ui <--version | init [--with-router] [--with-query] [--merge-lint] |\n sync [--force] [--check] [--tokens-only|--framework] |\n check-theme [--audit-allows] | check-coverage | info [--json] |\n doctor [--tokens-only|--framework] | guard-hook | tokens:css | fonts:css | help>\n\ncheck-theme [--tokens-only|--framework] [--audit-allows]\n --audit-allows reports instead of scanning: every `theme-allow` annotation and every\n `basalt.exemptRules` entry, with what each one still suppresses \u2014 proved by re-running the\n guard with that one waiver neutralized, not by reading its text. Exits 1 on a waiver that\n suppresses nothing (dead), which is what makes it usable as a CI gate.\n\ntokens:css [--out <path>] [--check] [--selector-attribute <attr> | --selector-class <class>]\n [--light-class <class>] [--dark-value <v>] [--light-value <v>]\n [--default-scheme <dark|light|none>] [--media-fallback] [--only <core|all>]\n [--no-legacy-aliases]\n Emit the --vx-* stylesheet (stdout unless --out). Defaults reproduce basalt-ui/tokens.css.\n --selector-class emits `:root.dark` instead of an attribute selector (the Tailwind convention).\n --check writes nothing and exits 1 when --out differs from what would be emitted (a CI gate).\n --no-legacy-aliases drops the deprecated camelCase spellings (--vx-accentFill and friends),\n which are emitted by default as aliases of the canonical kebab-case names.\n\nfonts:css [--out <path>] [--check]\n Emit the shipped --basalt-font-* stacks as plain CSS \u2014 the typeface half of the token layer,\n otherwise reachable only by importing styles.css.\n\ndoctor [--tokens-only|--framework]\n Auto-detects a tokens-only consumer (no manifest + no @mantine/core) and checks only what\n applies. A check that cannot RUN is reported as SKIPPED and exits non-zero.\n\nsync [--force] [--check] [--tokens-only|--framework]\n Refreshes an EXISTING install; it never creates one (that is init). A tokens-only consumer\n has no scaffold to reconcile, so sync reports n/a and exits 0 there \u2014 as doctor does.\n\ncheck-theme / doctor / sync all resolve their project the same way: they honour BASALT_CWD, and\nrelocate to the single package below the cwd carrying a basalt config when invoked from a repo\nroot that has none \u2014 several carrying one is ambiguous and exits 1 in ALL THREE.\n--tokens-only and --framework are alternatives; passing both is an error.\n\nEvery subcommand accepts --help / -h to print this message and exit without running.\n--version / -v prints the resolved package version and exits 0 \u2014 the one command that proves\nWHICH basalt-ui ran, which a `bunx` cache can otherwise make a lie. An unknown command or an\nunrecognized flag exits 1 and names what it did not understand; neither is ever ignored.";
2245
2385
  function run(argv, cwd = process.cwd()) {
2246
2386
  const [cmd, ...flags] = argv;
2247
2387
  if (cmd === "help" || cmd === "--help" || cmd === "-h" || flags.includes("--help") || flags.includes("-h")) {
2248
2388
  console.log(USAGE);
2249
2389
  return 0;
2250
2390
  }
2391
+ if (cmd === "--version" || cmd === "-v" || cmd === "version") {
2392
+ console.log(readFrameworkVersion(packageRoot()));
2393
+ return 0;
2394
+ }
2395
+ if (cmd !== void 0) {
2396
+ const bad = unknownFlag(cmd, flags);
2397
+ if (bad !== null) {
2398
+ console.error(
2399
+ `basalt-ui ${cmd}: unrecognized flag '${bad}'. Accepted: ${(COMMAND_FLAGS[cmd] ?? []).join(" ") || "(none)"} --help
2400
+ `
2401
+ );
2402
+ return 1;
2403
+ }
2404
+ }
2251
2405
  switch (cmd) {
2252
2406
  case "init":
2253
2407
  return init(cwd, {
@@ -2275,6 +2429,10 @@ function run(argv, cwd = process.cwd()) {
2275
2429
  case "fonts:css":
2276
2430
  return fontsCss(flags, cwd);
2277
2431
  default:
2432
+ console.error(
2433
+ cmd === void 0 ? "basalt-ui: no command given.\n" : `basalt-ui: unknown command '${cmd}'.
2434
+ `
2435
+ );
2278
2436
  console.error(USAGE);
2279
2437
  return 1;
2280
2438
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"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"}