@north-light/crouter 0.3.194 → 0.3.196
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/dist/clients/attach/render/assistant-message.d.ts +1 -1
- package/dist/clients/attach/render/assistant-message.js +3 -2
- package/dist/clients/attach/render/chat-view.d.ts +7 -17
- package/dist/clients/attach/render/chat-view.js +42 -57
- package/dist/clients/attach/render/diagram.d.ts +0 -10
- package/dist/clients/attach/render/diagram.js +0 -32
- package/dist/clients/attach/render/html-markdown.d.ts +0 -4
- package/dist/clients/attach/render/html-markdown.js +0 -22
- package/dist/clients/attach/render/markdown-source.d.ts +5 -0
- package/dist/clients/attach/render/markdown-source.js +9 -7
- package/dist/clients/attach/viewer.js +389 -389
- package/dist/pages/bundle.js +9 -9
- package/dist/pages/comments.d.ts +9 -0
- package/dist/pages/comments.js +53 -0
- package/dist/pages/elements/cards.js +19 -2
- package/dist/pages/elements/options.js +27 -2
- package/dist/pages/elements/table.js +31 -2
- package/dist/pages/elements/text.js +19 -2
- package/dist/pages/host.d.ts +26 -0
- package/dist/pages/host.js +33 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { registerElement } from '../register.js';
|
|
20
20
|
import { readSlotConfig, readSlotId } from '../slot-config.js';
|
|
21
|
-
import { artifactData, respond } from '../host.js';
|
|
22
|
-
import { anchorLabel, findComment, setComment } from '../comments.js';
|
|
21
|
+
import { artifactData, respond, savedIds, savedResponse } from '../host.js';
|
|
22
|
+
import { adoptComments, anchorLabel, findComment, setComment } from '../comments.js';
|
|
23
23
|
const COMMENT_BUBBLE = 'M3.25 3.5h9.5A1.75 1.75 0 0 1 14.5 5.25v5A1.75 1.75 0 0 1 12.75 12H7.4l-3.15 2.36A.5.5 0 0 1 3.5 14v-2H3.25A1.75 1.75 0 0 1 1.5 10.25v-5A1.75 1.75 0 0 1 3.25 3.5Z';
|
|
24
24
|
const STYLE = `
|
|
25
25
|
:host {
|
|
@@ -421,6 +421,7 @@ class CrtrTableElement extends HTMLElement {
|
|
|
421
421
|
return;
|
|
422
422
|
}
|
|
423
423
|
this.#rows = config.rows;
|
|
424
|
+
this.#hydrate();
|
|
424
425
|
this.#renderTable();
|
|
425
426
|
}
|
|
426
427
|
disconnectedCallback() {
|
|
@@ -440,8 +441,36 @@ class CrtrTableElement extends HTMLElement {
|
|
|
440
441
|
return;
|
|
441
442
|
}
|
|
442
443
|
this.#rows = rows.rows;
|
|
444
|
+
this.#hydrate();
|
|
443
445
|
this.#renderTable();
|
|
444
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* Seed local state from the answer the host is already holding, so a reopened page shows
|
|
449
|
+
* the rows and columns that were picked. It runs once the rows are known — after a `source`
|
|
450
|
+
* load, not before — because a saved id is only honoured while it still names something on
|
|
451
|
+
* screen. The select modes are re-imposed for the same reason.
|
|
452
|
+
*/
|
|
453
|
+
#hydrate() {
|
|
454
|
+
if (this.#slotId === undefined)
|
|
455
|
+
return;
|
|
456
|
+
const saved = savedResponse(this.#slotId);
|
|
457
|
+
if (saved === undefined)
|
|
458
|
+
return;
|
|
459
|
+
const rows = this.#orderRows(savedIds(saved.selectedRowIds));
|
|
460
|
+
const columns = this.#orderColumns(savedIds(saved.selectedColumnIds));
|
|
461
|
+
this.#selectedRowIds = this.#rowSelect === 'none' ? [] : this.#rowSelect === 'single' ? rows.slice(0, 1) : rows;
|
|
462
|
+
this.#selectedColumnIds =
|
|
463
|
+
this.#columnSelect === 'none' ? [] : this.#columnSelect === 'single' ? columns.slice(0, 1) : columns;
|
|
464
|
+
const rowIds = new Set(this.#rows.map((row) => row.id));
|
|
465
|
+
const columnIds = new Set((this.#config?.columns ?? []).map((column) => column.id));
|
|
466
|
+
this.#comments = adoptComments(saved.comments).filter((comment) => {
|
|
467
|
+
if (comment.anchor.kind === 'row')
|
|
468
|
+
return rowIds.has(comment.anchor.rowId);
|
|
469
|
+
if (comment.anchor.kind === 'column')
|
|
470
|
+
return columnIds.has(comment.anchor.columnId);
|
|
471
|
+
return true;
|
|
472
|
+
});
|
|
473
|
+
}
|
|
445
474
|
// ── the response ───────────────────────────────────────────────────────────────────────
|
|
446
475
|
get #rowSelect() {
|
|
447
476
|
return this.#config?.rowSelect ?? 'none';
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { registerElement } from '../register.js';
|
|
26
26
|
import { readSlotConfig, readSlotId } from '../slot-config.js';
|
|
27
|
-
import { respond } from '../host.js';
|
|
28
|
-
import { findComment, setComment } from '../comments.js';
|
|
27
|
+
import { respond, savedResponse } from '../host.js';
|
|
28
|
+
import { adoptComments, findComment, setComment } from '../comments.js';
|
|
29
29
|
const WHOLE = { kind: 'whole' };
|
|
30
30
|
const WHOLE_TARGET = 'the whole passage';
|
|
31
31
|
const RANGE_TARGET = 'the selected text';
|
|
@@ -622,6 +622,7 @@ class CrtrTextElement extends HTMLElement {
|
|
|
622
622
|
this.#config = read.config;
|
|
623
623
|
this.#slotId = readSlotId(this);
|
|
624
624
|
this.#text = read.config.initialText;
|
|
625
|
+
this.#hydrate();
|
|
625
626
|
this.#editing = read.config.editable === true && this.#text.length === 0;
|
|
626
627
|
this.#renderToolbar();
|
|
627
628
|
this.#renderSurface();
|
|
@@ -630,6 +631,22 @@ class CrtrTextElement extends HTMLElement {
|
|
|
630
631
|
disconnectedCallback() {
|
|
631
632
|
document.removeEventListener('pointerdown', this.#onDocumentPointerDown, true);
|
|
632
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Seed local state from the answer the host is already holding, so a reopened page shows
|
|
636
|
+
* the edited words and the comments on them rather than the agent's original text. An
|
|
637
|
+
* uneditable slot keeps its authored text — only comments carry over — because a saved
|
|
638
|
+
* edit there could not have come from this control.
|
|
639
|
+
*/
|
|
640
|
+
#hydrate() {
|
|
641
|
+
if (this.#slotId === undefined)
|
|
642
|
+
return;
|
|
643
|
+
const saved = savedResponse(this.#slotId);
|
|
644
|
+
if (saved === undefined)
|
|
645
|
+
return;
|
|
646
|
+
if (this.#config.editable === true && typeof saved.text === 'string')
|
|
647
|
+
this.#text = saved.text;
|
|
648
|
+
this.#comments = adoptComments(saved.comments);
|
|
649
|
+
}
|
|
633
650
|
/** The complete current response — what every change hands `respond()`. */
|
|
634
651
|
#response() {
|
|
635
652
|
return { text: this.#text, edited: this.#text !== this.#config.initialText, comments: this.#comments };
|
package/dist/pages/host.d.ts
CHANGED
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* the host autosave the partial map; it does not resolve the ticket. Only the pager's
|
|
17
17
|
* submit affordance calls `submit()`, which posts the complete map once.
|
|
18
18
|
*
|
|
19
|
+
* `respond()` has one counterpart, `savedResponse()`: the host hands back the response it is
|
|
20
|
+
* currently holding for a slot, so a page reopened after a partial answer re-mounts SHOWING
|
|
21
|
+
* that answer instead of blank. Every response-bearing element reads it at mount and seeds
|
|
22
|
+
* its visible state from it — that is what keeps "what submit sends" and "what the screen
|
|
23
|
+
* shows" the same thing.
|
|
24
|
+
*
|
|
19
25
|
* The host is optional at the type level (`window.crtr?`) because a page can be opened
|
|
20
26
|
* bare — dropped in a browser, or rendered by a host that installs nothing. Elements read
|
|
21
27
|
* the bridge through the accessors below rather than touching `window.crtr` directly, so
|
|
@@ -42,6 +48,12 @@ export interface CrtrHost {
|
|
|
42
48
|
* partial map. Called on every user change. NOT ticket resolution.
|
|
43
49
|
*/
|
|
44
50
|
respond(slotId: string, response: SlotResponse): void;
|
|
51
|
+
/**
|
|
52
|
+
* The response the host currently holds for this slot — an autosaved partial answer on a
|
|
53
|
+
* reopened page, or the published answer on a resolved one. `undefined` when the host has
|
|
54
|
+
* nothing for the slot. Elements read it at mount; it is the inbound half of `respond`.
|
|
55
|
+
*/
|
|
56
|
+
savedResponse(slotId: string): SlotResponse | undefined;
|
|
45
57
|
/** Posts the complete response map once. Only the pager's submit affordance calls it. */
|
|
46
58
|
submit(): Promise<void>;
|
|
47
59
|
/** Flushes the pending autosave of the partial map. */
|
|
@@ -98,6 +110,20 @@ export declare function host(): CrtrHost | undefined;
|
|
|
98
110
|
* so an unavailable host only means the answer is not being persisted.
|
|
99
111
|
*/
|
|
100
112
|
export declare function respond(slotId: string, response: SlotResponse): HostCall;
|
|
113
|
+
/**
|
|
114
|
+
* The response the host already holds for this slot, or `undefined` when it holds none — a
|
|
115
|
+
* bare page, a first open, or a host without the channel. Elements call this once at mount
|
|
116
|
+
* and seed their visible state from it, so a reopened page shows the answers the host would
|
|
117
|
+
* submit rather than an empty form beside a full response map.
|
|
118
|
+
*
|
|
119
|
+
* `T` is asserted, not verified, exactly like `readSlotConfig`'s config: the host's saved map
|
|
120
|
+
* was validated against this slot's kind before it was stored. What is not guaranteed is that
|
|
121
|
+
* a host implements the channel at all, which is what the `undefined` covers — so seed with
|
|
122
|
+
* the same defensiveness you would give any outside value (`savedIds`, `adoptComments`).
|
|
123
|
+
*/
|
|
124
|
+
export declare function savedResponse<T extends SlotResponse = SlotResponse>(slotId: string): T | undefined;
|
|
125
|
+
/** The string ids of a saved selection field, with anything else in it dropped. */
|
|
126
|
+
export declare function savedIds(value: unknown): string[];
|
|
101
127
|
/**
|
|
102
128
|
* Posts the complete response map once, resolving the ticket. Only the pager's submit
|
|
103
129
|
* affordance calls this.
|
package/dist/pages/host.js
CHANGED
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* the host autosave the partial map; it does not resolve the ticket. Only the pager's
|
|
17
17
|
* submit affordance calls `submit()`, which posts the complete map once.
|
|
18
18
|
*
|
|
19
|
+
* `respond()` has one counterpart, `savedResponse()`: the host hands back the response it is
|
|
20
|
+
* currently holding for a slot, so a page reopened after a partial answer re-mounts SHOWING
|
|
21
|
+
* that answer instead of blank. Every response-bearing element reads it at mount and seeds
|
|
22
|
+
* its visible state from it — that is what keeps "what submit sends" and "what the screen
|
|
23
|
+
* shows" the same thing.
|
|
24
|
+
*
|
|
19
25
|
* The host is optional at the type level (`window.crtr?`) because a page can be opened
|
|
20
26
|
* bare — dropped in a browser, or rendered by a host that installs nothing. Elements read
|
|
21
27
|
* the bridge through the accessors below rather than touching `window.crtr` directly, so
|
|
@@ -52,6 +58,33 @@ export function respond(slotId, response) {
|
|
|
52
58
|
return { status: 'failed', reason: reasonOf(error) };
|
|
53
59
|
}
|
|
54
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* The response the host already holds for this slot, or `undefined` when it holds none — a
|
|
63
|
+
* bare page, a first open, or a host without the channel. Elements call this once at mount
|
|
64
|
+
* and seed their visible state from it, so a reopened page shows the answers the host would
|
|
65
|
+
* submit rather than an empty form beside a full response map.
|
|
66
|
+
*
|
|
67
|
+
* `T` is asserted, not verified, exactly like `readSlotConfig`'s config: the host's saved map
|
|
68
|
+
* was validated against this slot's kind before it was stored. What is not guaranteed is that
|
|
69
|
+
* a host implements the channel at all, which is what the `undefined` covers — so seed with
|
|
70
|
+
* the same defensiveness you would give any outside value (`savedIds`, `adoptComments`).
|
|
71
|
+
*/
|
|
72
|
+
export function savedResponse(slotId) {
|
|
73
|
+
const bridge = host();
|
|
74
|
+
if (typeof bridge?.savedResponse !== 'function')
|
|
75
|
+
return undefined;
|
|
76
|
+
try {
|
|
77
|
+
const saved = bridge.savedResponse(slotId);
|
|
78
|
+
return typeof saved === 'object' && saved !== null && !Array.isArray(saved) ? saved : undefined;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** The string ids of a saved selection field, with anything else in it dropped. */
|
|
85
|
+
export function savedIds(value) {
|
|
86
|
+
return Array.isArray(value) ? value.filter((id) => typeof id === 'string') : [];
|
|
87
|
+
}
|
|
55
88
|
/**
|
|
56
89
|
* Posts the complete response map once, resolving the ticket. Only the pager's submit
|
|
57
90
|
* affordance calls this.
|
package/package.json
CHANGED
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.196",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/crouter",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.196",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|