@fasl-work/caos-app-shell 0.7.2 → 0.8.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/README.md +34 -14
- package/bin/caos-shell-gate.mjs +5 -2
- package/dist/chart.d.ts +28 -3
- package/dist/chart.js +59 -23
- package/dist/{chunk-LOSSTLPP.js → chunk-ZLJCB7DD.js} +43 -4
- package/dist/index.d.ts +248 -111
- package/dist/index.js +308 -22
- package/dist/{tokens-CSV0MOgR.d.ts → tokens-DkyEXX5g.d.ts} +21 -4
- package/gate/inpage.mjs +280 -9
- package/gate/run.mjs +126 -9
- package/package.json +1 -1
- package/reserved-classes.json +239 -3
- package/styles.css +445 -367
package/README.md
CHANGED
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
[](https://github.com/fsantibanezleal/CAOS_APP_SHELL/tags)
|
|
5
5
|
|
|
6
|
-
The shared **web-app shell
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
The shared **web-app shell, route types, views, drawings, design system and measured gate** of the CAOS / Faena
|
|
7
|
+
public apps, one of the three parts of the CAOS base with the product template
|
|
8
|
+
([CAOS_PRODUCT_TEMPLATE](https://github.com/fsantibanezleal/CAOS_PRODUCT_TEMPLATE)) and the policy (ADR-0016,
|
|
9
|
+
ADR-0017, ADR-0071, ADR-0078). The frame, the header, the icons, the tab structure, the viewport, the areas, the text in
|
|
10
|
+
drawings and the numbers are defined **once** here; every product composes them, so a fix lands in one place and no
|
|
11
|
+
product writes them again. **Documentation: [`docs/`](docs/README.md)** (structure, tokens, navigation, views,
|
|
12
|
+
drawings, icons and numbers, the gate, releasing).
|
|
10
13
|
|
|
11
14
|
## Install
|
|
12
15
|
|
|
13
16
|
```bash
|
|
14
|
-
npm i @fasl-work/caos-app-shell
|
|
17
|
+
npm i -E @fasl-work/caos-app-shell # an exact pin: the build you gated is the build you ship
|
|
15
18
|
# peer deps (the app provides them):
|
|
16
19
|
npm i react react-dom react-router lucide-react katex zustand
|
|
17
20
|
# optional: the house chart and the measured gate
|
|
@@ -50,7 +53,11 @@ const config: ShellConfig = {
|
|
|
50
53
|
</BrowserRouter>
|
|
51
54
|
```
|
|
52
55
|
|
|
53
|
-
- **
|
|
56
|
+
- **Three route types** ([docs/01](docs/01_structure.md)): the **workbench** (`CaseWorkbench`, a product about
|
|
57
|
+
cases), the **surface** (`SurfacePage`, a hub, an explorer or a console: a head, one row of views, the open view
|
|
58
|
+
filling the rest), the **document** (`DocPage`). Under `contain` each fills or scrolls inside the viewport; no product
|
|
59
|
+
writes containment CSS.
|
|
60
|
+
- **Land on the tool:** `/` is the App route; the five documentation routes are separate pages.
|
|
54
61
|
- **One React, one router:** set `resolve.dedupe: ['react', 'react-dom', 'react-router']` in Vite. A second copy
|
|
55
62
|
leaves the shell outside the router context; `AppShell` reports it with `console.error` and names the cause.
|
|
56
63
|
- **Product metadata:** `license` and `visibility` are required: the footer shows the product's licence and a
|
|
@@ -70,11 +77,16 @@ const config: ShellConfig = {
|
|
|
70
77
|
- **Drawing:** put canvas, WebGL and SVG instruments in a `Stage` (or `useStageSize`): nothing draws at zero
|
|
71
78
|
size, and colours come from `useThemeTokens()` (a canvas cannot read CSS variables).
|
|
72
79
|
- **Charts:** `import { UPlotChart } from "@fasl-work/caos-app-shell/chart"`: x and y titles with units, series
|
|
73
|
-
by token colour, `marks` for what the engine detected, a key of every series when
|
|
74
|
-
readout row, theme and language rebuilds
|
|
80
|
+
by token colour, `marks` for what the engine detected (placed inside the plot, haloed), a key of every series when
|
|
81
|
+
there are two or more, a cursor readout row, theme and language rebuilds, one tick notation per axis. Categories go
|
|
82
|
+
in `BarChart` (main entry, no uPlot). A drawing of your own measures its labels with the text kit (`textWidth`,
|
|
83
|
+
`fitLabel`, `niceTicks`) and declares `data-chart` ([docs/05](docs/05_drawings.md)).
|
|
84
|
+
- **Views in the URL:** `CaseWorkbench` and `SurfacePage` hold the open view in `?view=` (and the case selector the
|
|
85
|
+
case in `?case=`), so a view can be shared and survives a reload.
|
|
86
|
+
- **Icons:** lucide icons are sized by where they sit (`svg.lucide`); pass no `size` ([docs/06](docs/06_icons-and-numbers.md)).
|
|
75
87
|
- **Numbers:** `formatNumber(value, lang, opts)` or `useFormat()`; never `toFixed` in a view. A magnitude below 1e-4
|
|
76
88
|
is written in scientific notation (a p-value of 1e-200 is `1E-200`, not two hundred zeros); give `digits`, not
|
|
77
|
-
`decimals`, for p-values.
|
|
89
|
+
`decimals`, for p-values. A percent and a unit are joined by a no-break space.
|
|
78
90
|
- **Documentation routes:** `DocPage` and `DocSection` (each section ends in its own `Refs`, or states why it
|
|
79
91
|
cites nothing), `Equation` with a caption, `CitationsProvider` and `Cite` (every citation has a DOI or URL).
|
|
80
92
|
`Tabs`, `SubTabs` and `TabGroups` are controllable and render only the open panel inside a `PanelBoundary`.
|
|
@@ -85,9 +97,14 @@ const config: ShellConfig = {
|
|
|
85
97
|
every route, tab, sub-tab and case at five sizes, both themes and both languages, and fails on: a wrong subject
|
|
86
98
|
(G1) or mode (G2), console errors and 4xx/5xx (G3), broken deep links or HTML for an artifact (G4), anything a
|
|
87
99
|
reader cannot scroll to, see whole or click (G5), blank or underfilled drawings and an instrument under half the
|
|
88
|
-
viewport (G6), a view that never settles (G7), loops at rest (G8),
|
|
89
|
-
|
|
90
|
-
-
|
|
100
|
+
viewport (G6), a view that never settles (G7), loops at rest (G8), controls that change nothing (G9), labels cut or
|
|
101
|
+
overlapping in a drawing, also in a wider fallback font (G10), a decimal point on a Spanish page (G11), a vertical
|
|
102
|
+
sub-tab list that scrolls away (G12), text under WCAG AA contrast (G13). The report
|
|
103
|
+
(`gate-output/gate-report.json`) lists every failure and the smallest margins against each floor; `index.html`
|
|
104
|
+
beside it shows every capture (G14). Details: [docs/07](docs/07_gate.md).
|
|
105
|
+
- **Your own CSS:** never restyle a class of `reserved-classes.json` `components`; a `modifiers` word (`on`,
|
|
106
|
+
`active`, `fill`, `wide`) may be joined to your own class (`.my-row.on`), never used alone. The template's guard reads
|
|
107
|
+
that list. Values come from the tokens (`var(--rail-w)`, `var(--space-3)`, [docs/02](docs/02_tokens.md)).
|
|
91
108
|
- **Animated views:** drive every canvas or 3D loop through `usePausedViz` (default paused, run once, halt on a
|
|
92
109
|
hidden tab), never call `requestAnimationFrame` directly.
|
|
93
110
|
|
|
@@ -102,8 +119,11 @@ const config: ShellConfig = {
|
|
|
102
119
|
`ReferenceList` (deprecated), `DocPage`, `DocSection`, `WorkbenchLayout`, `CaseWorkbench`,
|
|
103
120
|
`MAX_WORKBENCH_GROUPS`, `VariantBar`, `LaneBadge`, `Readout`, `Gauge`, `Verdict`, `PlotCard`, `Knob`,
|
|
104
121
|
`ChipGroup`, `Stage`, `useStageSize`, `makeStateKey`, `isStale`, `useWorkbenchState`,
|
|
105
|
-
`WorkbenchStateContext`, `pick
|
|
106
|
-
|
|
122
|
+
`WorkbenchStateContext`, `pick`; since 0.8.0 `SurfacePage`, `useUrlView`, `viewParamOf`, `replaceQueryParam`,
|
|
123
|
+
`BREAKPOINTS`, `BarChart`, `textWidth`, `widestLabel`, `fitLabel`, `niceTicks`, `niceStep`, `fontFamily`,
|
|
124
|
+
`formatTicks`, `NBSP`, `SCIENTIFIC_BELOW`, the type `ShellColorToken`. Separate entries: `/chart` (`UPlotChart`,
|
|
125
|
+
`drawMarks`, `tickSteps`, `repeatedLabels`), `/keys` (the storage keys, no React), `/styles.css`, `/chart.css`,
|
|
126
|
+
`/reserved-classes.json`. Bin: `caos-shell-gate`.
|
|
107
127
|
|
|
108
128
|
### Authenticated workbenches
|
|
109
129
|
|
package/bin/caos-shell-gate.mjs
CHANGED
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
// --case-sample id1,id2 cases walked outside the primary mode; default the first and the last
|
|
15
15
|
// --single-case the workbench has one case and no case control
|
|
16
16
|
// --idle-ms 3000 --settle-ms 15000 --text-floor 400 --instrument-min 0.5 --stage-fill-min 0.3
|
|
17
|
-
// --
|
|
17
|
+
// --wide-font-sizes 390x844,1280x800 the sizes of the wide-font pass (G10); --no-wide-font skips it
|
|
18
|
+
// --out gate-output report (gate-report.json), screenshots (shots/) and the capture index (index.html)
|
|
18
19
|
// Needs `playwright` in the consuming project (optional peer dependency). Exit 1 on any failure, 2 on misuse.
|
|
19
20
|
|
|
20
21
|
import { runGate } from '../gate/run.mjs';
|
|
21
22
|
|
|
22
|
-
const FLAGS = new Set(['single-case']);
|
|
23
|
+
const FLAGS = new Set(['single-case', 'no-wide-font']);
|
|
23
24
|
const args = {};
|
|
24
25
|
const argv = process.argv.slice(2);
|
|
25
26
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -48,6 +49,8 @@ const options = {
|
|
|
48
49
|
textFloor: num('text-floor'),
|
|
49
50
|
instrumentMin: num('instrument-min'),
|
|
50
51
|
stageFillMin: num('stage-fill-min'),
|
|
52
|
+
wideFontSizes: args['wide-font-sizes'],
|
|
53
|
+
wideFont: args['no-wide-font'] === true ? false : undefined,
|
|
51
54
|
out: args.out,
|
|
52
55
|
};
|
|
53
56
|
for (const k of Object.keys(options)) if (options[k] === undefined) delete options[k];
|
package/dist/chart.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import
|
|
2
|
+
import uPlot from 'uplot';
|
|
3
|
+
import { F as FormatOptions, S as ShellColorToken } from './tokens-DkyEXX5g.js';
|
|
3
4
|
import { B as BiText } from './text-BlY47nIt.js';
|
|
4
5
|
import 'zustand';
|
|
5
6
|
|
|
@@ -8,7 +9,7 @@ interface ChartSeries {
|
|
|
8
9
|
/** One value per x; `null` leaves a gap. */
|
|
9
10
|
values: (number | null)[];
|
|
10
11
|
/** A shell colour token; defaults rotate through the accent palette. */
|
|
11
|
-
color?:
|
|
12
|
+
color?: ShellColorToken;
|
|
12
13
|
width?: number;
|
|
13
14
|
dash?: number[];
|
|
14
15
|
/** `points` draws markers only (a scatter of cases over a curve); `null` values are simply absent. */
|
|
@@ -42,6 +43,30 @@ interface UPlotChartProps {
|
|
|
42
43
|
/** Called with the index under the cursor (or null), for linked views. */
|
|
43
44
|
onCursor?: (index: number | null) => void;
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The tick steps an axis may use. With fixed `decimals` (scaled by 100 for a percent) only multiples of the smallest
|
|
48
|
+
* difference its labels can show, so no two ticks read the same: an integer axis ticks at integers, never at 1.5,
|
|
49
|
+
* which reads "2" beside the 2 (CAOS_Contraste, 2026-10-05). `undefined` leaves uPlot its own steps: an axis formatted
|
|
50
|
+
* by significant digits has no fixed resolution, and `data-ticks-repeat` reports what it does.
|
|
51
|
+
*/
|
|
52
|
+
declare function tickSteps(fmt: FormatOptions | undefined): number[] | undefined;
|
|
53
|
+
/** How many tick labels repeat the label before them (empty labels apart); the gate fails a chart with any (G6). */
|
|
54
|
+
declare function repeatedLabels(labels: readonly (string | null | undefined)[]): number;
|
|
55
|
+
/**
|
|
56
|
+
* The vertical marks of a chart and their labels. Every label is drawn with an explicit alignment (uPlot leaves the
|
|
57
|
+
* context right-aligned after its last axis, so a label meant to start at its line ended there and ran off the plot
|
|
58
|
+
* near the left edge, CAOS_Fragmenta 2026-10-06), on the side of its line where it fits inside the plot, on the next
|
|
59
|
+
* row down when it would overlap the label before it, with a halo in the surface colour so a curve under it does not
|
|
60
|
+
* cross its letters. A mark outside the x range is not drawn.
|
|
61
|
+
*/
|
|
62
|
+
declare function drawMarks(u: uPlot, marks: {
|
|
63
|
+
x: number;
|
|
64
|
+
label: string;
|
|
65
|
+
}[], style: {
|
|
66
|
+
color: string;
|
|
67
|
+
halo: string;
|
|
68
|
+
family: string;
|
|
69
|
+
}): void;
|
|
45
70
|
/**
|
|
46
71
|
* The house chart (S12 of the 2026-10-04 requirements; uPlot, ADR on interactive charts). It is built only once its
|
|
47
72
|
* box has a size; it resolves the theme's colours to concrete values and rebuilds when the theme or language changes
|
|
@@ -55,4 +80,4 @@ interface UPlotChartProps {
|
|
|
55
80
|
*/
|
|
56
81
|
declare function UPlotChart({ x, y, series, marks, height, onCursor }: UPlotChartProps): react.JSX.Element;
|
|
57
82
|
|
|
58
|
-
export { type ChartAxis, type ChartSeries, UPlotChart, type UPlotChartProps };
|
|
83
|
+
export { type ChartAxis, type ChartSeries, UPlotChart, type UPlotChartProps, drawMarks, repeatedLabels, tickSteps };
|
package/dist/chart.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useShellLang, useThemeStore, useStageSize, pick, resolveToken, formatNumber } from './chunk-
|
|
1
|
+
import { useShellLang, useThemeStore, useStageSize, pick, resolveToken, NBSP, formatNumber, formatTicks } from './chunk-ZLJCB7DD.js';
|
|
2
2
|
import './chunk-X6Y5CDUD.js';
|
|
3
3
|
import { useRef, useCallback, useState, useMemo, useEffect } from 'react';
|
|
4
4
|
import uPlot from 'uplot';
|
|
@@ -17,6 +17,46 @@ function repeatedLabels(labels) {
|
|
|
17
17
|
for (let i = 1; i < labels.length; i++) if (labels[i] && labels[i] === labels[i - 1]) n++;
|
|
18
18
|
return n;
|
|
19
19
|
}
|
|
20
|
+
function drawMarks(u, marks, style) {
|
|
21
|
+
const ctx = u.ctx;
|
|
22
|
+
const pr = uPlot.pxRatio || 1;
|
|
23
|
+
const left = u.bbox.left;
|
|
24
|
+
const right = u.bbox.left + u.bbox.width;
|
|
25
|
+
const gap = 4 * pr;
|
|
26
|
+
const rowH = 14 * pr;
|
|
27
|
+
const placed = [];
|
|
28
|
+
ctx.save();
|
|
29
|
+
ctx.font = `${Math.round(11 * pr)}px ${style.family}`;
|
|
30
|
+
ctx.textBaseline = "alphabetic";
|
|
31
|
+
ctx.lineJoin = "round";
|
|
32
|
+
for (const m of [...marks].sort((a, b) => a.x - b.x)) {
|
|
33
|
+
const px = u.valToPos(m.x, "x", true);
|
|
34
|
+
if (!Number.isFinite(px) || px < left - 0.5 || px > right + 0.5) continue;
|
|
35
|
+
ctx.strokeStyle = style.color;
|
|
36
|
+
ctx.lineWidth = Math.max(1, pr);
|
|
37
|
+
ctx.setLineDash([4 * pr, 4 * pr]);
|
|
38
|
+
ctx.beginPath();
|
|
39
|
+
ctx.moveTo(px, u.bbox.top);
|
|
40
|
+
ctx.lineTo(px, u.bbox.top + u.bbox.height);
|
|
41
|
+
ctx.stroke();
|
|
42
|
+
ctx.setLineDash([]);
|
|
43
|
+
const w = ctx.measureText(m.label).width;
|
|
44
|
+
let x0 = px + gap;
|
|
45
|
+
if (x0 + w > right) x0 = px - gap - w;
|
|
46
|
+
if (x0 < left) x0 = Math.max(left, Math.min(right - w, px - w / 2));
|
|
47
|
+
let row = 0;
|
|
48
|
+
while (placed.some((p) => p.row === row && x0 < p.x1 + gap && x0 + w + gap > p.x0)) row += 1;
|
|
49
|
+
placed.push({ x0, x1: x0 + w, row });
|
|
50
|
+
const y = u.bbox.top + 12 * pr + row * rowH;
|
|
51
|
+
ctx.textAlign = "left";
|
|
52
|
+
ctx.lineWidth = 3 * pr;
|
|
53
|
+
ctx.strokeStyle = style.halo;
|
|
54
|
+
ctx.strokeText(m.label, x0, y);
|
|
55
|
+
ctx.fillStyle = style.color;
|
|
56
|
+
ctx.fillText(m.label, x0, y);
|
|
57
|
+
}
|
|
58
|
+
ctx.restore();
|
|
59
|
+
}
|
|
20
60
|
function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
21
61
|
const lang = useShellLang();
|
|
22
62
|
const theme = useThemeStore((s) => s.theme);
|
|
@@ -57,10 +97,12 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
57
97
|
if (!el || width <= 0 || h <= 0) return;
|
|
58
98
|
const fg = resolveToken("--color-fg-subtle", "#888");
|
|
59
99
|
const grid = resolveToken("--color-border", "#ccc");
|
|
60
|
-
const
|
|
100
|
+
const family = resolveToken("--font-sans", "sans-serif");
|
|
101
|
+
const font = `11px ${family}`;
|
|
102
|
+
const surface = resolveToken("--color-surface", "#fff");
|
|
61
103
|
const repeats = { x: 0, y: 0 };
|
|
62
104
|
const tick = (fmt, axis) => (_u, vals) => {
|
|
63
|
-
const labels = vals
|
|
105
|
+
const labels = formatTicks(vals, lang, fmt ?? { digits: 4 });
|
|
64
106
|
repeats[axis] = repeatedLabels(labels);
|
|
65
107
|
hostRef.current?.setAttribute("data-ticks-repeat", String(repeats.x + repeats.y));
|
|
66
108
|
return labels;
|
|
@@ -92,11 +134,15 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
92
134
|
labelFont: font,
|
|
93
135
|
values: tick(y.format, "y"),
|
|
94
136
|
...ySteps ? { incrs: ySteps } : {},
|
|
137
|
+
// Sized to the longest tick label. uPlot draws in device pixels with a font scaled by its pixel ratio, so the
|
|
138
|
+
// label is measured in that font and divided back (measuring the unscaled font and dividing by the ratio
|
|
139
|
+
// made the axis too narrow on every high-density screen; the gate runs at ratio 1 and never saw it).
|
|
95
140
|
size: (u, values) => {
|
|
96
141
|
if (!values || values.length === 0) return 48;
|
|
97
|
-
|
|
142
|
+
const pr = uPlot.pxRatio || 1;
|
|
143
|
+
u.ctx.font = `${Math.round(11 * pr)}px ${family}`;
|
|
98
144
|
const widest = Math.max(...values.map((v) => u.ctx.measureText(v ?? "").width));
|
|
99
|
-
return Math.ceil(widest /
|
|
145
|
+
return Math.ceil(widest / pr) + 30;
|
|
100
146
|
}
|
|
101
147
|
}
|
|
102
148
|
],
|
|
@@ -118,21 +164,11 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
118
164
|
draw: [
|
|
119
165
|
(u) => {
|
|
120
166
|
if (!marks?.length) return;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
ctx.font = font;
|
|
127
|
-
for (const m of marks) {
|
|
128
|
-
const px = u.valToPos(m.x, "x", true);
|
|
129
|
-
ctx.beginPath();
|
|
130
|
-
ctx.moveTo(px, u.bbox.top);
|
|
131
|
-
ctx.lineTo(px, u.bbox.top + u.bbox.height);
|
|
132
|
-
ctx.stroke();
|
|
133
|
-
ctx.fillText(pick(m.label, lang), px + 4, u.bbox.top + 12);
|
|
134
|
-
}
|
|
135
|
-
ctx.restore();
|
|
167
|
+
drawMarks(u, marks.map((m) => ({ x: m.x, label: pick(m.label, lang) })), {
|
|
168
|
+
color: resolveToken("--color-warn", "#c80"),
|
|
169
|
+
halo: surface,
|
|
170
|
+
family
|
|
171
|
+
});
|
|
136
172
|
}
|
|
137
173
|
]
|
|
138
174
|
}
|
|
@@ -148,9 +184,9 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
148
184
|
uRef.current?.setData(data);
|
|
149
185
|
}, [data]);
|
|
150
186
|
const read = cursor !== null ? [
|
|
151
|
-
`${xLabel} ${formatNumber(x.values[cursor], lang, x.format ?? { digits: 4 })}${xUnit ?
|
|
187
|
+
`${xLabel} ${formatNumber(x.values[cursor], lang, x.format ?? { digits: 4 })}${xUnit ? `${NBSP}${xUnit}` : ""}`,
|
|
152
188
|
...series.map(
|
|
153
|
-
(s) => `${pick(s.label, lang)} ${formatNumber(s.values[cursor] ?? null, lang, y.format ?? { digits: 4 })}${yUnit ?
|
|
189
|
+
(s) => `${pick(s.label, lang)} ${formatNumber(s.values[cursor] ?? null, lang, y.format ?? { digits: 4 })}${yUnit ? `${NBSP}${yUnit}` : ""}`
|
|
154
190
|
)
|
|
155
191
|
].join(" \xB7 ") : lang === "es" ? "Pase el cursor sobre el gr\xE1fico para leer los valores" : "Hover the chart to read the values";
|
|
156
192
|
return /* @__PURE__ */ jsxs(
|
|
@@ -175,4 +211,4 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
175
211
|
);
|
|
176
212
|
}
|
|
177
213
|
|
|
178
|
-
export { UPlotChart };
|
|
214
|
+
export { UPlotChart, drawMarks, repeatedLabels, tickSteps };
|
|
@@ -93,8 +93,36 @@ var SHELL_TOKENS = [
|
|
|
93
93
|
"--color-shadow",
|
|
94
94
|
"--font-sans",
|
|
95
95
|
"--font-mono",
|
|
96
|
+
"--text-xs",
|
|
97
|
+
"--text-sm",
|
|
98
|
+
"--text-md",
|
|
99
|
+
"--text-base",
|
|
100
|
+
"--text-lg",
|
|
101
|
+
"--text-xl",
|
|
102
|
+
"--text-2xl",
|
|
103
|
+
"--space-1",
|
|
104
|
+
"--space-2",
|
|
105
|
+
"--space-3",
|
|
106
|
+
"--space-4",
|
|
107
|
+
"--space-5",
|
|
108
|
+
"--space-6",
|
|
109
|
+
"--radius-sm",
|
|
110
|
+
"--radius-md",
|
|
111
|
+
"--radius-lg",
|
|
112
|
+
"--radius-pill",
|
|
96
113
|
"--maxw",
|
|
97
|
-
"--maxw-wide"
|
|
114
|
+
"--maxw-wide",
|
|
115
|
+
"--measure",
|
|
116
|
+
"--measure-text",
|
|
117
|
+
"--header-h",
|
|
118
|
+
"--rail-w",
|
|
119
|
+
"--fade",
|
|
120
|
+
"--icon-sm",
|
|
121
|
+
"--icon-md",
|
|
122
|
+
"--icon-lg",
|
|
123
|
+
"--z-header",
|
|
124
|
+
"--z-focus",
|
|
125
|
+
"--z-modal"
|
|
98
126
|
];
|
|
99
127
|
function resolveToken(token, fallback = "") {
|
|
100
128
|
if (typeof document === "undefined") return fallback;
|
|
@@ -112,14 +140,25 @@ function useThemeTokens() {
|
|
|
112
140
|
|
|
113
141
|
// src/lib/format.ts
|
|
114
142
|
var LOCALE = { en: "en-US", es: "es-CL" };
|
|
143
|
+
var NBSP = "\xA0";
|
|
115
144
|
var SCIENTIFIC_BELOW = 1e-4;
|
|
116
145
|
var NOT_AVAILABLE = { en: "not available", es: "no disponible" };
|
|
117
146
|
function formatNumber(value, lang, opts = {}) {
|
|
118
147
|
if (value === null || value === void 0 || !Number.isFinite(value)) return NOT_AVAILABLE[lang];
|
|
119
148
|
const v = opts.percent ? value * 100 : value;
|
|
120
149
|
const digits = opts.digits ?? 4;
|
|
121
|
-
const
|
|
122
|
-
|
|
150
|
+
const scientific = v !== 0 && (opts.notation === "scientific" || Math.abs(v) < SCIENTIFIC_BELOW);
|
|
151
|
+
const nf = opts.decimals !== void 0 ? new Intl.NumberFormat(LOCALE[lang], { minimumFractionDigits: opts.decimals, maximumFractionDigits: opts.decimals }) : scientific ? new Intl.NumberFormat(LOCALE[lang], { notation: "scientific", maximumSignificantDigits: digits }) : Math.abs(v) >= 10 ** (digits - 1) ? new Intl.NumberFormat(LOCALE[lang], { maximumFractionDigits: 0 }) : new Intl.NumberFormat(LOCALE[lang], { maximumSignificantDigits: digits });
|
|
152
|
+
return opts.percent ? `${nf.format(v)}${NBSP}%` : nf.format(v);
|
|
153
|
+
}
|
|
154
|
+
function formatTicks(values, lang, opts = {}) {
|
|
155
|
+
let o = opts;
|
|
156
|
+
if (opts.decimals === void 0 && opts.notation === void 0) {
|
|
157
|
+
const scale = opts.percent ? 100 : 1;
|
|
158
|
+
const small = values.some((v) => v !== null && v !== void 0 && Number.isFinite(v) && v !== 0 && Math.abs(v * scale) < SCIENTIFIC_BELOW);
|
|
159
|
+
if (small) o = { ...opts, notation: "scientific" };
|
|
160
|
+
}
|
|
161
|
+
return values.map((v) => v === null || v === void 0 ? "" : formatNumber(v, lang, o));
|
|
123
162
|
}
|
|
124
163
|
function useFormat() {
|
|
125
164
|
const lang = useShellLang();
|
|
@@ -171,4 +210,4 @@ function Stage({ label, children, className }) {
|
|
|
171
210
|
);
|
|
172
211
|
}
|
|
173
212
|
|
|
174
|
-
export { NOT_AVAILABLE, SHELL_TOKENS, Stage, applyTheme, formatNumber, pick, readTheme, resolveToken, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens };
|
|
213
|
+
export { NBSP, NOT_AVAILABLE, SCIENTIFIC_BELOW, SHELL_TOKENS, Stage, applyTheme, formatNumber, formatTicks, pick, readTheme, resolveToken, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens };
|