@issuegraph/editor 0.1.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/LICENSE +201 -0
- package/README.md +238 -0
- package/dist/audit/findings.d.ts +225 -0
- package/dist/audit/findings.d.ts.map +1 -0
- package/dist/audit/findings.js +348 -0
- package/dist/audit/findings.js.map +1 -0
- package/dist/audit/styles.d.ts +37 -0
- package/dist/audit/styles.d.ts.map +1 -0
- package/dist/audit/styles.js +72 -0
- package/dist/audit/styles.js.map +1 -0
- package/dist/audit/surface.d.ts +155 -0
- package/dist/audit/surface.d.ts.map +1 -0
- package/dist/audit/surface.js +202 -0
- package/dist/audit/surface.js.map +1 -0
- package/dist/create/draft.d.ts +119 -0
- package/dist/create/draft.d.ts.map +1 -0
- package/dist/create/draft.js +114 -0
- package/dist/create/draft.js.map +1 -0
- package/dist/create/keys.d.ts +225 -0
- package/dist/create/keys.d.ts.map +1 -0
- package/dist/create/keys.js +228 -0
- package/dist/create/keys.js.map +1 -0
- package/dist/create/placement.d.ts +69 -0
- package/dist/create/placement.d.ts.map +1 -0
- package/dist/create/placement.js +76 -0
- package/dist/create/placement.js.map +1 -0
- package/dist/firstpass/batch.d.ts +190 -0
- package/dist/firstpass/batch.d.ts.map +1 -0
- package/dist/firstpass/batch.js +143 -0
- package/dist/firstpass/batch.js.map +1 -0
- package/dist/firstpass/candidates.d.ts +128 -0
- package/dist/firstpass/candidates.d.ts.map +1 -0
- package/dist/firstpass/candidates.js +39 -0
- package/dist/firstpass/candidates.js.map +1 -0
- package/dist/firstpass/keys.d.ts +90 -0
- package/dist/firstpass/keys.d.ts.map +1 -0
- package/dist/firstpass/keys.js +112 -0
- package/dist/firstpass/keys.js.map +1 -0
- package/dist/firstpass/queue.d.ts +183 -0
- package/dist/firstpass/queue.d.ts.map +1 -0
- package/dist/firstpass/queue.js +159 -0
- package/dist/firstpass/queue.js.map +1 -0
- package/dist/firstpass/render.d.ts +100 -0
- package/dist/firstpass/render.d.ts.map +1 -0
- package/dist/firstpass/render.js +216 -0
- package/dist/firstpass/render.js.map +1 -0
- package/dist/firstpass/styles.d.ts +36 -0
- package/dist/firstpass/styles.d.ts.map +1 -0
- package/dist/firstpass/styles.js +148 -0
- package/dist/firstpass/styles.js.map +1 -0
- package/dist/firstpass/view.d.ts +82 -0
- package/dist/firstpass/view.d.ts.map +1 -0
- package/dist/firstpass/view.js +60 -0
- package/dist/firstpass/view.js.map +1 -0
- package/dist/firstpass/words.d.ts +105 -0
- package/dist/firstpass/words.d.ts.map +1 -0
- package/dist/firstpass/words.js +28 -0
- package/dist/firstpass/words.js.map +1 -0
- package/dist/index.d.ts +150 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +147 -0
- package/dist/index.js.map +1 -0
- package/dist/overlay/grammar.d.ts +259 -0
- package/dist/overlay/grammar.d.ts.map +1 -0
- package/dist/overlay/grammar.js +223 -0
- package/dist/overlay/grammar.js.map +1 -0
- package/dist/overlay/render.d.ts +125 -0
- package/dist/overlay/render.d.ts.map +1 -0
- package/dist/overlay/render.js +439 -0
- package/dist/overlay/render.js.map +1 -0
- package/dist/overlay/styles.d.ts +41 -0
- package/dist/overlay/styles.d.ts.map +1 -0
- package/dist/overlay/styles.js +124 -0
- package/dist/overlay/styles.js.map +1 -0
- package/dist/picker/render.d.ts +80 -0
- package/dist/picker/render.d.ts.map +1 -0
- package/dist/picker/render.js +112 -0
- package/dist/picker/render.js.map +1 -0
- package/dist/picker/styles.d.ts +26 -0
- package/dist/picker/styles.d.ts.map +1 -0
- package/dist/picker/styles.js +116 -0
- package/dist/picker/styles.js.map +1 -0
- package/dist/picker/view.d.ts +135 -0
- package/dist/picker/view.d.ts.map +1 -0
- package/dist/picker/view.js +117 -0
- package/dist/picker/view.js.map +1 -0
- package/dist/picker/words.d.ts +53 -0
- package/dist/picker/words.d.ts.map +1 -0
- package/dist/picker/words.js +28 -0
- package/dist/picker/words.js.map +1 -0
- package/dist/reevaluate/render.d.ts +77 -0
- package/dist/reevaluate/render.d.ts.map +1 -0
- package/dist/reevaluate/render.js +211 -0
- package/dist/reevaluate/render.js.map +1 -0
- package/dist/reevaluate/styles.d.ts +24 -0
- package/dist/reevaluate/styles.d.ts.map +1 -0
- package/dist/reevaluate/styles.js +182 -0
- package/dist/reevaluate/styles.js.map +1 -0
- package/dist/reevaluate/view.d.ts +102 -0
- package/dist/reevaluate/view.d.ts.map +1 -0
- package/dist/reevaluate/view.js +111 -0
- package/dist/reevaluate/view.js.map +1 -0
- package/dist/reevaluate/words.d.ts +54 -0
- package/dist/reevaluate/words.d.ts.map +1 -0
- package/dist/reevaluate/words.js +29 -0
- package/dist/reevaluate/words.js.map +1 -0
- package/dist/scale/commands.d.ts +60 -0
- package/dist/scale/commands.d.ts.map +1 -0
- package/dist/scale/commands.js +49 -0
- package/dist/scale/commands.js.map +1 -0
- package/dist/scale/ladder.d.ts +141 -0
- package/dist/scale/ladder.d.ts.map +1 -0
- package/dist/scale/ladder.js +243 -0
- package/dist/scale/ladder.js.map +1 -0
- package/dist/scale/render.d.ts +85 -0
- package/dist/scale/render.d.ts.map +1 -0
- package/dist/scale/render.js +194 -0
- package/dist/scale/render.js.map +1 -0
- package/dist/scale/styles.d.ts +21 -0
- package/dist/scale/styles.d.ts.map +1 -0
- package/dist/scale/styles.js +105 -0
- package/dist/scale/styles.js.map +1 -0
- package/dist/workspace/inspector.d.ts +117 -0
- package/dist/workspace/inspector.d.ts.map +1 -0
- package/dist/workspace/inspector.js +140 -0
- package/dist/workspace/inspector.js.map +1 -0
- package/dist/workspace/rail.d.ts +122 -0
- package/dist/workspace/rail.d.ts.map +1 -0
- package/dist/workspace/rail.js +216 -0
- package/dist/workspace/rail.js.map +1 -0
- package/dist/workspace/render.d.ts +139 -0
- package/dist/workspace/render.d.ts.map +1 -0
- package/dist/workspace/render.js +366 -0
- package/dist/workspace/render.js.map +1 -0
- package/dist/workspace/selection.d.ts +92 -0
- package/dist/workspace/selection.d.ts.map +1 -0
- package/dist/workspace/selection.js +83 -0
- package/dist/workspace/selection.js.map +1 -0
- package/dist/workspace/styles.d.ts +39 -0
- package/dist/workspace/styles.d.ts.map +1 -0
- package/dist/workspace/styles.js +313 -0
- package/dist/workspace/styles.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay grammar, attached to a viewer scene.
|
|
3
|
+
*
|
|
4
|
+
* ## The constraint this module is shaped by
|
|
5
|
+
*
|
|
6
|
+
* Layer 2 does not know where an edge is. `index.ts` records the `together-with`
|
|
7
|
+
* connector as *the one declared crossing* precisely because "only the layer
|
|
8
|
+
* that computes the layout knows where its endpoints are", and that argument
|
|
9
|
+
* binds anything that needs a position — an arrowhead, a chip on a node, a
|
|
10
|
+
* sentence beside a line.
|
|
11
|
+
*
|
|
12
|
+
* So this module draws every treatment that can be stated WITHOUT a position,
|
|
13
|
+
* and declares the rest as marks for whoever owns the layout.
|
|
14
|
+
*
|
|
15
|
+
* ## The line, and it was drawn by evidence rather than by taste
|
|
16
|
+
*
|
|
17
|
+
* **An overlay that REUSES the path's own position can be drawn here. One that
|
|
18
|
+
* needs a NEW position cannot.**
|
|
19
|
+
*
|
|
20
|
+
* A halo is the path again, stroked wider. A marching or dotted ghost is the
|
|
21
|
+
* path again, patterned differently. Neither moves, so neither needs to know
|
|
22
|
+
* where the path goes, and cloning a solved `d` is enough.
|
|
23
|
+
*
|
|
24
|
+
* A conflict's second version is the case that looks identical and is not: it
|
|
25
|
+
* has to sit BESIDE the line, and "beside" is the path's perpendicular — which
|
|
26
|
+
* cannot be recovered from a `d` this layer does not interpret. Four review
|
|
27
|
+
* rounds each found a different way that goes wrong: three strokes where a pair
|
|
28
|
+
* was promised, a companion hidden underneath its twin, a companion that had
|
|
29
|
+
* lost the relationship's own double-line shape, and finally a vertical offset
|
|
30
|
+
* sliding ALONG a `together-with` connector that happens to run vertically —
|
|
31
|
+
* `connectorPath` emits exactly that whenever the two boxes are equal width.
|
|
32
|
+
*
|
|
33
|
+
* Each fix was correct and the next round found the next property, because the
|
|
34
|
+
* missing thing was never a property: it was the geometry. So the companion is
|
|
35
|
+
* no longer drawn here at all. It travels as the `second-version` mark, placed
|
|
36
|
+
* by the layer that computed the layout — the same treatment `node-chip`,
|
|
37
|
+
* `terminal-cross` and `inline-reason` already get, and the same argument
|
|
38
|
+
* `index.ts` makes for the `together-with` connector living in the viewer.
|
|
39
|
+
*
|
|
40
|
+
* What is left genuinely cannot be drawn here: `node-chip` sits on two nodes,
|
|
41
|
+
* `terminal-cross` and `inline-reason` need the line's end, and
|
|
42
|
+
* `second-version` needs its perpendicular. Those travel as
|
|
43
|
+
* {@link EdgeOverlay.marks} for the composer to place, declared rather than
|
|
44
|
+
* half-drawn here.
|
|
45
|
+
*
|
|
46
|
+
* ## How an edge is recognised
|
|
47
|
+
*
|
|
48
|
+
* Viewer edge paths publish no per-edge identity — only the `together-with`
|
|
49
|
+
* connector carries one — so an edge is matched by the accessible name the
|
|
50
|
+
* viewer gives it: `${from} ${treatment.label} ${to}`.
|
|
51
|
+
*
|
|
52
|
+
* The label is read from the viewer's OWN `treatmentFor`, never from a copy, so
|
|
53
|
+
* a renamed relationship moves both sides at once. What stays local is the
|
|
54
|
+
* SHAPE of that sentence, and a shape cannot be imported — so `render.test.ts`
|
|
55
|
+
* pins it with a positive control that attaches to a real rendered scene. If
|
|
56
|
+
* the viewer restyles its label, that control goes red rather than the overlays
|
|
57
|
+
* silently ceasing to attach, which is the failure mode worth buying a test.
|
|
58
|
+
*
|
|
59
|
+
* Publishing an identity on edge paths would be better and is deliberately NOT
|
|
60
|
+
* done here: `keyAt` reads `GROUP_ATTRIBUTE` as POINTER identity, so adding one
|
|
61
|
+
* would change what a click on an edge means. That belongs to the leaf that
|
|
62
|
+
* owns edge selection, not to a grammar.
|
|
63
|
+
*
|
|
64
|
+
* ## Attach to a freshly rendered scene, never to your own output
|
|
65
|
+
*
|
|
66
|
+
* The consequence of matching on the accessible name is that overlaying REWRITES
|
|
67
|
+
* that name — the states are announced there — so an overlaid edge no longer
|
|
68
|
+
* matches. A host renders a new scene on every state change and attaches to
|
|
69
|
+
* that, which is the intended shape and is why this is a boundary rather than a
|
|
70
|
+
* defect.
|
|
71
|
+
*
|
|
72
|
+
* Attaching to an already-overlaid scene is out of contract. It fails SAFELY
|
|
73
|
+
* rather than silently: nothing matches, the scene keeps the overlays it
|
|
74
|
+
* already had, and every edge is reported in {@link AttachResult.unattached}.
|
|
75
|
+
* `render.test.ts` pins that, so the behaviour is a decision rather than an
|
|
76
|
+
* accident. What it must never do is double the announcement, and it does not.
|
|
77
|
+
*
|
|
78
|
+
* ## No timer
|
|
79
|
+
*
|
|
80
|
+
* The marching dash is a CSS animation, which is what §17b asks for. The rule
|
|
81
|
+
* is that nothing changes STATE on its own — no `setTimeout`, no `setInterval`,
|
|
82
|
+
* no self-dismissal. A chip persists until the write settles, and a settled
|
|
83
|
+
* failure persists until the user acts on it.
|
|
84
|
+
*/
|
|
85
|
+
import { element, resolveTheme, treatmentFor, } from '@issuegraph/viewer';
|
|
86
|
+
import { HALO_OPACITY, STATE_ATTRIBUTE, overlayFor, overlayLabel, } from "./grammar.js";
|
|
87
|
+
/** The class every mark this module adds carries, so a host can find them. */
|
|
88
|
+
export const OVERLAY_CLASS = 'ig-overlay';
|
|
89
|
+
/** The class the viewer puts on an edge path. Matched, never written. */
|
|
90
|
+
const EDGE_CLASS = 'ig-edge';
|
|
91
|
+
/** The class the viewer puts on a terminal marker. NEVER matched — see below. */
|
|
92
|
+
const TERMINAL_CLASS = 'ig-terminal';
|
|
93
|
+
/**
|
|
94
|
+
* The class the viewer puts on a `together-with` connector.
|
|
95
|
+
*
|
|
96
|
+
* A `together-with` relationship is NOT drawn as an edge path — `graph.ts:657`
|
|
97
|
+
* skips it outright, because it shares a rank rather than ordering anything —
|
|
98
|
+
* so it is drawn as an enclosure plus this connector. Without matching it, one
|
|
99
|
+
* of the five relationships could never be overlaid at all: every state on a
|
|
100
|
+
* `together-with` came back `unattached`.
|
|
101
|
+
*/
|
|
102
|
+
const CONNECTOR_CLASS = 'ig-connector';
|
|
103
|
+
/** The attribute the connector publishes its edge identity on. */
|
|
104
|
+
const GROUP_ATTRIBUTE = 'data-ig-group';
|
|
105
|
+
/** The accessible name the viewer gives an edge, reconstructed from its parts. */
|
|
106
|
+
function edgeName(edge) {
|
|
107
|
+
return `${edge.from} ${treatmentFor(edge.kind).label} ${edge.to}`;
|
|
108
|
+
}
|
|
109
|
+
function classesOf(attrs) {
|
|
110
|
+
const value = attrs?.['class'];
|
|
111
|
+
return typeof value === 'string' ? value.split(' ').filter((name) => name !== '') : [];
|
|
112
|
+
}
|
|
113
|
+
function isEdgePath(spec) {
|
|
114
|
+
const names = classesOf(spec.attrs);
|
|
115
|
+
return names.includes(EDGE_CLASS) || names.includes(CONNECTOR_CLASS);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Which overlay this element carries, if any.
|
|
119
|
+
*
|
|
120
|
+
* TWO KEYS, AND IDENTITY IS THE BETTER ONE. Every edge mark publishes
|
|
121
|
+
* `edgeIdentity(field, from, to)` on `data-ig-group`, and that string IS
|
|
122
|
+
* `StoredEdge.id` — the same function derives both — so `ProjectedEdge.id`
|
|
123
|
+
* matches it with no new dependency and no reconstruction.
|
|
124
|
+
*
|
|
125
|
+
* THE NAME IS A FALLBACK THAT NO LONGER HAS A KNOWN CALLER, and it is kept
|
|
126
|
+
* rather than deleted for one reason: this package matches against markup layer
|
|
127
|
+
* 1 owns, and a viewer that has not yet shipped the identity on ordinary edge
|
|
128
|
+
* paths still renders against this reader. Deleting it would turn a version
|
|
129
|
+
* skew into silently unattached overlays instead of a working match.
|
|
130
|
+
*/
|
|
131
|
+
function overlayOn(spec, byIdentity, byName) {
|
|
132
|
+
const group = spec.attrs?.[GROUP_ATTRIBUTE];
|
|
133
|
+
if (typeof group === 'string') {
|
|
134
|
+
const overlay = byIdentity.get(group);
|
|
135
|
+
if (overlay !== undefined)
|
|
136
|
+
return { key: group, overlay };
|
|
137
|
+
}
|
|
138
|
+
const label = spec.attrs?.['aria-label'];
|
|
139
|
+
if (typeof label === 'string' && classesOf(spec.attrs).includes(EDGE_CLASS)) {
|
|
140
|
+
const overlay = byName.get(label);
|
|
141
|
+
if (overlay !== undefined)
|
|
142
|
+
return { key: label, overlay };
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The edge's own path, cloned into an overlay stroke.
|
|
148
|
+
*
|
|
149
|
+
* Every geometric attribute is carried across untouched and every identifying
|
|
150
|
+
* one is dropped: an overlay is decoration, so it must not answer to a name,
|
|
151
|
+
* take focus, or be read out a second time by a screen reader.
|
|
152
|
+
*/
|
|
153
|
+
function clonePath(spec, overrides) {
|
|
154
|
+
// `data-ig-group` IS CARRIED, and it is the one identifying attribute that
|
|
155
|
+
// stays — because dropping it would make a clone a DEAD ZONE over its own
|
|
156
|
+
// edge. A dash clone is drawn in FRONT of the stroke, so it is what a pointer
|
|
157
|
+
// lands on; with no identity the viewer's walk climbs past it to the canvas
|
|
158
|
+
// group and reports a click on the edge as a click on nothing, clearing the
|
|
159
|
+
// very selection the reader was making. The halo behind it widens the target
|
|
160
|
+
// for the same edge, which is the same answer either way.
|
|
161
|
+
// It is a POINTER identity and not a focus one — that separation is exactly
|
|
162
|
+
// why the viewer publishes decoration on this attribute — so a clone still
|
|
163
|
+
// takes no tab stop, and `aria-hidden` below still keeps it out of the
|
|
164
|
+
// accessibility tree.
|
|
165
|
+
const { class: _class, role: _role, 'aria-label': _label, ...geometry } = spec.attrs ?? {};
|
|
166
|
+
return {
|
|
167
|
+
tag: spec.tag,
|
|
168
|
+
ns: spec.ns,
|
|
169
|
+
attrs: { ...geometry, 'aria-hidden': 'true', ...overrides },
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The marks that can be drawn from the edge's own path, and nothing else.
|
|
174
|
+
*
|
|
175
|
+
* Order matters and is drawn back-to-front: the halo sits BEHIND the edge so it
|
|
176
|
+
* reads as a glow around the line rather than a second line over it, and the
|
|
177
|
+
* dash and the conflict's second version sit in front.
|
|
178
|
+
*/
|
|
179
|
+
function overlayMarks(spec, overlay, edge, theme) {
|
|
180
|
+
const behind = [];
|
|
181
|
+
const front = [];
|
|
182
|
+
// EVERY CLONE INHERITS THE TREATMENT, rather than the edge getting it and the
|
|
183
|
+
// clones being re-specified one property at a time. Six of this PR's review
|
|
184
|
+
// findings were one class — a clone that did not inherit the hue, the
|
|
185
|
+
// opacity, the dash, the stroke count or the position of the thing it was
|
|
186
|
+
// cloned from — and each was fixed on its own until the shape of the mistake
|
|
187
|
+
// was visible. Deriving it once is what stops the seventh.
|
|
188
|
+
const inherited = overlay.line?.opacity === null || overlay.line?.opacity === undefined
|
|
189
|
+
? {}
|
|
190
|
+
: { opacity: overlay.line.opacity };
|
|
191
|
+
if (overlay.halo) {
|
|
192
|
+
behind.push(clonePath(spec, {
|
|
193
|
+
...inherited,
|
|
194
|
+
class: `${OVERLAY_CLASS} ig-overlay-halo`,
|
|
195
|
+
// From the grammar, never from the stylesheet — see `HALO_OPACITY`.
|
|
196
|
+
opacity: HALO_OPACITY,
|
|
197
|
+
// Widened from the theme's own stroke rather than from a literal, so a
|
|
198
|
+
// host thickening its lines keeps the halo proportionate to them.
|
|
199
|
+
'stroke-width': theme.metrics['--ig-stroke'] * 3,
|
|
200
|
+
'stroke-dasharray': null,
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
const line = overlay.line;
|
|
204
|
+
if (line !== null && line.dash !== null) {
|
|
205
|
+
// EVERY dash the table declares, not just the marching one. `invalid` asks
|
|
206
|
+
// for `dotted` and an earlier draft drew only `marching`, so the dotted
|
|
207
|
+
// ghost silently never appeared — the table declared a shape channel that
|
|
208
|
+
// nothing rendered, which is a field that lies rather than a missing case.
|
|
209
|
+
//
|
|
210
|
+
// Drawn on a CLONE so the kind's own dash survives underneath: the pattern
|
|
211
|
+
// is one of the four channels the type identity rests on, and writing
|
|
212
|
+
// `stroke-dasharray` onto the edge itself would spend it.
|
|
213
|
+
front.push(clonePath(spec, {
|
|
214
|
+
...inherited,
|
|
215
|
+
class: `${OVERLAY_CLASS} ig-overlay-dash ig-overlay-${line.dash}`,
|
|
216
|
+
// THE HUE HAS TO BE STATED. The clone drops `class`, so it is no longer
|
|
217
|
+
// `.ig-edge` and the viewer's `.ig-edge[data-edge=…]` hue rules stop
|
|
218
|
+
// applying to it — a `currentColor` stroke then resolved to the
|
|
219
|
+
// inherited body-text grey and painted OVER the edge, collapsing the
|
|
220
|
+
// hue channel exactly while a write was pending.
|
|
221
|
+
//
|
|
222
|
+
// The state's own hue where it has one (a refusal is red), and the
|
|
223
|
+
// RELATIONSHIP's hue where it does not (a pending write is still a
|
|
224
|
+
// `blocked-by`). Both are read from their owning table — the viewer's
|
|
225
|
+
// `treatmentFor` for the kind — never copied.
|
|
226
|
+
stroke: `var(${line.hueToken ?? treatmentFor(edge.kind).hueToken})`,
|
|
227
|
+
'stroke-dasharray': null,
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
return { behind, front };
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The attributes the overlay writes onto the edge's own path.
|
|
234
|
+
*
|
|
235
|
+
* The name is rebuilt from `base` — the edge's own reconstructed name — rather
|
|
236
|
+
* than read back off the element. Reading the element makes the function
|
|
237
|
+
* accumulate: attaching twice produced `… — writing — writing`, because the
|
|
238
|
+
* second pass took the first pass's output as its starting point. Deriving it
|
|
239
|
+
* from the edge every time makes a second attach a no-op, which is what a
|
|
240
|
+
* caller re-rendering on every state change will do.
|
|
241
|
+
*/
|
|
242
|
+
function edgeAttributes(base, overlay) {
|
|
243
|
+
const opacity = overlay.line?.opacity;
|
|
244
|
+
return {
|
|
245
|
+
[STATE_ATTRIBUTE]: overlay.attribute,
|
|
246
|
+
// Re-announced, so a reader who cannot see the halo or the ghost still
|
|
247
|
+
// learns the edge is selected, writing, or refused.
|
|
248
|
+
'aria-label': overlayLabel(base, overlay),
|
|
249
|
+
// The table is the single source for this number; the stylesheet
|
|
250
|
+
// deliberately carries no opacity rule for a state.
|
|
251
|
+
...(opacity === null || opacity === undefined ? {} : { opacity }),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Walk a spec tree, overlaying every edge an overlay was supplied for.
|
|
256
|
+
*
|
|
257
|
+
* Rebuilt rather than mutated: an `ElementSpec` is `readonly` throughout, and a
|
|
258
|
+
* scene that changed under a host holding a previous one would defeat exactly
|
|
259
|
+
* the memoisation the viewer canonicalises its state order to enable.
|
|
260
|
+
*/
|
|
261
|
+
function overlayTree(spec, context) {
|
|
262
|
+
const children = spec.children ?? [];
|
|
263
|
+
const next = [];
|
|
264
|
+
for (const child of children) {
|
|
265
|
+
if (typeof child === 'string') {
|
|
266
|
+
next.push(child);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
// THE TERMINAL IS NEVER TOUCHED, and this is the line that keeps the four
|
|
270
|
+
// redundant channels alive. An overlay adds marks beside the type's own
|
|
271
|
+
// dash, terminal, glyph and hue; it never stands in for one. `failed`'s ✕
|
|
272
|
+
// travels as a MARK for the composer to add beside the terminal, which is
|
|
273
|
+
// why there is no branch here that would draw over it.
|
|
274
|
+
if (classesOf(child.attrs).includes(TERMINAL_CLASS)) {
|
|
275
|
+
next.push(child);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (!isEdgePath(child)) {
|
|
279
|
+
next.push(overlayTree(child, context));
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
// AN EDGE THIS MODULE HAS ALREADY OVERLAID IS NOT OVERLAID AGAIN, and this
|
|
283
|
+
// is a DELIBERATE refusal now rather than a side effect of the match key.
|
|
284
|
+
//
|
|
285
|
+
// It used to be one. The overlay rewrites `aria-label`, and the accessible
|
|
286
|
+
// name was the ONLY key an ordinary edge path could be matched by — so a
|
|
287
|
+
// second pass fell through and the scene survived by accident. Edge paths
|
|
288
|
+
// publish `data-ig-group` now, and an identity is not rewritten by
|
|
289
|
+
// decoration, so that accident is gone: a second pass would have matched
|
|
290
|
+
// again and drawn a second halo behind the first.
|
|
291
|
+
//
|
|
292
|
+
// Attaching to this module's own output stays OUT of contract — a host
|
|
293
|
+
// renders a fresh scene and attaches to that. What this pins is that going
|
|
294
|
+
// out of contract is REPORTED rather than silently corrupting: the element
|
|
295
|
+
// is left exactly as it is and its key never reaches `attached`, so the
|
|
296
|
+
// overlay comes back in `unattached` where a host or a test can see it.
|
|
297
|
+
if (child.attrs?.[STATE_ATTRIBUTE] !== undefined && child.attrs[STATE_ATTRIBUTE] !== null) {
|
|
298
|
+
next.push(child);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const match = overlayOn(child, context.byIdentity, context.byName);
|
|
302
|
+
if (match === null || match.overlay.states.length === 0) {
|
|
303
|
+
next.push(child);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const edge = context.edgeOf.get(match.key);
|
|
307
|
+
if (edge === undefined) {
|
|
308
|
+
next.push(child);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
context.attached.add(match.key);
|
|
312
|
+
// PER STROKE, NOT PER EDGE — and this is the class fix, not a preference.
|
|
313
|
+
//
|
|
314
|
+
// `serialize-with` is drawn as TWO `.ig-edge` paths, and an earlier
|
|
315
|
+
// revision drew the stroke-derived marks ONCE for the pair. That is what
|
|
316
|
+
// produced a single-stroke conflict companion beside a double-stroke
|
|
317
|
+
// original, and it would have produced a halo around one of two parallel
|
|
318
|
+
// lines next. Every mark built here is CLONED FROM A STROKE, so it belongs
|
|
319
|
+
// to that stroke: clone them all and the kind's shape survives for free
|
|
320
|
+
// instead of being re-derived for each new case.
|
|
321
|
+
//
|
|
322
|
+
// The marks that are genuinely per-edge — the chips, the ✕, the reason —
|
|
323
|
+
// are not built here at all. They need a position this layer does not have,
|
|
324
|
+
// so they travel as declared marks and are placed once by the composer.
|
|
325
|
+
const { behind, front } = overlayMarks(child, match.overlay, edge, context.theme);
|
|
326
|
+
next.push(...behind, { ...child, attrs: { ...child.attrs, ...edgeAttributes(edgeName(edge), match.overlay) } }, ...front);
|
|
327
|
+
}
|
|
328
|
+
return { ...spec, children: next };
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Overlay a scene's edges with the states their projection carries.
|
|
332
|
+
*
|
|
333
|
+
* Takes `ProjectedEdge`s rather than resolved overlays because an edge's kind
|
|
334
|
+
* and endpoints are what identify it in the scene, and asking a caller to hand
|
|
335
|
+
* those over separately is asking it to keep two things in step.
|
|
336
|
+
*/
|
|
337
|
+
export function attachEdgeOverlays(scene, edges, options = {}) {
|
|
338
|
+
const theme = resolveTheme(options.theme);
|
|
339
|
+
const overlays = edges.map(overlayFor);
|
|
340
|
+
const byIdentity = new Map();
|
|
341
|
+
const byName = new Map();
|
|
342
|
+
const edgeOf = new Map();
|
|
343
|
+
for (const [index, overlay] of overlays.entries()) {
|
|
344
|
+
const edge = edges[index];
|
|
345
|
+
if (edge === undefined || overlay.states.length === 0)
|
|
346
|
+
continue;
|
|
347
|
+
byIdentity.set(edge.id, overlay);
|
|
348
|
+
edgeOf.set(edge.id, edge);
|
|
349
|
+
const name = edgeName(edge);
|
|
350
|
+
byName.set(name, overlay);
|
|
351
|
+
edgeOf.set(name, edge);
|
|
352
|
+
}
|
|
353
|
+
const attached = new Set();
|
|
354
|
+
const context = {
|
|
355
|
+
byIdentity,
|
|
356
|
+
byName,
|
|
357
|
+
edgeOf,
|
|
358
|
+
attached,
|
|
359
|
+
theme,
|
|
360
|
+
};
|
|
361
|
+
const root = overlayTree(scene.root, context);
|
|
362
|
+
// REPORTED, NOT DROPPED. An overlay whose edge the scene does not draw is
|
|
363
|
+
// ordinary — the graph projection has a node budget and falls back to
|
|
364
|
+
// clusters — but it is also what a broken match looks like, and the two must
|
|
365
|
+
// not be indistinguishable. A host can surface it; a test can pin it.
|
|
366
|
+
//
|
|
367
|
+
// Either key counts: a `together-with` is only ever drawn as a connector, so
|
|
368
|
+
// it matches by identity and never by name.
|
|
369
|
+
const unattached = overlays.filter((overlay, index) => {
|
|
370
|
+
const edge = edges[index];
|
|
371
|
+
if (edge === undefined || overlay.states.length === 0)
|
|
372
|
+
return false;
|
|
373
|
+
return !attached.has(edge.id) && !attached.has(edgeName(edge));
|
|
374
|
+
});
|
|
375
|
+
return { scene: { ...scene, root }, overlays, unattached };
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* The `writing…`, `retry` and reason marks, as controls a host can dispatch.
|
|
379
|
+
*
|
|
380
|
+
* Positioned by whoever calls it — see the module note. It renders the control,
|
|
381
|
+
* publishing what it does as data on `data-ig-overlay`, the same contract
|
|
382
|
+
* `scale/render.ts` established: layer 2 publishes the control, and the mount
|
|
383
|
+
* that owns the state wires it.
|
|
384
|
+
*
|
|
385
|
+
* The reason mark carries the store's `InvalidCode` and NO sentence. A host
|
|
386
|
+
* keys its own message off the code, for the same reason `change.ts` ships
|
|
387
|
+
* counts rather than prose.
|
|
388
|
+
*/
|
|
389
|
+
export function renderOverlayMark(overlay, mark, reasonCode) {
|
|
390
|
+
switch (mark) {
|
|
391
|
+
case 'node-chip':
|
|
392
|
+
return element('span', { class: `${OVERLAY_CLASS} ig-overlay-chip`, 'data-ig-overlay': 'writing' },
|
|
393
|
+
// The one word this package renders, and it is a STATE name rather than
|
|
394
|
+
// a message — the same thing `grammar.ts` already announces to a screen
|
|
395
|
+
// reader, so a host that translates translates one vocabulary.
|
|
396
|
+
['writing…']);
|
|
397
|
+
case 'terminal-cross':
|
|
398
|
+
return element('span', {
|
|
399
|
+
class: `${OVERLAY_CLASS} ig-overlay-cross`,
|
|
400
|
+
'data-ig-overlay': 'failed',
|
|
401
|
+
role: 'img',
|
|
402
|
+
'aria-label': 'failed',
|
|
403
|
+
},
|
|
404
|
+
// THE GLYPH IS THE MARK. An earlier draft returned this span EMPTY,
|
|
405
|
+
// carrying colour and typography and no shape — so `failed` lost the
|
|
406
|
+
// one cue that separates it from `invalid` without colour, which is the
|
|
407
|
+
// whole reason a terminal mark is drawn rather than a hue changed.
|
|
408
|
+
//
|
|
409
|
+
// A glyph rather than a word, for the same reason the viewer's edge
|
|
410
|
+
// vocabulary uses ⊘ ⇄ ⧉ ≡ ⑃: it is the non-colour channel, and it needs
|
|
411
|
+
// no translation.
|
|
412
|
+
['✕']);
|
|
413
|
+
case 'inline-reason':
|
|
414
|
+
// A SLOT, NOT A GLYPH — and the distinction is deliberate rather than an
|
|
415
|
+
// oversight of the same class as the empty ✕ above. This element is
|
|
416
|
+
// EMPTY because the sentence is the host's: the package publishes the
|
|
417
|
+
// store's stable `InvalidCode` and the host keys its own message off it,
|
|
418
|
+
// exactly as `change.ts` ships counts rather than prose. `data-ig-slot`
|
|
419
|
+
// says so out loud, so an empty element here reads as intended rather
|
|
420
|
+
// than as the bug it looked like one case up.
|
|
421
|
+
return element('span', {
|
|
422
|
+
class: `${OVERLAY_CLASS} ig-overlay-reason`,
|
|
423
|
+
'data-ig-overlay': 'reason',
|
|
424
|
+
'data-ig-slot': 'reason',
|
|
425
|
+
'data-ig-code': reasonCode ?? null,
|
|
426
|
+
});
|
|
427
|
+
case 'second-version':
|
|
428
|
+
// Also a slot. The held version is DRAWN by `attachEdgeOverlays` as the
|
|
429
|
+
// companion stroke; what a host adds here is whatever labels or offers to
|
|
430
|
+
// act on it — view-diff, retry-on-latest, discard-mine. Never a merge.
|
|
431
|
+
return element('span', {
|
|
432
|
+
class: `${OVERLAY_CLASS} ig-overlay-held`,
|
|
433
|
+
'data-ig-overlay': 'conflict',
|
|
434
|
+
'data-ig-slot': 'held-version',
|
|
435
|
+
'aria-label': overlayLabel('', overlay).trim(),
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/overlay/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay's structural stylesheet.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the ladder's and the viewer's: layout, weight and state,
|
|
5
|
+
* never a value. Every colour, length and duration here is a `var(--ig-…)` the
|
|
6
|
+
* host's theme resolves, so a second theme keeps working on the surfaces layer
|
|
7
|
+
* 2 adds. `styles.test.ts` scans these bytes for a literal colour, a fixed
|
|
8
|
+
* length and a token the theme does not define.
|
|
9
|
+
*
|
|
10
|
+
* IT DECLARES NO OPACITY AT ALL. `grammar.ts` is the single source for every
|
|
11
|
+
* alpha this package applies, and `render.ts` writes each onto its element —
|
|
12
|
+
* so there is deliberately no `opacity` rule here, for a state OR for a mark.
|
|
13
|
+
*
|
|
14
|
+
* That rule was written for the state opacities and then broken by the halo,
|
|
15
|
+
* which was styled here at 0.35 because it is not a state. The composited
|
|
16
|
+
* contrast check reads the grammar, so the one alpha it could not see was the
|
|
17
|
+
* one that failed the 3:1 bar. `styles.test.ts` now enforces the rule instead
|
|
18
|
+
* of stating it. A rule would be a
|
|
19
|
+
* second copy of a number, and the two would drift the first time one was
|
|
20
|
+
* tuned. What CSS owns is what CSS can express and the table cannot: the halo's
|
|
21
|
+
* stroke, the marching animation, and the hue each state paints with.
|
|
22
|
+
*
|
|
23
|
+
* IT SELECTS ONLY WHAT THIS PACKAGE ADDS. In particular it never selects
|
|
24
|
+
* `.ig-terminal`: the terminal marker is one of the four redundant channels the
|
|
25
|
+
* edge's type identity rests on, and a rule here could occlude it as surely as
|
|
26
|
+
* a mark could. The four survive because nothing in this file reaches them.
|
|
27
|
+
*
|
|
28
|
+
* ## The marching dash, and why it is not a timer
|
|
29
|
+
*
|
|
30
|
+
* `pending-write` animates `stroke-dashoffset`, which is the design's "marching
|
|
31
|
+
* dash". Nothing about it changes STATE: the animation runs while the edge is
|
|
32
|
+
* pending and stops when the projection stops saying so. A chip that dismissed
|
|
33
|
+
* itself would be the banned thing, and there is none.
|
|
34
|
+
*
|
|
35
|
+
* It is written under `prefers-reduced-motion` guard, because a reader who has
|
|
36
|
+
* asked for less motion still needs to know a write is in flight — the opacity
|
|
37
|
+
* and the dash pattern carry that on their own, so the movement is what drops
|
|
38
|
+
* rather than the signal.
|
|
39
|
+
*/
|
|
40
|
+
export declare const edgeOverlayStylesheet = "\n.ig-overlay {\n pointer-events: none;\n}\n\n.ig-overlay-halo {\n fill: none;\n stroke: var(--ig-focus);\n stroke-linecap: round;\n}\n\n/* The stroke is set per element from the treatment table \u2014 a state's own hue\n where it has one, the relationship's where it does not \u2014 for the same reason\n the viewer sets its dash per element: one source for a channel. */\n.ig-overlay-dash {\n fill: none;\n}\n\n.ig-overlay-marching {\n stroke-dasharray: 4 4;\n animation: ig-overlay-march 1s linear infinite;\n}\n\n.ig-overlay-dotted {\n stroke-dasharray: 1 3;\n}\n\n@keyframes ig-overlay-march {\n to {\n stroke-dashoffset: -8;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .ig-overlay-marching {\n animation: none;\n }\n}\n\n/* NOT prefixed with the edge class. A together-with relationship is drawn as a\n connector rather than an edge path, so an edge-anchored rule left one of the\n five relationships unstyled in every state. Only an overlaid element carries\n the attribute at all, so the bare selector reaches exactly the intended set.\n (No backticks in here: this is inside a template literal, and one ends it.) */\n[data-ig-state~='invalid'] {\n stroke: var(--ig-state-invalid);\n}\n\n[data-ig-state~='failed'] {\n stroke: var(--ig-state-failed);\n}\n\n[data-ig-state~='conflict'] {\n stroke: var(--ig-state-conflict);\n}\n\n.ig-overlay-chip {\n background: var(--ig-surface-2);\n color: var(--ig-text-muted);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-tight);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-overlay-cross {\n color: var(--ig-state-failed);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n}\n\n.ig-overlay-reason {\n color: var(--ig-state-invalid);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-overlay-held {\n color: var(--ig-state-conflict);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n}\n";
|
|
41
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/overlay/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,eAAO,MAAM,qBAAqB,6hEAmFjC,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overlay's structural stylesheet.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the ladder's and the viewer's: layout, weight and state,
|
|
5
|
+
* never a value. Every colour, length and duration here is a `var(--ig-…)` the
|
|
6
|
+
* host's theme resolves, so a second theme keeps working on the surfaces layer
|
|
7
|
+
* 2 adds. `styles.test.ts` scans these bytes for a literal colour, a fixed
|
|
8
|
+
* length and a token the theme does not define.
|
|
9
|
+
*
|
|
10
|
+
* IT DECLARES NO OPACITY AT ALL. `grammar.ts` is the single source for every
|
|
11
|
+
* alpha this package applies, and `render.ts` writes each onto its element —
|
|
12
|
+
* so there is deliberately no `opacity` rule here, for a state OR for a mark.
|
|
13
|
+
*
|
|
14
|
+
* That rule was written for the state opacities and then broken by the halo,
|
|
15
|
+
* which was styled here at 0.35 because it is not a state. The composited
|
|
16
|
+
* contrast check reads the grammar, so the one alpha it could not see was the
|
|
17
|
+
* one that failed the 3:1 bar. `styles.test.ts` now enforces the rule instead
|
|
18
|
+
* of stating it. A rule would be a
|
|
19
|
+
* second copy of a number, and the two would drift the first time one was
|
|
20
|
+
* tuned. What CSS owns is what CSS can express and the table cannot: the halo's
|
|
21
|
+
* stroke, the marching animation, and the hue each state paints with.
|
|
22
|
+
*
|
|
23
|
+
* IT SELECTS ONLY WHAT THIS PACKAGE ADDS. In particular it never selects
|
|
24
|
+
* `.ig-terminal`: the terminal marker is one of the four redundant channels the
|
|
25
|
+
* edge's type identity rests on, and a rule here could occlude it as surely as
|
|
26
|
+
* a mark could. The four survive because nothing in this file reaches them.
|
|
27
|
+
*
|
|
28
|
+
* ## The marching dash, and why it is not a timer
|
|
29
|
+
*
|
|
30
|
+
* `pending-write` animates `stroke-dashoffset`, which is the design's "marching
|
|
31
|
+
* dash". Nothing about it changes STATE: the animation runs while the edge is
|
|
32
|
+
* pending and stops when the projection stops saying so. A chip that dismissed
|
|
33
|
+
* itself would be the banned thing, and there is none.
|
|
34
|
+
*
|
|
35
|
+
* It is written under `prefers-reduced-motion` guard, because a reader who has
|
|
36
|
+
* asked for less motion still needs to know a write is in flight — the opacity
|
|
37
|
+
* and the dash pattern carry that on their own, so the movement is what drops
|
|
38
|
+
* rather than the signal.
|
|
39
|
+
*/
|
|
40
|
+
export const edgeOverlayStylesheet = `
|
|
41
|
+
.ig-overlay {
|
|
42
|
+
pointer-events: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ig-overlay-halo {
|
|
46
|
+
fill: none;
|
|
47
|
+
stroke: var(--ig-focus);
|
|
48
|
+
stroke-linecap: round;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* The stroke is set per element from the treatment table — a state's own hue
|
|
52
|
+
where it has one, the relationship's where it does not — for the same reason
|
|
53
|
+
the viewer sets its dash per element: one source for a channel. */
|
|
54
|
+
.ig-overlay-dash {
|
|
55
|
+
fill: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.ig-overlay-marching {
|
|
59
|
+
stroke-dasharray: 4 4;
|
|
60
|
+
animation: ig-overlay-march 1s linear infinite;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ig-overlay-dotted {
|
|
64
|
+
stroke-dasharray: 1 3;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes ig-overlay-march {
|
|
68
|
+
to {
|
|
69
|
+
stroke-dashoffset: -8;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@media (prefers-reduced-motion: reduce) {
|
|
74
|
+
.ig-overlay-marching {
|
|
75
|
+
animation: none;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* NOT prefixed with the edge class. A together-with relationship is drawn as a
|
|
80
|
+
connector rather than an edge path, so an edge-anchored rule left one of the
|
|
81
|
+
five relationships unstyled in every state. Only an overlaid element carries
|
|
82
|
+
the attribute at all, so the bare selector reaches exactly the intended set.
|
|
83
|
+
(No backticks in here: this is inside a template literal, and one ends it.) */
|
|
84
|
+
[data-ig-state~='invalid'] {
|
|
85
|
+
stroke: var(--ig-state-invalid);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
[data-ig-state~='failed'] {
|
|
89
|
+
stroke: var(--ig-state-failed);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
[data-ig-state~='conflict'] {
|
|
93
|
+
stroke: var(--ig-state-conflict);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ig-overlay-chip {
|
|
97
|
+
background: var(--ig-surface-2);
|
|
98
|
+
color: var(--ig-text-muted);
|
|
99
|
+
border: var(--ig-stroke) solid var(--ig-line);
|
|
100
|
+
border-radius: var(--ig-radius);
|
|
101
|
+
padding: var(--ig-space-tight);
|
|
102
|
+
font-family: var(--ig-font-ui);
|
|
103
|
+
font-size: var(--ig-font-size-small);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.ig-overlay-cross {
|
|
107
|
+
color: var(--ig-state-failed);
|
|
108
|
+
font-family: var(--ig-font-ui);
|
|
109
|
+
font-size: var(--ig-font-size);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ig-overlay-reason {
|
|
113
|
+
color: var(--ig-state-invalid);
|
|
114
|
+
font-family: var(--ig-font-ui);
|
|
115
|
+
font-size: var(--ig-font-size-small);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ig-overlay-held {
|
|
119
|
+
color: var(--ig-state-conflict);
|
|
120
|
+
font-family: var(--ig-font-ui);
|
|
121
|
+
font-size: var(--ig-font-size-small);
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/overlay/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFpC,CAAC"}
|