@issuegraph/editor 0.1.0 → 0.3.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.
Files changed (49) hide show
  1. package/README.md +35 -3
  2. package/dist/audit/findings.d.ts +5 -2
  3. package/dist/audit/findings.d.ts.map +1 -1
  4. package/dist/audit/findings.js +33 -1
  5. package/dist/audit/findings.js.map +1 -1
  6. package/dist/firstpass/batch.d.ts +10 -0
  7. package/dist/firstpass/batch.d.ts.map +1 -1
  8. package/dist/firstpass/batch.js +26 -7
  9. package/dist/firstpass/batch.js.map +1 -1
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/overlay/projected.d.ts +21 -0
  15. package/dist/overlay/projected.d.ts.map +1 -0
  16. package/dist/overlay/projected.js +49 -0
  17. package/dist/overlay/projected.js.map +1 -0
  18. package/dist/scale/ladder.d.ts +6 -0
  19. package/dist/scale/ladder.d.ts.map +1 -1
  20. package/dist/scale/ladder.js +13 -0
  21. package/dist/scale/ladder.js.map +1 -1
  22. package/dist/scale/render.d.ts +19 -0
  23. package/dist/scale/render.d.ts.map +1 -1
  24. package/dist/scale/render.js +10 -29
  25. package/dist/scale/render.js.map +1 -1
  26. package/dist/workspace/chrome.d.ts +21 -0
  27. package/dist/workspace/chrome.d.ts.map +1 -0
  28. package/dist/workspace/chrome.js +178 -0
  29. package/dist/workspace/chrome.js.map +1 -0
  30. package/dist/workspace/host.d.ts +148 -0
  31. package/dist/workspace/host.d.ts.map +1 -0
  32. package/dist/workspace/host.js +316 -0
  33. package/dist/workspace/host.js.map +1 -0
  34. package/dist/workspace/mount.d.ts +139 -0
  35. package/dist/workspace/mount.d.ts.map +1 -0
  36. package/dist/workspace/mount.js +882 -0
  37. package/dist/workspace/mount.js.map +1 -0
  38. package/dist/workspace/rail.d.ts.map +1 -1
  39. package/dist/workspace/rail.js +11 -0
  40. package/dist/workspace/rail.js.map +1 -1
  41. package/dist/workspace/render.d.ts +7 -0
  42. package/dist/workspace/render.d.ts.map +1 -1
  43. package/dist/workspace/render.js +66 -5
  44. package/dist/workspace/render.js.map +1 -1
  45. package/dist/workspace/styles.d.ts +1 -1
  46. package/dist/workspace/styles.d.ts.map +1 -1
  47. package/dist/workspace/styles.js +20 -0
  48. package/dist/workspace/styles.js.map +1 -1
  49. package/package.json +6 -4
