@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 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/firstpass/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAEL,KAAK,KAAK,EAKX,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAA0B,KAAK,aAAa,EAAiB,MAAM,WAAW,CAAC;AACtF,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AACjD;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AACnD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,qBAAqB,CAAC;AAC3D,kCAAkC;AAClC,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AACrD,uDAAuD;AACvD,eAAO,MAAM,eAAe,kBAAkB,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,mEAAmE;IACnE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAyHD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAiD7F"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first-pass queue, as markup.
|
|
3
|
+
*
|
|
4
|
+
* ## Drawing a candidate answers nothing
|
|
5
|
+
*
|
|
6
|
+
* The property §17e turns on, and the one this file most has to be trusted
|
|
7
|
+
* with: rendering emits no proposal, wires no listener and dispatches nothing.
|
|
8
|
+
* It publishes `data-ig-answer` on three buttons and stops. The consent
|
|
9
|
+
* §17e requires — "it always costs one keystroke" — survives because the
|
|
10
|
+
* only thing in this package that builds a `Proposal` from a candidate is
|
|
11
|
+
* `queue.ts`'s `apply` arm, and nothing here calls it.
|
|
12
|
+
*
|
|
13
|
+
* `render.test.ts` asserts it from the outside: a rendered candidate produces
|
|
14
|
+
* no proposal, because there is no return channel on which it could.
|
|
15
|
+
*
|
|
16
|
+
* ## Every readable byte comes from the host or from the document
|
|
17
|
+
*
|
|
18
|
+
* The same total claim `picker/render.ts` makes, and it is stricter here than
|
|
19
|
+
* it looks, because the evidence text is host prose flowing through a package
|
|
20
|
+
* surface. This module never reads it, never truncates it and never summarises
|
|
21
|
+
* it — it places it, with the evidence `token` beside it as a data attribute so
|
|
22
|
+
* a host can style a class of reason and a test can assert one without matching
|
|
23
|
+
* on words.
|
|
24
|
+
*
|
|
25
|
+
* ## Progress is drawn as a number the host worded, not a bar
|
|
26
|
+
*
|
|
27
|
+
* §17e: "100% encoded is never the goal and the workspace never implies it is."
|
|
28
|
+
* A progress BAR implies a target by its geometry — an empty tail is a thing
|
|
29
|
+
* left undone — and no wording can undo that. So the surface publishes the two
|
|
30
|
+
* counts as attributes and renders the host's sentence, and a host that wants a
|
|
31
|
+
* bar draws one knowing what it is claiming. `<progress>` is deliberately not
|
|
32
|
+
* used for the same reason.
|
|
33
|
+
*
|
|
34
|
+
* ## It names itself without claiming a heading level
|
|
35
|
+
*
|
|
36
|
+
* Same call `picker/render.ts` records: a heading would be a claim about the
|
|
37
|
+
* HOST's document outline — whether this surface is a section of something, and
|
|
38
|
+
* at what depth — which a package rendered into an unknown page cannot make.
|
|
39
|
+
*
|
|
40
|
+
* That refusal used to be the whole of it, and it left the root `<section>`
|
|
41
|
+
* with no accessible name at all: a screen-reader user navigating by landmarks
|
|
42
|
+
* met an unnamed generic region and could not tell it from any other. The
|
|
43
|
+
* refusal was right and the silence that followed it was not, so the region now
|
|
44
|
+
* carries an `aria-label` from {@link ./words.ts FirstPassWords} — which names
|
|
45
|
+
* the surface without asserting anything about where it sits in an outline. A
|
|
46
|
+
* host that wants it in the outline still wraps it in a heading of its own
|
|
47
|
+
* choosing.
|
|
48
|
+
*/
|
|
49
|
+
import { element, renderMarkup, resolveTheme, themeCss, } from '@issuegraph/viewer';
|
|
50
|
+
import { firstPassView } from "./view.js";
|
|
51
|
+
import { firstPassStylesheet } from "./styles.js";
|
|
52
|
+
/** The attribute a shell reads to know which answer a control stands for. */
|
|
53
|
+
export const ANSWER_ATTRIBUTE = 'data-ig-answer';
|
|
54
|
+
/**
|
|
55
|
+
* The attribute on the undo control.
|
|
56
|
+
*
|
|
57
|
+
* ITS OWN ATTRIBUTE, not `data-ig-answer="undo"`. {@link ./queue.ts Answer} is
|
|
58
|
+
* a closed union of three, and undo is not one of them — so a shell reading
|
|
59
|
+
* `data-ig-answer` and switching over `Answer` would be handed a value outside
|
|
60
|
+
* the type it was told to expect. `data-ig-command` is the spelling
|
|
61
|
+
* `picker/render.ts` already uses for a control that is not a choice.
|
|
62
|
+
*/
|
|
63
|
+
export const COMMAND_ATTRIBUTE = 'data-ig-command';
|
|
64
|
+
/** The attribute carrying an evidence item's machine-readable token. */
|
|
65
|
+
export const EVIDENCE_TOKEN_ATTRIBUTE = 'data-ig-evidence';
|
|
66
|
+
/** Answers given, on the root. */
|
|
67
|
+
export const ANSWERED_ATTRIBUTE = 'data-ig-answered';
|
|
68
|
+
/** Candidates found — the denominator, on the root. */
|
|
69
|
+
export const FOUND_ATTRIBUTE = 'data-ig-found';
|
|
70
|
+
/** The three answer controls, in §17e's order. */
|
|
71
|
+
const ANSWER_ORDER = Object.freeze(['apply', 'reject', 'skip']);
|
|
72
|
+
/**
|
|
73
|
+
* One evidence item.
|
|
74
|
+
*
|
|
75
|
+
* The text is the host's sentence, placed verbatim. The token rides beside it
|
|
76
|
+
* as an attribute rather than in the text, which is what keeps the rendered
|
|
77
|
+
* prose entirely the host's while leaving the item addressable.
|
|
78
|
+
*/
|
|
79
|
+
function evidenceSpec(item) {
|
|
80
|
+
return element('li', { class: 'ig-firstpass-evidence-item', [EVIDENCE_TOKEN_ATTRIBUTE]: item.token }, [
|
|
81
|
+
item.text,
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The proposed relationship, drawn subject · kind · object.
|
|
86
|
+
*
|
|
87
|
+
* A DEFAULT WORD ORDER, bypassable exactly as the picker's statement is: the
|
|
88
|
+
* view model carries the ordered pair and the kind and no order beyond that, so
|
|
89
|
+
* a host whose language arranges it differently renders the model. The
|
|
90
|
+
* stylesheet lays it out as a flex row, which is what makes that bypass a
|
|
91
|
+
* restyle rather than a re-implementation.
|
|
92
|
+
*
|
|
93
|
+
* The kind is drawn as its FORMAT SPELLING (`blocked-by`), not as a phrase.
|
|
94
|
+
* `PickerWords` words the kinds for the picker, and asking a host to word them
|
|
95
|
+
* a second time here would be two vocabularies free to disagree about one
|
|
96
|
+
* relationship — while reusing `PickerWords` would couple this surface to a
|
|
97
|
+
* flow it is not part of. The spelling is the document's own token, so it is
|
|
98
|
+
* the document's word rather than ours, and it is what the owner will see in
|
|
99
|
+
* the issue body afterwards.
|
|
100
|
+
*/
|
|
101
|
+
function questionSpec(question, words) {
|
|
102
|
+
return element('div', { class: 'ig-firstpass-question' }, [
|
|
103
|
+
element('p', { class: 'ig-firstpass-statement', 'data-ig-kind': question.kind }, [
|
|
104
|
+
element('span', { class: 'ig-firstpass-ref', 'data-ig-role': 'from' }, [question.subject]),
|
|
105
|
+
element('span', { class: 'ig-firstpass-kind' }, [question.kind]),
|
|
106
|
+
element('span', { class: 'ig-firstpass-ref', 'data-ig-role': 'to' }, [question.object]),
|
|
107
|
+
]),
|
|
108
|
+
// NO EVIDENCE IS NO BLOCK, rather than an empty list with a heading. A host
|
|
109
|
+
// whose detector cannot explain itself says so by sending none
|
|
110
|
+
// (`candidates.ts`), and drawing a labelled empty container would turn that
|
|
111
|
+
// into a rendering fault the owner has to interpret.
|
|
112
|
+
question.evidence.length === 0
|
|
113
|
+
? null
|
|
114
|
+
: element('div', { class: 'ig-firstpass-evidence' }, [
|
|
115
|
+
element('p', { class: 'ig-firstpass-evidence-label' }, [words.evidence]),
|
|
116
|
+
element('ul', { class: 'ig-firstpass-evidence-list', 'aria-label': words.evidence }, question.evidence.map(evidenceSpec)),
|
|
117
|
+
]),
|
|
118
|
+
]);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The answer controls.
|
|
122
|
+
*
|
|
123
|
+
* BUTTONS, and a keyboard-first surface still needs them: §17e's claim is that
|
|
124
|
+
* the loop is reachable with no pointer, not that a pointer is refused. A
|
|
125
|
+
* surface with keys and no controls would also be a surface with no discoverable
|
|
126
|
+
* vocabulary and nothing for assistive technology to name.
|
|
127
|
+
*/
|
|
128
|
+
function answersSpec(words) {
|
|
129
|
+
return element('div', { class: 'ig-firstpass-answers', role: 'group', 'aria-label': words.answersLabel }, ANSWER_ORDER.map((answer) => element('button', { type: 'button', class: 'ig-firstpass-answer', [ANSWER_ATTRIBUTE]: answer }, [words.answers[answer]])));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The undo control, drawn whenever there is an answer to withdraw.
|
|
133
|
+
*
|
|
134
|
+
* ## It survives the finished state, and that is the point of the rule
|
|
135
|
+
*
|
|
136
|
+
* The last answer is the one most in need of taking back — an accidental `Y` on
|
|
137
|
+
* the final candidate creates the `duplicate-of` §17e says "silently removes
|
|
138
|
+
* real work from the order", and the queue then has no candidate left to show.
|
|
139
|
+
* An earlier revision replaced every control with the finished message at that
|
|
140
|
+
* exact moment, so a reader without a keyboard had no way back from the one
|
|
141
|
+
* answer that matters most.
|
|
142
|
+
*
|
|
143
|
+
* ## One rule, so the pointer and the keyboard cannot disagree
|
|
144
|
+
*
|
|
145
|
+
* `keys.ts` gates undo on `canUndo` — anything answered — and deliberately
|
|
146
|
+
* keeps it live once `hasCandidate` is false. Drawing the control on the same
|
|
147
|
+
* condition is what makes the two paths the same path. The previous version
|
|
148
|
+
* disagreed at BOTH edges, in opposite directions: it drew a dead control
|
|
149
|
+
* before anything was answered, and dropped a live one after the last answer.
|
|
150
|
+
*
|
|
151
|
+
* A control that does nothing is worse than no control, which is why this
|
|
152
|
+
* returns `null` rather than a disabled button: the queue is answered at speed,
|
|
153
|
+
* and an affordance that is sometimes inert teaches the reader to distrust it.
|
|
154
|
+
*/
|
|
155
|
+
function undoSpec(progress, words) {
|
|
156
|
+
if (progress.answered === 0)
|
|
157
|
+
return null;
|
|
158
|
+
return element('button', { type: 'button', class: 'ig-firstpass-undo', [COMMAND_ATTRIBUTE]: 'undo' }, [words.undo]);
|
|
159
|
+
}
|
|
160
|
+
/** The progress line. The host's sentence over this package's two numbers. */
|
|
161
|
+
function progressSpec(progress, words) {
|
|
162
|
+
return element('p', { class: 'ig-firstpass-progress' }, [
|
|
163
|
+
words.progress(progress.answered, progress.found),
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Draw the queue.
|
|
168
|
+
*
|
|
169
|
+
* Takes a {@link QueueState} — never a store and never a source. A host hands
|
|
170
|
+
* the proposal a reduction produced to `Store.propose`, which is the only thing
|
|
171
|
+
* in the family that dispatches.
|
|
172
|
+
*/
|
|
173
|
+
export function renderFirstPass(state, options) {
|
|
174
|
+
const view = firstPassView(state);
|
|
175
|
+
const theme = resolveTheme(options.theme);
|
|
176
|
+
const { words } = options;
|
|
177
|
+
const body = (() => {
|
|
178
|
+
switch (view.state) {
|
|
179
|
+
case 'asking':
|
|
180
|
+
return [questionSpec(view.question, words), answersSpec(words), undoSpec(view.progress, words)];
|
|
181
|
+
case 'finished':
|
|
182
|
+
// UNDO OUTLIVES THE QUESTIONS. `finished` always carries at least one
|
|
183
|
+
// answer — a queue that found nothing is `empty` instead — so the
|
|
184
|
+
// control is always drawn here, which is exactly the case that needs it.
|
|
185
|
+
return [
|
|
186
|
+
element('p', { class: 'ig-firstpass-finished' }, [words.finished]),
|
|
187
|
+
undoSpec(view.progress, words),
|
|
188
|
+
];
|
|
189
|
+
case 'empty':
|
|
190
|
+
// A DIFFERENT SENTENCE FROM `finished`, which is the whole reason the
|
|
191
|
+
// view model separates them. See `view.ts`.
|
|
192
|
+
//
|
|
193
|
+
// NO UNDO, and it needs no test to be sure of it: `empty` means the host
|
|
194
|
+
// found nothing, and nothing found is nothing that can have been
|
|
195
|
+
// answered — so `undoSpec` would return `null` here anyway.
|
|
196
|
+
return [element('p', { class: 'ig-firstpass-empty' }, [words.noCandidates])];
|
|
197
|
+
}
|
|
198
|
+
})();
|
|
199
|
+
const root = element('section', {
|
|
200
|
+
class: 'ig-firstpass',
|
|
201
|
+
// NAMED WITHOUT CLAIMING AN OUTLINE POSITION. The heading refusal above
|
|
202
|
+
// is unchanged — a heading LEVEL is a claim about the host's document
|
|
203
|
+
// structure — but an unnamed `<section>` is a landmark a screen-reader
|
|
204
|
+
// user cannot identify, so the region carries the host's own name here.
|
|
205
|
+
'aria-label': words.label,
|
|
206
|
+
'data-ig-state': view.state,
|
|
207
|
+
[ANSWERED_ATTRIBUTE]: String(view.progress.answered),
|
|
208
|
+
[FOUND_ATTRIBUTE]: String(view.progress.found),
|
|
209
|
+
}, [...body, progressSpec(view.progress, words)]);
|
|
210
|
+
return {
|
|
211
|
+
view,
|
|
212
|
+
markup: renderMarkup(root),
|
|
213
|
+
styles: `${themeCss(theme, options.themeSelector ?? ':root')}\n${firstPassStylesheet}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/firstpass/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first pass's structural stylesheet.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the picker's, the ladder's and the overlay's: layout, weight
|
|
5
|
+
* and state, never a value. Every colour, length and font is a `var(--ig-…)`
|
|
6
|
+
* the host's theme resolves, and `styles.test.ts` scans these bytes for a
|
|
7
|
+
* literal colour, a fixed length and a token the theme does not define — so the
|
|
8
|
+
* rule is enforced rather than remembered.
|
|
9
|
+
*
|
|
10
|
+
* IT ADDS SELECTORS RATHER THAN REDEFINING THEM. Nothing here reaches into the
|
|
11
|
+
* viewer's own classes; this file styles only what the first pass introduces.
|
|
12
|
+
*
|
|
13
|
+
* ## The statement is a FLEX ROW, and that is load-bearing
|
|
14
|
+
*
|
|
15
|
+
* `render.ts` draws the proposed relationship subject · kind · object and calls
|
|
16
|
+
* that word order a default a host may bypass. The CSS `order` property
|
|
17
|
+
* reorders flex children and does nothing to inline text, so laying it out any
|
|
18
|
+
* other way would make that claim true only in principle — the same reasoning
|
|
19
|
+
* the picker's stylesheet records, and enforced by the same kind of test.
|
|
20
|
+
*
|
|
21
|
+
* ## There is no progress BAR, and its absence is the design
|
|
22
|
+
*
|
|
23
|
+
* §17e: "100% encoded is never the goal and the workspace never implies it is."
|
|
24
|
+
* A bar implies a target by its geometry — an unfilled tail reads as work
|
|
25
|
+
* outstanding whatever the words beside it say. The progress line is therefore
|
|
26
|
+
* typographic, and this sheet gives it no track, no fill and no width driven by
|
|
27
|
+
* the counts. A host that wants a bar draws one knowing what it is claiming.
|
|
28
|
+
*
|
|
29
|
+
* ## Every control gets a focus ring
|
|
30
|
+
*
|
|
31
|
+
* The queue is keyboard-first, so a control with no `:focus-visible` rule is
|
|
32
|
+
* unreachable for the reader this surface is built for on any host that resets
|
|
33
|
+
* the UA outline. Enforced in `styles.test.ts`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const firstPassStylesheet = "\n.ig-firstpass {\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 background: var(--ig-surface);\n border-radius: var(--ig-radius);\n padding: var(--ig-space);\n}\n\n.ig-firstpass-question {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-firstpass-statement {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--ig-space-tight);\n margin: 0;\n color: var(--ig-text);\n}\n\n.ig-firstpass-ref {\n font-family: var(--ig-font-mono);\n}\n\n.ig-firstpass-kind {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n\n.ig-firstpass-evidence {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n border-left: var(--ig-stroke) solid var(--ig-line);\n padding-left: var(--ig-space);\n}\n\n.ig-firstpass-evidence-label {\n margin: 0;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text-muted);\n}\n\n.ig-firstpass-evidence-list {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.ig-firstpass-evidence-item {\n font-size: var(--ig-font-size-small);\n color: var(--ig-text-body);\n}\n\n.ig-firstpass-answers {\n display: flex;\n flex-wrap: wrap;\n gap: var(--ig-space-tight);\n}\n\n.ig-firstpass-answer,\n.ig-firstpass-undo {\n font: inherit;\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}\n\n/* The one answer that writes. Weighted so the irreversible option is the one\n the eye lands on \u2014 \u00A717e's consent rule is about knowing what you agreed to,\n and that starts before the keystroke. */\n.ig-firstpass-answer[data-ig-answer='apply'] {\n border-color: var(--ig-accent);\n}\n\n.ig-firstpass-undo {\n align-self: flex-start;\n color: var(--ig-text-muted);\n}\n\n.ig-firstpass-answer:focus-visible,\n.ig-firstpass-undo:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-stroke);\n}\n\n.ig-firstpass-progress {\n margin: 0;\n font-size: var(--ig-font-size-small);\n color: var(--ig-text-muted);\n}\n\n.ig-firstpass-finished,\n.ig-firstpass-empty {\n margin: 0;\n color: var(--ig-text);\n}\n";
|
|
36
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/firstpass/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,eAAO,MAAM,mBAAmB,m9EAgH/B,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first pass's structural stylesheet.
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the picker's, the ladder's and the overlay's: layout, weight
|
|
5
|
+
* and state, never a value. Every colour, length and font is a `var(--ig-…)`
|
|
6
|
+
* the host's theme resolves, and `styles.test.ts` scans these bytes for a
|
|
7
|
+
* literal colour, a fixed length and a token the theme does not define — so the
|
|
8
|
+
* rule is enforced rather than remembered.
|
|
9
|
+
*
|
|
10
|
+
* IT ADDS SELECTORS RATHER THAN REDEFINING THEM. Nothing here reaches into the
|
|
11
|
+
* viewer's own classes; this file styles only what the first pass introduces.
|
|
12
|
+
*
|
|
13
|
+
* ## The statement is a FLEX ROW, and that is load-bearing
|
|
14
|
+
*
|
|
15
|
+
* `render.ts` draws the proposed relationship subject · kind · object and calls
|
|
16
|
+
* that word order a default a host may bypass. The CSS `order` property
|
|
17
|
+
* reorders flex children and does nothing to inline text, so laying it out any
|
|
18
|
+
* other way would make that claim true only in principle — the same reasoning
|
|
19
|
+
* the picker's stylesheet records, and enforced by the same kind of test.
|
|
20
|
+
*
|
|
21
|
+
* ## There is no progress BAR, and its absence is the design
|
|
22
|
+
*
|
|
23
|
+
* §17e: "100% encoded is never the goal and the workspace never implies it is."
|
|
24
|
+
* A bar implies a target by its geometry — an unfilled tail reads as work
|
|
25
|
+
* outstanding whatever the words beside it say. The progress line is therefore
|
|
26
|
+
* typographic, and this sheet gives it no track, no fill and no width driven by
|
|
27
|
+
* the counts. A host that wants a bar draws one knowing what it is claiming.
|
|
28
|
+
*
|
|
29
|
+
* ## Every control gets a focus ring
|
|
30
|
+
*
|
|
31
|
+
* The queue is keyboard-first, so a control with no `:focus-visible` rule is
|
|
32
|
+
* unreachable for the reader this surface is built for on any host that resets
|
|
33
|
+
* the UA outline. Enforced in `styles.test.ts`.
|
|
34
|
+
*/
|
|
35
|
+
export const firstPassStylesheet = `
|
|
36
|
+
.ig-firstpass {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: var(--ig-space);
|
|
40
|
+
font-family: var(--ig-font-ui);
|
|
41
|
+
font-size: var(--ig-font-size);
|
|
42
|
+
line-height: var(--ig-line-height);
|
|
43
|
+
color: var(--ig-text-body);
|
|
44
|
+
background: var(--ig-surface);
|
|
45
|
+
border-radius: var(--ig-radius);
|
|
46
|
+
padding: var(--ig-space);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ig-firstpass-question {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: var(--ig-space-tight);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ig-firstpass-statement {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
align-items: baseline;
|
|
59
|
+
gap: var(--ig-space-tight);
|
|
60
|
+
margin: 0;
|
|
61
|
+
color: var(--ig-text);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ig-firstpass-ref {
|
|
65
|
+
font-family: var(--ig-font-mono);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.ig-firstpass-kind {
|
|
69
|
+
font-family: var(--ig-font-mono);
|
|
70
|
+
color: var(--ig-text-muted);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ig-firstpass-evidence {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: var(--ig-space-tight);
|
|
77
|
+
border-left: var(--ig-stroke) solid var(--ig-line);
|
|
78
|
+
padding-left: var(--ig-space);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.ig-firstpass-evidence-label {
|
|
82
|
+
margin: 0;
|
|
83
|
+
font-size: var(--ig-font-size-small);
|
|
84
|
+
color: var(--ig-text-muted);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ig-firstpass-evidence-list {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
gap: var(--ig-space-tight);
|
|
91
|
+
margin: 0;
|
|
92
|
+
padding: 0;
|
|
93
|
+
list-style: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ig-firstpass-evidence-item {
|
|
97
|
+
font-size: var(--ig-font-size-small);
|
|
98
|
+
color: var(--ig-text-body);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.ig-firstpass-answers {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-wrap: wrap;
|
|
104
|
+
gap: var(--ig-space-tight);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ig-firstpass-answer,
|
|
108
|
+
.ig-firstpass-undo {
|
|
109
|
+
font: inherit;
|
|
110
|
+
color: var(--ig-text);
|
|
111
|
+
background: var(--ig-surface-2);
|
|
112
|
+
border: var(--ig-stroke) solid var(--ig-line);
|
|
113
|
+
border-radius: var(--ig-radius);
|
|
114
|
+
padding: var(--ig-space-tight) var(--ig-space);
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* The one answer that writes. Weighted so the irreversible option is the one
|
|
119
|
+
the eye lands on — §17e's consent rule is about knowing what you agreed to,
|
|
120
|
+
and that starts before the keystroke. */
|
|
121
|
+
.ig-firstpass-answer[data-ig-answer='apply'] {
|
|
122
|
+
border-color: var(--ig-accent);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.ig-firstpass-undo {
|
|
126
|
+
align-self: flex-start;
|
|
127
|
+
color: var(--ig-text-muted);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ig-firstpass-answer:focus-visible,
|
|
131
|
+
.ig-firstpass-undo:focus-visible {
|
|
132
|
+
outline: var(--ig-focus-ring) solid var(--ig-focus);
|
|
133
|
+
outline-offset: var(--ig-stroke);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.ig-firstpass-progress {
|
|
137
|
+
margin: 0;
|
|
138
|
+
font-size: var(--ig-font-size-small);
|
|
139
|
+
color: var(--ig-text-muted);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.ig-firstpass-finished,
|
|
143
|
+
.ig-firstpass-empty {
|
|
144
|
+
margin: 0;
|
|
145
|
+
color: var(--ig-text);
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/firstpass/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgHlC,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The queue as a view model: one question, its evidence, and where you are.
|
|
3
|
+
*
|
|
4
|
+
* Everything a shell needs to draw the first pass, and nothing about how. Same
|
|
5
|
+
* split `picker/view.ts` and `reevaluate/view.ts` keep — the model is
|
|
6
|
+
* exhaustively testable on a runtime with no DOM, and `render.ts` is left with
|
|
7
|
+
* nothing to get wrong except markup.
|
|
8
|
+
*
|
|
9
|
+
* ## The three states are a union, not a candidate plus two flags
|
|
10
|
+
*
|
|
11
|
+
* A queue is showing a question, or it has finished, or the host found nothing
|
|
12
|
+
* to ask about. Modelled as one nullable candidate beside a `finished` boolean,
|
|
13
|
+
* two of the four combinations would be unreachable and a renderer would still
|
|
14
|
+
* have to answer for them. As a union each state carries exactly the fields it
|
|
15
|
+
* has, and §17e's insistence that an empty queue and a completed queue read
|
|
16
|
+
* DIFFERENTLY becomes something the type enforces rather than something a
|
|
17
|
+
* renderer remembers.
|
|
18
|
+
*
|
|
19
|
+
* ## Progress rides on every state
|
|
20
|
+
*
|
|
21
|
+
* Including `finished` — an owner who just answered the last question wants to
|
|
22
|
+
* see the 64 they answered, not a bare congratulation. And including `empty`,
|
|
23
|
+
* where it is honestly zero of zero: §17e's rule is that the denominator is
|
|
24
|
+
* candidates found, and a host that found none has a denominator, not a missing
|
|
25
|
+
* one.
|
|
26
|
+
*/
|
|
27
|
+
import type { Candidate } from './candidates.ts';
|
|
28
|
+
import { type QueueProgress, type QueueState } from './queue.ts';
|
|
29
|
+
/**
|
|
30
|
+
* The question on screen.
|
|
31
|
+
*
|
|
32
|
+
* It restates the candidate's own fields rather than nesting it, so a renderer
|
|
33
|
+
* reads `view.subject` instead of `view.candidate.from` — and so the ordered
|
|
34
|
+
* pair is named for what it MEANS in the sentence being asked. Nothing here
|
|
35
|
+
* chooses a word order; that is `render.ts`'s default and a host may bypass it,
|
|
36
|
+
* exactly as the picker's statement is bypassable.
|
|
37
|
+
*/
|
|
38
|
+
export interface FirstPassQuestion {
|
|
39
|
+
readonly candidate: Candidate;
|
|
40
|
+
/** The issue the proposed relationship starts from. */
|
|
41
|
+
readonly subject: string;
|
|
42
|
+
/** The issue it points at. */
|
|
43
|
+
readonly object: string;
|
|
44
|
+
/** Which relationship is proposed. */
|
|
45
|
+
readonly kind: string;
|
|
46
|
+
/** Why the host proposed it. May be empty — see `candidates.ts`. */
|
|
47
|
+
readonly evidence: readonly {
|
|
48
|
+
readonly token: string;
|
|
49
|
+
readonly text: string;
|
|
50
|
+
}[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* What the surface is showing.
|
|
54
|
+
*
|
|
55
|
+
* `asking` carries the question; the other two carry none, because there is
|
|
56
|
+
* none. A discriminated union so a renderer's switch is exhaustive and a fourth
|
|
57
|
+
* state — were the design ever to grow one — is a compile error rather than a
|
|
58
|
+
* blank panel.
|
|
59
|
+
*/
|
|
60
|
+
export type FirstPassView = {
|
|
61
|
+
readonly state: 'asking';
|
|
62
|
+
readonly question: FirstPassQuestion;
|
|
63
|
+
readonly progress: QueueProgress;
|
|
64
|
+
} | {
|
|
65
|
+
readonly state: 'finished';
|
|
66
|
+
readonly progress: QueueProgress;
|
|
67
|
+
} | {
|
|
68
|
+
readonly state: 'empty';
|
|
69
|
+
readonly progress: QueueProgress;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The view for a queue. Total and pure.
|
|
73
|
+
*
|
|
74
|
+
* `empty` is decided by the DENOMINATOR rather than by the cursor, which is the
|
|
75
|
+
* one subtlety here: a queue of zero candidates is finished the moment it
|
|
76
|
+
* opens, so a test on `finished` alone would report the misconfigured-detector
|
|
77
|
+
* case as a completed first pass. §17e's two facts stay separate because the
|
|
78
|
+
* question asked to tell them apart is "did the host find anything?", not "is
|
|
79
|
+
* there anything left?".
|
|
80
|
+
*/
|
|
81
|
+
export declare function firstPassView(state: QueueState): FirstPassView;
|
|
82
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/firstpass/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAmC,MAAM,YAAY,CAAC;AAElG;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjF;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GACpG;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAChE;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAAC;AAElE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAqB9D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The queue as a view model: one question, its evidence, and where you are.
|
|
3
|
+
*
|
|
4
|
+
* Everything a shell needs to draw the first pass, and nothing about how. Same
|
|
5
|
+
* split `picker/view.ts` and `reevaluate/view.ts` keep — the model is
|
|
6
|
+
* exhaustively testable on a runtime with no DOM, and `render.ts` is left with
|
|
7
|
+
* nothing to get wrong except markup.
|
|
8
|
+
*
|
|
9
|
+
* ## The three states are a union, not a candidate plus two flags
|
|
10
|
+
*
|
|
11
|
+
* A queue is showing a question, or it has finished, or the host found nothing
|
|
12
|
+
* to ask about. Modelled as one nullable candidate beside a `finished` boolean,
|
|
13
|
+
* two of the four combinations would be unreachable and a renderer would still
|
|
14
|
+
* have to answer for them. As a union each state carries exactly the fields it
|
|
15
|
+
* has, and §17e's insistence that an empty queue and a completed queue read
|
|
16
|
+
* DIFFERENTLY becomes something the type enforces rather than something a
|
|
17
|
+
* renderer remembers.
|
|
18
|
+
*
|
|
19
|
+
* ## Progress rides on every state
|
|
20
|
+
*
|
|
21
|
+
* Including `finished` — an owner who just answered the last question wants to
|
|
22
|
+
* see the 64 they answered, not a bare congratulation. And including `empty`,
|
|
23
|
+
* where it is honestly zero of zero: §17e's rule is that the denominator is
|
|
24
|
+
* candidates found, and a host that found none has a denominator, not a missing
|
|
25
|
+
* one.
|
|
26
|
+
*/
|
|
27
|
+
import { currentCandidate, queueProgress } from "./queue.js";
|
|
28
|
+
/**
|
|
29
|
+
* The view for a queue. Total and pure.
|
|
30
|
+
*
|
|
31
|
+
* `empty` is decided by the DENOMINATOR rather than by the cursor, which is the
|
|
32
|
+
* one subtlety here: a queue of zero candidates is finished the moment it
|
|
33
|
+
* opens, so a test on `finished` alone would report the misconfigured-detector
|
|
34
|
+
* case as a completed first pass. §17e's two facts stay separate because the
|
|
35
|
+
* question asked to tell them apart is "did the host find anything?", not "is
|
|
36
|
+
* there anything left?".
|
|
37
|
+
*/
|
|
38
|
+
export function firstPassView(state) {
|
|
39
|
+
const progress = queueProgress(state);
|
|
40
|
+
if (progress.found === 0)
|
|
41
|
+
return { state: 'empty', progress };
|
|
42
|
+
const candidate = currentCandidate(state);
|
|
43
|
+
if (candidate === null)
|
|
44
|
+
return { state: 'finished', progress };
|
|
45
|
+
return {
|
|
46
|
+
state: 'asking',
|
|
47
|
+
progress,
|
|
48
|
+
question: {
|
|
49
|
+
candidate,
|
|
50
|
+
subject: candidate.from,
|
|
51
|
+
object: candidate.to,
|
|
52
|
+
kind: candidate.kind,
|
|
53
|
+
// COPIED RATHER THAN PASSED THROUGH, so the view model is a plain value a
|
|
54
|
+
// host can serialise, compare or snapshot without carrying a reference
|
|
55
|
+
// into the candidate set it came from.
|
|
56
|
+
evidence: candidate.evidence.map((item) => ({ token: item.token, text: item.text })),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/firstpass/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAuC,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAoClG;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAE9D,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IAE/D,OAAO;QACL,KAAK,EAAE,QAAQ;QACf,QAAQ;QACR,QAAQ,EAAE;YACR,SAAS;YACT,OAAO,EAAE,SAAS,CAAC,IAAI;YACvB,MAAM,EAAE,SAAS,CAAC,EAAE;YACpB,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,0EAA0E;YAC1E,uEAAuE;YACvE,uCAAuC;YACvC,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;SACrF;KACF,CAAC;AACJ,CAAC"}
|