@fasl-work/caos-app-shell 0.8.1 → 0.9.0
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 +3 -2
- package/chart.css +3 -0
- package/dist/chart.d.ts +22 -4
- package/dist/chart.js +88 -17
- package/dist/{chunk-ZLJCB7DD.js → chunk-IDUNUMCR.js} +2 -1
- package/dist/index.d.ts +16 -3
- package/dist/index.js +11 -4
- package/dist/{tokens-DkyEXX5g.d.ts → tokens-BTOzar-U.d.ts} +3 -0
- package/gate/inpage.mjs +2 -1
- package/gate/run.mjs +5 -3
- package/package.json +1 -1
- package/reserved-classes.json +5 -1
- package/styles.css +3 -0
package/README.md
CHANGED
|
@@ -121,8 +121,9 @@ const config: ShellConfig = {
|
|
|
121
121
|
`ChipGroup`, `Stage`, `useStageSize`, `makeStateKey`, `isStale`, `useWorkbenchState`,
|
|
122
122
|
`WorkbenchStateContext`, `pick`; since 0.8.0 `SurfacePage`, `useUrlView`, `viewParamOf`, `replaceQueryParam`,
|
|
123
123
|
`BREAKPOINTS`, `BarChart`, `textWidth`, `widestLabel`, `fitLabel`, `niceTicks`, `niceStep`, `fontFamily`,
|
|
124
|
-
`formatTicks`, `NBSP`, `SCIENTIFIC_BELOW`, the type `ShellColorToken`. Separate entries:
|
|
125
|
-
`
|
|
124
|
+
`formatTicks`, `NBSP`, `SCIENTIFIC_BELOW`, the type `ShellColorToken`; since 0.9.0 `ViewsRow`. Separate entries:
|
|
125
|
+
`/chart` (`UPlotChart` with `x.log`, `parity`, `onPick`; `drawMarks`, `tickSteps`, `repeatedLabels`, `seriesStyle`,
|
|
126
|
+
`sortOrder`, `parityRange`), `/keys` (the storage keys, no React), `/styles.css`, `/chart.css`,
|
|
126
127
|
`/reserved-classes.json`. Bin: `caos-shell-gate`.
|
|
127
128
|
|
|
128
129
|
### Authenticated workbenches
|
package/chart.css
CHANGED
|
@@ -16,4 +16,7 @@
|
|
|
16
16
|
.caos-chart-swatch { flex: none; width: 16px; height: 0; border-top: 2px solid var(--swatch); }
|
|
17
17
|
.caos-chart-key[data-dash] .caos-chart-swatch { border-top-style: dashed; }
|
|
18
18
|
.caos-chart-key[data-mode="points"] .caos-chart-swatch { width: 7px; height: 7px; border: 0; border-radius: 50%; background: var(--swatch); }
|
|
19
|
+
/* A parity plot is square and centred in its box; a chart whose points can be picked shows a pointer. */
|
|
20
|
+
.caos-chart[data-parity] .uplot { margin-inline: auto; }
|
|
21
|
+
.caos-chart[data-pick] .u-over { cursor: pointer; }
|
|
19
22
|
.caos-chart .u-cursor-x, .caos-chart .u-cursor-y { border-color: var(--color-fg-faint) !important; }
|
package/dist/chart.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import uPlot from 'uplot';
|
|
3
|
-
import { F as FormatOptions, S as ShellColorToken } from './tokens-
|
|
3
|
+
import { F as FormatOptions, S as ShellColorToken } from './tokens-BTOzar-U.js';
|
|
4
4
|
import { B as BiText } from './text-BlY47nIt.js';
|
|
5
5
|
import 'zustand';
|
|
6
6
|
|
|
@@ -26,6 +26,7 @@ interface UPlotChartProps {
|
|
|
26
26
|
x: ChartAxis & {
|
|
27
27
|
values: number[];
|
|
28
28
|
time?: boolean;
|
|
29
|
+
log?: boolean;
|
|
29
30
|
};
|
|
30
31
|
y: ChartAxis & {
|
|
31
32
|
log?: boolean;
|
|
@@ -40,9 +41,26 @@ interface UPlotChartProps {
|
|
|
40
41
|
/** Height in pixels, or `fill` to take the container's height (inside `PlotCard fill`); the width is always the
|
|
41
42
|
* container's. */
|
|
42
43
|
height?: number | 'fill';
|
|
43
|
-
/** Called with the index under the cursor (or null), for linked views
|
|
44
|
+
/** Called with the index under the cursor (or null), for linked views; the index is the caller's, before any
|
|
45
|
+
* sorting by x. */
|
|
44
46
|
onCursor?: (index: number | null) => void;
|
|
47
|
+
/** Called with the caller's index of the point under the cursor when the plot is clicked (select a case, a blast). */
|
|
48
|
+
onPick?: (index: number) => void;
|
|
49
|
+
/** A parity plot: predicted (the series) against observed (x) on one shared range, in a square box, with the
|
|
50
|
+
* identity line. Unsorted x is allowed (the chart sorts it and maps every index back). */
|
|
51
|
+
parity?: boolean;
|
|
45
52
|
}
|
|
53
|
+
/** The colour and dash of a series: its own, or the rotation's; when the rotation comes round (a seventh series
|
|
54
|
+
* repeats the first colour) the repeat is dashed, so two series never look the same (CAOS_Fragmenta drew this for
|
|
55
|
+
* itself until 0.9.0). */
|
|
56
|
+
declare function seriesStyle(s: ChartSeries, i: number): {
|
|
57
|
+
color: ShellColorToken;
|
|
58
|
+
dash?: number[];
|
|
59
|
+
};
|
|
60
|
+
/** The order that sorts x ascending (uPlot draws aligned data by increasing x), or null when x is already sorted. */
|
|
61
|
+
declare function sortOrder(xs: readonly number[]): number[] | null;
|
|
62
|
+
/** One range for both axes of a parity plot, padded by 5% of the span on each side. */
|
|
63
|
+
declare function parityRange(...arrays: readonly (readonly (number | null)[])[]): [number, number];
|
|
46
64
|
/**
|
|
47
65
|
* The tick steps an axis may use. With fixed `decimals` (scaled by 100 for a percent) only multiples of the smallest
|
|
48
66
|
* difference its labels can show, so no two ticks read the same: an integer axis ticks at integers, never at 1.5,
|
|
@@ -78,6 +96,6 @@ declare function drawMarks(u: uPlot, marks: {
|
|
|
78
96
|
* (known shell defect 17). An axis with fixed decimals ticks only where its labels differ (`tickSteps`). The host
|
|
79
97
|
* declares `data-series`, `data-axis-titles`, `data-ticks-cut`, `data-ticks-repeat` and `data-drawn` for the gate.
|
|
80
98
|
*/
|
|
81
|
-
declare function UPlotChart({ x, y, series, marks, height, onCursor }: UPlotChartProps): react.JSX.Element;
|
|
99
|
+
declare function UPlotChart({ x, y, series, marks, height, onCursor, onPick, parity }: UPlotChartProps): react.JSX.Element;
|
|
82
100
|
|
|
83
|
-
export { type ChartAxis, type ChartSeries, UPlotChart, type UPlotChartProps, drawMarks, repeatedLabels, tickSteps };
|
|
101
|
+
export { type ChartAxis, type ChartSeries, UPlotChart, type UPlotChartProps, drawMarks, parityRange, repeatedLabels, seriesStyle, sortOrder, tickSteps };
|
package/dist/chart.js
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
|
-
import { useShellLang, useThemeStore, useStageSize, pick, resolveToken, NBSP, formatNumber, formatTicks } from './chunk-
|
|
1
|
+
import { useShellLang, useThemeStore, useStageSize, pick, resolveToken, NBSP, formatNumber, formatTicks } from './chunk-IDUNUMCR.js';
|
|
2
2
|
import './chunk-X6Y5CDUD.js';
|
|
3
3
|
import { useRef, useCallback, useState, useMemo, useEffect } from 'react';
|
|
4
4
|
import uPlot from 'uplot';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
var ROTATION = ["--color-accent", "--color-magenta", "--color-accent-2", "--color-good", "--color-warn", "--color-bad"];
|
|
8
|
+
function seriesStyle(s, i) {
|
|
9
|
+
const color = s.color ?? ROTATION[i % ROTATION.length];
|
|
10
|
+
const dash = s.dash ?? (!s.color && i >= ROTATION.length ? [6, 4] : void 0);
|
|
11
|
+
return { color, dash };
|
|
12
|
+
}
|
|
13
|
+
function sortOrder(xs) {
|
|
14
|
+
for (let i = 1; i < xs.length; i++) {
|
|
15
|
+
if (xs[i] < xs[i - 1]) return xs.map((_, j) => j).sort((a, b) => xs[a] - xs[b] || a - b);
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function parityRange(...arrays) {
|
|
20
|
+
let lo = Infinity;
|
|
21
|
+
let hi = -Infinity;
|
|
22
|
+
for (const a of arrays) {
|
|
23
|
+
for (const v of a) {
|
|
24
|
+
if (v === null || !Number.isFinite(v)) continue;
|
|
25
|
+
lo = Math.min(lo, v);
|
|
26
|
+
hi = Math.max(hi, v);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!Number.isFinite(lo)) return [0, 1];
|
|
30
|
+
const pad = (hi - lo || Math.abs(hi) || 1) * 0.05;
|
|
31
|
+
return [lo - pad, hi + pad];
|
|
32
|
+
}
|
|
8
33
|
var STEPS = [];
|
|
9
34
|
for (let e = -16; e <= 16; e++) for (const m of [1, 2, 2.5, 5]) STEPS.push(Number((m * 10 ** e).toPrecision(3)));
|
|
10
35
|
function tickSteps(fmt) {
|
|
@@ -57,7 +82,7 @@ function drawMarks(u, marks, style) {
|
|
|
57
82
|
}
|
|
58
83
|
ctx.restore();
|
|
59
84
|
}
|
|
60
|
-
function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
85
|
+
function UPlotChart({ x, y, series, marks, height = 280, onCursor, onPick, parity }) {
|
|
61
86
|
const lang = useShellLang();
|
|
62
87
|
const theme = useThemeStore((s) => s.theme);
|
|
63
88
|
const fill = height === "fill";
|
|
@@ -70,20 +95,30 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
70
95
|
},
|
|
71
96
|
[measureRef]
|
|
72
97
|
);
|
|
73
|
-
const width = box.width;
|
|
74
|
-
const h = fill ? box.height : height;
|
|
98
|
+
const width = parity ? Math.min(box.width, fill ? box.height : height) : box.width;
|
|
99
|
+
const h = parity ? width : fill ? box.height : height;
|
|
75
100
|
const uRef = useRef(null);
|
|
76
101
|
const hostRef = useRef(null);
|
|
77
102
|
const [cursor, setCursor] = useState(null);
|
|
78
103
|
const onCursorRef = useRef(onCursor);
|
|
79
104
|
onCursorRef.current = onCursor;
|
|
105
|
+
const onPickRef = useRef(onPick);
|
|
106
|
+
onPickRef.current = onPick;
|
|
107
|
+
const order = useMemo(() => sortOrder(x.values), [x.values]);
|
|
108
|
+
const orderRef = useRef(order);
|
|
109
|
+
orderRef.current = order;
|
|
110
|
+
const xs = useMemo(() => order ? order.map((i) => x.values[i]) : x.values, [order, x.values]);
|
|
111
|
+
const ys = useMemo(() => series.map((s) => order ? order.map((i) => s.values[i] ?? null) : s.values), [order, series]);
|
|
112
|
+
const range = useMemo(() => parity ? parityRange(xs, ...ys) : null, [parity, xs, ys]);
|
|
80
113
|
const xLabel = pick(x.label, lang);
|
|
81
114
|
const yLabel = pick(y.label, lang);
|
|
82
115
|
const xUnit = x.unit ? pick(x.unit, lang) : "";
|
|
83
116
|
const yUnit = y.unit ? pick(y.unit, lang) : "";
|
|
84
117
|
const structure = JSON.stringify({
|
|
85
|
-
s: series.map((s, i) => [pick(s.label, lang), s
|
|
86
|
-
x: [xLabel, xUnit, Boolean(x.time), x.format ?? null],
|
|
118
|
+
s: series.map((s, i) => [pick(s.label, lang), seriesStyle(s, i), s.width ?? 2, s.mode ?? "line"]),
|
|
119
|
+
x: [xLabel, xUnit, Boolean(x.time), Boolean(x.log), x.format ?? null],
|
|
120
|
+
p: range,
|
|
121
|
+
pick: Boolean(onPick),
|
|
87
122
|
y: [yLabel, yUnit, Boolean(y.log), y.range ?? null, y.format ?? null],
|
|
88
123
|
m: (marks ?? []).map((m) => [m.x, pick(m.label, lang)]),
|
|
89
124
|
theme,
|
|
@@ -91,7 +126,7 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
91
126
|
h,
|
|
92
127
|
w: width
|
|
93
128
|
});
|
|
94
|
-
const data = useMemo(() => [
|
|
129
|
+
const data = useMemo(() => [xs, ...ys], [xs, ys]);
|
|
95
130
|
useEffect(() => {
|
|
96
131
|
const el = plotRef.current;
|
|
97
132
|
if (!el || width <= 0 || h <= 0) return;
|
|
@@ -107,13 +142,23 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
107
142
|
hostRef.current?.setAttribute("data-ticks-repeat", String(repeats.x + repeats.y));
|
|
108
143
|
return labels;
|
|
109
144
|
};
|
|
110
|
-
const xSteps = x.time ? void 0 : tickSteps(x.format);
|
|
145
|
+
const xSteps = x.time || x.log ? void 0 : tickSteps(x.format);
|
|
111
146
|
const ySteps = y.log ? void 0 : tickSteps(y.format);
|
|
112
147
|
const opts = {
|
|
113
148
|
width,
|
|
114
149
|
height: h,
|
|
115
150
|
legend: { show: false },
|
|
116
|
-
|
|
151
|
+
// a log axis labels the ticks uPlot keeps and passes null for the rest, which formatTicks leaves blank
|
|
152
|
+
scales: {
|
|
153
|
+
// a log x axis spans the data, not the decades around it (uPlot rounds out to the next decade, which left an
|
|
154
|
+
// axis to 1,000 for data that ends at 120)
|
|
155
|
+
x: {
|
|
156
|
+
time: Boolean(x.time),
|
|
157
|
+
distr: x.log ? 3 : 1,
|
|
158
|
+
...range ? { range } : x.log ? { range: (_u, min, max) => [min, max] } : {}
|
|
159
|
+
},
|
|
160
|
+
y: { distr: y.log ? 3 : 1, ...range ? { range } : y.range ? { range: y.range } : {} }
|
|
161
|
+
},
|
|
117
162
|
axes: [
|
|
118
163
|
{
|
|
119
164
|
stroke: fg,
|
|
@@ -149,8 +194,9 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
149
194
|
series: [
|
|
150
195
|
{},
|
|
151
196
|
...series.map((s, i) => {
|
|
152
|
-
const
|
|
153
|
-
|
|
197
|
+
const style = seriesStyle(s, i);
|
|
198
|
+
const stroke = resolveToken(style.color, "#4a8");
|
|
199
|
+
return s.mode === "points" ? { label: pick(s.label, lang), stroke, width: 1.5, paths: () => null, points: { show: true, space: 0, size: 9, fill: stroke } } : { label: pick(s.label, lang), stroke, width: s.width ?? 2, dash: style.dash, spanGaps: false, points: { show: false } };
|
|
154
200
|
})
|
|
155
201
|
],
|
|
156
202
|
hooks: {
|
|
@@ -158,11 +204,33 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
158
204
|
(u) => {
|
|
159
205
|
const idx = u.cursor.idx ?? null;
|
|
160
206
|
setCursor(idx);
|
|
161
|
-
onCursorRef.current?.(idx);
|
|
207
|
+
onCursorRef.current?.(idx === null ? null : orderRef.current ? orderRef.current[idx] : idx);
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
ready: [
|
|
211
|
+
(u) => {
|
|
212
|
+
u.over.addEventListener("click", () => {
|
|
213
|
+
const idx = u.cursor.idx;
|
|
214
|
+
if (idx === null || idx === void 0 || !onPickRef.current) return;
|
|
215
|
+
onPickRef.current(orderRef.current ? orderRef.current[idx] : idx);
|
|
216
|
+
});
|
|
162
217
|
}
|
|
163
218
|
],
|
|
164
219
|
draw: [
|
|
165
220
|
(u) => {
|
|
221
|
+
if (range) {
|
|
222
|
+
const ctx = u.ctx;
|
|
223
|
+
const pr = uPlot.pxRatio || 1;
|
|
224
|
+
ctx.save();
|
|
225
|
+
ctx.strokeStyle = resolveToken("--color-fg-faint", "#888");
|
|
226
|
+
ctx.lineWidth = Math.max(1, pr);
|
|
227
|
+
ctx.setLineDash([5 * pr, 4 * pr]);
|
|
228
|
+
ctx.beginPath();
|
|
229
|
+
ctx.moveTo(u.valToPos(range[0], "x", true), u.valToPos(range[0], "y", true));
|
|
230
|
+
ctx.lineTo(u.valToPos(range[1], "x", true), u.valToPos(range[1], "y", true));
|
|
231
|
+
ctx.stroke();
|
|
232
|
+
ctx.restore();
|
|
233
|
+
}
|
|
166
234
|
if (!marks?.length) return;
|
|
167
235
|
drawMarks(u, marks.map((m) => ({ x: m.x, label: pick(m.label, lang) })), {
|
|
168
236
|
color: resolveToken("--color-warn", "#c80"),
|
|
@@ -184,9 +252,9 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
184
252
|
uRef.current?.setData(data);
|
|
185
253
|
}, [data]);
|
|
186
254
|
const read = cursor !== null ? [
|
|
187
|
-
`${xLabel} ${formatNumber(
|
|
255
|
+
`${xLabel} ${formatNumber(xs[cursor], lang, x.format ?? { digits: 4 })}${xUnit ? `${NBSP}${xUnit}` : ""}`,
|
|
188
256
|
...series.map(
|
|
189
|
-
(s) => `${pick(s.label, lang)} ${formatNumber(
|
|
257
|
+
(s, k) => `${pick(s.label, lang)} ${formatNumber(ys[k][cursor] ?? null, lang, y.format ?? { digits: 4 })}${yUnit ? `${NBSP}${yUnit}` : ""}`
|
|
190
258
|
)
|
|
191
259
|
].join(" \xB7 ") : lang === "es" ? "Pase el cursor sobre el gr\xE1fico para leer los valores" : "Hover the chart to read the values";
|
|
192
260
|
return /* @__PURE__ */ jsxs(
|
|
@@ -199,10 +267,13 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
199
267
|
"data-ticks-cut": "0",
|
|
200
268
|
"data-ticks-repeat": "0",
|
|
201
269
|
"data-drawn": width > 0 && h > 0 ? "1" : "0",
|
|
270
|
+
"data-parity": parity ? "1" : void 0,
|
|
271
|
+
"data-log-x": x.log ? "1" : void 0,
|
|
272
|
+
"data-pick": onPick ? "1" : void 0,
|
|
202
273
|
children: [
|
|
203
274
|
/* @__PURE__ */ jsx("div", { ref: setPlot, className: "caos-chart-plot" }),
|
|
204
|
-
series.length > 1 && /* @__PURE__ */ jsx("ul", { className: "caos-chart-legend", "aria-label": lang === "es" ? "Series del gr\xE1fico" : "Series of the chart", children: series.map((s, i) => /* @__PURE__ */ jsxs("li", { className: "caos-chart-key", "data-mode": s.mode ?? "line", "data-dash": s.dash ? "1" : void 0, children: [
|
|
205
|
-
/* @__PURE__ */ jsx("span", { className: "caos-chart-swatch", style: { "--swatch": `var(${s
|
|
275
|
+
series.length > 1 && /* @__PURE__ */ jsx("ul", { className: "caos-chart-legend", "aria-label": lang === "es" ? "Series del gr\xE1fico" : "Series of the chart", children: series.map((s, i) => /* @__PURE__ */ jsxs("li", { className: "caos-chart-key", "data-mode": s.mode ?? "line", "data-dash": seriesStyle(s, i).dash ? "1" : void 0, children: [
|
|
276
|
+
/* @__PURE__ */ jsx("span", { className: "caos-chart-swatch", style: { "--swatch": `var(${seriesStyle(s, i).color})` }, "aria-hidden": "true" }),
|
|
206
277
|
pick(s.label, lang)
|
|
207
278
|
] }, i)) }),
|
|
208
279
|
/* @__PURE__ */ jsx("p", { className: "caos-chart-readout", "aria-live": "polite", title: read, children: read })
|
|
@@ -211,4 +282,4 @@ function UPlotChart({ x, y, series, marks, height = 280, onCursor }) {
|
|
|
211
282
|
);
|
|
212
283
|
}
|
|
213
284
|
|
|
214
|
-
export { UPlotChart, drawMarks, repeatedLabels, tickSteps };
|
|
285
|
+
export { UPlotChart, drawMarks, parityRange, repeatedLabels, seriesStyle, sortOrder, tickSteps };
|
|
@@ -148,7 +148,8 @@ function formatNumber(value, lang, opts = {}) {
|
|
|
148
148
|
const v = opts.percent ? value * 100 : value;
|
|
149
149
|
const digits = opts.digits ?? 4;
|
|
150
150
|
const scientific = v !== 0 && (opts.notation === "scientific" || Math.abs(v) < SCIENTIFIC_BELOW);
|
|
151
|
-
const
|
|
151
|
+
const grouping = opts.grouping === false ? { useGrouping: false } : {};
|
|
152
|
+
const nf = opts.decimals !== void 0 ? new Intl.NumberFormat(LOCALE[lang], { minimumFractionDigits: opts.decimals, maximumFractionDigits: opts.decimals, ...grouping }) : scientific ? new Intl.NumberFormat(LOCALE[lang], { notation: "scientific", maximumSignificantDigits: digits }) : Math.abs(v) >= 10 ** (digits - 1) ? new Intl.NumberFormat(LOCALE[lang], { maximumFractionDigits: 0, ...grouping }) : new Intl.NumberFormat(LOCALE[lang], { maximumSignificantDigits: digits, ...grouping });
|
|
152
153
|
return opts.percent ? `${nf.format(v)}${NBSP}%` : nf.format(v);
|
|
153
154
|
}
|
|
154
155
|
function formatTicks(values, lang, opts = {}) {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export { A as AppShell, a as ArchTab, b as ArchitectureConfig, c as Architecture
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, Component, ErrorInfo } from 'react';
|
|
4
4
|
import * as zustand from 'zustand';
|
|
5
|
-
import { F as FormatOptions } from './tokens-
|
|
6
|
-
export { N as NBSP, a as NOT_AVAILABLE, b as SCIENTIFIC_BELOW, c as SHELL_TOKENS, S as ShellColorToken, d as ShellToken, f as formatNumber, e as formatTicks, r as resolveToken, u as useFormat, g as useThemeTokens } from './tokens-
|
|
5
|
+
import { F as FormatOptions } from './tokens-BTOzar-U.js';
|
|
6
|
+
export { N as NBSP, a as NOT_AVAILABLE, b as SCIENTIFIC_BELOW, c as SHELL_TOKENS, S as ShellColorToken, d as ShellToken, f as formatNumber, e as formatTicks, r as resolveToken, u as useFormat, g as useThemeTokens } from './tokens-BTOzar-U.js';
|
|
7
7
|
import { L as Lang, B as BiText } from './text-BlY47nIt.js';
|
|
8
8
|
export { p as pick, u as useLangStore, a as useShellLang } from './text-BlY47nIt.js';
|
|
9
9
|
|
|
@@ -823,4 +823,17 @@ declare function Stage({ label, children, className }: {
|
|
|
823
823
|
className?: string;
|
|
824
824
|
}): react.JSX.Element;
|
|
825
825
|
|
|
826
|
-
|
|
826
|
+
interface ViewsRowProps {
|
|
827
|
+
/** The views side by side: `PlotCard`s, or components that render one. */
|
|
828
|
+
children: ReactNode;
|
|
829
|
+
/** The share of the row each view takes, in order (`[3, 2]`: the first takes three fifths); equal when absent. */
|
|
830
|
+
shares?: number[];
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Views side by side in an instrument panel, each in a column the shell owns, so a filling `PlotCard` keeps its height
|
|
834
|
+
* chain and the row splits by `shares` (CAOS_Fragmenta's design row, three fifths for the response surface). Before
|
|
835
|
+
* 0.9.0 a product wrote this column itself (`.fr-viewcol`). Below 900 px the views stack.
|
|
836
|
+
*/
|
|
837
|
+
declare function ViewsRow({ children, shares }: ViewsRowProps): react.JSX.Element;
|
|
838
|
+
|
|
839
|
+
export { BREAKPOINTS, BarChart, type BarChartProps, type BarDatum, BiText, Callout, type CaseDef, type CaseGroup, type CaseKind, CaseSelector, type CaseSelectorProps, type CaseSelectorText, CaseWorkbench, type CaseWorkbenchProps, ChipGroup, type ChipGroupProps, type ChipOption, type Citation, CitationsProvider, Cite, DocPage, DocSection, type DocSectionProps, Equation, Figure, type FittedLabel, FocusShell, type FocusShellProps, FormatOptions, Gauge, type GaugeProps, type GaugeZone, InlineMath, Knob, type KnobProps, type Lane, LaneBadge, Lang, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, type PausedVizController, PlotCard, type PlotCardProps, type Provenance, type RailSection, Readout, type ReadoutItem, type ReadoutProps, ReferenceList, Refs, Stage, type StageSize, type SubTabDef, SubTabs, type SubTabsProps, SurfacePage, type SurfacePageProps, type TabDef, type TabGroupDef, TabGroups, type TabGroupsProps, Tabs, type TabsProps, type Theme, ThemeToggle, type Tone, type UsePausedVizOptions, VariantBar, type VariantBarProps, type VariantDef, Verdict, type VerdictProps, ViewsRow, type ViewsRowProps, type VizFrame, type VizLoop, type VizLoopDeps, type VizLoopOptions, type WorkbenchGroup, WorkbenchLayout, type WorkbenchLayoutProps, type WorkbenchRoute, WorkbenchShell, type WorkbenchShellProps, type WorkbenchState, WorkbenchStateContext, applyTheme, caseKind, caseTooltip, casesInSource, createVizLoop, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, readCaseParam, readTheme, replaceQueryParam, sourcesPresent, textWidth, usePausedViz, useStageSize, useThemeStore, useUrlView, useWorkbenchState, viewParamOf, widestLabel, withCaseParam };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useThemeStore, useShellLang, useLangStore, SHELL_TOKENS, pick, useStageSize, NOT_AVAILABLE, formatTicks, formatNumber, NBSP } from './chunk-
|
|
2
|
-
export { NBSP, NOT_AVAILABLE, SCIENTIFIC_BELOW, SHELL_TOKENS, Stage, applyTheme, formatNumber, formatTicks, pick, readTheme, resolveToken, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens } from './chunk-
|
|
1
|
+
import { useThemeStore, useShellLang, useLangStore, SHELL_TOKENS, pick, useStageSize, NOT_AVAILABLE, formatTicks, formatNumber, NBSP } from './chunk-IDUNUMCR.js';
|
|
2
|
+
export { NBSP, NOT_AVAILABLE, SCIENTIFIC_BELOW, SHELL_TOKENS, Stage, applyTheme, formatNumber, formatTicks, pick, readTheme, resolveToken, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens } from './chunk-IDUNUMCR.js';
|
|
3
3
|
export { LANG_STORAGE_KEY, STANDARD_ROUTES, THEME_BOOT_SCRIPT, THEME_STORAGE_KEY } from './chunk-X6Y5CDUD.js';
|
|
4
|
-
import { createContext, Component, useState, useRef, useId, useEffect, useCallback, useContext, useMemo } from 'react';
|
|
4
|
+
import { createContext, Component, useState, useRef, useId, useEffect, useCallback, useContext, useMemo, Children } from 'react';
|
|
5
5
|
import { useInRouterContext, NavLink, useLocation } from 'react-router';
|
|
6
6
|
import { Sun, Moon, Languages, Boxes, CodeXml, Globe, Briefcase, Info } from 'lucide-react';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1740,5 +1740,12 @@ function ChipGroup({ id, label, options, value, onChange }) {
|
|
|
1740
1740
|
)) })
|
|
1741
1741
|
] });
|
|
1742
1742
|
}
|
|
1743
|
+
function ViewsRow({ children, shares }) {
|
|
1744
|
+
const items = Children.toArray(children).filter(Boolean);
|
|
1745
|
+
return /* @__PURE__ */ jsx("div", { className: "caos-views-row", "data-views": items.length, children: items.map((child, i) => {
|
|
1746
|
+
const share = shares?.[i];
|
|
1747
|
+
return /* @__PURE__ */ jsx("div", { className: "caos-views-col", "data-share": share ?? 1, style: share && share > 0 ? { flexGrow: share } : void 0, children: child }, i);
|
|
1748
|
+
}) });
|
|
1749
|
+
}
|
|
1743
1750
|
|
|
1744
|
-
export { AppShell, ArchitectureModal, BREAKPOINTS, BarChart, Callout, CaseSelector, CaseWorkbench, ChipGroup, CitationsProvider, Cite, DocPage, DocSection, Equation, Figure, FocusShell, Gauge, InlineMath, Knob, LaneBadge, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, PlotCard, Readout, ReferenceList, Refs, SubTabs, SurfacePage, TabGroups, Tabs, ThemeToggle, VariantBar, Verdict, WorkbenchLayout, WorkbenchShell, WorkbenchStateContext, caseKind, caseTooltip, casesInSource, createVizLoop, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, readCaseParam, replaceQueryParam, sourcesPresent, textWidth, usePausedViz, useUrlView, useWorkbenchState, validateArchitectureConfig, viewParamOf, widestLabel, withCaseParam };
|
|
1751
|
+
export { AppShell, ArchitectureModal, BREAKPOINTS, BarChart, Callout, CaseSelector, CaseWorkbench, ChipGroup, CitationsProvider, Cite, DocPage, DocSection, Equation, Figure, FocusShell, Gauge, InlineMath, Knob, LaneBadge, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, PlotCard, Readout, ReferenceList, Refs, SubTabs, SurfacePage, TabGroups, Tabs, ThemeToggle, VariantBar, Verdict, ViewsRow, WorkbenchLayout, WorkbenchShell, WorkbenchStateContext, caseKind, caseTooltip, casesInSource, createVizLoop, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, readCaseParam, replaceQueryParam, sourcesPresent, textWidth, usePausedViz, useUrlView, useWorkbenchState, validateArchitectureConfig, viewParamOf, widestLabel, withCaseParam };
|
|
@@ -12,6 +12,9 @@ interface FormatOptions {
|
|
|
12
12
|
/** `scientific` writes every non-zero value in scientific notation with `digits` significant digits; the default
|
|
13
13
|
* chooses by magnitude. An axis uses it so all its ticks share one notation (`formatTicks`). */
|
|
14
14
|
notation?: 'auto' | 'scientific';
|
|
15
|
+
/** `false` writes the integer part without a group separator, in both languages: a calendar year on an axis, in a
|
|
16
|
+
* readout or in a table reads 2021, never 2,021 or 2.021 (known shell defect 30). Default true. */
|
|
17
|
+
grouping?: boolean;
|
|
15
18
|
}
|
|
16
19
|
/** The no-break space (U+00A0) that joins a value to its unit or sign. */
|
|
17
20
|
declare const NBSP = "\u00A0";
|
package/gate/inpage.mjs
CHANGED
|
@@ -621,7 +621,8 @@ export function installLib() {
|
|
|
621
621
|
const out = [];
|
|
622
622
|
const skip = 'code, pre, kbd, samp, .katex, [data-version], [data-build], [translate="no"], script, style, [aria-hidden="true"]';
|
|
623
623
|
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
|
624
|
-
|
|
624
|
+
// an exponent belongs to the number: 2.7e-08 on a Spanish page writes its decimal with a point too
|
|
625
|
+
const re = /(?<![\w.,/:@#])(\d+)\.(\d+)(?:[eE][-+]?\d+)?(?![\w/@]|\.\d)/g;
|
|
625
626
|
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
626
627
|
const text = n.nodeValue || '';
|
|
627
628
|
if (!/\d\.\d/.test(text)) continue;
|
package/gate/run.mjs
CHANGED
|
@@ -318,7 +318,7 @@ export async function runGate(o) {
|
|
|
318
318
|
if (primary) {
|
|
319
319
|
// ADR-0071 rule 9 / G5: every header route reached by a real pointer click from the App route.
|
|
320
320
|
for (const route of routes.filter((r) => r !== '/')) {
|
|
321
|
-
await page.goto(urlFor('/'), { waitUntil: 'load', timeout: 30000 });
|
|
321
|
+
await page.goto(urlFor('/'), { waitUntil: 'load', timeout: 30000 }).catch(() => undefined);
|
|
322
322
|
await settle(page);
|
|
323
323
|
const link = page.locator('header nav a[href]');
|
|
324
324
|
const hrefs = await link.evaluateAll((as) => as.map((a) => a.href));
|
|
@@ -326,8 +326,10 @@ export async function runGate(o) {
|
|
|
326
326
|
let ok = false;
|
|
327
327
|
if (idx >= 0) {
|
|
328
328
|
// A reader scrolls a narrow nav row to the link first; so does the gate, then clicks with the pointer.
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
// A link that does not answer in time is a failure of this route, never an exception that ends the
|
|
330
|
+
// whole run (a locator waited its default 30 s under load and aborted the gate, 0.9.0 self-test).
|
|
331
|
+
await link.nth(idx).evaluate((el) => window.__caosGate.bringEl(el), undefined, { timeout: 10000 }).catch(() => undefined);
|
|
332
|
+
const box = await link.nth(idx).boundingBox({ timeout: 10000 }).catch(() => null);
|
|
331
333
|
if (box) {
|
|
332
334
|
await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
|
|
333
335
|
await page.waitForURL((u) => routeOf(u.href) === route, { timeout: 3000 }).catch(() => undefined);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fasl-work/caos-app-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Shared web-app shell, workbench primitives, content primitives, design system and measured gate for the CAOS / Faena public apps (ADR-0016, ADR-0017, ADR-0071).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Felipe Santibáñez-Leal",
|
package/reserved-classes.json
CHANGED
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"caos-verdict",
|
|
95
95
|
"caos-verdict-text",
|
|
96
96
|
"caos-verdict-title",
|
|
97
|
+
"caos-views-col",
|
|
97
98
|
"caos-views-row",
|
|
98
99
|
"caos-wb",
|
|
99
100
|
"caos-wb-main",
|
|
@@ -210,7 +211,8 @@
|
|
|
210
211
|
"tone-good",
|
|
211
212
|
"tone-neutral",
|
|
212
213
|
"tone-warn",
|
|
213
|
-
"two-col"
|
|
214
|
+
"two-col",
|
|
215
|
+
"uplot"
|
|
214
216
|
],
|
|
215
217
|
"modifiers": [
|
|
216
218
|
"accent",
|
|
@@ -325,6 +327,7 @@
|
|
|
325
327
|
"caos-verdict",
|
|
326
328
|
"caos-verdict-text",
|
|
327
329
|
"caos-verdict-title",
|
|
330
|
+
"caos-views-col",
|
|
328
331
|
"caos-views-row",
|
|
329
332
|
"caos-wb",
|
|
330
333
|
"caos-wb-main",
|
|
@@ -454,6 +457,7 @@
|
|
|
454
457
|
"tone-neutral",
|
|
455
458
|
"tone-warn",
|
|
456
459
|
"two-col",
|
|
460
|
+
"uplot",
|
|
457
461
|
"warn",
|
|
458
462
|
"wide"
|
|
459
463
|
]
|
package/styles.css
CHANGED
|
@@ -579,6 +579,9 @@ svg.lucide { flex: none; }
|
|
|
579
579
|
defect 23, #54: `.caos-plot.fill` outranked the row's zero basis and took the row). */
|
|
580
580
|
.caos-views-row { display: flex; gap: 0.9rem; flex: 1 1 auto; min-height: 0; min-width: 0; }
|
|
581
581
|
.caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: 1 1 0; min-width: 0; }
|
|
582
|
+
/* ViewsRow's column: a view inside it keeps its height chain (a filling card fills the column); its share of the row
|
|
583
|
+
is its flex-grow. */
|
|
584
|
+
.caos-views-col { display: flex; flex-direction: column; min-width: 0; min-height: 0; gap: 0.6rem; }
|
|
582
585
|
|
|
583
586
|
/* Staleness: a view showing data for an earlier selection says so. */
|
|
584
587
|
.caos-stale .caos-plot-body > :not(.caos-stale-overlay), .caos-readout.caos-stale dl { opacity: 0.45; }
|