@@ -0,0 +1,316 @@
1
+ /**
2
+ * The workspace's host reducer — every decision a mount makes, with no DOM.
3
+ *
4
+ * `renderWorkspace` renders and publishes: each control says what it does as
5
+ * `data-ig-command`, and the viewer publishes its two identities, `data-ig-key`
6
+ * and `data-ig-group`. This file is the DECISIONS a mount takes on reading
7
+ * them. The shell in `mount.ts` reads the DOM and turns what it saw into a
8
+ * {@link HostCommand}; this file turns the command into the next state and a
9
+ * list of {@link HostEffect}s the shell then performs against the store.
10
+ *
11
+ * It composes the package's own reducers — `selectionReducer`, `scaleReducer`,
12
+ * `createReducer`, `pickerView` — and adds only what those leave to a mount:
13
+ * which one selection is shared, when the create draft begins and ends, the
14
+ * rail's scroll offset, and the drag that turns a canvas drop into a draft.
15
+ * Nothing here reaches a node, so all of it runs under `node --test` with no
16
+ * DOM, which is the property the package's other reducers are shaped for and
17
+ * the reason this is not written into listeners.
18
+ *
19
+ * ## Lifted from the demo, and why
20
+ *
21
+ * This was the demo's `host.ts`, written once for that page. A second host
22
+ * re-implemented it from scratch and re-ran the review rounds that shaped it;
23
+ * the design kit's layer rule puts the interaction shell in layer 2, not in
24
+ * the host. What stayed behind in the demo is exactly what was demo-shaped:
25
+ * the theme switch, the armed dispatch outcome, and the sandbox reset — none
26
+ * of which a host reducer should know about, and each of which the demo now
27
+ * handles beside the mount rather than through it.
28
+ */
29
+ import { EDGE_FIELDS, isEdgeField } from '@issuegraph/core';
30
+ import { findEdge } from '@issuegraph/store';
31
+ import { IDLE_CREATE_DRAFT, createReducer } from "../create/draft.js";
32
+ import { pickerView } from "../picker/view.js";
33
+ import { INITIAL_SCALE_STATE, scaleReducer } from "../scale/commands.js";
34
+ import { INITIAL_SELECTION, selectedEdgeId, selectedKey, selectionReducer, } from "./selection.js";
35
+ export const INITIAL_HOST_STATE = Object.freeze({
36
+ selection: INITIAL_SELECTION,
37
+ scale: INITIAL_SCALE_STATE,
38
+ auditFiltered: false,
39
+ railStart: 0,
40
+ draft: IDLE_CREATE_DRAFT,
41
+ targetQuery: '',
42
+ drag: null,
43
+ drop: null,
44
+ });
45
+ function settled(state) {
46
+ return { state, effects: [] };
47
+ }
48
+ /** A draft step: apply the create reducer, and emit the proposal it completes. */
49
+ function drafted(state, command) {
50
+ const result = createReducer(state.draft, command);
51
+ if (result.proposal === null) {
52
+ // BEGINNING A DRAFT SELECTS ITS SOURCE. The inspector draws the picker for
53
+ // a selected edge ahead of any draft, so a draft begun by R from a focused
54
+ // row while an edge stayed selected would render behind the picker and
55
+ // could never reach its target search. One selection, and it is the
56
+ // draft's subject — the same rule the canvas drop already applies.
57
+ const selection = command.kind === 'begin' ? { kind: 'issue', key: command.source } : state.selection;
58
+ // A CANCEL CLEARS THE DRAFT'S CHROME TOO — the drop point a canvas chooser
59
+ // was placed at and the query typed into the target search — exactly as
60
+ // the explicit cancel control does. Escape reaches here through the key
61
+ // map, and a draft begun afterwards must not open at the old drop point
62
+ // or with the old query already in the box.
63
+ const chrome = command.kind === 'cancel' ? { targetQuery: '', drop: null } : {};
64
+ return settled({ ...state, draft: result.draft, selection, ...chrome });
65
+ }
66
+ return {
67
+ state: { ...state, draft: IDLE_CREATE_DRAFT, targetQuery: '', drop: null },
68
+ effects: [{ kind: 'propose', proposal: result.proposal }],
69
+ };
70
+ }
71
+ /** A pointer on an issue: a target while one is being chosen, a selection otherwise. */
72
+ function pointed(state, key) {
73
+ const choosingTarget = state.draft.kind !== null && state.draft.target === null;
74
+ if (choosingTarget && key !== state.draft.source) {
75
+ return drafted(state, { kind: 'target', ref: key });
76
+ }
77
+ return settled({
78
+ ...state,
79
+ selection: selectionReducer(state.selection, { kind: 'select-issue', key }),
80
+ });
81
+ }
82
+ function selectEdge(state, edgeId) {
83
+ return settled({
84
+ ...state,
85
+ selection: selectionReducer(state.selection, { kind: 'select-edge', edgeId }),
86
+ draft: IDLE_CREATE_DRAFT,
87
+ targetQuery: '',
88
+ drop: null,
89
+ });
90
+ }
91
+ /** The retype and flip proposals come from the picker's own view, never built here. */
92
+ function pickerProposal(document, edgeId, choice) {
93
+ const view = pickerView(document, edgeId);
94
+ if (choice.kind === 'flip')
95
+ return view.flip?.proposal ?? null;
96
+ return view.options.find((option) => option.kind === choice.field && !option.current)?.proposal ?? null;
97
+ }
98
+ function controlled(state, name, target, value, document) {
99
+ const edgeId = selectedEdgeId(state.selection);
100
+ switch (name) {
101
+ // --- the package's own commands ---
102
+ case 'select-edge':
103
+ return target === undefined ? settled(state) : selectEdge(state, target);
104
+ case 'select-issue':
105
+ // THE HOLDER DEEP LINK. The inspector publishes a hold's subject — the
106
+ // open blocker, the claimed peer — as this control, so a reader can reach
107
+ // the issue holding the one they are looking at. It is a pointer on that
108
+ // issue, with a pointer's rules: a selection, or the target of a draft.
109
+ return target === undefined ? settled(state) : pointed(state, target);
110
+ case 'clear':
111
+ return settled({
112
+ ...state,
113
+ selection: INITIAL_SELECTION,
114
+ draft: IDLE_CREATE_DRAFT,
115
+ targetQuery: '',
116
+ drop: null,
117
+ });
118
+ case 'focus':
119
+ return target === undefined
120
+ ? settled(state)
121
+ : settled({ ...state, scale: scaleReducer(state.scale, { kind: 'focus', key: target }) });
122
+ case 'clear-focus':
123
+ return settled({ ...state, scale: scaleReducer(state.scale, { kind: 'clear-focus' }) });
124
+ case 'search':
125
+ return settled({
126
+ ...state,
127
+ scale: scaleReducer(state.scale, { kind: 'search', query: value ?? '' }),
128
+ });
129
+ case 'open-isolated':
130
+ return settled({ ...state, scale: scaleReducer(state.scale, { kind: 'open-isolated' }) });
131
+ case 'close-isolated':
132
+ return settled({ ...state, scale: scaleReducer(state.scale, { kind: 'close-isolated' }) });
133
+ case 'retype': {
134
+ if (edgeId === null || value === undefined || !isEdgeField(value))
135
+ return settled(state);
136
+ const proposal = pickerProposal(document, edgeId, { kind: 'retype', field: value });
137
+ return proposal === null ? settled(state) : { state, effects: [{ kind: 'propose', proposal }] };
138
+ }
139
+ case 'flip': {
140
+ if (edgeId === null)
141
+ return settled(state);
142
+ const proposal = pickerProposal(document, edgeId, { kind: 'flip' });
143
+ return proposal === null ? settled(state) : { state, effects: [{ kind: 'propose', proposal }] };
144
+ }
145
+ case 'dismiss-change':
146
+ return { state, effects: [{ kind: 'dismiss-change' }] };
147
+ // --- the mount's chrome ---
148
+ case 'audit-filter':
149
+ return settled({ ...state, auditFiltered: !state.auditFiltered });
150
+ case 'add': {
151
+ const source = selectedKey(state.selection);
152
+ return source === null ? settled(state) : drafted(state, { kind: 'begin', source });
153
+ }
154
+ case 'kind':
155
+ return value === undefined || !isEdgeField(value)
156
+ ? settled(state)
157
+ : drafted(state, { kind: 'type', edgeKind: value });
158
+ case 'target-query':
159
+ return settled({ ...state, targetQuery: value ?? '' });
160
+ case 'target':
161
+ return target === undefined ? settled(state) : drafted(state, { kind: 'target', ref: target });
162
+ case 'cancel':
163
+ return settled({ ...state, draft: IDLE_CREATE_DRAFT, targetQuery: '', drop: null });
164
+ case 'delete':
165
+ return edgeId === null
166
+ ? settled(state)
167
+ : { state, effects: [{ kind: 'propose', proposal: { op: 'delete', edgeId } }] };
168
+ case 'retry':
169
+ return target === undefined ? settled(state) : { state, effects: [{ kind: 'retry', mutationId: target }] };
170
+ case 'discard':
171
+ return target === undefined
172
+ ? settled(state)
173
+ : { state, effects: [{ kind: 'discard', mutationId: target }] };
174
+ default:
175
+ // A COMMAND THIS REDUCER DOES NOT KNOW CHANGES NOTHING. A host's own
176
+ // chrome may publish commands on the same attribute — the demo's theme
177
+ // switch does — and those are the host's to read from its own listener,
178
+ // never a reason for this reducer to guess.
179
+ return settled(state);
180
+ }
181
+ }
182
+ function intended(state, intent) {
183
+ switch (intent.kind) {
184
+ case 'none':
185
+ // `T` opens the picker; the picker is already drawn whenever an edge is
186
+ // selected, so there is nothing to change.
187
+ case 'retype':
188
+ return settled(state);
189
+ case 'create':
190
+ return drafted(state, intent.command);
191
+ case 'propose':
192
+ return { state, effects: [{ kind: 'propose', proposal: intent.proposal }] };
193
+ }
194
+ }
195
+ /** The one reducer. `document` is the landed document, for edge lookups. */
196
+ export function reduceHost(state, command, document) {
197
+ switch (command.kind) {
198
+ case 'point':
199
+ return pointed(state, command.key);
200
+ case 'group': {
201
+ // A mark names either an edge (its store identity) or a slot (its lead).
202
+ // A MARK NAMING NEITHER CHANGES NOTHING. The canvas draws an edge the
203
+ // store has not landed yet — a pending create carries a mark from the
204
+ // moment it is proposed — and its identity is in no landed document and
205
+ // is no issue key. Falling through to `pointed` would select that
206
+ // identity as an issue, or worse, commit it as a draft's target.
207
+ if (findEdge(document, command.id) !== undefined)
208
+ return selectEdge(state, command.id);
209
+ if (document.issues.some((issue) => issue.ref === command.id))
210
+ return pointed(state, command.id);
211
+ return settled(state);
212
+ }
213
+ case 'control':
214
+ return controlled(state, command.name, command.target, command.value, document);
215
+ case 'intent':
216
+ return intended(state, command.intent);
217
+ case 'scroll':
218
+ return settled({ ...state, railStart: Math.max(0, Math.floor(command.start)) });
219
+ case 'drag-start':
220
+ return settled({ ...state, drag: command.key });
221
+ case 'drop': {
222
+ const source = state.drag;
223
+ const released = { ...state, drag: null };
224
+ if (source === null || command.key === null || command.key === source)
225
+ return settled(released);
226
+ // A drop is the canvas path's first two facts at once: source, then
227
+ // target. The kind is still to be gathered, at the drop point.
228
+ const begun = createReducer(IDLE_CREATE_DRAFT, { kind: 'begin', source });
229
+ const targeted = createReducer(begun.draft, { kind: 'target', ref: command.key });
230
+ return settled({
231
+ ...released,
232
+ draft: targeted.draft,
233
+ drop: command.at,
234
+ selection: selectionReducer(INITIAL_SELECTION, { kind: 'select-issue', key: source }),
235
+ });
236
+ }
237
+ }
238
+ }
239
+ /**
240
+ * Bring the state back into agreement with a document that moved under it.
241
+ *
242
+ * The store re-renders on every landed write, and a write can remove what the
243
+ * state names: a retype or a flip gives the edge a NEW identity, a delete
244
+ * removes it, and a conflict's rehydrate can drop an issue a draft was aimed
245
+ * at. A selection naming an edge the document no longer carries would leave
246
+ * the inspector showing a picker for nothing — the viewer already refuses a
247
+ * stale selection the same way, so the host does too, from the document
248
+ * rather than from memory of what it just proposed.
249
+ */
250
+ export function reconcileHost(state, document) {
251
+ const edgeId = selectedEdgeId(state.selection);
252
+ const selection = edgeId !== null && findEdge(document, edgeId) === undefined ? INITIAL_SELECTION : state.selection;
253
+ const issueKey = selectedKey(state.selection);
254
+ const known = new Set(document.issues.map((issue) => issue.ref));
255
+ const draftStands = (state.draft.source === null || known.has(state.draft.source)) &&
256
+ (state.draft.target === null || known.has(state.draft.target));
257
+ if (selection === state.selection && draftStands && (issueKey === null || known.has(issueKey))) {
258
+ return state;
259
+ }
260
+ return {
261
+ ...state,
262
+ selection: issueKey !== null && !known.has(issueKey) ? INITIAL_SELECTION : selection,
263
+ ...(draftStands ? {} : { draft: IDLE_CREATE_DRAFT, targetQuery: '', drop: null }),
264
+ };
265
+ }
266
+ /** The issues a target search offers, by reference or title, never the source itself. */
267
+ export function targetMatches(issues, query, source, limit = 8) {
268
+ const needle = query.trim().toLowerCase();
269
+ if (needle === '')
270
+ return [];
271
+ return issues
272
+ .filter((issue) => issue.ref !== source)
273
+ .filter((issue) => issue.ref.includes(needle) || issue.title.toLowerCase().includes(needle))
274
+ .slice(0, limit);
275
+ }
276
+ /** The edge kinds, in the format's order — the keyboard path's `1`–`5` is this list. */
277
+ export const KINDS = EDGE_FIELDS;
278
+ /** How far the reader may scroll into the rail window before it is re-cut around them, in rows. */
279
+ export const RAIL_SLACK = 20;
280
+ /**
281
+ * The slack a window of `count` rows actually gets: `RAIL_SLACK`, bounded to a
282
+ * quarter of the window and never below one row. A slack as wide as the window
283
+ * re-cut a small window onto its own start — ArrowDown on the last drawn row
284
+ * computed `offset - slack` at or below the current start, dispatched it
285
+ * unchanged, and keyboard navigation could not leave the first window.
286
+ */
287
+ export function railSlackFor(count) {
288
+ return Math.min(RAIL_SLACK, Math.max(1, Math.floor(count / 4)));
289
+ }
290
+ /**
291
+ * Where the rail window should be re-cut for a scroll position, or `null` when
292
+ * it should stay where it is.
293
+ *
294
+ * `row` is the first visible row (scroll offset over pitch), `start` the
295
+ * window's current first slot, `count` the window's size and `total` the rows
296
+ * in the order. Inside the window's slack band nothing moves. Outside it, the
297
+ * window is re-cut `RAIL_SLACK` rows above the reader, clamped to the order.
298
+ *
299
+ * THE CLAMP CAN LAND ON THE CURRENT START, AND THAT CASE MUST ANSWER `null`.
300
+ * At the end of a long order the window is already pinned to its last start
301
+ * while the reader is deep inside it, so every scroll position there is
302
+ * "outside the band" and clamps back to the same start. A shell that
303
+ * dispatched that as a change redrew, restored the scroll offset — which
304
+ * fires `scroll` again — and never stopped. The decision is a pure function
305
+ * here so that cycle is refused where it can be tested without a browser.
306
+ */
307
+ export function railWindowTarget(row, start, count, total) {
308
+ const slack = railSlackFor(count);
309
+ const offset = row - start;
310
+ if (offset >= 0 && offset <= count - slack * 2)
311
+ return null;
312
+ const lastStart = Math.max(0, total - count);
313
+ const next = Math.min(lastStart, Math.max(0, Math.floor(row) - slack));
314
+ return next === start ? null : next;
315
+ }
316
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/workspace/host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The workspace's DOM shell — the only module in this package that touches
3
+ * nodes.
4
+ *
5
+ * `renderWorkspace` renders the three-zone workspace as markup and publishes
6
+ * every control as `data-ig-command`; `@issuegraph/viewer` publishes its two
7
+ * identities, `data-ig-key` and `data-ig-group`. A mount reads those, reduces,
8
+ * and renders again — and that loop is this file. What it DECIDES lives in
9
+ * `host.ts`, as a reducer with no DOM, so this file is left with listeners, an
10
+ * `innerHTML` assignment, and the chrome the panels leave to a mount: the add
11
+ * button, the kind chooser, the target search, the delete button.
12
+ *
13
+ * ## Lifted from the demo, in the viewer's shape
14
+ *
15
+ * This was the demo's `workspace.ts`, written once for that page. The viewer
16
+ * made the opposite call for the same problem — it exports `mountViewer` with
17
+ * `update` and `destroy` — and that is the entry point a typed host actually
18
+ * consumes. It took nine review rounds to get this shell right, and every
19
+ * finding was in the shell, none in the reducer; a second host would have
20
+ * re-run them. So the shell ships, in the viewer's shape: one function, one
21
+ * handle, and a container it touches and nothing else.
22
+ *
23
+ * ## `innerHTML`, and why it is not the thing `render.ts` refused
24
+ *
25
+ * Nothing in this file interpolates host text into markup. What IS assigned as
26
+ * markup is the package's own rendered output, which `renderMarkup` escaped —
27
+ * the exact bytes a server-rendered host would send. The chrome beside it is
28
+ * built with `createElement` and `textContent`, so the two disciplines meet at
29
+ * the seam rather than mixing.
30
+ *
31
+ * ## One listener per event, at the root
32
+ *
33
+ * The workspace is re-rendered on every change, so a listener attached to a
34
+ * rendered node dies with it. Delegation at the root is what makes the loop
35
+ * cheap to reason about: one `click`, one `input`, one `keydown`, one scroll
36
+ * (captured, because scroll does not bubble), and the three pointer events the
37
+ * canvas drag needs.
38
+ *
39
+ * ## It reaches no global
40
+ *
41
+ * The document comes from the element the caller passed, which is what keeps
42
+ * this module importable on a runtime that has no DOM — the property
43
+ * `purity.test.ts` measures. An element is recognised by what it can do rather
44
+ * than by `instanceof` against a constructor this module would have to reach
45
+ * for, and a pointer release outside the element is heard on the element's own
46
+ * document rather than on a window.
47
+ */
48
+ import type { Store, StoreSnapshot } from '@issuegraph/store';
49
+ import { type Theme, type ViewerDocument } from '@issuegraph/viewer';
50
+ import type { AuditInput } from '../audit/findings.ts';
51
+ import type { PickerWords } from '../picker/words.ts';
52
+ import { type HostCommand, type HostState } from './host.ts';
53
+ import { type WorkspaceWords } from './render.ts';
54
+ /** What the canvas zone draws: the editor's scale ladder, or the viewer's tree projection. */
55
+ export declare const CANVAS_MODES: readonly ["neighbourhood", "tree"];
56
+ export type CanvasMode = (typeof CANVAS_MODES)[number];
57
+ /**
58
+ * The words the mount's chrome needs on top of the workspace's own.
59
+ *
60
+ * Required, for the reason `WorkspaceWords` gives: this package does not
61
+ * invent an English sentence, and a default would be one. `picker` is the
62
+ * picker's vocabulary, which the mount draws for a selected edge; `keys` is
63
+ * the one optional entry, because a host may prefer to document the keyboard
64
+ * elsewhere.
65
+ */
66
+ export interface MountWords extends WorkspaceWords {
67
+ readonly picker: PickerWords;
68
+ /** The control that begins a relationship from the selected issue. */
69
+ readonly addRelationship: string;
70
+ /** The control that proposes deleting the selected edge. */
71
+ readonly deleteRelationship: string;
72
+ /** The control that returns a draft to idle. */
73
+ readonly cancel: string;
74
+ /** The chooser's sentence tail while no target is known yet. */
75
+ readonly chooseKind: string;
76
+ /** The target search's accessible name. */
77
+ readonly targetLabel: string;
78
+ /** The target search's placeholder. */
79
+ readonly targetPlaceholder: string;
80
+ /** A one-line key legend under the inspector, when the host wants one drawn. */
81
+ readonly keys?: string | undefined;
82
+ }
83
+ /**
84
+ * What the host projects a store snapshot onto.
85
+ *
86
+ * The viewer derives nothing — the order, the holds and the provenance are all
87
+ * inputs — and the audit reads a graph the host built, so both come from the
88
+ * host's projection rather than from anything this mount could compute. An
89
+ * absent `audit` means "not run", which the workspace renders as no header.
90
+ */
91
+ export interface WorkspaceProjection {
92
+ readonly viewer: ViewerDocument;
93
+ readonly audit?: AuditInput | undefined;
94
+ }
95
+ export interface MountWorkspaceOptions {
96
+ /**
97
+ * The store the host built, with its own `DataSource` and `OrderDeriver`.
98
+ * Fixed for the life of the mount; a host that swaps stores destroys and
99
+ * mounts again. Hydration is the host's: the mount subscribes and redraws on
100
+ * every notification, so a `hydrate()` before or after mounting both land.
101
+ */
102
+ readonly store: Store;
103
+ /** The host's projection of a snapshot — the landed document is `{ issues, edges: landed }`. */
104
+ readonly project: (snapshot: StoreSnapshot) => WorkspaceProjection;
105
+ readonly words: MountWords;
106
+ readonly theme?: Theme | undefined;
107
+ /** The selector the theme's custom properties are written onto. */
108
+ readonly themeSelector?: string | undefined;
109
+ readonly canvas?: CanvasMode | undefined;
110
+ /** How many rail rows are drawn per window. Wider than the package default so a scroll rarely lands past the drawn rows. */
111
+ readonly railCount?: number | undefined;
112
+ }
113
+ /** What `update` may change. The store is not among them — see {@link MountWorkspaceOptions.store}. */
114
+ export type WorkspaceUpdate = Partial<Omit<MountWorkspaceOptions, 'store'>>;
115
+ export interface WorkspaceHandle {
116
+ /** Take new options, redraw in place, keep the selection and the focus. */
117
+ update(options?: WorkspaceUpdate): void;
118
+ /**
119
+ * Hand the mount a command from the host's own chrome.
120
+ *
121
+ * A host draws controls the mount does not — the demo's writes log, with its
122
+ * retry and discard buttons — outside the mounted element, and this is how
123
+ * those reach the one reducer rather than a second copy of it.
124
+ */
125
+ dispatch(command: HostCommand): void;
126
+ readonly state: HostState;
127
+ /** Remove every listener this handle added and the nodes it built. */
128
+ destroy(): void;
129
+ }
130
+ /** The package default: wide enough that a scroll rarely lands past the drawn rows. */
131
+ export declare const MOUNT_RAIL_COUNT = 80;
132
+ /**
133
+ * Mount the workspace into an element.
134
+ *
135
+ * Returns a handle rather than nothing, for the viewer's reason: a host that
136
+ * cannot tear this down leaks a listener on every re-render.
137
+ */
138
+ export declare function mountWorkspace(element: HTMLElement, options: MountWorkspaceOptions): WorkspaceHandle;
139
+ //# sourceMappingURL=mount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/workspace/mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,OAAO,KAAK,EAA2B,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,cAAc,EAIpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,SAAS,EAQf,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,aAAa,CAAC;AAGnE,8FAA8F;AAC9F,eAAO,MAAM,YAAY,oCAAoD,CAAC;AAC9E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,uCAAuC;IACvC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,gFAAgF;IAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,mBAAmB,CAAC;IACnE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,mEAAmE;IACnE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACzC,4HAA4H;IAC5H,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,uGAAuG;AACvG,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,MAAM,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,sEAAsE;IACtE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AA0CnC;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,GAAG,eAAe,CAgxBpG"}