flowfig 0.11.0 → 0.12.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 +148 -21
- package/dist/atlas.js +6 -2
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +9 -4
- package/dist/check.d.ts +2 -2
- package/dist/check.js +135 -5
- package/dist/cli.js +174 -70
- package/dist/diff.d.ts +2 -0
- package/dist/diff.js +79 -24
- package/dist/element-looks.js +4 -0
- package/dist/element-world.js +6 -0
- package/dist/element.d.ts +27 -0
- package/dist/element.js +67 -0
- package/dist/explain.d.ts +45 -0
- package/dist/explain.js +161 -0
- package/dist/frames.d.ts +34 -0
- package/dist/frames.js +117 -0
- package/dist/index.js +283 -131
- package/dist/load.js +9 -4
- package/dist/looks.d.ts +15 -0
- package/dist/looks.js +32 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.js +14 -6
- package/dist/model.d.ts +97 -0
- package/dist/model.js +182 -1
- package/dist/scene.d.ts +2 -0
- package/dist/source.d.ts +4 -2
- package/dist/source.js +15 -9
- package/dist/svg.d.ts +12 -0
- package/dist/svg.js +235 -75
- package/dist/verify.d.ts +6 -0
- package/dist/verify.js +104 -56
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/world-art.d.ts +59 -0
- package/dist/world-art.js +854 -0
- package/dist/world.d.ts +233 -0
- package/dist/world.js +1577 -0
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import { createElement as _createElement } from "react";
|
|
2
3
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Fragment, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { Fragment, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
4
5
|
import { arcRoom, avoidOf, markSide, route } from './geometry.js';
|
|
5
6
|
import { foldedLabel, groupBox, layoutRail, railState, RAIL } from './rail.js';
|
|
6
7
|
import { textWidth } from './text.js';
|
|
7
8
|
import { checkScene, checkSpec, checkTheme } from './check.js';
|
|
8
9
|
import { autoLayout, rowBreaks } from './auto.js';
|
|
9
|
-
import { ASYNC_TAG_W, BASE_RATE, CARD_LINE, CARD_PAD, EDGE_OFF, EDGE_ON, LIGHT, TONES, ON_ACCENT, toneFill, toneTint, decisions, edgeId, groupGap, isGroup, isRows, lanePlan as planLanes, laneEnd, laneBlock, STUB_ROOM, labelPillW, str, altText, LANE_BLOCK_GAP, LANE_PAD, LANE_ROW_GAP, isLanesLayout, nodes, timelineBeats, timelineLayout, TL_AXIS_H, TL_AXIS_W, TL_BAR_H, TL_ROW_GAP, toBeat, diamondLines, diamondRoom, tightCopies, nodeWidth, labelLines, fitCap, LABEL_LINE, beatMs, STEP_HOLD_MS, playheadItem, loopStartItem, dateLabelRaised, edgeTip, fitScale, shownFont, textFloor, specKey, nextWide, } from './model.js';
|
|
10
|
+
import { ASYNC_TAG_W, BASE_RATE, CARD_LINE, CARD_PAD, EDGE_OFF, EDGE_ON, LIGHT, TONES, ON_ACCENT, toneFill, toneTint, decisions, edgeId, groupGap, isGroup, isRows, lanePlan as planLanes, laneEnd, laneBlock, STUB_ROOM, labelPillW, str, altText, LANE_BLOCK_GAP, LANE_PAD, LANE_ROW_GAP, isLanesLayout, nodes, timelineBeats, timelineLayout, TL_AXIS_H, TL_AXIS_W, TL_BAR_H, TL_ROW_GAP, toBeat, diamondLines, diamondRoom, tightCopies, nodeWidth, labelLines, fitCap, LABEL_LINE, beatMs, STEP_HOLD_MS, playheadItem, loopStartItem, dateLabelRaised, edgeTip, fitScale, shownFont, textFloor, specKey, nextWide, scenes, insideStep, flowOrder, readMs, portLabel, OPEN_MS, } from './model.js';
|
|
10
11
|
export { LIGHT, DARK } from './model.js';
|
|
11
12
|
const DEFAULTS = { ...LIGHT, font: 'inherit' };
|
|
12
13
|
const v = (k) => `var(--fig-${k}, ${DEFAULTS[k]})`;
|
|
@@ -56,15 +57,64 @@ const HIDDEN = {
|
|
|
56
57
|
* Use `toSvg` from `flowfig/svg` for a static animated SVG.
|
|
57
58
|
*/
|
|
58
59
|
export function Flow(props) {
|
|
59
|
-
const
|
|
60
|
+
const all = useMemo(() => scenes(props), [props.layout, props.edges, props.steps, props.lanes, props.timeline, props.rail, props.theme, props.speed]);
|
|
61
|
+
const [path, setPath] = useState([]);
|
|
62
|
+
const [full, setFull] = useState(false);
|
|
63
|
+
const [start, setStart] = useState();
|
|
64
|
+
const memo = useRef({});
|
|
65
|
+
const at = path.join('>');
|
|
66
|
+
const s = all.find((x) => x.path.join('>') === at) ?? all[0];
|
|
67
|
+
const { layout, edges, steps, lanes, timeline } = s.props;
|
|
60
68
|
const key = useMemo(() => specKey(layout, edges, steps), [layout, edges, steps]);
|
|
61
69
|
const [narrow, setNarrow] = useState({ wide: 0, key: '' });
|
|
62
70
|
const fold = !lanes && !timeline && props.rail !== 'only';
|
|
63
71
|
const wide = fold && narrow.key === key ? narrow.wide : 0;
|
|
64
72
|
const setWide = useCallback((w) => setNarrow({ wide: w, key }), [key]);
|
|
65
73
|
const placed = useMemo(() => autoLayout({ layout: wide > 0 ? { ...layout, auto: true, direction: 'column' } : layout, edges, steps, lanes, timeline }), [wide, layout, edges, steps, lanes, timeline]);
|
|
66
|
-
|
|
74
|
+
const level = all.length > 1
|
|
75
|
+
? {
|
|
76
|
+
scene: s,
|
|
77
|
+
owners: new Map(all.filter((x) => x.path.slice(0, -1).join('>') === at && x.path.length > s.path.length).map((x) => [x.path.at(-1), x.parts])),
|
|
78
|
+
path: s.path.map((id, i) => ({ id, name: all.find((x) => x.path.join('>') === s.path.slice(0, i + 1).join('>')).name })),
|
|
79
|
+
onOpen: (id, from) => {
|
|
80
|
+
memo.current[at] = from;
|
|
81
|
+
const child = all.find((x) => x.path.join('>') === [...s.path, id].join('>'));
|
|
82
|
+
setStart({
|
|
83
|
+
step: child.props.steps?.length ? insideStep(child, from.port) : null,
|
|
84
|
+
beat: 0,
|
|
85
|
+
playing: from.playing,
|
|
86
|
+
rect: from.rect,
|
|
87
|
+
});
|
|
88
|
+
setPath([...s.path, id]);
|
|
89
|
+
},
|
|
90
|
+
onUp: (depth) => {
|
|
91
|
+
const to = s.path.slice(0, depth);
|
|
92
|
+
const { step, beat, playing } = memo.current[to.join('>')];
|
|
93
|
+
const beats = step == null ? 1 : (all.find((x) => x.path.join('>') === to.join('>')).props.steps?.[step].flow.length ?? 1);
|
|
94
|
+
setStart({ step, beat: Math.min(beat + 1, beats - 1), playing, box: s.path[depth] });
|
|
95
|
+
setPath(to);
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
: undefined;
|
|
99
|
+
const figure = useRef(null);
|
|
100
|
+
const descId = useId();
|
|
101
|
+
const alt = useMemo(() => altText({ layout: placed.layout, edges: placed.edges, steps }), [placed, steps]);
|
|
102
|
+
return (_jsxs("figure", { ref: figure, className: "flowfig", "data-inside": level ? '' : undefined, "aria-label": alt.title, "aria-describedby": descId, style: {
|
|
103
|
+
...Object.fromEntries(Object.entries(props.theme ?? {}).map(([k, val]) => [`--fig-${k}`, val])),
|
|
104
|
+
position: full ? 'fixed' : 'relative',
|
|
105
|
+
inset: full ? 0 : undefined,
|
|
106
|
+
zIndex: full ? 1000 : undefined,
|
|
107
|
+
overflow: full ? 'auto' : undefined,
|
|
108
|
+
margin: full ? 0 : '24px 0',
|
|
109
|
+
padding: full ? '48px 24px 24px' : '20px 16px 16px',
|
|
110
|
+
border: full ? 'none' : `1px solid ${v('border')}`,
|
|
111
|
+
borderRadius: full ? 0 : 16,
|
|
112
|
+
background: v('bg'),
|
|
113
|
+
fontFamily: v('font'),
|
|
114
|
+
color: v('fg'),
|
|
115
|
+
}, children: [_jsx("div", { id: descId, style: HIDDEN, children: alt.desc }), _createElement(FlowBody, { ...props, ...s.props, key: at, layout: placed.layout, edges: placed.edges, written: s.props, wide: wide, setWide: fold ? setWide : undefined, full: full, setFull: setFull, level: level, start: start, figure: figure })] }));
|
|
67
116
|
}
|
|
117
|
+
const reduced = () => window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
68
118
|
// The ASYNC tag is 9 px.
|
|
69
119
|
const RAIL_TEXT = 9;
|
|
70
120
|
// offsetWidth is rounded, so a rect ratio reads scale 1 as 0.999.
|
|
@@ -74,10 +124,8 @@ const shownScale = (el) => {
|
|
|
74
124
|
k *= new DOMMatrix(getComputedStyle(n).transform).a;
|
|
75
125
|
return k;
|
|
76
126
|
};
|
|
77
|
-
function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, autoplay = true, check = false, rail: withRail = false, lanes, timeline, today, written, wide, setWide, }) {
|
|
127
|
+
function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, autoplay = true, check = false, rail: withRail = false, lanes, timeline, today, written, wide, setWide, full, setFull, level, start, figure, }) {
|
|
78
128
|
const tl = timeline && isLanesLayout(layout);
|
|
79
|
-
const alt = useMemo(() => altText({ layout, edges, steps: stepsIn }), [layout, edges, stepsIn]);
|
|
80
|
-
const descId = useId();
|
|
81
129
|
const tabsId = useId();
|
|
82
130
|
const synthetic = tl && !stepsIn.length;
|
|
83
131
|
const steps = useMemo(() => (synthetic ? timelineBeats({ layout, edges, timeline, today }) : stepsIn), [synthetic, layout, edges, timeline, today, stepsIn]);
|
|
@@ -86,18 +134,63 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
86
134
|
const root = useRef(null);
|
|
87
135
|
const outer = useRef(null);
|
|
88
136
|
const [fit, setFit] = useState({ scale: 1, height: 0, scroll: false });
|
|
89
|
-
const
|
|
137
|
+
const backBtn = useRef(null);
|
|
138
|
+
const ghost = useRef(null);
|
|
139
|
+
const place = (n) => {
|
|
140
|
+
const f = figure.current, a = f.getBoundingClientRect(), r = n.getBoundingClientRect();
|
|
141
|
+
return { x: r.left - a.left - f.clientLeft + f.scrollLeft, y: r.top - a.top - f.clientTop + f.scrollTop, w: r.width, h: r.height };
|
|
142
|
+
};
|
|
143
|
+
const showGhost = (r) => {
|
|
144
|
+
Object.assign(ghost.current.style, { display: 'block', left: `${r.x}px`, top: `${r.y}px`, width: `${r.w}px`, height: `${r.h}px` });
|
|
145
|
+
return ghost.current;
|
|
146
|
+
};
|
|
147
|
+
const toward = (from, to) => `translate(${from.x - to.x}px, ${from.y - to.y}px) scale(${from.w / to.w}, ${from.h / to.h})`;
|
|
148
|
+
const moving = useRef(false);
|
|
149
|
+
const goUp = (depth) => {
|
|
150
|
+
const map = root.current, r = start?.rect;
|
|
151
|
+
if (moving.current)
|
|
152
|
+
return;
|
|
153
|
+
if (reduced() || !map || !r)
|
|
154
|
+
return level.onUp(depth);
|
|
155
|
+
moving.current = true;
|
|
156
|
+
map.animate([{ opacity: 1 }, { opacity: 0 }], { duration: OPEN_MS.hide, fill: 'forwards' });
|
|
157
|
+
const to = place(map);
|
|
158
|
+
showGhost(to).animate([{ transform: 'none' }, { transform: toward(r, to) }], {
|
|
159
|
+
duration: OPEN_MS.shrink,
|
|
160
|
+
delay: OPEN_MS.hide,
|
|
161
|
+
easing: 'cubic-bezier(0.4, 0, 1, 1)',
|
|
162
|
+
fill: 'forwards',
|
|
163
|
+
}).onfinish = () => level.onUp(depth);
|
|
164
|
+
};
|
|
165
|
+
const up = level?.path.length ? () => goUp(level.path.length - 1) : undefined;
|
|
90
166
|
useEffect(() => {
|
|
91
|
-
if (!full)
|
|
167
|
+
if (!full && !up)
|
|
92
168
|
return;
|
|
93
|
-
const onKey = (e) =>
|
|
169
|
+
const onKey = (e) => {
|
|
170
|
+
const at = document.activeElement;
|
|
171
|
+
const inside = !!at && !!figure.current?.contains(at);
|
|
172
|
+
if (e.key === 'Escape' && up && (inside || full))
|
|
173
|
+
up();
|
|
174
|
+
else if (e.key === 'Escape')
|
|
175
|
+
setFull(false);
|
|
176
|
+
else if (e.key === 'Backspace' && up && inside && !at.closest('input,textarea,[contenteditable]')) {
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
up();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
94
181
|
addEventListener('keydown', onKey);
|
|
95
182
|
return () => removeEventListener('keydown', onKey);
|
|
96
|
-
}, [full]);
|
|
183
|
+
}, [full, up]);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (start?.box)
|
|
186
|
+
figure.current?.querySelector(`[data-fig="${CSS.escape(start.box)}"]`)?.focus();
|
|
187
|
+
else if (level?.path.length)
|
|
188
|
+
backBtn.current?.focus();
|
|
189
|
+
}, []);
|
|
97
190
|
const dots = useRef([]);
|
|
98
191
|
const chips = useRef([]);
|
|
99
192
|
const bar = useRef(null);
|
|
100
|
-
const [beat, setBeat] = useState(0);
|
|
193
|
+
const [beat, setBeat] = useState(start?.beat ?? 0);
|
|
101
194
|
const [holding, setHolding] = useState(false);
|
|
102
195
|
const [returning, setReturning] = useState(false);
|
|
103
196
|
const firstLabel = useRef('');
|
|
@@ -109,8 +202,8 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
109
202
|
const lanePlan = useMemo(() => lanes && !tl && isLanesLayout(layout)
|
|
110
203
|
? planLanes({ layout, edges, steps, lanes }, { floor: withRail ? (layoutRail({ layout, edges, steps, rail: true }, 560)?.width ?? 0) : 0 })
|
|
111
204
|
: null, [lanes, tl, layout, edges, steps, withRail]);
|
|
112
|
-
const [active, setActive] = useState(steps.length ? 0 : null);
|
|
113
|
-
const [playing, setPlaying] = useState(autoplay);
|
|
205
|
+
const [active, setActive] = useState(start ? start.step : steps.length ? 0 : null);
|
|
206
|
+
const [playing, setPlaying] = useState(start ? start.playing : autoplay);
|
|
114
207
|
const playingRef = useRef(playing);
|
|
115
208
|
playingRef.current = playing;
|
|
116
209
|
const [rate, setRate] = useState(1);
|
|
@@ -147,7 +240,6 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
147
240
|
beats.slice(0, beat + 1).forEach((b, i) => Object.keys(b.show ?? {}).forEach((k) => (at[k] = i)));
|
|
148
241
|
return at;
|
|
149
242
|
}, [beats, beat]);
|
|
150
|
-
const figure = useRef(null);
|
|
151
243
|
const [mapW, setMapW] = useState(0);
|
|
152
244
|
const railOnly = withRail === 'only';
|
|
153
245
|
const rail = useMemo(() => (withRail ? layoutRail({ layout, edges, steps, rail: true }, railOnly ? 560 : mapW) : null), [withRail, railOnly, layout, edges, steps, mapW]);
|
|
@@ -159,7 +251,34 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
159
251
|
const user = useRef(false);
|
|
160
252
|
const left = useRef(0);
|
|
161
253
|
const busy = useRef(0);
|
|
162
|
-
const jump = useRef(null);
|
|
254
|
+
const jump = useRef(start?.beat ?? null);
|
|
255
|
+
const wait = useRef(start?.rect && start.playing
|
|
256
|
+
? OPEN_MS.grow +
|
|
257
|
+
OPEN_MS.stagger * (nodes(layout).length - 1) +
|
|
258
|
+
readMs([level.scene.line, ...level.scene.ports.map(portLabel)].join(' '))
|
|
259
|
+
: 0);
|
|
260
|
+
useLayoutEffect(() => {
|
|
261
|
+
const map = root.current;
|
|
262
|
+
if (!map || reduced())
|
|
263
|
+
return;
|
|
264
|
+
if (start?.box)
|
|
265
|
+
return void map.animate([{ opacity: 0 }, { opacity: 1 }], { duration: OPEN_MS.fade });
|
|
266
|
+
if (!start?.rect)
|
|
267
|
+
return;
|
|
268
|
+
const to = place(map);
|
|
269
|
+
showGhost(to).animate([{ transform: toward(start.rect, to) }, { transform: 'none' }], {
|
|
270
|
+
duration: OPEN_MS.grow,
|
|
271
|
+
easing: 'cubic-bezier(0.2, 0, 0, 1)',
|
|
272
|
+
});
|
|
273
|
+
for (const e of map.querySelectorAll(':scope > svg'))
|
|
274
|
+
e.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 1, delay: OPEN_MS.grow, fill: 'backwards' });
|
|
275
|
+
const shows = flowOrder(level.scene).map((id, k) => map.querySelector(`[data-fig="${CSS.escape(id)}"]`)?.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
276
|
+
duration: OPEN_MS.fade,
|
|
277
|
+
delay: OPEN_MS.grow + OPEN_MS.stagger * k,
|
|
278
|
+
fill: 'backwards',
|
|
279
|
+
}));
|
|
280
|
+
shows.at(-1)?.finished.then(() => ghost.current && (ghost.current.style.display = 'none'));
|
|
281
|
+
}, []);
|
|
163
282
|
const [hoverEdge, setHoverEdge] = useState(null);
|
|
164
283
|
const [still, setStill] = useState(false);
|
|
165
284
|
useEffect(() => setStill(window.matchMedia('(prefers-reduced-motion: reduce)').matches), []);
|
|
@@ -416,7 +535,8 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
416
535
|
if (clock.current.beats !== beats) {
|
|
417
536
|
const j = jump.current ?? 0;
|
|
418
537
|
jump.current = null;
|
|
419
|
-
clock.current = { beats, elapsed: beats.slice(0, j).reduce((t, b) => t + beatMs(b, speed), 0) };
|
|
538
|
+
clock.current = { beats, elapsed: beats.slice(0, j).reduce((t, b) => t + beatMs(b, speed), 0) - wait.current * BASE_RATE };
|
|
539
|
+
wait.current = 0;
|
|
420
540
|
setBeat(j);
|
|
421
541
|
}
|
|
422
542
|
if (!beats.length || (!noMap && !routed.length && !(tl && !edges.length)))
|
|
@@ -438,7 +558,7 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
438
558
|
return setActive((a) => ((a ?? 0) + 1) % steps.length);
|
|
439
559
|
clock.current.elapsed = 0;
|
|
440
560
|
}
|
|
441
|
-
const t = clock.current.elapsed;
|
|
561
|
+
const t = Math.max(0, clock.current.elapsed);
|
|
442
562
|
if (bar.current)
|
|
443
563
|
bar.current.style.transform = `scaleX(${Math.min(1, t / total)})`;
|
|
444
564
|
const next = ends.findIndex((e) => t < e);
|
|
@@ -542,7 +662,6 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
542
662
|
}
|
|
543
663
|
};
|
|
544
664
|
const focus = hover != null || hoverEdge != null || step != null;
|
|
545
|
-
const vars = Object.fromEntries(Object.entries(theme ?? {}).map(([k, val]) => [`--fig-${k}`, val]));
|
|
546
665
|
const timelineFig = useMemo(() => (tl ? timelineLayout({ layout, edges, timeline, today }, axisW) : null), [tl, layout, edges, timeline, today, axisW]);
|
|
547
666
|
const renderBar = (n, it) => {
|
|
548
667
|
const lit = litNodes.has(n.id);
|
|
@@ -736,9 +855,36 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
736
855
|
const card = carded.has(item.id);
|
|
737
856
|
const dl = diamond && !card ? diamondLines(item, nodeWidth(item, false) + 70) : null;
|
|
738
857
|
const w = diamond || card || item.width != null || str(item.label) ? nodeWidth(item, card, cap) + (diamond ? 70 : 0) : undefined;
|
|
739
|
-
const lines = w != null && str(item.label) ? labelLines(item, w) : null;
|
|
740
858
|
const bt = item.tone && TONES[item.tone];
|
|
741
|
-
|
|
859
|
+
const parts = level?.owners.get(item.id);
|
|
860
|
+
const port = level?.scene.ports.some((p) => p.id === item.id);
|
|
861
|
+
const lines = w != null && str(item.label) ? labelLines(item, w) : null;
|
|
862
|
+
const open = () => {
|
|
863
|
+
const hop = cur?.hops.find((h) => (h.back ? edges[ids.indexOf(h.edge)]?.from : edges[ids.indexOf(h.edge)]?.to) === item.id);
|
|
864
|
+
const e = hop && edges[ids.indexOf(hop.edge)];
|
|
865
|
+
const at = { step: active, beat, playing, port: e ? (hop.back ? e.to : e.from) : undefined };
|
|
866
|
+
const map = root.current, n = map?.querySelector(`[data-fig="${CSS.escape(item.id)}"]`);
|
|
867
|
+
if (moving.current)
|
|
868
|
+
return;
|
|
869
|
+
if (reduced() || !map || !n)
|
|
870
|
+
return level.onOpen(item.id, at);
|
|
871
|
+
moving.current = true;
|
|
872
|
+
const rect = place(n);
|
|
873
|
+
showGhost(rect);
|
|
874
|
+
map.animate([{ opacity: 1 }, { opacity: 0 }], { duration: OPEN_MS.fade, fill: 'forwards' }).onfinish = () => level.onOpen(item.id, { ...at, rect });
|
|
875
|
+
};
|
|
876
|
+
return (_jsxs("div", { "data-fig": item.id, title: item.source, "data-diamond": diamond || undefined, onMouseEnter: () => setHover(item.id), onMouseLeave: () => setHover(null), ...(parts != null && {
|
|
877
|
+
role: 'button',
|
|
878
|
+
tabIndex: 0,
|
|
879
|
+
'aria-label': `Open ${str(item.label) || item.id}, ${parts} parts`,
|
|
880
|
+
onClick: open,
|
|
881
|
+
onKeyDown: (e) => {
|
|
882
|
+
if (e.key !== 'Enter' && e.key !== ' ')
|
|
883
|
+
return;
|
|
884
|
+
e.preventDefault();
|
|
885
|
+
open();
|
|
886
|
+
},
|
|
887
|
+
}), style: {
|
|
742
888
|
position: 'relative',
|
|
743
889
|
isolation: 'isolate',
|
|
744
890
|
minWidth: 100,
|
|
@@ -751,19 +897,23 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
751
897
|
justifyContent: 'center',
|
|
752
898
|
padding: diamond
|
|
753
899
|
? '22px 34px'
|
|
754
|
-
: `calc(${store ?
|
|
900
|
+
: `calc(${store ? 23 : 9}px - var(--ff-b, 0px)) calc(${card ? 10 : 16}px - var(--ff-b, 0px)) calc(9px - var(--ff-b, 0px))`,
|
|
755
901
|
textAlign: 'center',
|
|
756
902
|
background: diamond ? undefined : bt ? toneTint(bt, v('bg')) : v('bg'),
|
|
757
|
-
color: v('fg'),
|
|
758
|
-
border: diamond ? undefined : `1px solid ${bt ?? (lit ? v('accent') : v('border'))}`,
|
|
903
|
+
color: port ? v('muted') : v('fg'),
|
|
904
|
+
border: diamond ? undefined : `1px ${port ? 'dashed' : 'solid'} ${bt ?? (lit ? v('accent') : v('border'))}`,
|
|
759
905
|
...(bt && { '--ff-box': bt }),
|
|
760
|
-
boxShadow: diamond
|
|
906
|
+
boxShadow: diamond
|
|
907
|
+
? undefined
|
|
908
|
+
: parts != null
|
|
909
|
+
? `3px 3px 0 -1px ${v('bg')}, 3px 3px 0 0 ${v('border')}`
|
|
910
|
+
: '0 1px 2px rgba(0,0,0,.06)',
|
|
761
911
|
opacity: focus && !lit ? 0.7 : 1,
|
|
762
912
|
borderRadius: store ? '50% / 12px' : 10,
|
|
763
913
|
fontSize: 14,
|
|
764
914
|
fontWeight: 500,
|
|
765
915
|
transition: 'border-color .4s, background .4s, box-shadow .4s, border-width .4s, padding .4s, opacity .25s',
|
|
766
|
-
cursor: 'default',
|
|
916
|
+
cursor: parts != null ? 'pointer' : 'default',
|
|
767
917
|
}, children: [diamond && (_jsx("svg", { viewBox: "0 0 100 100", preserveAspectRatio: "none", style: {
|
|
768
918
|
position: 'absolute',
|
|
769
919
|
inset: 0,
|
|
@@ -794,7 +944,7 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
794
944
|
border: `1.5px solid ${bt ?? v('accent')}`,
|
|
795
945
|
background: `radial-gradient(circle, ${bt ?? v('accent')} 0 4px, transparent 4.5px)`,
|
|
796
946
|
}),
|
|
797
|
-
} })), lines ? (lines.map((l, i) => (_jsx("div", { style: { whiteSpace: 'nowrap', lineHeight: `${LABEL_LINE}px` }, children: l }, i)))) : (_jsx("div", { style: { lineHeight: `${LABEL_LINE}px` }, children: item.label })), dl
|
|
947
|
+
} })), lines && port ? (_jsx("div", { style: { lineHeight: `${LABEL_LINE}px`, width: 'min-content', margin: '0 auto' }, children: lines.map((l, i) => (_jsxs(Fragment, { children: [i > 0 && ' ', _jsx("span", { style: { whiteSpace: 'nowrap' }, children: l })] }, i))) })) : lines ? (lines.map((l, i) => (_jsx("div", { style: { whiteSpace: 'nowrap', lineHeight: `${LABEL_LINE}px` }, children: l }, i)))) : (_jsx("div", { style: { lineHeight: `${LABEL_LINE}px` }, children: item.label })), dl
|
|
798
948
|
? dl.subs.map((l, i) => (_jsx("div", { style: { fontSize: 12, fontWeight: 400, color: v('muted'), lineHeight: '15px', whiteSpace: 'nowrap' }, children: l.text }, i)))
|
|
799
949
|
: item.sub != null && _jsx("div", { style: { fontSize: 12, fontWeight: 400, color: v('muted'), marginTop: 2 }, children: item.sub }), card && (_jsxs("div", { style: {
|
|
800
950
|
marginTop: 8,
|
|
@@ -827,20 +977,7 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
827
977
|
background: v('bg'),
|
|
828
978
|
color: v('muted'),
|
|
829
979
|
};
|
|
830
|
-
return (_jsxs(
|
|
831
|
-
...vars,
|
|
832
|
-
position: full ? 'fixed' : 'relative',
|
|
833
|
-
inset: full ? 0 : undefined,
|
|
834
|
-
zIndex: full ? 1000 : undefined,
|
|
835
|
-
overflow: full ? 'auto' : undefined,
|
|
836
|
-
margin: full ? 0 : '24px 0',
|
|
837
|
-
padding: full ? '48px 24px 24px' : '20px 16px 16px',
|
|
838
|
-
border: full ? 'none' : `1px solid ${v('border')}`,
|
|
839
|
-
borderRadius: full ? 0 : 16,
|
|
840
|
-
background: v('bg'),
|
|
841
|
-
fontFamily: v('font'),
|
|
842
|
-
color: v('fg'),
|
|
843
|
-
}, children: [_jsx("div", { id: descId, style: HIDDEN, children: alt.desc }), _jsx("button", { type: "button", "aria-label": full ? 'Close full screen' : 'Full screen', title: full ? 'Close (Esc)' : 'Full screen', onClick: () => setFull((f) => !f), style: {
|
|
980
|
+
return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": full ? 'Close full screen' : 'Full screen', title: full ? 'Close (Esc)' : 'Full screen', onClick: () => setFull(!full), style: {
|
|
844
981
|
...iconBtn,
|
|
845
982
|
position: 'absolute',
|
|
846
983
|
top: 10,
|
|
@@ -851,105 +988,120 @@ function FlowBody({ layout, edges, steps: stepsIn = NONE, theme, speed = 900, au
|
|
|
851
988
|
}, children: _jsx(Icon, { d: full ? 'M4 4l8 8M12 4l-8 8' : 'M9 3h4v4M7 13H3V9M13 3L9 7M3 13l4-4' }) }), _jsx("style", { children: '@keyframes flowfig-label{from{opacity:0}to{opacity:0}}@keyframes flowfig-in{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:none}}' +
|
|
852
989
|
// The 2 px active border takes 1 px of padding, so the box size stays.
|
|
853
990
|
`.${ACTIVE}:not([data-diamond]){--ff-b:1px;border-width:2px!important;background:color-mix(in srgb, ${hue} 10%, ${v('surface')})!important;box-shadow:${glow}!important;border-color:${hue}!important}` +
|
|
854
|
-
`.${ACTIVE} polygon{fill:color-mix(in srgb, ${hue} 10%, ${v('surface')});stroke:${hue};stroke-width:2px}`
|
|
991
|
+
`.${ACTIVE} polygon{fill:color-mix(in srgb, ${hue} 10%, ${v('surface')});stroke:${hue};stroke-width:2px}` +
|
|
992
|
+
(level
|
|
993
|
+
? '@media (prefers-reduced-motion: reduce){.flowfig[data-inside] *{transition:none!important;animation:none!important}}'
|
|
994
|
+
: '') }), level && (_jsx("div", { ref: ghost, style: {
|
|
995
|
+
display: 'none',
|
|
996
|
+
position: 'absolute',
|
|
997
|
+
zIndex: 4,
|
|
998
|
+
boxSizing: 'border-box',
|
|
999
|
+
border: `1.5px solid ${v('accent')}`,
|
|
1000
|
+
borderRadius: 10,
|
|
1001
|
+
transformOrigin: '0 0',
|
|
1002
|
+
pointerEvents: 'none',
|
|
1003
|
+
} })), !noMap && (_jsx(_Fragment, { children: _jsxs("div", { style: {
|
|
855
1004
|
margin: full ? '-48px -24px 0' : '-20px -16px 0',
|
|
856
1005
|
padding: full ? '48px 24px 24px' : '24px 16px',
|
|
857
1006
|
borderRadius: full ? 0 : '16px 16px 0 0',
|
|
858
1007
|
borderBottom: `1px solid ${v('border')}`,
|
|
859
1008
|
backgroundImage: `radial-gradient(color-mix(in srgb, ${v('fg')} 16%, transparent) 1px, transparent 1.2px)`,
|
|
860
1009
|
backgroundSize: '14px 14px',
|
|
861
|
-
}, children:
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1010
|
+
}, children: [up && (_jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'center', marginBottom: 12, fontSize: 13, color: v('muted') }, children: [_jsx("button", { ref: backBtn, type: "button", onClick: up, style: { ...iconBtn, width: 'auto', padding: '0 12px', font: 'inherit' }, children: "Back" }), level.path.map((p, i) => i < level.path.length - 1 ? (_jsxs(Fragment, { children: [_jsx("button", { type: "button", onClick: () => goUp(i + 1), style: { border: 0, padding: 0, background: 'none', font: 'inherit', color: v('accent'), cursor: 'pointer' }, children: p.name }), ' > '] }, p.id)) : (_jsx("span", { style: { color: v('fg') }, children: p.name }, p.id))), _jsx("div", { "aria-live": "polite", style: HIDDEN, children: `${level.scene.line}: ${level.scene.parts} parts.` +
|
|
1011
|
+
level.scene.ports
|
|
1012
|
+
.map((p) => p.way === 'in' ? ` In from ${p.name}.` : p.way === 'out' ? ` Out to ${p.name}.` : ` In and out: ${p.name}.`)
|
|
1013
|
+
.join('') })] })), _jsx("div", { ref: outer, role: "tabpanel", id: `${tabsId}-panel`, "aria-labelledby": `${tabsId}-tab-${active ?? 0}`, style: {
|
|
1014
|
+
overflow: wide || fit.scroll ? 'auto' : 'hidden',
|
|
1015
|
+
height: fit.scale < 1 ? fit.height : undefined,
|
|
1016
|
+
}, children: _jsxs("div", { ref: root, style: {
|
|
1017
|
+
position: 'relative',
|
|
1018
|
+
width: 'max-content',
|
|
1019
|
+
margin: '0 auto',
|
|
1020
|
+
transform: fit.scale < 1 ? `scale(${fit.scale})` : undefined,
|
|
1021
|
+
transformOrigin: 'top left',
|
|
1022
|
+
paddingTop: arcRoom(routed, 'above') || (markSides.has('t') ? 20 : 4),
|
|
1023
|
+
paddingBottom: arcRoom(routed, 'below') || (markSides.has('b') ? 20 : 4),
|
|
1024
|
+
paddingLeft: arcRoom(routed, 'left') || 4,
|
|
1025
|
+
paddingRight: arcRoom(routed, 'right') || 4,
|
|
1026
|
+
}, children: [renderItem(layout, 0), _jsxs("svg", { style: {
|
|
1027
|
+
position: 'absolute',
|
|
1028
|
+
inset: 0,
|
|
1029
|
+
width: '100%',
|
|
1030
|
+
height: '100%',
|
|
1031
|
+
overflow: 'visible',
|
|
1032
|
+
pointerEvents: 'none',
|
|
1033
|
+
zIndex: tl ? 0 : undefined,
|
|
1034
|
+
}, children: [_jsx("defs", { children: ['off', 'on'].map((k) => (_jsx("marker", { id: `fig-arrow-${k}`, viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "7", markerHeight: "7", orient: "auto-start-reverse", children: _jsx("path", { d: "M 0 1 L 9 5 L 0 9 z", fill: "context-stroke" }) }, k))) }), routed.map((r) => {
|
|
1035
|
+
const on = litEdges.has(r.id);
|
|
1036
|
+
const tone = hopTone(r.id);
|
|
1037
|
+
const hidden = !on && edges[ids.indexOf(r.id)].quiet;
|
|
1038
|
+
const tip = edgeTip(r.id, edges[ids.indexOf(r.id)].source, allBeats);
|
|
1039
|
+
const look = (d, key, guides = false) => (_jsx("path", { ref: guides
|
|
1040
|
+
? (p) => {
|
|
1041
|
+
paths.current[r.id] = p;
|
|
1042
|
+
}
|
|
1043
|
+
: undefined, d: d, fill: "none", stroke: on ? (tone ?? v('accent')) : v('muted'), strokeWidth: on ? EDGE_ON : EDGE_OFF, strokeOpacity: hidden ? 0 : focus && !on ? 0.35 : 1, markerEnd: hidden ? undefined : `url(#fig-arrow-${on ? 'on' : 'off'})`, style: { transition: 'stroke .25s, stroke-opacity .25s', pointerEvents: tip ? 'stroke' : undefined }, children: tip && _jsx("title", { children: tip }) }, key));
|
|
1044
|
+
const guide = (_jsx("path", { ref: (p) => {
|
|
889
1045
|
paths.current[r.id] = p;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}
|
|
899
|
-
dots.current[j] = g;
|
|
900
|
-
}, style: { opacity: 0, color: v('accent') }, children: [_jsx("circle", { r: 10, fill: "currentColor", opacity: 0.2 }), _jsx("circle", { r: 4.5, fill: "currentColor" })] }, j)))] }), Array.from({ length: Math.max(1, ...beats.map((b) => b.hops.length)) }, (_, j) => (_jsx("div", { ref: (c) => {
|
|
901
|
-
chips.current[j] = c;
|
|
902
|
-
}, style: {
|
|
903
|
-
position: 'absolute',
|
|
904
|
-
left: 0,
|
|
905
|
-
top: 0,
|
|
906
|
-
zIndex: 2,
|
|
907
|
-
opacity: 0,
|
|
908
|
-
maxWidth: 220,
|
|
909
|
-
width: 'max-content',
|
|
910
|
-
padding: '4px 9px',
|
|
911
|
-
borderRadius: 8,
|
|
912
|
-
fontSize: 11.5,
|
|
913
|
-
lineHeight: '15px',
|
|
914
|
-
pointerEvents: 'none',
|
|
915
|
-
background: v('accent'),
|
|
916
|
-
color: ON_ACCENT,
|
|
917
|
-
boxShadow: '0 4px 14px rgba(0,0,0,.18)',
|
|
918
|
-
transition: 'opacity .2s',
|
|
919
|
-
}, children: cur?.hops[j]?.data }, j))), routed.flatMap((r) => {
|
|
920
|
-
const e = edges[ids.indexOf(r.id)];
|
|
921
|
-
const texts = r.stub && lanePlan?.stubs.get(r.id);
|
|
922
|
-
if (!texts && (e.label == null || tl))
|
|
923
|
-
return [];
|
|
924
|
-
const on = litEdges.has(r.id);
|
|
925
|
-
const tone = hopTone(r.id);
|
|
926
|
-
const pills = texts
|
|
927
|
-
? r.stub.pills.map((p, j) => ({
|
|
928
|
-
key: `${r.id}:${j}`,
|
|
929
|
-
x: p.x + p.w / 2,
|
|
930
|
-
y: p.y + p.h / 2,
|
|
931
|
-
text: (j === 0 && r.stub.short ? texts[2] : texts[j]),
|
|
932
|
-
}))
|
|
933
|
-
: [{ key: r.id, x: r.mid.x, y: r.mid.y, text: e.label }];
|
|
934
|
-
return pills.map((p) => (_jsx("div", { "data-fig-label": p.key, style: {
|
|
1046
|
+
}, d: r.d, fill: "none", stroke: "none" }, r.id));
|
|
1047
|
+
if (r.stub)
|
|
1048
|
+
return [...r.stub.parts.map((d, j) => look(d, `${r.id}:${j}`)), guide];
|
|
1049
|
+
return look(r.d, r.id, true);
|
|
1050
|
+
}), Array.from({ length: Math.max(1, ...beats.map((b) => b.hops.length)) }, (_, j) => (_jsxs("g", { ref: (g) => {
|
|
1051
|
+
dots.current[j] = g;
|
|
1052
|
+
}, style: { opacity: 0, color: v('accent') }, children: [_jsx("circle", { r: 10, fill: "currentColor", opacity: 0.2 }), _jsx("circle", { r: 4.5, fill: "currentColor" })] }, j)))] }), Array.from({ length: Math.max(1, ...beats.map((b) => b.hops.length)) }, (_, j) => (_jsx("div", { ref: (c) => {
|
|
1053
|
+
chips.current[j] = c;
|
|
1054
|
+
}, style: {
|
|
935
1055
|
position: 'absolute',
|
|
936
|
-
left:
|
|
937
|
-
top:
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1056
|
+
left: 0,
|
|
1057
|
+
top: 0,
|
|
1058
|
+
zIndex: 2,
|
|
1059
|
+
opacity: 0,
|
|
1060
|
+
maxWidth: 220,
|
|
1061
|
+
width: 'max-content',
|
|
1062
|
+
padding: '4px 9px',
|
|
1063
|
+
borderRadius: 8,
|
|
1064
|
+
fontSize: 11.5,
|
|
1065
|
+
lineHeight: '15px',
|
|
944
1066
|
pointerEvents: 'none',
|
|
945
|
-
background:
|
|
946
|
-
color:
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1067
|
+
background: v('accent'),
|
|
1068
|
+
color: ON_ACCENT,
|
|
1069
|
+
boxShadow: '0 4px 14px rgba(0,0,0,.18)',
|
|
1070
|
+
transition: 'opacity .2s',
|
|
1071
|
+
}, children: cur?.hops[j]?.data }, j))), routed.flatMap((r) => {
|
|
1072
|
+
const e = edges[ids.indexOf(r.id)];
|
|
1073
|
+
const texts = r.stub && lanePlan?.stubs.get(r.id);
|
|
1074
|
+
if (!texts && (e.label == null || tl))
|
|
1075
|
+
return [];
|
|
1076
|
+
const on = litEdges.has(r.id);
|
|
1077
|
+
const tone = hopTone(r.id);
|
|
1078
|
+
const pills = texts
|
|
1079
|
+
? r.stub.pills.map((p, j) => ({
|
|
1080
|
+
key: `${r.id}:${j}`,
|
|
1081
|
+
x: p.x + p.w / 2,
|
|
1082
|
+
y: p.y + p.h / 2,
|
|
1083
|
+
text: (j === 0 && r.stub.short ? texts[2] : texts[j]),
|
|
1084
|
+
}))
|
|
1085
|
+
: [{ key: r.id, x: r.mid.x, y: r.mid.y, text: e.label }];
|
|
1086
|
+
return pills.map((p) => (_jsx("div", { "data-fig-label": p.key, style: {
|
|
1087
|
+
position: 'absolute',
|
|
1088
|
+
left: p.x,
|
|
1089
|
+
top: p.y,
|
|
1090
|
+
transform: 'translate(-50%, -50%)',
|
|
1091
|
+
fontSize: 11,
|
|
1092
|
+
lineHeight: '16px',
|
|
1093
|
+
padding: '0 7px',
|
|
1094
|
+
borderRadius: 999,
|
|
1095
|
+
whiteSpace: 'nowrap',
|
|
1096
|
+
pointerEvents: 'none',
|
|
1097
|
+
background: on ? (tone ? toneFill(tone) : v('accent')) : v('bg'),
|
|
1098
|
+
color: on ? ON_ACCENT : v('muted'),
|
|
1099
|
+
border: `1px solid ${on ? (tone ?? v('accent')) : v('border')}`,
|
|
1100
|
+
opacity: !on && e.quiet ? 0 : focus && !on ? 0.6 : 1,
|
|
1101
|
+
fontFamily: MONO,
|
|
1102
|
+
transition: 'background .25s, color .25s, opacity .25s',
|
|
1103
|
+
}, children: p.text }, p.key)));
|
|
1104
|
+
})] }) })] }) })), rail && (_jsx("div", { ref: railPane, onWheel: () => (user.current = true), onPointerDown: () => (user.current = true), onTouchStart: () => (user.current = true), onScroll: (e) => {
|
|
953
1105
|
const x = e.currentTarget.scrollLeft;
|
|
954
1106
|
if (user.current && x !== left.current && performance.now() > busy.current)
|
|
955
1107
|
follow.current = false;
|
package/dist/load.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { altText, counts, toBeat } from './model.js';
|
|
3
|
-
import { coverageLine, detailFindings, owners, unsureLines, verifyReport } from './verify.js';
|
|
2
|
+
import { altText, counts, scenes, toBeat, tourPlan } from './model.js';
|
|
3
|
+
import { coverageLine, detailFindings, levelLines, owners, unsureLines, verifyReport } from './verify.js';
|
|
4
4
|
import { toSvg } from './svg.js';
|
|
5
5
|
const SPEC_OPEN = '<metadata id="figure-spec"><![CDATA[';
|
|
6
6
|
const SPEC_CLOSE = ']]></metadata>';
|
|
@@ -47,12 +47,16 @@ export function sortFindings(findings, strict) {
|
|
|
47
47
|
const n = (k, word) => `${k} ${word}${k === 1 ? '' : 's'}`;
|
|
48
48
|
/** One line per finding, the counts line (unless `withCounts` is false), and the `figure:` line. No color: the CLI adds it. */
|
|
49
49
|
export function reportLines(props, findings, withCounts = true) {
|
|
50
|
-
const out = findings.map((f) => `${f.severity.padEnd(8)} ${f.rule.padEnd(18)} ${f.message}`);
|
|
50
|
+
const out = findings.map((f) => `${f.severity.padEnd(8)} ${f.rule.padEnd(18)} ${f.scene ? `[${f.scene}] ` : ''}${f.message}`);
|
|
51
51
|
const errors = findings.filter((f) => f.severity === 'error').length;
|
|
52
52
|
if (withCounts)
|
|
53
53
|
out.push(`${n(errors, 'error')}, ${n(findings.length - errors, 'warning')}`);
|
|
54
54
|
const c = counts(props);
|
|
55
|
-
|
|
55
|
+
const all = scenes(props);
|
|
56
|
+
const levels = all.length > 1
|
|
57
|
+
? `; ${1 + Math.max(...all.map((s) => s.path.length))} levels, ${all.length} scenes, ${all.reduce((k, s) => k + s.parts, 0)} parts; tour ${Math.round(tourPlan(props).ms / 1000)} s`
|
|
58
|
+
: '';
|
|
59
|
+
out.push(`figure: ${n(c.boxes, 'box').replace('boxs', 'boxes')}, ${n(c.groups, 'group')}, ${n(c.edges, 'edge')}, ${n(c.steps, 'step')}, ${n(c.messages, 'message')}${levels}`);
|
|
56
60
|
return out;
|
|
57
61
|
}
|
|
58
62
|
const text = (x) => (typeof x === 'string' ? x : '');
|
|
@@ -75,6 +79,7 @@ export function verifyLines(props, figure, root = process.cwd()) {
|
|
|
75
79
|
return [
|
|
76
80
|
...findings.map((f) => `${f.severity.padEnd(8)} ${f.rule.padEnd(18)} ${figure}: ${f.message}`),
|
|
77
81
|
coverageLine(figure, coverage),
|
|
82
|
+
...levelLines(coverage),
|
|
78
83
|
...unsureLines(coverage),
|
|
79
84
|
];
|
|
80
85
|
}
|
package/dist/looks.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const TOKENS: {
|
|
2
|
+
light: Record<string, string>;
|
|
3
|
+
dark: Record<string, string>;
|
|
4
|
+
};
|
|
5
|
+
export declare const HUD: {
|
|
6
|
+
wide: number;
|
|
7
|
+
roomy: number;
|
|
8
|
+
panel: number;
|
|
9
|
+
slim: number;
|
|
10
|
+
pad: number;
|
|
11
|
+
chips: number;
|
|
12
|
+
sheet: number;
|
|
13
|
+
short: number;
|
|
14
|
+
tall: number;
|
|
15
|
+
};
|