@fasl-work/caos-app-shell 0.16.0 → 0.18.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/chart.css +5 -0
- package/dist/chart.d.ts +107 -9
- package/dist/chart.js +311 -31
- package/dist/{chunk-YECZXGVG.js → chunk-DBCMAL2G.js} +73 -1
- package/dist/index.d.ts +7 -40
- package/dist/index.js +67 -94
- package/dist/{tokens-BTOzar-U.d.ts → text-DyQ1A8oo.d.ts} +39 -1
- package/gate/inpage.mjs +67 -1
- package/gate/run.mjs +15 -2
- package/package.json +3 -4
- package/reserved-classes.json +10 -2
- package/styles.css +25 -4
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export { A as APP_ROUTE, a as AppShell, b as ArchTab, c as ArchitectureConfig, d
|
|
|
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 './
|
|
6
|
-
export { N as NBSP,
|
|
5
|
+
import { F as FormatOptions } from './text-DyQ1A8oo.js';
|
|
6
|
+
export { a as FittedLabel, N as NBSP, b as NOT_AVAILABLE, c as SCIENTIFIC_BELOW, d as SHELL_TOKENS, S as ShellColorToken, e as ShellToken, f as fitLabel, g as fontFamily, h as formatNumber, i as formatTicks, n as niceStep, j as niceTicks, k as resolveToken, t as textWidth, u as useFormat, l as useThemeTokens, w as widestLabel } from './text-DyQ1A8oo.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
|
|
|
@@ -260,8 +260,9 @@ interface CaseSelectorProps {
|
|
|
260
260
|
* category structure is preserved either way; only the height changes.
|
|
261
261
|
*/
|
|
262
262
|
layout?: 'chips' | 'select';
|
|
263
|
-
/** A control that sits on the select's row, after it
|
|
264
|
-
*
|
|
263
|
+
/** A control of the product that sits on the select's row, after it: the select shrinks to make room, so the selector is no taller with
|
|
264
|
+
* it (a long case name may then be cut: keep the control narrow). The workbench's own Focus control is not an accessory since 0.17.0:
|
|
265
|
+
* it sits in the group tab row. With `layout: 'chips'` it gets a row of its own, after the chips. */
|
|
265
266
|
accessory?: ReactNode;
|
|
266
267
|
}
|
|
267
268
|
/**
|
|
@@ -1117,40 +1118,6 @@ interface BarChartProps {
|
|
|
1117
1118
|
*/
|
|
1118
1119
|
declare function BarChart({ title, data, axis, orientation, values, height, onSelect }: BarChartProps): react.JSX.Element;
|
|
1119
1120
|
|
|
1120
|
-
/**
|
|
1121
|
-
* Text that fits the drawing it labels, measured in the font the page renders.
|
|
1122
|
-
*
|
|
1123
|
-
* Products drew their axes and labels with fixed margins and a fixed width per character. The Linux fonts (DejaVu
|
|
1124
|
-
* Sans) are wider than the Windows ones and Spanish labels are longer than English ones, so a column sized for one
|
|
1125
|
-
* ran its labels out of the drawing in the other (CAOS_Fragmenta 0.05.000: "Tamaño medio clásico, limitado al bloque
|
|
1126
|
-
* in situ" read "dio clásico, limitado al bloque in situ"; its deploy gate failed on Linux). Here a label is measured
|
|
1127
|
-
* with the canvas text metrics of the page's own font (`--font-sans`, which the gate's wide-font pass replaces),
|
|
1128
|
-
* broken over two lines at a word when it does not fit, and only then shortened with an ellipsis, so the drawing can
|
|
1129
|
-
* give the whole label as its title. Ported from CAOS_Fragmenta `viz/text.ts` (0.07.000).
|
|
1130
|
-
*/
|
|
1131
|
-
/** The page's sans-serif stack as the shell token resolves it. */
|
|
1132
|
-
declare function fontFamily(): string;
|
|
1133
|
-
/** The width of one line of text at a font size, in CSS pixels; outside a browser, an estimate on the wide side. */
|
|
1134
|
-
declare function textWidth(text: string, px: number, weight?: number): number;
|
|
1135
|
-
/** The widest a set of labels needs, each on one line. */
|
|
1136
|
-
declare function widestLabel(labels: readonly string[], px: number, weight?: number): number;
|
|
1137
|
-
interface FittedLabel {
|
|
1138
|
-
/** One or two lines; the last is shortened with an ellipsis only when the lines allowed are not enough. */
|
|
1139
|
-
lines: string[];
|
|
1140
|
-
/** Whether the label was shortened, so the drawing gives the whole label as its title. */
|
|
1141
|
-
shortened: boolean;
|
|
1142
|
-
}
|
|
1143
|
-
/** A label in at most `maxLines` lines of `width` pixels: whole when it fits, broken at a word, shortened last. */
|
|
1144
|
-
declare function fitLabel(label: string, width: number, px: number, maxLines?: 1 | 2): FittedLabel;
|
|
1145
|
-
/** The 1, 2, 2.5 or 5 times a power of ten at or above `x`. */
|
|
1146
|
-
declare function niceStep(x: number): number;
|
|
1147
|
-
/**
|
|
1148
|
-
* Round ticks covering [lo, hi], as many as leave room for labels about `labelSize` pixels along an axis of `room`
|
|
1149
|
-
* pixels (at least two, at most `most`). The first tick is at or below `lo` and the last at or above `hi`, so a bar
|
|
1150
|
-
* or a point never runs past the last labelled value.
|
|
1151
|
-
*/
|
|
1152
|
-
declare function niceTicks(lo: number, hi: number, room: number, labelSize: number, most?: number): number[];
|
|
1153
|
-
|
|
1154
1121
|
/** One section of the control rail. A rail whose content does not fit is SPLIT into sections, one shown at a
|
|
1155
1122
|
* time, never scrolled (ADR-0071 rule 6: a panel must show its own controls). */
|
|
1156
1123
|
interface RailSection {
|
|
@@ -1251,7 +1218,7 @@ interface CaseWorkbenchProps {
|
|
|
1251
1218
|
deepLinkView?: boolean | string;
|
|
1252
1219
|
ariaLabel?: BiText;
|
|
1253
1220
|
/**
|
|
1254
|
-
* Focus mode for the App (ADR-0070, shell 0.14.0): a Focus
|
|
1221
|
+
* Focus mode for the App (ADR-0070, shell 0.14.0): a Focus control at the end of the group tab row opens the selected case's open group in
|
|
1255
1222
|
* the full viewport through `FocusShell` (the stage is the view, the rail stays), holds `?focus=1` beside `?case=` and
|
|
1256
1223
|
* `?view=` in the URL, and returns with Escape or the exit button to the same case, group and sub-view. `true` takes all
|
|
1257
1224
|
* the defaults. Omit it and the App is exactly what it was.
|
|
@@ -1379,4 +1346,4 @@ interface ViewsRowProps {
|
|
|
1379
1346
|
*/
|
|
1380
1347
|
declare function ViewsRow({ children, shares }: ViewsRowProps): react.JSX.Element;
|
|
1381
1348
|
|
|
1382
|
-
export { BREAKPOINTS, BarChart, type BarChartProps, type BarDatum, BiText, Callout, CardDeck, type CardDeckProps, type CaseDef, type CaseFocusConfig, type CaseGroup, type CaseKind, CaseSelector, type CaseSelectorProps, type CaseSelectorText, CaseWorkbench, type CaseWorkbenchProps, ChipGroup, type ChipGroupProps, type ChipOption, type Citation, CitationsProvider, Cite, DECK_TEXT, DOC_AREAS, type DeckCard, DocPage, type DocPageProps, DocReferences, DocRefsScope, DocSection, type DocSectionProps, EXECUTIVE_SCHEMA_VERSION, Equation, type ExecutiveData, type ExecutiveProblem, ExecutiveView, type ExecutiveViewProps, FLIP_LIMITS, FLIP_TEXT, FOCUS_PARAM, FOCUS_TEXT, FOUR_CS, Figure,
|
|
1349
|
+
export { BREAKPOINTS, BarChart, type BarChartProps, type BarDatum, BiText, Callout, CardDeck, type CardDeckProps, type CaseDef, type CaseFocusConfig, type CaseGroup, type CaseKind, CaseSelector, type CaseSelectorProps, type CaseSelectorText, CaseWorkbench, type CaseWorkbenchProps, ChipGroup, type ChipGroupProps, type ChipOption, type Citation, CitationsProvider, Cite, DECK_TEXT, DOC_AREAS, type DeckCard, DocPage, type DocPageProps, DocReferences, DocRefsScope, DocSection, type DocSectionProps, EXECUTIVE_SCHEMA_VERSION, Equation, type ExecutiveData, type ExecutiveProblem, ExecutiveView, type ExecutiveViewProps, FLIP_LIMITS, FLIP_TEXT, FOCUS_PARAM, FOCUS_TEXT, FOUR_CS, Figure, FlipCard, type FlipCardProps, type FocusMode, type FocusModeConfig, type FocusModeOptions, FocusShell, type FocusShellProps, FormatOptions, Gauge, type GaugeProps, type GaugeZone, Glossary, type GlossaryEntry, InlineMath, Knob, type KnobProps, Landing, type Lane, LaneBadge, Lang, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, type PausedVizController, PlotCard, type PlotCardProps, type Provenance, Question, type QuestionProps, type RailSection, Readout, type ReadoutItem, type ReadoutProps, ReferenceList, Refs, Stage, type StageSize, Stat, type StatProps, type SubTabDef, SubTabs, type SubTabsProps, type SurfaceFocusConfig, 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, type ViewFocusConfig, 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, deckPosition, deckWindow, firstAppearance, groupByCategory, isStale, makeStateKey, perPageFor, readCaseParam, readTheme, removeQueryParam, replaceQueryParam, sourcesPresent, useFocusMode, usePausedViz, useStageSize, useThemeStore, useUrlView, useWorkbenchState, validateExecutive, viewParamOf, withCaseParam };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, widestLabel, fitLabel, formatTicks, niceTicks, textWidth, formatNumber, NBSP } from './chunk-DBCMAL2G.js';
|
|
2
|
+
export { NBSP, NOT_AVAILABLE, SCIENTIFIC_BELOW, SHELL_TOKENS, Stage, applyTheme, fitLabel, fontFamily, formatNumber, formatTicks, niceStep, niceTicks, pick, readTheme, resolveToken, textWidth, useFormat, useLangStore, useShellLang, useStageSize, useThemeStore, useThemeTokens, widestLabel } from './chunk-DBCMAL2G.js';
|
|
3
3
|
import { APP_ROUTE, LANDING_ROUTE } from './chunk-33WTUQ7Q.js';
|
|
4
4
|
export { APP_ROUTE, LANDING_ROUTE, LANG_STORAGE_KEY, STANDARD_ROUTES, THEME_BOOT_SCRIPT, THEME_STORAGE_KEY } from './chunk-33WTUQ7Q.js';
|
|
5
5
|
import { createContext, Component, useState, useRef, useId, useEffect, useLayoutEffect, useCallback, useContext, useMemo, Children, isValidElement } from 'react';
|
|
@@ -795,17 +795,64 @@ function CaseSelector(props) {
|
|
|
795
795
|
const visible = casesInSource(cases, source);
|
|
796
796
|
const groups = groupByCategory(visible);
|
|
797
797
|
const modified = cases.find((c) => c.id === modifiedFromId) ?? null;
|
|
798
|
+
const wrapRef = useRef(null);
|
|
799
|
+
const [minHeight, setMinHeight] = useState(null);
|
|
800
|
+
const nameKey = visible.map((c) => c.name).join("");
|
|
801
|
+
useLayoutEffect(() => {
|
|
802
|
+
const wrap = wrapRef.current;
|
|
803
|
+
const display = wrap?.querySelector(".cs-select-display");
|
|
804
|
+
if (!wrap || !display) return void 0;
|
|
805
|
+
const names = nameKey ? nameKey.split("") : [];
|
|
806
|
+
const measure = () => {
|
|
807
|
+
const st = getComputedStyle(display);
|
|
808
|
+
const room = display.clientWidth - parseFloat(st.paddingLeft) - parseFloat(st.paddingRight);
|
|
809
|
+
if (!(room > 0)) return;
|
|
810
|
+
const copy = document.createElement("span");
|
|
811
|
+
copy.className = "cs-select-text";
|
|
812
|
+
copy.setAttribute("aria-hidden", "true");
|
|
813
|
+
copy.setAttribute("style", `position:absolute;visibility:hidden;left:0;top:0;width:${room}px;display:block;overflow:visible;max-height:none;-webkit-line-clamp:unset;line-clamp:unset`);
|
|
814
|
+
display.append(copy);
|
|
815
|
+
let tallest = 0;
|
|
816
|
+
for (const n of names) {
|
|
817
|
+
copy.textContent = n;
|
|
818
|
+
tallest = Math.max(tallest, copy.getBoundingClientRect().height);
|
|
819
|
+
}
|
|
820
|
+
const line = parseFloat(getComputedStyle(copy).lineHeight) || parseFloat(st.fontSize) * 1.25;
|
|
821
|
+
copy.remove();
|
|
822
|
+
const frame = parseFloat(st.paddingTop) + parseFloat(st.paddingBottom) + parseFloat(st.borderTopWidth) + parseFloat(st.borderBottomWidth);
|
|
823
|
+
const next = tallest > line * 1.5 ? Math.ceil((tallest + frame) * 100) / 100 : null;
|
|
824
|
+
setMinHeight((prev) => prev === next ? prev : next);
|
|
825
|
+
};
|
|
826
|
+
measure();
|
|
827
|
+
let width = wrap.getBoundingClientRect().width;
|
|
828
|
+
const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => {
|
|
829
|
+
const w = wrap.getBoundingClientRect().width;
|
|
830
|
+
if (w !== width) {
|
|
831
|
+
width = w;
|
|
832
|
+
measure();
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
ro?.observe(wrap);
|
|
836
|
+
void document.fonts?.ready.then(measure);
|
|
837
|
+
return () => ro?.disconnect();
|
|
838
|
+
}, [layout, nameKey]);
|
|
839
|
+
const options = groups.flatMap((g) => g.cases);
|
|
840
|
+
const selectedName = (options.find((c) => c.id === selectedId) ?? options.find((c) => !c.disabled))?.name ?? "";
|
|
798
841
|
const select = /* @__PURE__ */ jsx(
|
|
799
842
|
"select",
|
|
800
843
|
{
|
|
801
844
|
"data-control": "case",
|
|
802
|
-
className: "select cs-select",
|
|
845
|
+
className: "select cs-select cs-select-native",
|
|
803
846
|
"aria-label": ariaLabel ?? "Case selector",
|
|
804
847
|
value: selectedId,
|
|
805
848
|
onChange: (e) => onSelect(e.target.value),
|
|
806
849
|
children: groups.map((g) => /* @__PURE__ */ jsx("optgroup", { label: g.category || " ", children: g.cases.map((c) => /* @__PURE__ */ jsx("option", { value: c.id, disabled: c.disabled, title: caseTooltip(c) || void 0, children: c.name }, c.id)) }, g.category || "_"))
|
|
807
850
|
}
|
|
808
851
|
);
|
|
852
|
+
const selectBox = /* @__PURE__ */ jsxs("div", { className: "cs-select-wrap", ref: wrapRef, children: [
|
|
853
|
+
/* @__PURE__ */ jsx("div", { className: "cs-select-display", style: minHeight === null ? void 0 : { minHeight }, "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "cs-select-text", children: selectedName }) }),
|
|
854
|
+
select
|
|
855
|
+
] });
|
|
809
856
|
return /* @__PURE__ */ jsxs("div", { className: `cs${className ? ` ${className}` : ""}`, role: "group", "aria-label": ariaLabel ?? "Case selector", children: [
|
|
810
857
|
source && lanes.length > 1 && /* @__PURE__ */ jsxs("div", { className: "cs-source", children: [
|
|
811
858
|
/* @__PURE__ */ jsx("span", { className: "cs-source-label", children: t2.source }),
|
|
@@ -824,9 +871,9 @@ function CaseSelector(props) {
|
|
|
824
871
|
] }),
|
|
825
872
|
source && source !== "synthetic" && /* @__PURE__ */ jsx("p", { className: "cs-locked banner", children: lockedNote ?? t2.lockedNote }),
|
|
826
873
|
layout === "select" && (props.accessory ? /* @__PURE__ */ jsxs("div", { className: "cs-select-row", children: [
|
|
827
|
-
|
|
874
|
+
selectBox,
|
|
828
875
|
props.accessory
|
|
829
|
-
] }) :
|
|
876
|
+
] }) : selectBox),
|
|
830
877
|
layout === "chips" && groups.map((g) => /* @__PURE__ */ jsxs("div", { className: "cs-group", role: "group", "aria-label": g.category || void 0, "data-control": "case", children: [
|
|
831
878
|
g.category && /* @__PURE__ */ jsx("span", { className: "cs-group-label", children: g.category }),
|
|
832
879
|
/* @__PURE__ */ jsx("div", { className: "cs-chips", children: g.cases.map((c) => {
|
|
@@ -2045,7 +2092,7 @@ function executiveTextFields(d) {
|
|
|
2045
2092
|
add("title", d.title, 1);
|
|
2046
2093
|
add("key_statement", d.key_statement, 2);
|
|
2047
2094
|
d.headline_figures.forEach((f, i) => figure(`headline_figures[${i}]`, f));
|
|
2048
|
-
const { pain, context
|
|
2095
|
+
const { pain, context, situation, trends, proposal } = d;
|
|
2049
2096
|
add("pain.key_message", pain.key_message, 1);
|
|
2050
2097
|
pain.paragraphs.forEach((p, i) => add(`pain.paragraphs[${i}]`, p, void 0, EXEC_LIMITS.minParagraphWords));
|
|
2051
2098
|
pain.bearers.forEach((b, i) => {
|
|
@@ -2055,11 +2102,11 @@ function executiveTextFields(d) {
|
|
|
2055
2102
|
});
|
|
2056
2103
|
pain.figures.forEach((f, i) => figure(`pain.figures[${i}]`, f));
|
|
2057
2104
|
pain.causes.forEach((c, i) => add(`pain.causes[${i}].cause`, c.cause));
|
|
2058
|
-
add("context.key_message",
|
|
2059
|
-
|
|
2060
|
-
add("context.setting",
|
|
2061
|
-
|
|
2062
|
-
|
|
2105
|
+
add("context.key_message", context.key_message, 1);
|
|
2106
|
+
context.paragraphs.forEach((p, i) => add(`context.paragraphs[${i}]`, p, void 0, EXEC_LIMITS.minParagraphWords));
|
|
2107
|
+
add("context.setting", context.setting);
|
|
2108
|
+
context.forces.forEach((f, i) => add(`context.forces[${i}].force`, f.force));
|
|
2109
|
+
context.evidence.forEach((e, i) => add(`context.evidence[${i}].statement`, e.statement, 1));
|
|
2063
2110
|
add("situation.key_message", situation.key_message, 1);
|
|
2064
2111
|
situation.roles.forEach((r, i) => {
|
|
2065
2112
|
add(`situation.roles[${i}].role`, r.role);
|
|
@@ -3086,74 +3133,6 @@ var BREAKPOINTS = {
|
|
|
3086
3133
|
/** The gate's large screen: the viewport rules of ADR-0071 are measured from here up. */
|
|
3087
3134
|
large: 1280
|
|
3088
3135
|
};
|
|
3089
|
-
|
|
3090
|
-
// src/chart/text.ts
|
|
3091
|
-
var context;
|
|
3092
|
-
function fontFamily() {
|
|
3093
|
-
if (typeof document === "undefined") return "sans-serif";
|
|
3094
|
-
return getComputedStyle(document.documentElement).getPropertyValue("--font-sans").trim() || "sans-serif";
|
|
3095
|
-
}
|
|
3096
|
-
function textWidth(text, px, weight = 400) {
|
|
3097
|
-
if (context === void 0) {
|
|
3098
|
-
try {
|
|
3099
|
-
context = typeof document === "undefined" ? null : document.createElement("canvas").getContext("2d");
|
|
3100
|
-
} catch {
|
|
3101
|
-
context = null;
|
|
3102
|
-
}
|
|
3103
|
-
}
|
|
3104
|
-
if (!context) return text.length * px * 0.62;
|
|
3105
|
-
context.font = `${weight} ${px}px ${fontFamily()}`;
|
|
3106
|
-
return context.measureText(text).width;
|
|
3107
|
-
}
|
|
3108
|
-
function widestLabel(labels, px, weight = 400) {
|
|
3109
|
-
return Math.max(0, ...labels.map((label) => textWidth(label, px, weight)));
|
|
3110
|
-
}
|
|
3111
|
-
function shorten(line, width, px) {
|
|
3112
|
-
if (textWidth(line, px) <= width) return line;
|
|
3113
|
-
let cut = line;
|
|
3114
|
-
while (cut.length > 1 && textWidth(`${cut}\u2026`, px) > width) cut = cut.slice(0, -1);
|
|
3115
|
-
return `${cut.trimEnd()}\u2026`;
|
|
3116
|
-
}
|
|
3117
|
-
function fitLabel(label, width, px, maxLines = 2) {
|
|
3118
|
-
if (textWidth(label, px) <= width) return { lines: [label], shortened: false };
|
|
3119
|
-
const words = label.split(" ");
|
|
3120
|
-
if (maxLines === 2 && words.length > 1) {
|
|
3121
|
-
let best = null;
|
|
3122
|
-
let bestWidth = Infinity;
|
|
3123
|
-
for (let k = 1; k < words.length; k += 1) {
|
|
3124
|
-
const first = words.slice(0, k).join(" ");
|
|
3125
|
-
const second = words.slice(k).join(" ");
|
|
3126
|
-
const widest = Math.max(textWidth(first, px), textWidth(second, px));
|
|
3127
|
-
if (widest < bestWidth) {
|
|
3128
|
-
bestWidth = widest;
|
|
3129
|
-
best = [first, second];
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
if (best && bestWidth <= width) return { lines: best, shortened: false };
|
|
3133
|
-
if (best) return { lines: [shorten(best[0], width, px), shorten(best[1], width, px)], shortened: true };
|
|
3134
|
-
}
|
|
3135
|
-
return { lines: [shorten(label, width, px)], shortened: true };
|
|
3136
|
-
}
|
|
3137
|
-
function niceStep(x) {
|
|
3138
|
-
if (!(x > 0) || !Number.isFinite(x)) return 1;
|
|
3139
|
-
const magnitude = 10 ** Math.floor(Math.log10(x));
|
|
3140
|
-
return ([1, 2, 2.5, 5, 10].find((m) => m * magnitude >= x * (1 - 1e-12)) ?? 10) * magnitude;
|
|
3141
|
-
}
|
|
3142
|
-
function niceTicks(lo, hi, room, labelSize, most = 6) {
|
|
3143
|
-
if (!Number.isFinite(lo) || !Number.isFinite(hi)) return [0];
|
|
3144
|
-
if (hi < lo) [lo, hi] = [hi, lo];
|
|
3145
|
-
if (hi === lo) hi = lo === 0 ? 1 : lo + Math.abs(lo);
|
|
3146
|
-
const count = Math.max(2, Math.min(most, Math.floor(room / (labelSize + 16)) + 1));
|
|
3147
|
-
const step = niceStep((hi - lo) / (count - 1));
|
|
3148
|
-
const first = Math.floor(lo / step + 1e-9) * step;
|
|
3149
|
-
const ticks = [];
|
|
3150
|
-
for (let k = 0; first + k * step <= hi + step * 1e-9 || ticks.length < 2; k += 1) {
|
|
3151
|
-
ticks.push(Number((first + k * step).toPrecision(12)));
|
|
3152
|
-
if (ticks.length > 50) break;
|
|
3153
|
-
}
|
|
3154
|
-
if (ticks[ticks.length - 1] < hi - step * 1e-9) ticks.push(Number((ticks[ticks.length - 1] + step).toPrecision(12)));
|
|
3155
|
-
return ticks;
|
|
3156
|
-
}
|
|
3157
3136
|
var PX = 11;
|
|
3158
3137
|
var LINE = 13;
|
|
3159
3138
|
var TONE = {
|
|
@@ -3442,7 +3421,7 @@ function panel(id, lane, provenance, content) {
|
|
|
3442
3421
|
return /* @__PURE__ */ jsx("div", { className: "caos-cw-panel", "data-group": id, "data-lane": lane, "data-provenance": provenance, children: content });
|
|
3443
3422
|
}
|
|
3444
3423
|
function CaseWorkbench(props) {
|
|
3445
|
-
const { caseId, cases, source, controls, replayOnly, variants, rail, railLabel, groups, compare, context
|
|
3424
|
+
const { caseId, cases, source, controls, replayOnly, variants, rail, railLabel, groups, compare, context, group, onGroupChange, deepLinkView = true, ariaLabel, focus } = props;
|
|
3446
3425
|
const lang = useShellLang();
|
|
3447
3426
|
const focusCfg = focus === true ? {} : focus || null;
|
|
3448
3427
|
const { show: showFocus, setFocus, enterRef, memory } = useFocusMode(focusCfg);
|
|
@@ -3462,8 +3441,8 @@ function CaseWorkbench(props) {
|
|
|
3462
3441
|
}
|
|
3463
3442
|
tabs.push({
|
|
3464
3443
|
id: "context",
|
|
3465
|
-
label: pick(
|
|
3466
|
-
content: /* @__PURE__ */ jsx("div", { className: "prose caos-cw-context", children:
|
|
3444
|
+
label: pick(context.label ?? { en: "Context", es: "Contexto" }, lang),
|
|
3445
|
+
content: /* @__PURE__ */ jsx("div", { className: "prose caos-cw-context", children: context.content })
|
|
3467
3446
|
});
|
|
3468
3447
|
if (tabs.length > MAX_WORKBENCH_GROUPS) {
|
|
3469
3448
|
throw new Error(
|
|
@@ -3487,19 +3466,12 @@ function CaseWorkbench(props) {
|
|
|
3487
3466
|
]
|
|
3488
3467
|
}
|
|
3489
3468
|
);
|
|
3490
|
-
const besideSelect = Boolean(cases && (cases.layout ?? "chips") === "select");
|
|
3491
3469
|
const pickers = cases || variants ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3492
|
-
cases && /* @__PURE__ */ jsx(CaseSelector, { lang, ...cases
|
|
3493
|
-
variants && /* @__PURE__ */ jsx(VariantBar, { ...variants })
|
|
3494
|
-
] }) : null;
|
|
3495
|
-
const focusPickers = cases || variants ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3496
|
-
cases && /* @__PURE__ */ jsx(CaseSelector, { lang, ...cases, accessory: cases.accessory }),
|
|
3470
|
+
cases && /* @__PURE__ */ jsx(CaseSelector, { lang, ...cases }),
|
|
3497
3471
|
variants && /* @__PURE__ */ jsx(VariantBar, { ...variants })
|
|
3498
3472
|
] }) : null;
|
|
3499
|
-
const railHead = pickers
|
|
3500
|
-
|
|
3501
|
-
besideSelect ? null : enter
|
|
3502
|
-
] }) : null;
|
|
3473
|
+
const railHead = pickers;
|
|
3474
|
+
const focusPickers = pickers;
|
|
3503
3475
|
const instrumentData = {
|
|
3504
3476
|
"data-case-workbench": "",
|
|
3505
3477
|
"data-group-count": tabs.length,
|
|
@@ -3533,7 +3505,8 @@ function CaseWorkbench(props) {
|
|
|
3533
3505
|
tabs,
|
|
3534
3506
|
value: openGroup,
|
|
3535
3507
|
onChange: selectGroup,
|
|
3536
|
-
ariaLabel: pick(ariaLabel ?? { en: "Case views", es: "Vistas del caso" }, lang)
|
|
3508
|
+
ariaLabel: pick(ariaLabel ?? { en: "Case views", es: "Vistas del caso" }, lang),
|
|
3509
|
+
trailing: enter || void 0
|
|
3537
3510
|
}
|
|
3538
3511
|
) }) }) }) });
|
|
3539
3512
|
}
|
|
@@ -3737,4 +3710,4 @@ function ViewsRow({ children, shares }) {
|
|
|
3737
3710
|
}) });
|
|
3738
3711
|
}
|
|
3739
3712
|
|
|
3740
|
-
export { AppShell, ArchitectureModal, BREAKPOINTS, BarChart, Callout, CardDeck, CaseSelector, CaseWorkbench, ChipGroup, CitationsProvider, Cite, DECK_TEXT, DOC_AREAS, DocPage, DocReferences, DocRefsScope, DocSection, EXECUTIVE_SCHEMA_VERSION, Equation, ExecutiveView, FLIP_LIMITS, FLIP_TEXT, FOCUS_PARAM, FOCUS_TEXT, FOUR_CS, Figure, FlipCard, FocusShell, Gauge, Glossary, InlineMath, Knob, Landing, LaneBadge, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, PlotCard, Question, Readout, ReferenceList, Refs, Stat, SubTabs, SurfacePage, TabGroups, Tabs, ThemeToggle, VariantBar, Verdict, ViewsRow, WorkbenchLayout, WorkbenchShell, WorkbenchStateContext, caseKind, caseTooltip, casesInSource, createVizLoop, deckPosition, deckWindow, firstAppearance,
|
|
3713
|
+
export { AppShell, ArchitectureModal, BREAKPOINTS, BarChart, Callout, CardDeck, CaseSelector, CaseWorkbench, ChipGroup, CitationsProvider, Cite, DECK_TEXT, DOC_AREAS, DocPage, DocReferences, DocRefsScope, DocSection, EXECUTIVE_SCHEMA_VERSION, Equation, ExecutiveView, FLIP_LIMITS, FLIP_TEXT, FOCUS_PARAM, FOCUS_TEXT, FOUR_CS, Figure, FlipCard, FocusShell, Gauge, Glossary, InlineMath, Knob, Landing, LaneBadge, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, PlotCard, Question, Readout, ReferenceList, Refs, Stat, SubTabs, SurfacePage, TabGroups, Tabs, ThemeToggle, VariantBar, Verdict, ViewsRow, WorkbenchLayout, WorkbenchShell, WorkbenchStateContext, caseKind, caseTooltip, casesInSource, createVizLoop, deckPosition, deckWindow, firstAppearance, groupByCategory, isStale, makeStateKey, perPageFor, readCaseParam, removeQueryParam, replaceQueryParam, sourcesPresent, useFocusMode, usePausedViz, useUrlView, useWorkbenchState, validateArchitectureConfig, validateExecutive, viewParamOf, withCaseParam };
|
|
@@ -58,4 +58,42 @@ declare function resolveToken(token: string, fallback?: string): string;
|
|
|
58
58
|
*/
|
|
59
59
|
declare function useThemeTokens(): Record<ShellToken, string>;
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Text that fits the drawing it labels, measured in the font the page renders.
|
|
63
|
+
*
|
|
64
|
+
* Products drew their axes and labels with fixed margins and a fixed width per character. The Linux fonts (DejaVu
|
|
65
|
+
* Sans) are wider than the Windows ones and Spanish labels are longer than English ones, so a column sized for one
|
|
66
|
+
* ran its labels out of the drawing in the other (CAOS_Fragmenta 0.05.000: "Tamaño medio clásico, limitado al bloque
|
|
67
|
+
* in situ" read "dio clásico, limitado al bloque in situ"; its deploy gate failed on Linux). Here a label is measured
|
|
68
|
+
* with the canvas text metrics of the page's own font (`--font-sans`, which the gate's wide-font pass replaces),
|
|
69
|
+
* broken over two lines at a word when it does not fit, and only then shortened with an ellipsis, so the drawing can
|
|
70
|
+
* give the whole label as its title. Ported from CAOS_Fragmenta `viz/text.ts` (0.07.000).
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
/** The name of a reference line that has no label, for the handle a reader drags (a screen reader says it): numbered when
|
|
74
|
+
* several unlabelled lines of one chart can be dragged, so each handle has a name of its own. */
|
|
75
|
+
declare function referenceLineName(lang: Lang, n: number, of: number): string;
|
|
76
|
+
/** The page's sans-serif stack as the shell token resolves it. */
|
|
77
|
+
declare function fontFamily(): string;
|
|
78
|
+
/** The width of one line of text at a font size, in CSS pixels; outside a browser, an estimate on the wide side. */
|
|
79
|
+
declare function textWidth(text: string, px: number, weight?: number): number;
|
|
80
|
+
/** The widest a set of labels needs, each on one line. */
|
|
81
|
+
declare function widestLabel(labels: readonly string[], px: number, weight?: number): number;
|
|
82
|
+
interface FittedLabel {
|
|
83
|
+
/** One or two lines; the last is shortened with an ellipsis only when the lines allowed are not enough. */
|
|
84
|
+
lines: string[];
|
|
85
|
+
/** Whether the label was shortened, so the drawing gives the whole label as its title. */
|
|
86
|
+
shortened: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** A label in at most `maxLines` lines of `width` pixels: whole when it fits, broken at a word, shortened last. */
|
|
89
|
+
declare function fitLabel(label: string, width: number, px: number, maxLines?: 1 | 2): FittedLabel;
|
|
90
|
+
/** The 1, 2, 2.5 or 5 times a power of ten at or above `x`. */
|
|
91
|
+
declare function niceStep(x: number): number;
|
|
92
|
+
/**
|
|
93
|
+
* Round ticks covering [lo, hi], as many as leave room for labels about `labelSize` pixels along an axis of `room`
|
|
94
|
+
* pixels (at least two, at most `most`). The first tick is at or below `lo` and the last at or above `hi`, so a bar
|
|
95
|
+
* or a point never runs past the last labelled value.
|
|
96
|
+
*/
|
|
97
|
+
declare function niceTicks(lo: number, hi: number, room: number, labelSize: number, most?: number): number[];
|
|
98
|
+
|
|
99
|
+
export { type FormatOptions as F, NBSP as N, type ShellColorToken as S, type FittedLabel as a, NOT_AVAILABLE as b, SCIENTIFIC_BELOW as c, SHELL_TOKENS as d, type ShellToken as e, fitLabel as f, fontFamily as g, formatNumber as h, formatTicks as i, niceTicks as j, resolveToken as k, useThemeTokens as l, niceStep as n, referenceLineName as r, textWidth as t, useFormat as u, widestLabel as w };
|
package/gate/inpage.mjs
CHANGED
|
@@ -181,6 +181,67 @@ export function installLib() {
|
|
|
181
181
|
};
|
|
182
182
|
};
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Selects whose selected option does not fit the room it leaves, or a case select that shows another name than the one it holds (BL-074, shell
|
|
186
|
+
* 0.17.0; the reviews of 0.17.0). What is measured is what the reader sees:
|
|
187
|
+
* - a select with the shell's display (`.cs-select-wrap`, the case select since the trial of 0.17.0) shows the name whole at any length in the
|
|
188
|
+
* display's real `.cs-select-text` element: the name is cut when that element overflows its box (`scrollHeight` or `scrollWidth` past its
|
|
189
|
+
* `clientHeight` or `clientWidth` by more than 1px, e.g. a product stylesheet that clamps it), measured on the element itself, never on a probe
|
|
190
|
+
* copy, and when the display's own box is smaller than its content (a product stylesheet that fixes its height); the display is stale when the name it shows, whitespace normalized, differs from the text of the option the select holds;
|
|
191
|
+
* - any other select shows its text on one line: the room is its width less its own CSS padding and less the native arrow, which is
|
|
192
|
+
* measured, not assumed (a probe select of the same class holding one character, sized to its content; 0 with `appearance: none`).
|
|
193
|
+
* Plain text is measured with the select's own font on one canvas. Runs in the App and inside Focus (its rail holds a case select too).
|
|
194
|
+
*/
|
|
195
|
+
const selectCuts = () => {
|
|
196
|
+
const cuts = [];
|
|
197
|
+
const mctx = document.createElement('canvas').getContext('2d');
|
|
198
|
+
const norm = (t) => (t ?? '').trim().replace(/\s+/g, ' ');
|
|
199
|
+
for (const sel of document.querySelectorAll('select')) {
|
|
200
|
+
if (!mctx || !visible(sel)) continue;
|
|
201
|
+
const ss = getComputedStyle(sel);
|
|
202
|
+
const held = norm(sel.options[sel.selectedIndex]?.textContent);
|
|
203
|
+
const display = sel.closest('.cs-select-wrap')?.querySelector('.cs-select-display');
|
|
204
|
+
if (display) {
|
|
205
|
+
const t = display.querySelector('.cs-select-text') ?? display;
|
|
206
|
+
const shown = norm(t.textContent);
|
|
207
|
+
if (shown !== held) {
|
|
208
|
+
cuts.push(`${describe(sel)} shows "${shown}" while the select holds "${held}" (a stale display)`);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const overV = t.scrollHeight > t.clientHeight + 1;
|
|
212
|
+
const overH = t.scrollWidth > t.clientWidth + 1;
|
|
213
|
+
if (overV || overH) {
|
|
214
|
+
const line = Number.parseFloat(getComputedStyle(t).lineHeight) || 1;
|
|
215
|
+
cuts.push(`${describe(sel)} cuts the case name "${shown}" (the name needs ${Math.round(t.scrollHeight / line)} lines, ${Math.round(t.scrollHeight)}px high and ${Math.round(t.scrollWidth)}px wide, and its box holds ${Math.round(t.clientHeight)}px by ${Math.round(t.clientWidth)}px; held option "${held}")`);
|
|
216
|
+
} else if (display.scrollHeight > display.clientHeight + 1 || display.scrollWidth > display.clientWidth + 1) {
|
|
217
|
+
// the text fits its own box but the display's box is smaller (a product stylesheet that fixes the display's height)
|
|
218
|
+
cuts.push(`${describe(sel)} cuts the case name "${shown}" in its display (the name needs ${Math.round(display.scrollHeight)}px by ${Math.round(display.scrollWidth)}px, the display holds ${Math.round(display.clientHeight)}px by ${Math.round(display.clientWidth)}px; held option "${held}")`);
|
|
219
|
+
}
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const text = held;
|
|
223
|
+
if (!text) continue;
|
|
224
|
+
mctx.font = `${ss.fontStyle} ${ss.fontWeight} ${ss.fontSize} ${ss.fontFamily}`;
|
|
225
|
+
const pad = Number.parseFloat(ss.paddingLeft) + Number.parseFloat(ss.paddingRight);
|
|
226
|
+
let arrow = 0;
|
|
227
|
+
const host = sel.parentElement;
|
|
228
|
+
if (host) {
|
|
229
|
+
const probe = sel.cloneNode(false);
|
|
230
|
+
for (const a of [...probe.attributes]) if (a.name !== 'class') probe.removeAttribute(a.name);
|
|
231
|
+
probe.append(new Option('x'));
|
|
232
|
+
probe.setAttribute('style', 'position:absolute;visibility:hidden;width:auto;min-width:0;max-width:none;flex:none;left:0;top:0');
|
|
233
|
+
host.append(probe);
|
|
234
|
+
const pv = getComputedStyle(probe);
|
|
235
|
+
arrow = Math.max(0, probe.clientWidth - Number.parseFloat(pv.paddingLeft) - Number.parseFloat(pv.paddingRight) - mctx.measureText('x').width);
|
|
236
|
+
probe.remove();
|
|
237
|
+
}
|
|
238
|
+
const need = mctx.measureText(text).width;
|
|
239
|
+
const has = sel.clientWidth - pad - arrow;
|
|
240
|
+
if (need > has + 1) cuts.push(`${describe(sel)} cuts "${text}" (${Math.round(need)}px of text in ${Math.round(has)}px of room, the ${Math.round(arrow)}px arrow taken out)`);
|
|
241
|
+
}
|
|
242
|
+
return cuts;
|
|
243
|
+
};
|
|
244
|
+
|
|
184
245
|
/** The static layout of the current view (G5, G6 inputs, ADR-0071 and ADR-0017 measures). */
|
|
185
246
|
G.facts = () => {
|
|
186
247
|
const vw = window.innerWidth;
|
|
@@ -272,6 +333,8 @@ export function installLib() {
|
|
|
272
333
|
if (!named) truncated.push(describe(el));
|
|
273
334
|
}
|
|
274
335
|
|
|
336
|
+
const cutSelects = selectCuts();
|
|
337
|
+
|
|
275
338
|
// Containers that cut their content: overflow hidden or clip with more content than box (S1, G5).
|
|
276
339
|
const clipped = [];
|
|
277
340
|
const containers = new Set([de, body, document.getElementById('root'), ...document.querySelectorAll('main, .page, .page-body, [data-instrument], [data-rail], .tabpanel, .caos-cw, [data-plot]')]);
|
|
@@ -415,6 +478,8 @@ export function installLib() {
|
|
|
415
478
|
rail,
|
|
416
479
|
truncated: truncated.slice(0, 5),
|
|
417
480
|
truncatedCount: truncated.length,
|
|
481
|
+
cutSelects: cutSelects.slice(0, 5),
|
|
482
|
+
cutSelectCount: cutSelects.length,
|
|
418
483
|
clipped,
|
|
419
484
|
instrument,
|
|
420
485
|
surfaces,
|
|
@@ -433,7 +498,7 @@ export function installLib() {
|
|
|
433
498
|
// charts whose axis gives a tick the label of the tick before it (UPlotChart declares data-ticks-repeat)
|
|
434
499
|
repeatedTicks: [...document.querySelectorAll('[data-ticks-repeat]')]
|
|
435
500
|
.filter((el) => visible(el) && Number(el.getAttribute('data-ticks-repeat')) > 0)
|
|
436
|
-
.map((el) => ({ label: describe(el.closest('[data-plot]') || el), n: Number(el.getAttribute('data-ticks-repeat')) })),
|
|
501
|
+
.map((el) => ({ label: describe(el.closest('[data-plot]') || el), n: Number(el.getAttribute('data-ticks-repeat')), names: el.getAttribute('data-ticks-repeated') || '' })),
|
|
437
502
|
// the drawing a filling card keeps under its note (G6 stage floor): the body of every visible `PlotCard fill`
|
|
438
503
|
fillStages: [...document.querySelectorAll('.caos-plot.fill')]
|
|
439
504
|
.filter(visible)
|
|
@@ -1063,6 +1128,7 @@ export function installLib() {
|
|
|
1063
1128
|
return {
|
|
1064
1129
|
focus: Boolean(shell),
|
|
1065
1130
|
covered,
|
|
1131
|
+
cutSelects: (() => { const c = selectCuts(); return { count: c.length, list: c.slice(0, 5) }; })(),
|
|
1066
1132
|
enterInside: [...document.querySelectorAll('[data-focus-shell] [data-focus-enter]')].filter(visible).length,
|
|
1067
1133
|
app: Boolean(document.querySelector('[data-workbench], [data-surface]')),
|
|
1068
1134
|
caseId: stage ? stage.getAttribute('data-case') : null,
|
package/gate/run.mjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// G4 deep links every route loaded directly (and with a trailing slash), 200 and rendered; artifacts
|
|
9
9
|
// are JSON, not the HTML fallback; a missing asset answers 404; doc text clears a floor
|
|
10
10
|
// G5 scroll and reach boxes inside the viewport, the rail and their scrollers; tall views scroll; nothing is
|
|
11
|
-
// cut; truncated text carries its full text; every control reachable by the pointer
|
|
11
|
+
// cut; truncated text carries its full text; a select shows its whole selected text (0.17.0); every control reachable by the pointer
|
|
12
12
|
// G6 painted area drawing surfaces have painted pixels, fill their stage, and cover at least half the
|
|
13
13
|
// viewport on the App route, measured on the screenshot, never on a host box
|
|
14
14
|
// G7 walk everything every route, tab, sub-tab and case, at five sizes, both themes, both languages,
|
|
@@ -269,6 +269,15 @@ export async function runGate(o) {
|
|
|
269
269
|
fail('G18', { route: appRoute, mode: 'routes' }, `the App route ${appRoute} is not among the measured routes (${routes.join(', ') || 'none'}): with --workbench '' and --require-focus the gate measures the App as a surface and must walk it; add it to --routes or name it with --app-route`);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
// ---- G18 on a workbench App (shell 0.17.0): under --require-focus every workbench route must be among the measured routes, or no Focus would be measured
|
|
273
|
+
if (opt.requireFocus) {
|
|
274
|
+
for (const wr of workbenchRoutes) {
|
|
275
|
+
if (!routes.includes(wr)) {
|
|
276
|
+
fail('G18', { route: wr, mode: 'routes' }, `the workbench route ${wr} is not among the measured routes (${routes.join(', ') || 'none'}): with --require-focus the gate must walk the App to measure its Focus mode; add it to --routes or drop it from --workbench`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
272
281
|
// ---- The landing (shell 0.13.0): the root opens the Introduction on its executive view; an old App link with a query string reaches the App.
|
|
273
282
|
{
|
|
274
283
|
const ctx = await openContext(primarySize, themes[0], langs[0]);
|
|
@@ -460,6 +469,7 @@ export async function runGate(o) {
|
|
|
460
469
|
if (f.rail.outsideCount) fail('G5', where, `${f.rail.outsideCount} rail element(s) outside the rail: ${f.rail.outside.join('; ')}`);
|
|
461
470
|
}
|
|
462
471
|
if (f.truncatedCount) fail('G5', where, `${f.truncatedCount} truncated text(s) without the full text in a title: ${f.truncated.join('; ')}`);
|
|
472
|
+
if (f.cutSelectCount) fail('G5', where, `${f.cutSelectCount} select(s) cut the selected text (a case name cut in its box, or a display that names another case than the one the select holds, or a plain select with a text wider than its room): ${f.cutSelects.join('; ')}`);
|
|
463
473
|
for (const c of f.clipped) fail('G5', where, c);
|
|
464
474
|
if (f.offCentre !== null && f.offCentre > 2) fail('ADR-0017.1', where, `the prose page is off-centre by ${f.offCentre.toFixed(1)}px`);
|
|
465
475
|
if (f.referenceLists) fail('ADR-0017.4', where, `${f.referenceLists} bibliography outside the end-of-page references block (a .reference-list); give each DocSection its refs and let the page list them once`);
|
|
@@ -471,7 +481,9 @@ export async function runGate(o) {
|
|
|
471
481
|
if (d) s.walkState.doc.push(d);
|
|
472
482
|
}
|
|
473
483
|
for (const r of f.repeatedTicks ?? []) {
|
|
474
|
-
|
|
484
|
+
// named x ticks (UPlotChart declares the repeated names): a name used twice, wherever the two ticks sit on the axis
|
|
485
|
+
if (r.names) fail('G6', where, `${r.label}: ${r.n} named x tick label(s) repeat another tick's label (${r.names.split('|').map((n) => `"${n}"`).join(', ')}); give every named tick a label of its own`);
|
|
486
|
+
else fail('G6', where, `${r.label}: ${r.n} axis tick label(s) repeat the label before them (give the axis fixed decimals)`);
|
|
475
487
|
}
|
|
476
488
|
// a filling card whose note leaves its drawing under the floor (CAOS_APP_SHELL#95); below 1280 px the document scrolls
|
|
477
489
|
if (big) for (const c of f.fillStages ?? []) if (c.h < opt.stageFloor) fail('G6', where, `the drawing of ${c.label} keeps ${Math.round(c.h)} px under its note (floor ${opt.stageFloor} px)`);
|
|
@@ -913,6 +925,7 @@ export async function runGate(o) {
|
|
|
913
925
|
if (big && f.share < opt.instrumentMin) fail('G18', at, `${label}: the stage covers ${(100 * f.share).toFixed(1)}% of the viewport (floor ${(100 * opt.instrumentMin).toFixed(0)}%)`);
|
|
914
926
|
if (f.exitInside === false) fail('G18', at, `${label}: the exit control is outside the viewport`);
|
|
915
927
|
for (const c of f.covered) fail('G18', at, `${label}: ${c.chrome} covers the control "${c.control}" (the stage must clear the Focus chrome)`);
|
|
928
|
+
if (f.cutSelects.count) fail('G5', at, `${label}: ${f.cutSelects.count} select(s) cut the selected text (a case name cut in its box, or a display that names another case than the one the select holds, or a plain select with a text wider than its room): ${f.cutSelects.list.join('; ')}`);
|
|
916
929
|
if (f.enterInside > 0) fail('G18', at, `${label}: the Focus control shows inside Focus mode (it opens the mode the reader is already in)`);
|
|
917
930
|
for (const m of await page.evaluate(() => window.__caosGate.drawingText())) fail('G10', at, m);
|
|
918
931
|
for (const m of await page.evaluate(() => window.__caosGate.brokenValues())) fail('G19', at, m);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fasl-work/caos-app-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"check:sdd": "python scripts/check_sdd.py ."
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"katex": "^0.16.0",
|
|
59
|
+
"katex": "^0.16.0 || ^0.17.0 || ^0.18.0 || ^0.19.0",
|
|
60
60
|
"lucide-react": ">=0.400.0",
|
|
61
61
|
"react": "^18 || ^19",
|
|
62
62
|
"react-dom": "^18 || ^19",
|
|
@@ -67,11 +67,10 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@playwright/test": "1.63.0",
|
|
70
|
-
"@types/katex": "^0.16.7",
|
|
71
70
|
"@types/react": "^19.0.0",
|
|
72
71
|
"@types/react-dom": "^19.0.0",
|
|
73
72
|
"esbuild": "0.28.1",
|
|
74
|
-
"katex": "
|
|
73
|
+
"katex": "0.19.0",
|
|
75
74
|
"lucide-react": "1.43.0",
|
|
76
75
|
"react": "^19.0.0",
|
|
77
76
|
"react-dom": "^19.0.0",
|
package/reserved-classes.json
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"caos-card",
|
|
26
26
|
"caos-chart",
|
|
27
27
|
"caos-chart-key",
|
|
28
|
+
"caos-chart-key-button",
|
|
28
29
|
"caos-chart-legend",
|
|
29
30
|
"caos-chart-plot",
|
|
30
31
|
"caos-chart-readout",
|
|
@@ -198,8 +199,11 @@
|
|
|
198
199
|
"cs-locked",
|
|
199
200
|
"cs-modified",
|
|
200
201
|
"cs-reset",
|
|
201
|
-
"cs-select",
|
|
202
|
+
"cs-select-display",
|
|
203
|
+
"cs-select-native",
|
|
202
204
|
"cs-select-row",
|
|
205
|
+
"cs-select-text",
|
|
206
|
+
"cs-select-wrap",
|
|
203
207
|
"cs-source",
|
|
204
208
|
"cs-source-label",
|
|
205
209
|
"cs-source-tabs",
|
|
@@ -335,6 +339,7 @@
|
|
|
335
339
|
"caos-card",
|
|
336
340
|
"caos-chart",
|
|
337
341
|
"caos-chart-key",
|
|
342
|
+
"caos-chart-key-button",
|
|
338
343
|
"caos-chart-legend",
|
|
339
344
|
"caos-chart-plot",
|
|
340
345
|
"caos-chart-readout",
|
|
@@ -512,8 +517,11 @@
|
|
|
512
517
|
"cs-locked",
|
|
513
518
|
"cs-modified",
|
|
514
519
|
"cs-reset",
|
|
515
|
-
"cs-select",
|
|
520
|
+
"cs-select-display",
|
|
521
|
+
"cs-select-native",
|
|
516
522
|
"cs-select-row",
|
|
523
|
+
"cs-select-text",
|
|
524
|
+
"cs-select-wrap",
|
|
517
525
|
"cs-source",
|
|
518
526
|
"cs-source-label",
|
|
519
527
|
"cs-source-tabs",
|