@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,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three-zone workspace: the package's top-level surface.
|
|
3
|
+
*
|
|
4
|
+
* Rail on the left, canvas in the centre, inspector on the right, with the
|
|
5
|
+
* ambient audit count in the header. Every zone is COMPOSED from the leaf that
|
|
6
|
+
* already owns it — this file assembles, it does not re-derive.
|
|
7
|
+
*
|
|
8
|
+
* | zone | comes from |
|
|
9
|
+
* |-----------|-------------------------------------------------------|
|
|
10
|
+
* | header | `auditOverlay` + `renderAuditHeader` |
|
|
11
|
+
* | rail | `renderViewer(…, { projection: 'linear' })`, windowed |
|
|
12
|
+
* | canvas | `renderScaleLadder` |
|
|
13
|
+
* | inspector | `inspectorView`, rendered here |
|
|
14
|
+
*
|
|
15
|
+
* ## The audit left-bar is applied to the rail's SPEC, never to its markup
|
|
16
|
+
*
|
|
17
|
+
* The rail's rows are layer 1's, and this package's standing rule is that
|
|
18
|
+
* nothing splices a rendered string — that is the hand-rolled escaping surface
|
|
19
|
+
* the spec grammar exists to remove, and `reevaluate/render.ts` records the
|
|
20
|
+
* same decision when it nests `scene.root` rather than concatenating chips into
|
|
21
|
+
* the rail.
|
|
22
|
+
*
|
|
23
|
+
* `scene.root` is DATA, and `KEY_ATTRIBUTE` is published, so {@link markRail}
|
|
24
|
+
* walks the spec tree and adds `data-ig-audit` to the keyed rows. That is a
|
|
25
|
+
* pure transform over a public value rather than a reach past a surface, and it
|
|
26
|
+
* means no attribute in this file is ever escaped by anything but `renderMarkup`.
|
|
27
|
+
*
|
|
28
|
+
* ## A row's severity is the heaviest across its MEMBERS
|
|
29
|
+
*
|
|
30
|
+
* A `together-with` unit is one row and several refs, and a finding can name a
|
|
31
|
+
* member that does not lead. Read off the lead alone, an affected unit renders
|
|
32
|
+
* clean — which is the audit failing silently on exactly the rows where an
|
|
33
|
+
* encoding error is hardest to see.
|
|
34
|
+
*
|
|
35
|
+
* ## The zone frames, and the one place a tag is written here
|
|
36
|
+
*
|
|
37
|
+
* Two of the four zones hand back a STRING rather than a spec — the ladder's
|
|
38
|
+
* chrome and the audit header — so the frames are assembled by concatenation,
|
|
39
|
+
* as `renderScaleLadder` already assembles its own canvas and chrome. What
|
|
40
|
+
* makes that safe is not care: {@link ZONES} is a closed union of literals, so
|
|
41
|
+
* no caller value can reach an attribute here at all, and `zones.test.ts` pins
|
|
42
|
+
* it. Everything with a dynamic value in it goes through `renderMarkup`.
|
|
43
|
+
*
|
|
44
|
+
* ## Dark only
|
|
45
|
+
*
|
|
46
|
+
* The pass-2 brief carries "light + dark" over from pass 1; light was cut after
|
|
47
|
+
* that pass, and dark-only is the decision rather than an omission. There is no
|
|
48
|
+
* forked token set here and no second palette: the theme is the viewer's, and
|
|
49
|
+
* `styles.ts` writes structure against its custom properties.
|
|
50
|
+
*/
|
|
51
|
+
import { KEY_ATTRIBUTE, element, normalizeDocument, renderMarkup, renderViewer, resolveTheme, themeCss, viewerStylesheet, } from '@issuegraph/viewer';
|
|
52
|
+
import { auditStylesheet } from "../audit/styles.js";
|
|
53
|
+
import { edgeOverlayStylesheet } from "../overlay/styles.js";
|
|
54
|
+
import { AUDIT_SEVERITY_ATTRIBUTE, auditFilterKeeps, auditOverlay, heaviestRow, renderAuditHeader, } from "../audit/surface.js";
|
|
55
|
+
import { INITIAL_SCALE_STATE } from "../scale/commands.js";
|
|
56
|
+
import { renderScaleLadder } from "../scale/render.js";
|
|
57
|
+
import { scaleLadderStylesheet } from "../scale/styles.js";
|
|
58
|
+
import { inspectorView } from "./inspector.js";
|
|
59
|
+
import { railWindow } from "./rail.js";
|
|
60
|
+
import { INITIAL_SELECTION, selectedEdgeId, selectedKey, } from "./selection.js";
|
|
61
|
+
import { workspaceStylesheet } from "./styles.js";
|
|
62
|
+
/** The four fixed positions. A closed union, which is what keeps `zone` safe. */
|
|
63
|
+
export const ZONES = Object.freeze(['header', 'rail', 'canvas', 'inspector']);
|
|
64
|
+
/**
|
|
65
|
+
* A zone frame.
|
|
66
|
+
*
|
|
67
|
+
* The only tag written by hand in this package, and it takes no caller value:
|
|
68
|
+
* `zone` is one of {@link ZONES} and `inner` is already-rendered markup from
|
|
69
|
+
* `renderMarkup` or from a sibling leaf's renderer.
|
|
70
|
+
*/
|
|
71
|
+
function zone(name, inner) {
|
|
72
|
+
return `<section class="ig-zone" data-zone="${name}">${inner}</section>`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The height the rows outside the window would have taken.
|
|
76
|
+
*
|
|
77
|
+
* WITHOUT THESE THE SCROLL CONTAINER CANNOT REACH THE ORDER. The rail zone
|
|
78
|
+
* scrolls, and a zone containing only the drawn rows is exactly as tall as
|
|
79
|
+
* those rows — so native scrolling stops at the end of the first window, and a
|
|
80
|
+
* host has no scroll offset to turn into the next `start`. `addressOf` keeps
|
|
81
|
+
* the MODEL complete, and a reader who cannot scroll to rank 287 does not care.
|
|
82
|
+
*
|
|
83
|
+
* ONE ROW HEIGHT FOR ALL OF THEM, which is an approximation and is stated as
|
|
84
|
+
* one: a row carrying holds is taller than a bare one, so the scrollbar is
|
|
85
|
+
* proportional rather than exact. That is the standard cost of fixed-height
|
|
86
|
+
* virtualisation and the alternative — measuring rows — needs a mount, which
|
|
87
|
+
* this package does not have and will not grow.
|
|
88
|
+
*
|
|
89
|
+
* `aria-hidden`, because a spacer is geometry: it names no row, and a reader
|
|
90
|
+
* moving by rank uses the order rather than the scrollbar.
|
|
91
|
+
*/
|
|
92
|
+
function railSpacer(rows, edge) {
|
|
93
|
+
return rows === 0
|
|
94
|
+
? ''
|
|
95
|
+
: renderMarkup(element('div', {
|
|
96
|
+
class: 'ig-rail-spacer',
|
|
97
|
+
'data-edge': edge,
|
|
98
|
+
'aria-hidden': 'true',
|
|
99
|
+
// Through `element`, so the one dynamic value here is escaped by the
|
|
100
|
+
// same renderer as every other attribute in this package.
|
|
101
|
+
style: `--ig-rail-rows:${String(rows)}`,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
/** The heaviest severity across a row's members, or `undefined` when clean. */
|
|
105
|
+
function severityForRow(overlay, members) {
|
|
106
|
+
// THE RANKING BELONGS NEXT TO THE WEIGHTS, which is why this delegates rather
|
|
107
|
+
// than scanning. An earlier version walked `overlay.rows` and took the first
|
|
108
|
+
// member it matched, on the stated grounds that those rows are "sorted" — and
|
|
109
|
+
// they are, by `ref`, LEXICOGRAPHICALLY. So it returned whichever member
|
|
110
|
+
// sorted earliest, and a `stale-blocker` on `a` masked a `cycle` on `b`: the
|
|
111
|
+
// bar still appeared, understating what it was about. The comment asserting
|
|
112
|
+
// the justification was the defect, not the loop.
|
|
113
|
+
return overlay === null ? undefined : heaviestRow(overlay, members)?.severity;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Add `data-ig-audit` to the rail's keyed rows.
|
|
117
|
+
*
|
|
118
|
+
* A total walk that rebuilds the tree rather than mutating it: `ElementSpec` is
|
|
119
|
+
* `readonly` throughout, and a mutating walk would also be visible to the
|
|
120
|
+
* caller's own copy of `scene.root`.
|
|
121
|
+
*/
|
|
122
|
+
function markRail(root, severityOf) {
|
|
123
|
+
// TYPED AS `ElementSpec -> ElementSpec` AT THE BOUNDARY, with the child walk
|
|
124
|
+
// kept inside. A single function over `SpecChild` would hand `renderMarkup` a
|
|
125
|
+
// union it does not take, and the obvious repair — casting the result back —
|
|
126
|
+
// is the one this repository bans outright. The narrowing belongs where the
|
|
127
|
+
// string case actually lives.
|
|
128
|
+
const markChild = (child) => typeof child === 'string' ? child : markSpec(child);
|
|
129
|
+
function markSpec(spec) {
|
|
130
|
+
const key = spec.attrs?.[KEY_ATTRIBUTE];
|
|
131
|
+
// A KEY IS A STRING OR IT IS NOT A KEY. `AttrValue` admits numbers and
|
|
132
|
+
// booleans, and `String(true)` would look up a row named "true" — which
|
|
133
|
+
// resolves to nothing today and to something the day a host names an issue
|
|
134
|
+
// that. Narrowed rather than coerced.
|
|
135
|
+
const severity = typeof key === 'string' ? severityOf(key) : undefined;
|
|
136
|
+
const children = spec.children?.map(markChild);
|
|
137
|
+
const attrs = severity === undefined
|
|
138
|
+
? spec.attrs
|
|
139
|
+
: { ...spec.attrs, [AUDIT_SEVERITY_ATTRIBUTE]: severity };
|
|
140
|
+
return {
|
|
141
|
+
...spec,
|
|
142
|
+
...(attrs === undefined ? {} : { attrs }),
|
|
143
|
+
...(children === undefined ? {} : { children }),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return markSpec(root);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* One relationship, as a row the reader can actually operate.
|
|
150
|
+
*
|
|
151
|
+
* THE COMMAND SITS ON A BUTTON, NOT ON THE `li`. A plain list item has no tab
|
|
152
|
+
* stop and no native Enter/Space activation, so a `data-ig-command` on one is
|
|
153
|
+
* reachable by pointer and by nothing else — and a host wiring the published
|
|
154
|
+
* attributes cannot fix that without rebuilding the semantics this package
|
|
155
|
+
* should have supplied. Every other command in the package is already on a
|
|
156
|
+
* button; `refusalSpec`'s capsule is the same `li` + `button` shape.
|
|
157
|
+
*
|
|
158
|
+
* The `li` keeps the hue and the direction, because those describe the
|
|
159
|
+
* relationship rather than the action.
|
|
160
|
+
*/
|
|
161
|
+
function relationshipSpec(relationship) {
|
|
162
|
+
return element('li', {
|
|
163
|
+
class: 'ig-relationship',
|
|
164
|
+
'data-edge': relationship.field,
|
|
165
|
+
// Omitted rather than falsified when the subject is not an issue: an edge
|
|
166
|
+
// selection has no "my end", and `data-direction=""` would claim one.
|
|
167
|
+
'data-direction': relationship.direction ?? undefined,
|
|
168
|
+
}, [
|
|
169
|
+
element('button', {
|
|
170
|
+
type: 'button',
|
|
171
|
+
class: 'ig-relationship-select',
|
|
172
|
+
'data-ig-command': 'select-edge',
|
|
173
|
+
'data-ig-target': relationship.edgeId,
|
|
174
|
+
}, [
|
|
175
|
+
element('span', { class: 'ig-relationship-kind' }, [relationship.field]),
|
|
176
|
+
element('span', { class: 'ig-relationship-ref' }, [relationship.from]),
|
|
177
|
+
element('span', { class: 'ig-relationship-ref' }, [relationship.to]),
|
|
178
|
+
]),
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
function inspectorSpec(view, words) {
|
|
182
|
+
const subject = view.subject;
|
|
183
|
+
return element('div', { class: 'ig-inspector', 'data-subject': subject.kind }, [
|
|
184
|
+
subject.kind === 'none'
|
|
185
|
+
? element('p', { class: 'ig-inspector-empty' }, [words.nothingSelected])
|
|
186
|
+
: null,
|
|
187
|
+
subject.kind === 'issue'
|
|
188
|
+
? element('div', { class: 'ig-inspector-issue' }, [
|
|
189
|
+
element('h2', { class: 'ig-inspector-title' }, [subject.issue.title]),
|
|
190
|
+
element('span', { class: 'ig-inspector-key' }, [subject.issue.key]),
|
|
191
|
+
subject.position === null
|
|
192
|
+
? null
|
|
193
|
+
: element('p', {
|
|
194
|
+
class: 'ig-inspector-position',
|
|
195
|
+
'data-ready': subject.position.ready ? 'true' : 'false',
|
|
196
|
+
},
|
|
197
|
+
// A HELD SLOT PRINTS THE VIEWER'S EM DASH, not a number. It has
|
|
198
|
+
// no position in the sequence, and printing one would claim work
|
|
199
|
+
// is queued that nothing can start.
|
|
200
|
+
[subject.position.rank === null ? '—' : String(subject.position.rank)]),
|
|
201
|
+
subject.position === null || subject.position.holds.length === 0
|
|
202
|
+
? null
|
|
203
|
+
: element('ul', { class: 'ig-inspector-holds' }, subject.position.holds.map((hold) => element('li', { class: 'ig-inspector-hold', 'data-family': hold.family }, [
|
|
204
|
+
hold.reason,
|
|
205
|
+
]))),
|
|
206
|
+
])
|
|
207
|
+
: null,
|
|
208
|
+
element('div', { class: 'ig-inspector-relationships', 'data-filtered': view.filtered ? 'true' : 'false' }, [
|
|
209
|
+
element('h3', { class: 'ig-inspector-heading' }, [words.relationships]),
|
|
210
|
+
view.filtered
|
|
211
|
+
? element('button', { type: 'button', class: 'ig-inspector-clear', 'data-ig-command': 'clear' }, [words.clearSelection])
|
|
212
|
+
: null,
|
|
213
|
+
view.relationships.length === 0
|
|
214
|
+
? null
|
|
215
|
+
: element('ul', { class: 'ig-relationship-list' }, view.relationships.map((relationship) => relationshipSpec(relationship))),
|
|
216
|
+
]),
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
/** Render one document at one reader position, as the whole workspace. */
|
|
220
|
+
export function renderWorkspace(input, options) {
|
|
221
|
+
const selection = options.selection ?? INITIAL_SELECTION;
|
|
222
|
+
const theme = resolveTheme(options.theme);
|
|
223
|
+
const overlay = options.audit === undefined ? null : auditOverlay(options.audit);
|
|
224
|
+
// NORMALIZE ONCE, AT THE TOP, AND DERIVE EVERYTHING FROM THAT — this replaces
|
|
225
|
+
// four separate defects rather than fixing them one at a time, and the class
|
|
226
|
+
// is worth naming because it is not obvious from any one of them.
|
|
227
|
+
//
|
|
228
|
+
// Every zone normalizes the document it is handed; this function did NOT, so
|
|
229
|
+
// it derived the window, the severity map, the filter set and the inspector's
|
|
230
|
+
// relationships from the RAW input while the zones drew the normalized one.
|
|
231
|
+
// Anything layer 1 drops — a duplicate placement, a self-edge, an edge naming
|
|
232
|
+
// an issue the document does not carry — therefore survived in this
|
|
233
|
+
// function's answers and vanished from the picture beside them. Two of the
|
|
234
|
+
// shapes that reached: the inspector published a `select-edge` command for an
|
|
235
|
+
// edge no zone had drawn, and a duplicate placement straddling a window
|
|
236
|
+
// boundary became VALID whenever its earlier copy fell outside the window, so
|
|
237
|
+
// the visible order changed with the scroll position.
|
|
238
|
+
//
|
|
239
|
+
// Normalizing here makes those unrepresentable instead of handled.
|
|
240
|
+
// `normalizeDocument` is idempotent — measured: re-normalizing its own output
|
|
241
|
+
// yields zero further diagnostics — so the zones' own passes now find nothing
|
|
242
|
+
// left to drop, and this is the one place that reports what was dropped.
|
|
243
|
+
const sound = normalizeDocument(input);
|
|
244
|
+
const document = sound.document;
|
|
245
|
+
// THE FILTER NARROWS THE RAIL, AND ONLY THE RAIL. §17a gives the audit a
|
|
246
|
+
// filter for focus and deliberately no mode; the canvas answers "what
|
|
247
|
+
// surrounds this issue", which the filter says nothing about.
|
|
248
|
+
//
|
|
249
|
+
// It narrows BEFORE the window, or it would narrow only whichever rows the
|
|
250
|
+
// window had already reached and read as doing nothing on a long backlog. On
|
|
251
|
+
// members rather than the lead, for the reason the bar is: a finding can name
|
|
252
|
+
// a member that does not lead its unit.
|
|
253
|
+
const filtered = overlay !== null && options.auditFiltered === true;
|
|
254
|
+
const railInput = filtered
|
|
255
|
+
? {
|
|
256
|
+
...document,
|
|
257
|
+
order: {
|
|
258
|
+
// EXCLUSIONS ARE ROWS TOO, and filtering only the slots left the clean
|
|
259
|
+
// ones on screen while the header said the filter was on — the toggle
|
|
260
|
+
// narrowing part of the rail and claiming to have narrowed it.
|
|
261
|
+
slots: document.order.slots.filter((slot) => slot.members.some((member) => auditFilterKeeps(overlay, member))),
|
|
262
|
+
excluded: document.order.excluded.filter((exclusion) => auditFilterKeeps(overlay, exclusion.key)),
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
: document;
|
|
266
|
+
const rail = railWindow(railInput, options.rail ?? {});
|
|
267
|
+
const railRender = renderViewer(rail.document, {
|
|
268
|
+
projection: 'linear',
|
|
269
|
+
theme,
|
|
270
|
+
// The rail is where a selected ISSUE reads as current. An edge selection
|
|
271
|
+
// resolves to no key, which is `selectedKey`'s whole job.
|
|
272
|
+
selected: selectedKey(selection),
|
|
273
|
+
});
|
|
274
|
+
// Built once, over the window's rows, so a rail of 312 costs one pass rather
|
|
275
|
+
// than one scan of `overlay.rows` per drawn row.
|
|
276
|
+
const severityByKey = new Map();
|
|
277
|
+
for (const slot of rail.rows) {
|
|
278
|
+
const severity = severityForRow(overlay, slot.members);
|
|
279
|
+
if (severity !== undefined)
|
|
280
|
+
severityByKey.set(slot.lead, severity);
|
|
281
|
+
}
|
|
282
|
+
// EXCLUSIONS CARRY A KEY AND RENDER A ROW, so the bar belongs on them too.
|
|
283
|
+
// Built from the slots alone, the map missed exactly the row a
|
|
284
|
+
// `dead-duplicate-ref` finding is about — the class most associated with an
|
|
285
|
+
// exclusion in the first place — and the ambient warning went missing on the
|
|
286
|
+
// one row it most obviously described.
|
|
287
|
+
for (const exclusion of rail.document.order.excluded) {
|
|
288
|
+
const severity = severityForRow(overlay, [exclusion.key]);
|
|
289
|
+
if (severity !== undefined)
|
|
290
|
+
severityByKey.set(exclusion.key, severity);
|
|
291
|
+
}
|
|
292
|
+
// THE CANVAS IS THE WHOLE DOCUMENT, NOT THE WINDOW. The window is the rail's
|
|
293
|
+
// scrolling position and says nothing about what surrounds the selected
|
|
294
|
+
// issue; handing the ladder a windowed document would make its budgets — and
|
|
295
|
+
// therefore its refusal — depend on where the reader had scrolled to.
|
|
296
|
+
const canvas = renderScaleLadder(document, {
|
|
297
|
+
state: options.scale ?? INITIAL_SCALE_STATE,
|
|
298
|
+
theme,
|
|
299
|
+
// THE SAME ONE VALUE THE RAIL READ. Without this the canvas drew the
|
|
300
|
+
// selected issue as ordinary while the rail marked it current, so the
|
|
301
|
+
// single selection this surface advertises disagreed with itself between
|
|
302
|
+
// two zones on every render.
|
|
303
|
+
selected: selectedKey(selection),
|
|
304
|
+
// AND ITS OTHER HALF. The union has two payloads, and reading only the
|
|
305
|
+
// issue one left the canvas the single zone that could not see an edge
|
|
306
|
+
// selection: the inspector filtered to the edge while the canvas drew it
|
|
307
|
+
// as ordinary — the same disagreement the line above closed for issues,
|
|
308
|
+
// still open for the other kind.
|
|
309
|
+
selectedEdge: selectedEdgeId(selection),
|
|
310
|
+
});
|
|
311
|
+
const inspector = inspectorView(document, selection);
|
|
312
|
+
const markup = [
|
|
313
|
+
`<div class="ig-workspace">`,
|
|
314
|
+
overlay === null ? '' : zone('header', renderAuditHeader(overlay, { filtered })),
|
|
315
|
+
zone('rail', [
|
|
316
|
+
railSpacer(rail.before, 'before'),
|
|
317
|
+
renderMarkup(markRail(railRender.scene.root, (key) => severityByKey.get(key))),
|
|
318
|
+
railSpacer(rail.after, 'after'),
|
|
319
|
+
].join('')),
|
|
320
|
+
zone('canvas', canvas.markup),
|
|
321
|
+
zone('inspector', renderMarkup(inspectorSpec(inspector, options.words))),
|
|
322
|
+
`</div>`,
|
|
323
|
+
].join('');
|
|
324
|
+
return {
|
|
325
|
+
view: { selection, rail, inspector, audit: overlay, auditFiltered: filtered },
|
|
326
|
+
markup,
|
|
327
|
+
// THE THEME IS WRITTEN ONCE. Both leaves below emit their own copy of the
|
|
328
|
+
// viewer's stylesheet and the theme rule, so taking `canvas.styles`
|
|
329
|
+
// wholesale would install the custom properties two or three times over —
|
|
330
|
+
// harmless to render and impossible to debug when a host overrides one.
|
|
331
|
+
styles: [
|
|
332
|
+
viewerStylesheet,
|
|
333
|
+
themeCss(theme, options.themeSelector ?? ':root'),
|
|
334
|
+
scaleLadderStylesheet,
|
|
335
|
+
// THE CANVAS CAN DRAW A SELECTION HALO NOW, so the sheet that styles one
|
|
336
|
+
// has to be installed. It is listed here rather than inherited from
|
|
337
|
+
// `canvas.styles` for the reason directly above: that value carries its
|
|
338
|
+
// own copy of the viewer sheet and the theme.
|
|
339
|
+
// UNCONDITIONAL, unlike the audit sheet beside it. An audit overlay is a
|
|
340
|
+
// whole zone a caller opts into; an edge selection arrives from a click
|
|
341
|
+
// AFTER this render, so a sheet installed only when something is already
|
|
342
|
+
// selected is one that is missing on exactly the render that first needs
|
|
343
|
+
// it.
|
|
344
|
+
edgeOverlayStylesheet,
|
|
345
|
+
...(overlay === null ? [] : [auditStylesheet]),
|
|
346
|
+
workspaceStylesheet,
|
|
347
|
+
].join('\n'),
|
|
348
|
+
// CONCATENATED, NOT DEDUPED — and the dedupe that used to sit here is worth
|
|
349
|
+
// recording rather than deleting quietly, because it was CORRECT when it
|
|
350
|
+
// was added and became wrong two commits later without being touched.
|
|
351
|
+
//
|
|
352
|
+
// It was added when both zones normalized the raw document independently
|
|
353
|
+
// and reported the same defect twice. Normalizing once removed that source,
|
|
354
|
+
// and the same `Set` then had only one thing left to collapse: the
|
|
355
|
+
// deliberately REPEATED diagnostics a single pass emits, one per occurrence
|
|
356
|
+
// — two identical self-edges, the same unknown member in several slots.
|
|
357
|
+
// Understating how many times an input is malformed is worse than the
|
|
358
|
+
// duplication it was guarding against, and it is a count a host acts on.
|
|
359
|
+
//
|
|
360
|
+
// Nothing replaces it, because nothing needs to: the zones now receive an
|
|
361
|
+
// already-sound document, so they contribute nothing to this list at all.
|
|
362
|
+
// `reports every occurrence, and the zones add nothing` pins both halves.
|
|
363
|
+
diagnostics: [...sound.diagnostics, ...railRender.diagnostics, ...canvas.diagnostics],
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/workspace/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one piece of state that crosses all three zones.
|
|
3
|
+
*
|
|
4
|
+
* §17b: `selected` is the only edge state that also filters the inspector. So
|
|
5
|
+
* the workspace owns exactly one cross-zone value, and it owns it as ONE value
|
|
6
|
+
* rather than three synchronised copies — the rail, the canvas and the
|
|
7
|
+
* inspector all read this, and none of them mints a second.
|
|
8
|
+
*
|
|
9
|
+
* ## Why a union rather than two nullable fields
|
|
10
|
+
*
|
|
11
|
+
* The obvious shape is `{ issue: string | null; edge: string | null }`, and it
|
|
12
|
+
* is wrong in a way that is invisible until it bites: it can represent
|
|
13
|
+
* "an issue AND an edge are both selected", which is not a state this design
|
|
14
|
+
* has. Every reader would then need a rule for it, the three zones would be
|
|
15
|
+
* free to pick different rules, and the bug would show up as two zones
|
|
16
|
+
* disagreeing about what is selected rather than as a type error.
|
|
17
|
+
*
|
|
18
|
+
* A discriminated union has no such cell. `kind` answers what is selected, and
|
|
19
|
+
* the payload that belongs to that answer is the only payload in scope.
|
|
20
|
+
*
|
|
21
|
+
* ## It carries no document
|
|
22
|
+
*
|
|
23
|
+
* A selection names a key or an edge id and nothing else. It is deliberately
|
|
24
|
+
* not a resolved issue or a resolved edge: the document changes under it — a
|
|
25
|
+
* write lands, the order recomputes — and a selection holding a snapshot of the
|
|
26
|
+
* thing it names would go stale silently. Every zone resolves the name against
|
|
27
|
+
* the document it is rendering, so a selection that no longer resolves renders
|
|
28
|
+
* as nothing selected rather than as last render's answer.
|
|
29
|
+
*/
|
|
30
|
+
/** What the reader has selected. Exactly one thing, or nothing. */
|
|
31
|
+
export type WorkspaceSelection = {
|
|
32
|
+
readonly kind: 'none';
|
|
33
|
+
} | {
|
|
34
|
+
readonly kind: 'issue';
|
|
35
|
+
readonly key: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: 'edge';
|
|
38
|
+
readonly edgeId: string;
|
|
39
|
+
};
|
|
40
|
+
/** Nothing selected. The state a freshly-loaded workspace is in. */
|
|
41
|
+
export declare const INITIAL_SELECTION: WorkspaceSelection;
|
|
42
|
+
/**
|
|
43
|
+
* What a zone can ask for.
|
|
44
|
+
*
|
|
45
|
+
* `select-issue` and `select-edge` REPLACE rather than add, which is the
|
|
46
|
+
* reducer half of the union above: there is no command that could put the
|
|
47
|
+
* workspace in two selections at once, so no reader has to handle one.
|
|
48
|
+
*/
|
|
49
|
+
export type SelectionCommand = {
|
|
50
|
+
readonly kind: 'select-issue';
|
|
51
|
+
readonly key: string;
|
|
52
|
+
} | {
|
|
53
|
+
readonly kind: 'select-edge';
|
|
54
|
+
readonly edgeId: string;
|
|
55
|
+
} | {
|
|
56
|
+
readonly kind: 'clear';
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The next selection.
|
|
60
|
+
*
|
|
61
|
+
* Pure and total, like `scaleReducer` beside it: a host reads a
|
|
62
|
+
* `data-ig-command` off a control, calls this, and renders again. Selecting
|
|
63
|
+
* what is already selected CLEARS it — a second click on the same row is how a
|
|
64
|
+
* reader gets back to the whole document without hunting for a control, and it
|
|
65
|
+
* is the behaviour the canvas and the rail both need.
|
|
66
|
+
*/
|
|
67
|
+
export declare function selectionReducer(selection: WorkspaceSelection, command: SelectionCommand): WorkspaceSelection;
|
|
68
|
+
/**
|
|
69
|
+
* The key the VIEWER should draw as selected, if any.
|
|
70
|
+
*
|
|
71
|
+
* An edge selection resolves to no key on purpose: the viewer's `selected`
|
|
72
|
+
* renders `aria-current` on a NODE, and an edge is not a node. Handing it an
|
|
73
|
+
* edge id would either match nothing — the quiet failure — or, worse, match an
|
|
74
|
+
* issue whose key happened to collide with an edge id.
|
|
75
|
+
*/
|
|
76
|
+
export declare function selectedKey(selection: WorkspaceSelection): string | null;
|
|
77
|
+
/**
|
|
78
|
+
* The edge identity the CANVAS should draw as selected, if any.
|
|
79
|
+
*
|
|
80
|
+
* The mirror of {@link selectedKey}, and it exists for the same reason that one
|
|
81
|
+
* does: the union has two payloads and a zone reads exactly the one that
|
|
82
|
+
* belongs to it. `selectedKey` answers the viewer's `aria-current`, which is a
|
|
83
|
+
* NODE question; this answers the canvas's selection overlay, which is an EDGE
|
|
84
|
+
* question. Neither zone gets to ask the other's.
|
|
85
|
+
*
|
|
86
|
+
* An issue selection resolves to no edge for the same reason the other returns
|
|
87
|
+
* no key: an issue key and an edge identity are different name spaces, and
|
|
88
|
+
* handing one to the reader of the other either matches nothing — the quiet
|
|
89
|
+
* failure — or matches the wrong thing.
|
|
90
|
+
*/
|
|
91
|
+
export declare function selectedEdgeId(selection: WorkspaceSelection): string | null;
|
|
92
|
+
//# sourceMappingURL=selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/workspace/selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,mEAAmE;AACnE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,oEAAoE;AACpE,eAAO,MAAM,iBAAiB,EAAE,kBAAqC,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/B;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,gBAAgB,GACxB,kBAAkB,CAapB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAExE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAE3E"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one piece of state that crosses all three zones.
|
|
3
|
+
*
|
|
4
|
+
* §17b: `selected` is the only edge state that also filters the inspector. So
|
|
5
|
+
* the workspace owns exactly one cross-zone value, and it owns it as ONE value
|
|
6
|
+
* rather than three synchronised copies — the rail, the canvas and the
|
|
7
|
+
* inspector all read this, and none of them mints a second.
|
|
8
|
+
*
|
|
9
|
+
* ## Why a union rather than two nullable fields
|
|
10
|
+
*
|
|
11
|
+
* The obvious shape is `{ issue: string | null; edge: string | null }`, and it
|
|
12
|
+
* is wrong in a way that is invisible until it bites: it can represent
|
|
13
|
+
* "an issue AND an edge are both selected", which is not a state this design
|
|
14
|
+
* has. Every reader would then need a rule for it, the three zones would be
|
|
15
|
+
* free to pick different rules, and the bug would show up as two zones
|
|
16
|
+
* disagreeing about what is selected rather than as a type error.
|
|
17
|
+
*
|
|
18
|
+
* A discriminated union has no such cell. `kind` answers what is selected, and
|
|
19
|
+
* the payload that belongs to that answer is the only payload in scope.
|
|
20
|
+
*
|
|
21
|
+
* ## It carries no document
|
|
22
|
+
*
|
|
23
|
+
* A selection names a key or an edge id and nothing else. It is deliberately
|
|
24
|
+
* not a resolved issue or a resolved edge: the document changes under it — a
|
|
25
|
+
* write lands, the order recomputes — and a selection holding a snapshot of the
|
|
26
|
+
* thing it names would go stale silently. Every zone resolves the name against
|
|
27
|
+
* the document it is rendering, so a selection that no longer resolves renders
|
|
28
|
+
* as nothing selected rather than as last render's answer.
|
|
29
|
+
*/
|
|
30
|
+
/** Nothing selected. The state a freshly-loaded workspace is in. */
|
|
31
|
+
export const INITIAL_SELECTION = { kind: 'none' };
|
|
32
|
+
/**
|
|
33
|
+
* The next selection.
|
|
34
|
+
*
|
|
35
|
+
* Pure and total, like `scaleReducer` beside it: a host reads a
|
|
36
|
+
* `data-ig-command` off a control, calls this, and renders again. Selecting
|
|
37
|
+
* what is already selected CLEARS it — a second click on the same row is how a
|
|
38
|
+
* reader gets back to the whole document without hunting for a control, and it
|
|
39
|
+
* is the behaviour the canvas and the rail both need.
|
|
40
|
+
*/
|
|
41
|
+
export function selectionReducer(selection, command) {
|
|
42
|
+
switch (command.kind) {
|
|
43
|
+
case 'select-issue':
|
|
44
|
+
return selection.kind === 'issue' && selection.key === command.key
|
|
45
|
+
? INITIAL_SELECTION
|
|
46
|
+
: { kind: 'issue', key: command.key };
|
|
47
|
+
case 'select-edge':
|
|
48
|
+
return selection.kind === 'edge' && selection.edgeId === command.edgeId
|
|
49
|
+
? INITIAL_SELECTION
|
|
50
|
+
: { kind: 'edge', edgeId: command.edgeId };
|
|
51
|
+
case 'clear':
|
|
52
|
+
return INITIAL_SELECTION;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The key the VIEWER should draw as selected, if any.
|
|
57
|
+
*
|
|
58
|
+
* An edge selection resolves to no key on purpose: the viewer's `selected`
|
|
59
|
+
* renders `aria-current` on a NODE, and an edge is not a node. Handing it an
|
|
60
|
+
* edge id would either match nothing — the quiet failure — or, worse, match an
|
|
61
|
+
* issue whose key happened to collide with an edge id.
|
|
62
|
+
*/
|
|
63
|
+
export function selectedKey(selection) {
|
|
64
|
+
return selection.kind === 'issue' ? selection.key : null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The edge identity the CANVAS should draw as selected, if any.
|
|
68
|
+
*
|
|
69
|
+
* The mirror of {@link selectedKey}, and it exists for the same reason that one
|
|
70
|
+
* does: the union has two payloads and a zone reads exactly the one that
|
|
71
|
+
* belongs to it. `selectedKey` answers the viewer's `aria-current`, which is a
|
|
72
|
+
* NODE question; this answers the canvas's selection overlay, which is an EDGE
|
|
73
|
+
* question. Neither zone gets to ask the other's.
|
|
74
|
+
*
|
|
75
|
+
* An issue selection resolves to no edge for the same reason the other returns
|
|
76
|
+
* no key: an issue key and an edge identity are different name spaces, and
|
|
77
|
+
* handing one to the reader of the other either matches nothing — the quiet
|
|
78
|
+
* failure — or matches the wrong thing.
|
|
79
|
+
*/
|
|
80
|
+
export function selectedEdgeId(selection) {
|
|
81
|
+
return selection.kind === 'edge' ? selection.edgeId : null;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/workspace/selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,oEAAoE;AACpE,MAAM,CAAC,MAAM,iBAAiB,GAAuB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AActE;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAA6B,EAC7B,OAAyB;IAEzB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,cAAc;YACjB,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG;gBAChE,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1C,KAAK,aAAa;YAChB,OAAO,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,SAAS,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;gBACrE,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QAC/C,KAAK,OAAO;YACV,OAAO,iBAAiB,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,SAA6B;IACvD,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,SAA6B;IAC1D,OAAO,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workspace's structural stylesheet: three fixed zones, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the viewer's, the ladder's and the re-evaluate surface's —
|
|
5
|
+
* layout, weight and state, never a value. Every colour, length and font is a
|
|
6
|
+
* `var(--ig-…)` the host's theme resolves, and `styles.test.ts` scans these
|
|
7
|
+
* bytes for a literal or an unresolvable token.
|
|
8
|
+
*
|
|
9
|
+
* ## Fixed, and that is the requirement
|
|
10
|
+
*
|
|
11
|
+
* §17f gives the rail and the canvas opposite obligations — the rail is
|
|
12
|
+
* complete at any backlog size, the canvas refuses above its budget — and
|
|
13
|
+
* assembling them must not average the two. Positions are therefore FIXED
|
|
14
|
+
* rather than negotiated: `grid-template-columns` gives the rail and the
|
|
15
|
+
* inspector their own tracks and the canvas the remaining `1fr`, so a large
|
|
16
|
+
* document grows the canvas's refusal rather than squeezing the rail out of
|
|
17
|
+
* the layout.
|
|
18
|
+
*
|
|
19
|
+
* The rail scrolls in its own track. That is what makes windowing a rendering
|
|
20
|
+
* decision rather than a visible one: the reader scrolls a complete order, and
|
|
21
|
+
* which slice is currently drawn is the host's business.
|
|
22
|
+
*
|
|
23
|
+
* ## Dark only, with no forked token set
|
|
24
|
+
*
|
|
25
|
+
* Light was cut after pass 1, so there is no second palette here and no
|
|
26
|
+
* `prefers-color-scheme` block. The single palette is the viewer's, reached
|
|
27
|
+
* through its custom properties — a forked set would be exactly the drifting
|
|
28
|
+
* second implementation the package split exists to remove.
|
|
29
|
+
*
|
|
30
|
+
* ## No animation, anywhere
|
|
31
|
+
*
|
|
32
|
+
* §17a: the audit is ambient, and a count that animates is a count demanding
|
|
33
|
+
* attention it has not earned. The re-evaluate surface already rejected the
|
|
34
|
+
* animated re-sort for a stronger reason — rows moving under the cursor mean
|
|
35
|
+
* the next edit targets the wrong thing — and this is the file where both
|
|
36
|
+
* could creep back in without touching a line of TypeScript.
|
|
37
|
+
*/
|
|
38
|
+
export declare const workspaceStylesheet = "\n.ig-workspace {\n display: grid;\n /* HEADER SPANS, THE THREE ZONES SIT UNDER IT. The audit count is ambient: it\n belongs to the whole workspace rather than to one zone, and putting it in a\n zone's own track would make it move when that zone resized. */\n grid-template-areas:\n 'header header header'\n 'rail canvas inspector';\n /* The rail and the inspector are sized in TYPE, not in pixels: a host that\n scales the type scales the zones with it, which a fixed track would not.\n\n A LENGTH TIMES A UNITLESS COUNT, which is the viewer's own idiom\n (styles.ts writes min-width: calc(var(--ig-char-width) * 4)). An earlier\n version multiplied --ig-char-width by --ig-label-char-width, having read\n the second as \"how many characters wide a label is\". It is not: it is the\n average width OF one character, and themeCss renders every metric with px\n \u2014 so the expression was calc(7.8px * 6px), which is not a length. CSS\n discards a declaration it cannot parse, so the whole template went with it\n and all three zones fell back to auto columns: long content could then\n squeeze the canvas, which is the one thing fixed positions exist to stop.\n Nothing failed loudly, because an invalid declaration is simply absent.\n\n 40 is a reading measure for a title plus its id, in characters. */\n grid-template-columns:\n calc(var(--ig-char-width) * 40)\n 1fr\n calc(var(--ig-char-width) * 40);\n grid-template-rows: auto 1fr;\n gap: var(--ig-space);\n background: var(--ig-bg);\n color: var(--ig-text-body);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n line-height: var(--ig-line-height);\n}\n\n.ig-zone {\n min-width: 0;\n /* Without this a long title in any zone sets that track's minimum width and\n the grid stops honouring its own template. */\n min-height: 0;\n}\n\n.ig-zone[data-zone='header'] {\n grid-area: header;\n}\n\n.ig-zone[data-zone='rail'] {\n grid-area: rail;\n /* The rail scrolls; the window slides underneath. */\n overflow-y: auto;\n border-right: var(--ig-stroke) solid var(--ig-line);\n}\n\n.ig-zone[data-zone='canvas'] {\n grid-area: canvas;\n overflow: auto;\n}\n\n.ig-zone[data-zone='inspector'] {\n grid-area: inspector;\n overflow-y: auto;\n border-left: var(--ig-stroke) solid var(--ig-line);\n}\n\n/* THE AMBIENT LEFT-BAR. A 2px gold rule on the affected row and nothing else \u2014\n no fill, no icon, no badge. \u00A717a's whole ask is that encoding errors stay\n visible while you work rather than pulling you out of it.\n\n An inset box-shadow rather than a border: a border changes the row's box and\n would shift every marked row against its neighbours, which is a layout jump\n the eye reads as movement. The width is the theme's spine, so the bar scales\n with the rest of the rail. */\n.ig-zone[data-zone='rail'] [data-ig-audit] {\n box-shadow: inset var(--ig-spine-width) 0 0 0 var(--ig-accent);\n}\n\n.ig-zone[data-zone='rail'] [data-ig-audit='misleading'] {\n box-shadow: inset var(--ig-spine-width) 0 0 0 var(--ig-state-invalid);\n}\n\n/* THE ROWS OUTSIDE THE WINDOW, AS HEIGHT. The rail scrolls, so without a spacer\n at each end the container is exactly as tall as the drawn rows and native\n scrolling stops at the end of the first window \u2014 leaving a host no offset to\n turn into the next start, and a reader no way to reach rank 287 of 312.\n\n NO BACKTICKS ANYWHERE IN THIS FILE'S COMMENTS. The stylesheet is a template\n literal, so a backtick closes it \u2014 and the failure is a parse error pages\n away from the character that caused it.\n\n THE PITCH IS THE OUTER BOX, NOT THE ROW HEIGHT. A .ig-slot is\n min-height: --ig-row-height PLUS margin-bottom: --ig-space-tight, so\n row-to-row is the sum of the two. Sized on --ig-row-height alone, this\n undercounted EVERY omitted row by the gap \u2014 44 of a 50px pitch on the default\n theme, so 300 omitted rows left the scroll extent 1,800px short and a host\n dividing its scroll position by the measured pitch could reach about offset\n 264 of 300. The tail of the order became unreachable by the very mechanism\n added to make it reachable.\n\n That is a SYSTEMATIC undercount, not the approximation below, which is why it\n is corrected exactly rather than tolerated: the gap is constant per row and\n both terms are theme metrics.\n\n --ig-rail-rows is the count, set inline by the renderer. What remains\n approximate is only VARIABLE row height \u2014 a row carrying holds is taller than\n a bare one \u2014 so the scrollbar stays proportional rather than exact. Measuring\n that needs a mount, which this package does not have. */\n.ig-rail-spacer {\n height: calc((var(--ig-row-height) + var(--ig-space-tight)) * var(--ig-rail-rows, 0));\n}\n\n.ig-inspector {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space);\n padding: var(--ig-space);\n}\n\n.ig-inspector-empty {\n margin: 0;\n color: var(--ig-text-muted);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-inspector-issue {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-inspector-title {\n margin: 0;\n font-size: var(--ig-font-size);\n color: var(--ig-text);\n}\n\n.ig-inspector-key {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n\n.ig-inspector-position {\n margin: 0;\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n\n.ig-inspector-position[data-ready='true'] {\n color: var(--ig-station-ready);\n}\n\n.ig-inspector-holds {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n/* The two hold families never share a treatment \u2014 layer 1's rule, carried\n across so the inspector cannot contradict the rail it sits beside. */\n.ig-inspector-hold[data-family='graph'] {\n color: var(--ig-station-held);\n}\n\n.ig-inspector-hold[data-family='tracker'] {\n color: var(--ig-text-muted);\n}\n\n.ig-inspector-relationships {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-inspector-heading {\n margin: 0;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text-muted);\n}\n\n.ig-inspector-clear {\n align-self: flex-start;\n background: var(--ig-surface-2);\n color: var(--ig-text-body);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-tight) var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n cursor: pointer;\n}\n\n.ig-inspector-clear:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-relationship-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-relationship {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n padding: var(--ig-space-tight);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n background: var(--ig-surface);\n}\n\n/* Hue by field, from the theme's own edge tokens \u2014 the same channel layer 1\n uses, so a relationship reads the same colour in the list as on the canvas. */\n.ig-relationship[data-edge='blocked-by'] {\n border-left-color: var(--ig-edge-blocked-by);\n}\n\n.ig-relationship[data-edge='duplicate-of'] {\n border-left-color: var(--ig-edge-duplicate-of);\n}\n\n.ig-relationship[data-edge='serialize-with'] {\n border-left-color: var(--ig-edge-serialize-with);\n}\n\n.ig-relationship[data-edge='together-with'] {\n border-left-color: var(--ig-edge-together-with);\n}\n\n.ig-relationship[data-edge='decomposed-from'] {\n border-left-color: var(--ig-edge-decomposed-from);\n}\n\n/* The button fills its row, so the whole relationship is the hit target rather\n than the words inside it. Transparent and borderless: the li already carries\n the border and the hue, and a second box around it would read as two\n controls. */\n.ig-relationship-select {\n flex: 1;\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n background: none;\n border: none;\n padding: 0;\n font-family: inherit;\n font-size: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.ig-relationship-select:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-relationship-kind {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-body);\n}\n\n.ig-relationship-ref {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n";
|
|
39
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/workspace/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,eAAO,MAAM,mBAAmB,2jRAkR/B,CAAC"}
|