@issuegraph/editor 0.4.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -9
- package/dist/a11y/baseline.d.ts +182 -0
- package/dist/a11y/baseline.d.ts.map +1 -0
- package/dist/a11y/baseline.js +434 -0
- package/dist/a11y/baseline.js.map +1 -0
- package/dist/audit/findings.d.ts +107 -1
- package/dist/audit/findings.d.ts.map +1 -1
- package/dist/audit/findings.js +113 -6
- package/dist/audit/findings.js.map +1 -1
- package/dist/audit/panel.d.ts +277 -0
- package/dist/audit/panel.d.ts.map +1 -0
- package/dist/audit/panel.js +462 -0
- package/dist/audit/panel.js.map +1 -0
- package/dist/audit/refused.d.ts +99 -0
- package/dist/audit/refused.d.ts.map +1 -0
- package/dist/audit/refused.js +276 -0
- package/dist/audit/refused.js.map +1 -0
- package/dist/audit/styles.d.ts +1 -1
- package/dist/audit/styles.d.ts.map +1 -1
- package/dist/audit/styles.js +429 -1
- package/dist/audit/styles.js.map +1 -1
- package/dist/audit/surface.d.ts +54 -12
- package/dist/audit/surface.d.ts.map +1 -1
- package/dist/audit/surface.js +53 -13
- package/dist/audit/surface.js.map +1 -1
- package/dist/create/draft.d.ts +36 -0
- package/dist/create/draft.d.ts.map +1 -1
- package/dist/create/draft.js +40 -0
- package/dist/create/draft.js.map +1 -1
- package/dist/create/keys.d.ts +134 -9
- package/dist/create/keys.d.ts.map +1 -1
- package/dist/create/keys.js +119 -20
- package/dist/create/keys.js.map +1 -1
- package/dist/firstpass/candidates.d.ts +17 -1
- package/dist/firstpass/candidates.d.ts.map +1 -1
- package/dist/index.d.ts +42 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -14
- package/dist/index.js.map +1 -1
- package/dist/overlay/render.d.ts +11 -3
- package/dist/overlay/render.d.ts.map +1 -1
- package/dist/overlay/render.js +76 -20
- package/dist/overlay/render.js.map +1 -1
- package/dist/overlay/request.d.ts +71 -0
- package/dist/overlay/request.d.ts.map +1 -0
- package/dist/overlay/request.js +129 -0
- package/dist/overlay/request.js.map +1 -0
- package/dist/overlay/styles.d.ts +1 -1
- package/dist/overlay/styles.d.ts.map +1 -1
- package/dist/overlay/styles.js +78 -7
- package/dist/overlay/styles.js.map +1 -1
- package/dist/picker/render.d.ts +26 -16
- package/dist/picker/render.d.ts.map +1 -1
- package/dist/picker/render.js +25 -36
- package/dist/picker/render.js.map +1 -1
- package/dist/picker/styles.d.ts +7 -7
- package/dist/picker/styles.d.ts.map +1 -1
- package/dist/picker/styles.js +7 -36
- package/dist/picker/styles.js.map +1 -1
- package/dist/picker/view.d.ts +8 -4
- package/dist/picker/view.d.ts.map +1 -1
- package/dist/picker/view.js +4 -3
- package/dist/picker/view.js.map +1 -1
- package/dist/picker/words.d.ts +12 -10
- package/dist/picker/words.d.ts.map +1 -1
- package/dist/picker/words.js +12 -8
- package/dist/picker/words.js.map +1 -1
- package/dist/reevaluate/parts.d.ts +130 -0
- package/dist/reevaluate/parts.d.ts.map +1 -0
- package/dist/reevaluate/parts.js +260 -0
- package/dist/reevaluate/parts.js.map +1 -0
- package/dist/reevaluate/render.d.ts +18 -11
- package/dist/reevaluate/render.d.ts.map +1 -1
- package/dist/reevaluate/render.js +21 -135
- package/dist/reevaluate/render.js.map +1 -1
- package/dist/reevaluate/styles.d.ts +1 -1
- package/dist/reevaluate/styles.d.ts.map +1 -1
- package/dist/reevaluate/styles.js +26 -0
- package/dist/reevaluate/styles.js.map +1 -1
- package/dist/reevaluate/view.d.ts +16 -1
- package/dist/reevaluate/view.d.ts.map +1 -1
- package/dist/reevaluate/view.js +21 -1
- package/dist/reevaluate/view.js.map +1 -1
- package/dist/reevaluate/words.d.ts +7 -0
- package/dist/reevaluate/words.d.ts.map +1 -1
- package/dist/scale/ladder.d.ts +62 -6
- package/dist/scale/ladder.d.ts.map +1 -1
- package/dist/scale/ladder.js +129 -11
- package/dist/scale/ladder.js.map +1 -1
- package/dist/scale/render.d.ts +44 -0
- package/dist/scale/render.d.ts.map +1 -1
- package/dist/scale/render.js +206 -28
- package/dist/scale/render.js.map +1 -1
- package/dist/scale/styles.d.ts +11 -5
- package/dist/scale/styles.d.ts.map +1 -1
- package/dist/scale/styles.js +133 -4
- package/dist/scale/styles.js.map +1 -1
- package/dist/workspace/chrome.d.ts +1 -1
- package/dist/workspace/chrome.d.ts.map +1 -1
- package/dist/workspace/chrome.js +48 -0
- package/dist/workspace/chrome.js.map +1 -1
- package/dist/workspace/firstpass.d.ts +166 -0
- package/dist/workspace/firstpass.d.ts.map +1 -0
- package/dist/workspace/firstpass.js +151 -0
- package/dist/workspace/firstpass.js.map +1 -0
- package/dist/workspace/host.d.ts +283 -11
- package/dist/workspace/host.d.ts.map +1 -1
- package/dist/workspace/host.js +614 -43
- package/dist/workspace/host.js.map +1 -1
- package/dist/workspace/inspector.d.ts +72 -2
- package/dist/workspace/inspector.d.ts.map +1 -1
- package/dist/workspace/inspector.js +26 -0
- package/dist/workspace/inspector.js.map +1 -1
- package/dist/workspace/mount.d.ts +75 -6
- package/dist/workspace/mount.d.ts.map +1 -1
- package/dist/workspace/mount.js +1851 -60
- package/dist/workspace/mount.js.map +1 -1
- package/dist/workspace/rail.d.ts +5 -2
- package/dist/workspace/rail.d.ts.map +1 -1
- package/dist/workspace/rail.js.map +1 -1
- package/dist/workspace/recovery.d.ts +155 -0
- package/dist/workspace/recovery.d.ts.map +1 -0
- package/dist/workspace/recovery.js +156 -0
- package/dist/workspace/recovery.js.map +1 -0
- package/dist/workspace/render.d.ts +779 -2
- package/dist/workspace/render.d.ts.map +1 -1
- package/dist/workspace/render.js +1727 -61
- package/dist/workspace/render.js.map +1 -1
- package/dist/workspace/selection.d.ts +11 -0
- package/dist/workspace/selection.d.ts.map +1 -1
- package/dist/workspace/selection.js +10 -0
- package/dist/workspace/selection.js.map +1 -1
- package/dist/workspace/styles.d.ts +1 -1
- package/dist/workspace/styles.d.ts.map +1 -1
- package/dist/workspace/styles.js +1405 -42
- package/dist/workspace/styles.js.map +1 -1
- package/package.json +4 -4
package/dist/scale/styles.d.ts
CHANGED
|
@@ -8,14 +8,20 @@
|
|
|
8
8
|
* scans these bytes for a literal colour or a fixed length and for a token the
|
|
9
9
|
* theme does not define, so the rule is enforced rather than remembered.
|
|
10
10
|
*
|
|
11
|
-
* IT ADDS SELECTORS RATHER THAN REDEFINING THEM
|
|
12
|
-
*
|
|
13
|
-
* introduces: the ladder container, the routes, the search box, the
|
|
14
|
-
* chip
|
|
11
|
+
* IT ADDS SELECTORS RATHER THAN REDEFINING THEM, with ONE declared exception.
|
|
12
|
+
* The refusal and its counts already have a look, so this file styles what
|
|
13
|
+
* layer 2 introduces: the ladder container, the routes, the search box, the
|
|
14
|
+
* isolated chip, the list it opens, and §17f's capsule card. The exception is
|
|
15
|
+
* `.ig-ladder .ig-refusal .ig-list`, which lays layer 1's list out as a board —
|
|
16
|
+
* declared here because the arrangement is this surface's, and scoped so §16's
|
|
17
|
+
* single-column list and the ladder's own search matches are untouched. The
|
|
18
|
+
* capsule CARD is a new class rather than a redefinition of `.ig-capsule` for
|
|
19
|
+
* the same reason, which is why the list item beside it carries no layer 1
|
|
20
|
+
* class at all.
|
|
15
21
|
*
|
|
16
22
|
* Shipped as a string for the same reason the viewer's is: an entry that
|
|
17
23
|
* imports CSS cannot be loaded by a bare Node runtime, and a string needs no
|
|
18
24
|
* bundler.
|
|
19
25
|
*/
|
|
20
|
-
export declare const scaleLadderStylesheet = "\n.ig-ladder {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n.ig-ladder-routes {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n color: var(--ig-text-muted);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-ladder-search {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-ladder-search input {\n background: var(--ig-surface);\n color: var(--ig-text);\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);\n}\n\n.ig-ladder-search input:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-ladder-match {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n}\n\n.ig-chip {\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-chip:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chip[aria-expanded='true'] {\n border-color: var(--ig-accent);\n color: var(--ig-text);\n}\n\n.ig-isolated-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-isolated-list .ig-id {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n";
|
|
26
|
+
export declare const scaleLadderStylesheet = "\n.ig-ladder {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n.ig-ladder-routes {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n color: var(--ig-text-muted);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-ladder-search {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-ladder-search input {\n background: var(--ig-surface);\n color: var(--ig-text);\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);\n}\n\n.ig-ladder-search input:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-ladder-match {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n}\n\n.ig-chip {\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-chip:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chip[aria-expanded='true'] {\n border-color: var(--ig-accent);\n color: var(--ig-text);\n}\n\n/* THE LIST ITEM IS A GRID CELL AND NOTHING ELSE. It deliberately does not\n carry .ig-capsule: that is layer 1's own card, and a card inside a card put\n the stuck tint and the hover on the inner border only. */\n.ig-capsule-cell {\n display: flex;\n min-width: 0;\n}\n\n/* FOUR CARDS ACROSS A COLUMN, NOT FOUR ROWS DOWN IT. Frame 17f lays the\n capsules out as a board, which is what makes the counts comparable at a\n glance \u2014 the whole reason the count leads. minmax(0, 1fr) rather than a\n width, because this stylesheet declares no fixed length: a title is arbitrary\n and auto would let the longest one set every column. Scoped to the ladder's\n own refusal so \u00A716's single-column list, drawn from the same class in layer\n 1, is untouched. */\n.ig-ladder .ig-refusal .ig-list {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--ig-space);\n}\n\n/* THE WHOLE CAPSULE IS THE CONTROL, so the button carries the card and the\n list item carries nothing. A button wrapping a card needs its own alignment\n and wrapping reset: a user agent centres and nowraps button content, and both\n are wrong for a four-part card with a title in it. */\n.ig-capsule-enter {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: start;\n gap: var(--ig-space-tight) var(--ig-space);\n width: 100%;\n height: 100%;\n text-align: left;\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);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n cursor: pointer;\n}\n\n.ig-capsule-enter:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-capsule-enter:hover {\n border-color: var(--ig-accent);\n}\n\n/* THE WHOLE STUCK CARD IS TINTED, as frame 17f draws it \u2014 the badge alone puts\n the one finding that stops work outright at the size of every other chip on\n the board. Same hue as the badge inside it, which is blocked-by's, because\n that is the edge the cycle is made of. */\n.ig-capsule-enter[data-reach='cyclic'] {\n border-color: var(--ig-edge-blocked-by);\n}\n\n.ig-capsule-enter[data-reach='cyclic'] .ig-capsule-reach {\n color: var(--ig-edge-blocked-by);\n}\n\n/* THE COUNT LEADS, so it is the one part sized to be read down the board rather\n than within a card. The --ig-font-size-rank token is the one the theme defines\n for exactly this \u2014 \"the rank number itself\" \u2014 so a capsule's count and a rail\n rank are one size by declaration rather than by coincidence. */\n.ig-capsule-size {\n grid-column: 1;\n font-family: var(--ig-font-mono);\n font-size: var(--ig-font-size-rank);\n font-variant-numeric: tabular-nums;\n color: var(--ig-text);\n}\n\n/* END-ALIGNED AND CONTENT-WIDTH. A grid item stretches by default, which drew\n the cycle badge as a full-width bar across the top of the card. The pill is\n the frame's: the blocked count and the cycle sit in one slot, so they read as\n one kind of thing rather than as a bordered badge beside bare text. */\n.ig-capsule-load {\n grid-column: 2;\n justify-self: end;\n background: var(--ig-bg);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-micro) var(--ig-space-snug);\n font-family: var(--ig-font-mono);\n font-size: var(--ig-font-size-small);\n font-variant-numeric: tabular-nums;\n color: var(--ig-text-muted);\n}\n\n/* THE NAME AND THE REACH SPAN BOTH COLUMNS, and the name is the one part\n allowed to wrap: a title is arbitrary length, and letting it size the grid\n would make every card on the board a different shape. */\n.ig-capsule-name {\n grid-column: 1 / -1;\n color: var(--ig-text);\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.ig-capsule-reach {\n grid-column: 1 / -1;\n color: var(--ig-text-muted);\n font-size: var(--ig-font-size-small);\n font-variant-numeric: tabular-nums;\n}\n\n.ig-isolated-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/* A ROW PER ENTRY, WITH A GAP THE MARKUP DOES NOT SUPPLY. The element helper\n concatenates its children with no whitespace, so the key and the title\n rendered as one run of text \u2014 #492Audit log pagination. Latent until \u00A717a\n moved the CONTROL to the rail footer and made this list the thing a reader is\n sent to, rather than a chip's afterthought. */\n.ig-isolated-list li {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n min-width: 0;\n}\n\n.ig-isolated-list .ig-id {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n flex: none;\n}\n";
|
|
21
27
|
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/scale/styles.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/scale/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,eAAO,MAAM,qBAAqB,q3MA+MjC,CAAC"}
|
package/dist/scale/styles.js
CHANGED
|
@@ -8,10 +8,16 @@
|
|
|
8
8
|
* scans these bytes for a literal colour or a fixed length and for a token the
|
|
9
9
|
* theme does not define, so the rule is enforced rather than remembered.
|
|
10
10
|
*
|
|
11
|
-
* IT ADDS SELECTORS RATHER THAN REDEFINING THEM
|
|
12
|
-
*
|
|
13
|
-
* introduces: the ladder container, the routes, the search box, the
|
|
14
|
-
* chip
|
|
11
|
+
* IT ADDS SELECTORS RATHER THAN REDEFINING THEM, with ONE declared exception.
|
|
12
|
+
* The refusal and its counts already have a look, so this file styles what
|
|
13
|
+
* layer 2 introduces: the ladder container, the routes, the search box, the
|
|
14
|
+
* isolated chip, the list it opens, and §17f's capsule card. The exception is
|
|
15
|
+
* `.ig-ladder .ig-refusal .ig-list`, which lays layer 1's list out as a board —
|
|
16
|
+
* declared here because the arrangement is this surface's, and scoped so §16's
|
|
17
|
+
* single-column list and the ladder's own search matches are untouched. The
|
|
18
|
+
* capsule CARD is a new class rather than a redefinition of `.ig-capsule` for
|
|
19
|
+
* the same reason, which is why the list item beside it carries no layer 1
|
|
20
|
+
* class at all.
|
|
15
21
|
*
|
|
16
22
|
* Shipped as a string for the same reason the viewer's is: an entry that
|
|
17
23
|
* imports CSS cannot be loaded by a bare Node runtime, and a string needs no
|
|
@@ -88,6 +94,116 @@ export const scaleLadderStylesheet = `
|
|
|
88
94
|
color: var(--ig-text);
|
|
89
95
|
}
|
|
90
96
|
|
|
97
|
+
/* THE LIST ITEM IS A GRID CELL AND NOTHING ELSE. It deliberately does not
|
|
98
|
+
carry .ig-capsule: that is layer 1's own card, and a card inside a card put
|
|
99
|
+
the stuck tint and the hover on the inner border only. */
|
|
100
|
+
.ig-capsule-cell {
|
|
101
|
+
display: flex;
|
|
102
|
+
min-width: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* FOUR CARDS ACROSS A COLUMN, NOT FOUR ROWS DOWN IT. Frame 17f lays the
|
|
106
|
+
capsules out as a board, which is what makes the counts comparable at a
|
|
107
|
+
glance — the whole reason the count leads. minmax(0, 1fr) rather than a
|
|
108
|
+
width, because this stylesheet declares no fixed length: a title is arbitrary
|
|
109
|
+
and auto would let the longest one set every column. Scoped to the ladder's
|
|
110
|
+
own refusal so §16's single-column list, drawn from the same class in layer
|
|
111
|
+
1, is untouched. */
|
|
112
|
+
.ig-ladder .ig-refusal .ig-list {
|
|
113
|
+
display: grid;
|
|
114
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
115
|
+
gap: var(--ig-space);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* THE WHOLE CAPSULE IS THE CONTROL, so the button carries the card and the
|
|
119
|
+
list item carries nothing. A button wrapping a card needs its own alignment
|
|
120
|
+
and wrapping reset: a user agent centres and nowraps button content, and both
|
|
121
|
+
are wrong for a four-part card with a title in it. */
|
|
122
|
+
.ig-capsule-enter {
|
|
123
|
+
display: grid;
|
|
124
|
+
grid-template-columns: 1fr auto;
|
|
125
|
+
align-items: start;
|
|
126
|
+
gap: var(--ig-space-tight) var(--ig-space);
|
|
127
|
+
width: 100%;
|
|
128
|
+
height: 100%;
|
|
129
|
+
text-align: left;
|
|
130
|
+
background: var(--ig-surface-2);
|
|
131
|
+
color: var(--ig-text-body);
|
|
132
|
+
border: var(--ig-stroke) solid var(--ig-line);
|
|
133
|
+
border-radius: var(--ig-radius);
|
|
134
|
+
padding: var(--ig-space);
|
|
135
|
+
font-family: var(--ig-font-ui);
|
|
136
|
+
font-size: var(--ig-font-size);
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.ig-capsule-enter:focus-visible {
|
|
141
|
+
outline: var(--ig-focus-ring) solid var(--ig-focus);
|
|
142
|
+
outline-offset: var(--ig-space-tight);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.ig-capsule-enter:hover {
|
|
146
|
+
border-color: var(--ig-accent);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* THE WHOLE STUCK CARD IS TINTED, as frame 17f draws it — the badge alone puts
|
|
150
|
+
the one finding that stops work outright at the size of every other chip on
|
|
151
|
+
the board. Same hue as the badge inside it, which is blocked-by's, because
|
|
152
|
+
that is the edge the cycle is made of. */
|
|
153
|
+
.ig-capsule-enter[data-reach='cyclic'] {
|
|
154
|
+
border-color: var(--ig-edge-blocked-by);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.ig-capsule-enter[data-reach='cyclic'] .ig-capsule-reach {
|
|
158
|
+
color: var(--ig-edge-blocked-by);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* THE COUNT LEADS, so it is the one part sized to be read down the board rather
|
|
162
|
+
than within a card. The --ig-font-size-rank token is the one the theme defines
|
|
163
|
+
for exactly this — "the rank number itself" — so a capsule's count and a rail
|
|
164
|
+
rank are one size by declaration rather than by coincidence. */
|
|
165
|
+
.ig-capsule-size {
|
|
166
|
+
grid-column: 1;
|
|
167
|
+
font-family: var(--ig-font-mono);
|
|
168
|
+
font-size: var(--ig-font-size-rank);
|
|
169
|
+
font-variant-numeric: tabular-nums;
|
|
170
|
+
color: var(--ig-text);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* END-ALIGNED AND CONTENT-WIDTH. A grid item stretches by default, which drew
|
|
174
|
+
the cycle badge as a full-width bar across the top of the card. The pill is
|
|
175
|
+
the frame's: the blocked count and the cycle sit in one slot, so they read as
|
|
176
|
+
one kind of thing rather than as a bordered badge beside bare text. */
|
|
177
|
+
.ig-capsule-load {
|
|
178
|
+
grid-column: 2;
|
|
179
|
+
justify-self: end;
|
|
180
|
+
background: var(--ig-bg);
|
|
181
|
+
border: var(--ig-stroke) solid var(--ig-line);
|
|
182
|
+
border-radius: var(--ig-radius);
|
|
183
|
+
padding: var(--ig-space-micro) var(--ig-space-snug);
|
|
184
|
+
font-family: var(--ig-font-mono);
|
|
185
|
+
font-size: var(--ig-font-size-small);
|
|
186
|
+
font-variant-numeric: tabular-nums;
|
|
187
|
+
color: var(--ig-text-muted);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* THE NAME AND THE REACH SPAN BOTH COLUMNS, and the name is the one part
|
|
191
|
+
allowed to wrap: a title is arbitrary length, and letting it size the grid
|
|
192
|
+
would make every card on the board a different shape. */
|
|
193
|
+
.ig-capsule-name {
|
|
194
|
+
grid-column: 1 / -1;
|
|
195
|
+
color: var(--ig-text);
|
|
196
|
+
min-width: 0;
|
|
197
|
+
overflow-wrap: anywhere;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.ig-capsule-reach {
|
|
201
|
+
grid-column: 1 / -1;
|
|
202
|
+
color: var(--ig-text-muted);
|
|
203
|
+
font-size: var(--ig-font-size-small);
|
|
204
|
+
font-variant-numeric: tabular-nums;
|
|
205
|
+
}
|
|
206
|
+
|
|
91
207
|
.ig-isolated-list {
|
|
92
208
|
list-style: none;
|
|
93
209
|
margin: 0;
|
|
@@ -97,9 +213,22 @@ export const scaleLadderStylesheet = `
|
|
|
97
213
|
gap: var(--ig-space-tight);
|
|
98
214
|
}
|
|
99
215
|
|
|
216
|
+
/* A ROW PER ENTRY, WITH A GAP THE MARKUP DOES NOT SUPPLY. The element helper
|
|
217
|
+
concatenates its children with no whitespace, so the key and the title
|
|
218
|
+
rendered as one run of text — #492Audit log pagination. Latent until §17a
|
|
219
|
+
moved the CONTROL to the rail footer and made this list the thing a reader is
|
|
220
|
+
sent to, rather than a chip's afterthought. */
|
|
221
|
+
.ig-isolated-list li {
|
|
222
|
+
display: flex;
|
|
223
|
+
gap: var(--ig-space-tight);
|
|
224
|
+
align-items: baseline;
|
|
225
|
+
min-width: 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
100
228
|
.ig-isolated-list .ig-id {
|
|
101
229
|
font-family: var(--ig-font-mono);
|
|
102
230
|
color: var(--ig-text-muted);
|
|
231
|
+
flex: none;
|
|
103
232
|
}
|
|
104
233
|
`;
|
|
105
234
|
//# sourceMappingURL=styles.js.map
|
package/dist/scale/styles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/scale/styles.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/scale/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+MpC,CAAC"}
|
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
* that imports CSS cannot be loaded by a bare Node runtime, and a string needs
|
|
18
18
|
* no bundler.
|
|
19
19
|
*/
|
|
20
|
-
export declare const mountStylesheet = "\n.ig-mount {\n position: relative;\n height: 100%;\n min-height: 0;\n}\n\n.ig-mount > .ig-workspace {\n /* THE FLOATING CHOOSER'S BOX. A canvas drop places the kind chooser inside\n the workspace root, so a host that scopes its theme to that root still\n resolves the chooser's tokens; the root is the positioning box for it. */\n position: relative;\n height: 100%;\n box-sizing: border-box;\n}\n\n.ig-mount[data-dragging='true'] {\n cursor: grabbing;\n user-select: none;\n}\n\n.ig-chrome {\n padding: var(--ig-space-tight) var(--ig-space);\n border-top: var(--ig-stroke) solid var(--ig-line);\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n.ig-chrome-sentence {\n margin: 0;\n font-family: var(--ig-font-mono);\n color: var(--ig-text);\n}\n\n.ig-chrome-button {\n font: inherit;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text);\n background: var(--ig-surface-2);\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 cursor: pointer;\n text-align: left;\n}\n\n.ig-chrome-button:hover {\n border-color: var(--ig-accent);\n}\n\n.ig-chrome-button:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chrome-quiet {\n background: none;\n color: var(--ig-text-muted);\n}\n\n.ig-chrome-danger {\n color: var(--ig-state-failed);\n border-color: var(--ig-state-failed);\n}\n\n.ig-chrome-input {\n font: inherit;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text);\n background: var(--ig-surface-2);\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 width: 100%;\n box-sizing: border-box;\n}\n\n.ig-chrome-input:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chrome-kinds {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n/* EACH KIND CARRIES ITS HUE ON THE LEFT, the same hue the viewer draws the\n edge in, so the chooser and the canvas name a relationship the same way. */\n.ig-chrome-kinds .ig-chrome-button {\n border-left: var(--ig-terminal-width) solid var(--ig-line);\n}\n\n.ig-chrome-kinds [data-edge='blocked-by'] {\n border-left-color: var(--ig-edge-blocked-by);\n}\n\n.ig-chrome-kinds [data-edge='serialize-with'] {\n border-left-color: var(--ig-edge-serialize-with);\n}\n\n.ig-chrome-kinds [data-edge='together-with'] {\n border-left-color: var(--ig-edge-together-with);\n}\n\n.ig-chrome-kinds [data-edge='duplicate-of'] {\n border-left-color: var(--ig-edge-duplicate-of);\n}\n\n.ig-chrome-kinds [data-edge='decomposed-from'] {\n border-left-color: var(--ig-edge-decomposed-from);\n}\n\n.ig-chrome-matches {\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-chrome-match {\n width: 100%;\n}\n\n.ig-chrome-search,\n.ig-chrome-chooser {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n/* PLACED BY THE MOUNT, at the drop point `pickerPlacement` chose: `left` and\n `top` are written inline on the element, so this rule carries the box and\n nothing about where it sits. */\n.ig-chrome-floating {\n position: absolute;\n width: calc(var(--ig-char-width) * 40);\n padding: var(--ig-space-tight) var(--ig-space);\n background: var(--ig-surface-2);\n border: var(--ig-stroke) solid var(--ig-accent);\n border-radius: var(--ig-radius);\n z-index: 2;\n}\n\n.ig-chrome-keys {\n margin: 0;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text-muted);\n}\n";
|
|
20
|
+
export declare const mountStylesheet = "\n.ig-mount {\n position: relative;\n height: 100%;\n min-height: 0;\n}\n\n.ig-mount > .ig-workspace {\n /* THE FLOATING CHOOSER'S BOX. A canvas drop places the kind chooser inside\n the workspace root, so a host that scopes its theme to that root still\n resolves the chooser's tokens; the root is the positioning box for it. */\n position: relative;\n height: 100%;\n box-sizing: border-box;\n}\n\n.ig-mount[data-dragging='true'] {\n cursor: grabbing;\n user-select: none;\n}\n\n.ig-chrome {\n padding: var(--ig-space-tight) var(--ig-space);\n border-top: var(--ig-stroke) solid var(--ig-line);\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n.ig-chrome-sentence {\n margin: 0;\n font-family: var(--ig-font-mono);\n color: var(--ig-text);\n}\n\n.ig-chrome-button {\n font: inherit;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text);\n background: var(--ig-surface-2);\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 cursor: pointer;\n text-align: left;\n}\n\n.ig-chrome-button:hover {\n border-color: var(--ig-accent);\n}\n\n.ig-chrome-button:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chrome-quiet {\n background: none;\n color: var(--ig-text-muted);\n}\n\n.ig-chrome-danger {\n color: var(--ig-state-failed);\n border-color: var(--ig-state-failed);\n}\n\n.ig-chrome-input {\n font: inherit;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text);\n background: var(--ig-surface-2);\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 width: 100%;\n box-sizing: border-box;\n}\n\n.ig-chrome-input:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chrome-kinds {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n/* EACH KIND CARRIES ITS HUE ON THE LEFT, the same hue the viewer draws the\n edge in, so the chooser and the canvas name a relationship the same way. */\n.ig-chrome-kinds .ig-chrome-button {\n border-left: var(--ig-terminal-width) solid var(--ig-line);\n}\n\n.ig-chrome-kinds [data-edge='blocked-by'] {\n border-left-color: var(--ig-edge-blocked-by);\n}\n\n.ig-chrome-kinds [data-edge='serialize-with'] {\n border-left-color: var(--ig-edge-serialize-with);\n}\n\n.ig-chrome-kinds [data-edge='together-with'] {\n border-left-color: var(--ig-edge-together-with);\n}\n\n.ig-chrome-kinds [data-edge='duplicate-of'] {\n border-left-color: var(--ig-edge-duplicate-of);\n}\n\n.ig-chrome-kinds [data-edge='decomposed-from'] {\n border-left-color: var(--ig-edge-decomposed-from);\n}\n\n.ig-chrome-matches {\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-chrome-match {\n width: 100%;\n}\n\n.ig-chrome-search,\n.ig-chrome-chooser {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n/* PLACED BY THE MOUNT, at the drop point `pickerPlacement` chose: `left` and\n `top` are written inline on the element, so this rule carries the box and\n nothing about where it sits. */\n.ig-chrome-floating {\n position: absolute;\n width: calc(var(--ig-char-width) * 40);\n padding: var(--ig-space-tight) var(--ig-space);\n background: var(--ig-surface-2);\n border: var(--ig-stroke) solid var(--ig-accent);\n border-radius: var(--ig-radius);\n z-index: 2;\n}\n\n.ig-chrome-keys {\n margin: 0;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text-muted);\n}\n\n/* THE FIRST PASS COVERS THE WORKSPACE. \u00A717e is a review queue rather than a\n fourth column, so it is drawn over the three zones instead of beside them.\n Placed against the workspace root, which is this sheet's positioning box. */\n.ig-firstpass-overlay {\n position: absolute;\n inset: 0;\n z-index: 3;\n display: flex;\n flex-direction: column;\n align-items: center;\n /* START-SAFE, NOT CENTRED. Evidence is host prose of no fixed length, and a\n short workspace makes any panel too tall \u2014 centring overflow puts the\n question above the container's own origin, where no scroll can reach it.\n Laid out from the top and centred by the panel's own auto margins, which\n collapse the moment there is not enough room. */\n justify-content: flex-start;\n overflow: auto;\n gap: var(--ig-space);\n padding: var(--ig-space-loose);\n box-sizing: border-box;\n background: var(--ig-bg);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n/* A CONTAINER THAT TAKES FOCUS NEEDS A RING. The wrapper is focused on open and\n after every answer, so without one a sighted keyboard user cannot see where\n they are on the surface built for them. */\n.ig-firstpass-overlay:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: calc(var(--ig-stroke) * -1);\n}\n\n.ig-firstpass-panel {\n width: 100%;\n max-width: calc(var(--ig-char-width) * 72);\n /* Centres while it fits, and starts at the top the moment it does not. */\n margin-block: auto;\n}\n\n/* The scanning and failed sentences. Both are the host's words. */\n.ig-firstpass-note {\n margin: 0;\n color: var(--ig-text-muted);\n}\n";
|
|
21
21
|
//# sourceMappingURL=chrome.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/workspace/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../src/workspace/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,eAAe,ijLA6M3B,CAAC"}
|
package/dist/workspace/chrome.js
CHANGED
|
@@ -174,5 +174,53 @@ export const mountStylesheet = `
|
|
|
174
174
|
font-size: var(--ig-font-size-small);
|
|
175
175
|
color: var(--ig-text-muted);
|
|
176
176
|
}
|
|
177
|
+
|
|
178
|
+
/* THE FIRST PASS COVERS THE WORKSPACE. §17e is a review queue rather than a
|
|
179
|
+
fourth column, so it is drawn over the three zones instead of beside them.
|
|
180
|
+
Placed against the workspace root, which is this sheet's positioning box. */
|
|
181
|
+
.ig-firstpass-overlay {
|
|
182
|
+
position: absolute;
|
|
183
|
+
inset: 0;
|
|
184
|
+
z-index: 3;
|
|
185
|
+
display: flex;
|
|
186
|
+
flex-direction: column;
|
|
187
|
+
align-items: center;
|
|
188
|
+
/* START-SAFE, NOT CENTRED. Evidence is host prose of no fixed length, and a
|
|
189
|
+
short workspace makes any panel too tall — centring overflow puts the
|
|
190
|
+
question above the container's own origin, where no scroll can reach it.
|
|
191
|
+
Laid out from the top and centred by the panel's own auto margins, which
|
|
192
|
+
collapse the moment there is not enough room. */
|
|
193
|
+
justify-content: flex-start;
|
|
194
|
+
overflow: auto;
|
|
195
|
+
gap: var(--ig-space);
|
|
196
|
+
padding: var(--ig-space-loose);
|
|
197
|
+
box-sizing: border-box;
|
|
198
|
+
background: var(--ig-bg);
|
|
199
|
+
font-family: var(--ig-font-ui);
|
|
200
|
+
font-size: var(--ig-font-size);
|
|
201
|
+
line-height: var(--ig-line-height);
|
|
202
|
+
color: var(--ig-text-body);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* A CONTAINER THAT TAKES FOCUS NEEDS A RING. The wrapper is focused on open and
|
|
206
|
+
after every answer, so without one a sighted keyboard user cannot see where
|
|
207
|
+
they are on the surface built for them. */
|
|
208
|
+
.ig-firstpass-overlay:focus-visible {
|
|
209
|
+
outline: var(--ig-focus-ring) solid var(--ig-focus);
|
|
210
|
+
outline-offset: calc(var(--ig-stroke) * -1);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.ig-firstpass-panel {
|
|
214
|
+
width: 100%;
|
|
215
|
+
max-width: calc(var(--ig-char-width) * 72);
|
|
216
|
+
/* Centres while it fits, and starts at the top the moment it does not. */
|
|
217
|
+
margin-block: auto;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* The scanning and failed sentences. Both are the host's words. */
|
|
221
|
+
.ig-firstpass-note {
|
|
222
|
+
margin: 0;
|
|
223
|
+
color: var(--ig-text-muted);
|
|
224
|
+
}
|
|
177
225
|
`;
|
|
178
226
|
//# sourceMappingURL=chrome.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../src/workspace/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG
|
|
1
|
+
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../src/workspace/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6M9B,CAAC"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first pass as a slice of the workspace's state — no DOM, no promises.
|
|
3
|
+
*
|
|
4
|
+
* `firstpass/queue.ts` is the review loop itself and knows nothing about being
|
|
5
|
+
* opened or closed; `firstpass/candidates.ts` declares a port whose one method
|
|
6
|
+
* is asynchronous by construction. Between them sits a lifecycle nobody owned:
|
|
7
|
+
* the surface is shut, then a scan is out, then a queue is up, and a scan can
|
|
8
|
+
* fail. That lifecycle is this file, in the shape `selectionReducer`,
|
|
9
|
+
* `scaleReducer` and `createReducer` already use here — so `host.ts` composes a
|
|
10
|
+
* fourth reducer rather than growing a fourth set of rules.
|
|
11
|
+
*
|
|
12
|
+
* ## The phase is a union, and `decided` sits outside it
|
|
13
|
+
*
|
|
14
|
+
* Everything the phase carries belongs to one phase only, so it is a
|
|
15
|
+
* discriminated union for the reason `firstpass/view.ts` records about its own
|
|
16
|
+
* three states: the impossible combinations stop existing.
|
|
17
|
+
*
|
|
18
|
+
* {@link FirstPassState.decided} is deliberately NOT in the union, because it
|
|
19
|
+
* is the one fact that has to outlive every phase. See below.
|
|
20
|
+
*
|
|
21
|
+
* ## A re-open re-scans, and `decided` is what makes that honest
|
|
22
|
+
*
|
|
23
|
+
* Closing drops the queue rather than resuming it: a queue held across a close
|
|
24
|
+
* carries a candidate set taken before the writes the reader just made, so it
|
|
25
|
+
* would go on asking about relationships that now exist.
|
|
26
|
+
*
|
|
27
|
+
* But a re-scan on its own would re-ask every question the reader already
|
|
28
|
+
* answered — `queue.ts` defines `reject` as "no, this is not a relationship.
|
|
29
|
+
* Answered, and gone", and a host's `findCandidates` is never told what was
|
|
30
|
+
* decided, so it cannot filter them out on the reader's behalf. Forty rejections
|
|
31
|
+
* would come back on the next open, which is a worse outcome than the resume
|
|
32
|
+
* this refuses and defeats §17e's "first pass has an end" across sessions.
|
|
33
|
+
*
|
|
34
|
+
* So the decided ids ride outside the phase and filter the next scan.
|
|
35
|
+
*
|
|
36
|
+
* **`skip` is not decided, and that is the design rather than an omission.**
|
|
37
|
+
* §17e's `S` is "not now", and `queue.ts` ships `skippedCandidates` precisely
|
|
38
|
+
* because "the deferred set is the thing a second pass is built from". A skipped
|
|
39
|
+
* candidate coming back in the next pass is what deferring it meant.
|
|
40
|
+
*
|
|
41
|
+
* ## Scans carry a generation, or the newest answer can lose
|
|
42
|
+
*
|
|
43
|
+
* A reader who closes during a slow scan and opens again has two scans in
|
|
44
|
+
* flight. Discriminating on the phase alone cannot tell their answers apart, so
|
|
45
|
+
* the STALE set — taken before the reader's writes — would open the queue while
|
|
46
|
+
* the fresh one arrived on `open` and was dropped. That is the exact failure the
|
|
47
|
+
* re-scan rule exists to prevent, arriving through the door the rule opened.
|
|
48
|
+
*
|
|
49
|
+
* {@link FirstPassState.scan} is a monotonic counter. Every scan is issued under
|
|
50
|
+
* it, every answer carries the number it was issued under, and an answer whose
|
|
51
|
+
* number is not the current one is dropped.
|
|
52
|
+
*/
|
|
53
|
+
import type { Candidate, CandidateId } from '../firstpass/candidates.ts';
|
|
54
|
+
import { type QueueCommand, type QueueResult, type QueueState } from '../firstpass/queue.ts';
|
|
55
|
+
/** What the surface is doing. Exactly one of these, always. */
|
|
56
|
+
export type FirstPassPhase =
|
|
57
|
+
/** Shut. The header's entry is the only way in. */
|
|
58
|
+
{
|
|
59
|
+
readonly kind: 'closed';
|
|
60
|
+
}
|
|
61
|
+
/** A scan is out. The generation is {@link FirstPassState.scan}. */
|
|
62
|
+
| {
|
|
63
|
+
readonly kind: 'scanning';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The host's scan rejected.
|
|
67
|
+
*
|
|
68
|
+
* ITS OWN PHASE rather than an empty queue: `empty` means the host found
|
|
69
|
+
* nothing to encode, which is a claim about the backlog that a failed scan
|
|
70
|
+
* does not license — the vacuity `firstpass/view.ts` separates its own two
|
|
71
|
+
* end states to avoid. And its own phase rather than a silent return to
|
|
72
|
+
* `closed`, which made a broken port indistinguishable from a dead button.
|
|
73
|
+
*
|
|
74
|
+
* It carries no payload: the reason is the host's and this package does not
|
|
75
|
+
* read it. A shell draws its own sentence and its own way out.
|
|
76
|
+
*/
|
|
77
|
+
| {
|
|
78
|
+
readonly kind: 'failed';
|
|
79
|
+
} | {
|
|
80
|
+
readonly kind: 'open';
|
|
81
|
+
readonly queue: QueueState;
|
|
82
|
+
};
|
|
83
|
+
export interface FirstPassState {
|
|
84
|
+
readonly phase: FirstPassPhase;
|
|
85
|
+
/**
|
|
86
|
+
* The candidates DECIDED in this state's lifetime — `apply` and `reject`.
|
|
87
|
+
*
|
|
88
|
+
* Filters the next scan, so a re-open does not re-ask a decided question. Held
|
|
89
|
+
* as ids rather than candidates because that is what a scan can be compared
|
|
90
|
+
* against, and because {@link CandidateId} is the identity the HOST minted:
|
|
91
|
+
* `firstpass/candidates.ts` is explicit that two findings about the same pair
|
|
92
|
+
* are not necessarily the same finding, so nothing here derives an identity of
|
|
93
|
+
* its own.
|
|
94
|
+
*/
|
|
95
|
+
readonly decided: readonly CandidateId[];
|
|
96
|
+
/** The generation the newest scan was issued under. Monotonic. */
|
|
97
|
+
readonly scan: number;
|
|
98
|
+
}
|
|
99
|
+
export declare const INITIAL_FIRST_PASS: FirstPassState;
|
|
100
|
+
/**
|
|
101
|
+
* One act on the surface.
|
|
102
|
+
*
|
|
103
|
+
* `candidates` and `scan-failed` are the two answers a scan can have, and both
|
|
104
|
+
* carry the generation they were issued under — see the module header.
|
|
105
|
+
*/
|
|
106
|
+
export type FirstPassCommand = {
|
|
107
|
+
readonly kind: 'open';
|
|
108
|
+
} | {
|
|
109
|
+
readonly kind: 'candidates';
|
|
110
|
+
readonly scan: number;
|
|
111
|
+
readonly candidates: readonly Candidate[];
|
|
112
|
+
} | {
|
|
113
|
+
readonly kind: 'scan-failed';
|
|
114
|
+
readonly scan: number;
|
|
115
|
+
} | {
|
|
116
|
+
readonly kind: 'queue';
|
|
117
|
+
readonly command: QueueCommand;
|
|
118
|
+
} | {
|
|
119
|
+
readonly kind: 'close';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Close, and forget the decisions too.
|
|
123
|
+
*
|
|
124
|
+
* A DIFFERENT SCANNER IS A DIFFERENT FIRST PASS. {@link CandidateId} is
|
|
125
|
+
* opaque and host-minted, and `candidates.ts` promises only that it is stable
|
|
126
|
+
* for a queue's life — so two independently written detectors may reuse the
|
|
127
|
+
* same id for entirely different findings. Carrying one scanner's decisions
|
|
128
|
+
* into another's scan would silently drop the next detector's question on an
|
|
129
|
+
* id collision, which is the one failure a first pass cannot afford: a
|
|
130
|
+
* question nobody was asked looks exactly like a question already answered.
|
|
131
|
+
*/
|
|
132
|
+
| {
|
|
133
|
+
readonly kind: 'reset';
|
|
134
|
+
};
|
|
135
|
+
export interface FirstPassOutcome {
|
|
136
|
+
readonly state: FirstPassState;
|
|
137
|
+
/**
|
|
138
|
+
* The queue transition, when one happened.
|
|
139
|
+
*
|
|
140
|
+
* Passed through UNCHANGED rather than interpreted: `QueueResult` already
|
|
141
|
+
* carries the proposal an `apply` stands for and the answer an `undo` took
|
|
142
|
+
* back, and re-deriving either here would be a second opinion about what the
|
|
143
|
+
* queue just did.
|
|
144
|
+
*/
|
|
145
|
+
readonly result: QueueResult | null;
|
|
146
|
+
/**
|
|
147
|
+
* The generation of a scan the caller must now run, or `null`.
|
|
148
|
+
*
|
|
149
|
+
* REPORTED RATHER THAN PERFORMED, because `findCandidates` returns a promise
|
|
150
|
+
* and this reducer is pure. The caller runs the scan and sends the answer back
|
|
151
|
+
* as `candidates` or `scan-failed` carrying this number.
|
|
152
|
+
*/
|
|
153
|
+
readonly scanning: number | null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Apply one command. Total, pure, and never mutates what it is given.
|
|
157
|
+
*
|
|
158
|
+
* Every arm guards on the phase, and a command that does not belong to the
|
|
159
|
+
* current phase changes nothing — the same call `queueReducer` makes about
|
|
160
|
+
* answering a finished queue, and for the same reason: these arrive from a
|
|
161
|
+
* reader going fast and from a promise settling late, so neither is an error.
|
|
162
|
+
*/
|
|
163
|
+
export declare function firstPassReducer(state: FirstPassState, command: FirstPassCommand): FirstPassOutcome;
|
|
164
|
+
/** The queue on screen, or `null` when none is. For a shell deciding what to draw. */
|
|
165
|
+
export declare function openQueueOf(state: FirstPassState): QueueState | null;
|
|
166
|
+
//# sourceMappingURL=firstpass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firstpass.d.ts","sourceRoot":"","sources":["../../src/workspace/firstpass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,EAGhB,MAAM,uBAAuB,CAAC;AAE/B,+DAA+D;AAC/D,MAAM,MAAM,cAAc;AACxB,mDAAmD;AACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE;AAC7B,oEAAoE;GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE;AAC/B;;;;;;;;;;;GAWG;GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,kBAAkB,EAAE,cAI/B,CAAC;AAEH;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;CAC3C,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE;AAC5B;;;;;;;;;;GAUG;GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAgCD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,CAiDlB;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,GAAG,IAAI,CAEpE"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first pass as a slice of the workspace's state — no DOM, no promises.
|
|
3
|
+
*
|
|
4
|
+
* `firstpass/queue.ts` is the review loop itself and knows nothing about being
|
|
5
|
+
* opened or closed; `firstpass/candidates.ts` declares a port whose one method
|
|
6
|
+
* is asynchronous by construction. Between them sits a lifecycle nobody owned:
|
|
7
|
+
* the surface is shut, then a scan is out, then a queue is up, and a scan can
|
|
8
|
+
* fail. That lifecycle is this file, in the shape `selectionReducer`,
|
|
9
|
+
* `scaleReducer` and `createReducer` already use here — so `host.ts` composes a
|
|
10
|
+
* fourth reducer rather than growing a fourth set of rules.
|
|
11
|
+
*
|
|
12
|
+
* ## The phase is a union, and `decided` sits outside it
|
|
13
|
+
*
|
|
14
|
+
* Everything the phase carries belongs to one phase only, so it is a
|
|
15
|
+
* discriminated union for the reason `firstpass/view.ts` records about its own
|
|
16
|
+
* three states: the impossible combinations stop existing.
|
|
17
|
+
*
|
|
18
|
+
* {@link FirstPassState.decided} is deliberately NOT in the union, because it
|
|
19
|
+
* is the one fact that has to outlive every phase. See below.
|
|
20
|
+
*
|
|
21
|
+
* ## A re-open re-scans, and `decided` is what makes that honest
|
|
22
|
+
*
|
|
23
|
+
* Closing drops the queue rather than resuming it: a queue held across a close
|
|
24
|
+
* carries a candidate set taken before the writes the reader just made, so it
|
|
25
|
+
* would go on asking about relationships that now exist.
|
|
26
|
+
*
|
|
27
|
+
* But a re-scan on its own would re-ask every question the reader already
|
|
28
|
+
* answered — `queue.ts` defines `reject` as "no, this is not a relationship.
|
|
29
|
+
* Answered, and gone", and a host's `findCandidates` is never told what was
|
|
30
|
+
* decided, so it cannot filter them out on the reader's behalf. Forty rejections
|
|
31
|
+
* would come back on the next open, which is a worse outcome than the resume
|
|
32
|
+
* this refuses and defeats §17e's "first pass has an end" across sessions.
|
|
33
|
+
*
|
|
34
|
+
* So the decided ids ride outside the phase and filter the next scan.
|
|
35
|
+
*
|
|
36
|
+
* **`skip` is not decided, and that is the design rather than an omission.**
|
|
37
|
+
* §17e's `S` is "not now", and `queue.ts` ships `skippedCandidates` precisely
|
|
38
|
+
* because "the deferred set is the thing a second pass is built from". A skipped
|
|
39
|
+
* candidate coming back in the next pass is what deferring it meant.
|
|
40
|
+
*
|
|
41
|
+
* ## Scans carry a generation, or the newest answer can lose
|
|
42
|
+
*
|
|
43
|
+
* A reader who closes during a slow scan and opens again has two scans in
|
|
44
|
+
* flight. Discriminating on the phase alone cannot tell their answers apart, so
|
|
45
|
+
* the STALE set — taken before the reader's writes — would open the queue while
|
|
46
|
+
* the fresh one arrived on `open` and was dropped. That is the exact failure the
|
|
47
|
+
* re-scan rule exists to prevent, arriving through the door the rule opened.
|
|
48
|
+
*
|
|
49
|
+
* {@link FirstPassState.scan} is a monotonic counter. Every scan is issued under
|
|
50
|
+
* it, every answer carries the number it was issued under, and an answer whose
|
|
51
|
+
* number is not the current one is dropped.
|
|
52
|
+
*/
|
|
53
|
+
import { openQueue, queueReducer, } from "../firstpass/queue.js";
|
|
54
|
+
export const INITIAL_FIRST_PASS = Object.freeze({
|
|
55
|
+
phase: Object.freeze({ kind: 'closed' }),
|
|
56
|
+
decided: Object.freeze([]),
|
|
57
|
+
scan: 0,
|
|
58
|
+
});
|
|
59
|
+
function still(state) {
|
|
60
|
+
return { state, result: null, scanning: null };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The decided set after one queue transition.
|
|
64
|
+
*
|
|
65
|
+
* An added `apply` or `reject` joins it; an `undo` takes its candidate back out.
|
|
66
|
+
* Neither case can collide with an id carried in from an earlier pass, because
|
|
67
|
+
* the queue was built by filtering those ids out — so the set stays a set
|
|
68
|
+
* without this function ever having to ask which pass an id came from.
|
|
69
|
+
*/
|
|
70
|
+
function decidedAfter(decided, before, after) {
|
|
71
|
+
if (after.answers.length > before.answers.length) {
|
|
72
|
+
const given = after.answers[after.answers.length - 1];
|
|
73
|
+
if (given === undefined || given.answer === 'skip')
|
|
74
|
+
return decided;
|
|
75
|
+
return [...decided, given.candidate.id];
|
|
76
|
+
}
|
|
77
|
+
if (after.answers.length < before.answers.length) {
|
|
78
|
+
const taken = before.answers[before.answers.length - 1];
|
|
79
|
+
if (taken === undefined || taken.answer === 'skip')
|
|
80
|
+
return decided;
|
|
81
|
+
return decided.filter((id) => id !== taken.candidate.id);
|
|
82
|
+
}
|
|
83
|
+
return decided;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Apply one command. Total, pure, and never mutates what it is given.
|
|
87
|
+
*
|
|
88
|
+
* Every arm guards on the phase, and a command that does not belong to the
|
|
89
|
+
* current phase changes nothing — the same call `queueReducer` makes about
|
|
90
|
+
* answering a finished queue, and for the same reason: these arrive from a
|
|
91
|
+
* reader going fast and from a promise settling late, so neither is an error.
|
|
92
|
+
*/
|
|
93
|
+
export function firstPassReducer(state, command) {
|
|
94
|
+
switch (command.kind) {
|
|
95
|
+
case 'open': {
|
|
96
|
+
// ONLY FROM `closed`. A second press while a scan is out must not issue a
|
|
97
|
+
// second scan, and neither `open` nor `failed` is re-openable in place:
|
|
98
|
+
// both draw a way out, and the way back in is through `closed`.
|
|
99
|
+
if (state.phase.kind !== 'closed')
|
|
100
|
+
return still(state);
|
|
101
|
+
const scan = state.scan + 1;
|
|
102
|
+
return {
|
|
103
|
+
state: { ...state, phase: { kind: 'scanning' }, scan },
|
|
104
|
+
result: null,
|
|
105
|
+
scanning: scan,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
case 'candidates': {
|
|
109
|
+
if (state.phase.kind !== 'scanning' || command.scan !== state.scan)
|
|
110
|
+
return still(state);
|
|
111
|
+
const decided = new Set(state.decided);
|
|
112
|
+
// THE DECIDED ARE DROPPED BEFORE THE QUEUE IS BUILT, not hidden after, so
|
|
113
|
+
// the denominator §17e bounds progress by counts what is actually being
|
|
114
|
+
// asked. A queue of five that silently skips four would report "0 of 5".
|
|
115
|
+
const fresh = command.candidates.filter((candidate) => !decided.has(candidate.id));
|
|
116
|
+
return still({ ...state, phase: { kind: 'open', queue: openQueue(fresh) } });
|
|
117
|
+
}
|
|
118
|
+
case 'scan-failed': {
|
|
119
|
+
if (state.phase.kind !== 'scanning' || command.scan !== state.scan)
|
|
120
|
+
return still(state);
|
|
121
|
+
return still({ ...state, phase: { kind: 'failed' } });
|
|
122
|
+
}
|
|
123
|
+
case 'queue': {
|
|
124
|
+
if (state.phase.kind !== 'open')
|
|
125
|
+
return still(state);
|
|
126
|
+
const before = state.phase.queue;
|
|
127
|
+
const result = queueReducer(before, command.command);
|
|
128
|
+
return {
|
|
129
|
+
state: {
|
|
130
|
+
...state,
|
|
131
|
+
phase: { kind: 'open', queue: result.state },
|
|
132
|
+
decided: decidedAfter(state.decided, before, result.state),
|
|
133
|
+
},
|
|
134
|
+
result,
|
|
135
|
+
scanning: null,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
case 'close':
|
|
139
|
+
// THE QUEUE GOES, `decided` STAYS. See the module header: dropping the
|
|
140
|
+
// queue is what keeps a re-open fresh, and keeping the decisions is what
|
|
141
|
+
// keeps it from re-asking. That holds for the SAME scanner; see `reset`.
|
|
142
|
+
return still({ ...state, phase: { kind: 'closed' } });
|
|
143
|
+
case 'reset':
|
|
144
|
+
return still({ ...state, phase: { kind: 'closed' }, decided: [] });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** The queue on screen, or `null` when none is. For a shell deciding what to draw. */
|
|
148
|
+
export function openQueueOf(state) {
|
|
149
|
+
return state.phase.kind === 'open' ? state.phase.queue : null;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=firstpass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firstpass.js","sourceRoot":"","sources":["../../src/workspace/firstpass.ts"],"names":[],"mappings":"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"}
|