@kontourai/survey 1.13.0 → 1.15.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/README.md +26 -0
- package/dist/src/current-proposed-review-item.d.ts +6 -0
- package/dist/src/current-proposed-review-item.js +1 -0
- package/dist/src/review-resource.d.ts +11 -0
- package/dist/src/review-workbench/review-queue-session.js +45 -12
- package/dist/src/review-workbench/review-workbench-css.generated.js +90 -90
- package/dist/src/review-workbench/review-workbench.css +90 -90
- package/dist/src/review-workbench/review-workbench.js +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -147,6 +147,32 @@ The embedded stylesheet is scoped to `.survey-workbench-embed` and bundles Conso
|
|
|
147
147
|
|
|
148
148
|
`@kontourai/survey/review-workbench/standalone.css` exists for pages Survey owns entirely.
|
|
149
149
|
|
|
150
|
+
### Theme it as your own brand
|
|
151
|
+
|
|
152
|
+
The bundled `--k-*` token defaults are emitted in overridable form
|
|
153
|
+
(`--k-brand: var(--k-brand, <default>)`), so a host brand is authoritative: set
|
|
154
|
+
any `--k-*` token on an ancestor of the embed (or inline on the embed element,
|
|
155
|
+
or the host element of the web component) and it propagates in — no need to
|
|
156
|
+
out-specificity the embed's own selectors. Unset tokens keep their default, so
|
|
157
|
+
you only declare what you re-brand.
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
/* Your app's own palette drives the workbench — no Kontour branding. */
|
|
161
|
+
.survey-workbench-embed {
|
|
162
|
+
--k-brand: var(--brand-accent);
|
|
163
|
+
--k-bg: var(--paper);
|
|
164
|
+
--k-panel: var(--paper-2);
|
|
165
|
+
--k-text: var(--ink);
|
|
166
|
+
--k-line: var(--hairline);
|
|
167
|
+
--k-font-ui: var(--font-body);
|
|
168
|
+
--k-radius-md: 2px;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The full token list is in the [Consumer Integration Guide](docs/consumer-integration-guide.md).
|
|
173
|
+
Prefer this over the built-in `theme-survey`/`theme-console`/… presets when the
|
|
174
|
+
host app should read as itself.
|
|
175
|
+
|
|
150
176
|
## Review MCP
|
|
151
177
|
|
|
152
178
|
Drive review-queue decisions from an MCP agent (Claude Desktop, Cursor, or any MCP host):
|
|
@@ -38,6 +38,12 @@ export interface CurrentProposedReviewItemInput {
|
|
|
38
38
|
readonly current?: string;
|
|
39
39
|
readonly proposed?: string;
|
|
40
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Whether the reviewer may edit the proposed value inline. Defaults to
|
|
43
|
+
* `true`. Pass `false` for keep/use/reject-only queues (see
|
|
44
|
+
* {@link ReviewItemSpec.editable}).
|
|
45
|
+
*/
|
|
46
|
+
readonly editable?: boolean;
|
|
41
47
|
}
|
|
42
48
|
/**
|
|
43
49
|
* Builds the two-candidate current/proposed {@link ReviewItem} envelope that
|
|
@@ -38,6 +38,7 @@ export function currentProposedReviewItem(input) {
|
|
|
38
38
|
...(selectedCandidateId ? { selectedCandidateId } : {}),
|
|
39
39
|
...(input.rationale ? { rationale: input.rationale } : {}),
|
|
40
40
|
...(input.producerPolicy ? { producerPolicy: input.producerPolicy } : {}),
|
|
41
|
+
...(input.editable === false ? { editable: false } : {}),
|
|
41
42
|
projection: { ...input.projection, candidateSetId },
|
|
42
43
|
},
|
|
43
44
|
status: {
|
|
@@ -142,6 +142,17 @@ export interface ReviewItemSpec {
|
|
|
142
142
|
* Absent → a plain text editor with no validation (today's behavior).
|
|
143
143
|
*/
|
|
144
144
|
valueDescriptor?: ReviewValueDescriptor;
|
|
145
|
+
/**
|
|
146
|
+
* Whether the reviewer may edit the proposed value inline before accepting
|
|
147
|
+
* it. Defaults to `true` (today's behavior). Set `false` for queues where an
|
|
148
|
+
* edited value is meaningless or must not be accepted — an approve/keep
|
|
149
|
+
* identity decision, a value the producer will re-derive, a review that only
|
|
150
|
+
* chooses between the two candidates as given. The workbench then renders no
|
|
151
|
+
* editor at all: the decision is keep-current / use-proposed / reject only,
|
|
152
|
+
* and `effectiveValue` is always the selected candidate's own value. This is
|
|
153
|
+
* enforcement (the affordance is absent), not a cosmetic hide.
|
|
154
|
+
*/
|
|
155
|
+
editable?: boolean;
|
|
145
156
|
}
|
|
146
157
|
export interface ReviewItemStatus {
|
|
147
158
|
observedCandidateCount?: number;
|
|
@@ -197,7 +197,15 @@ export function buildReviewSessionEvents(session, sessionName = defaultReviewSes
|
|
|
197
197
|
const candidate = candidateForDecision(item, decision);
|
|
198
198
|
const definition = workbenchDecisionDefinitions[decision];
|
|
199
199
|
const reviewDecisionName = `${item.metadata.name}-${decision}`;
|
|
200
|
-
|
|
200
|
+
// Carry the reviewer's inline edit in the event itself (accept-proposed
|
|
201
|
+
// only — it is the sole decision where an edited value is meaningful), so
|
|
202
|
+
// that replaying snapshot + events reconstructs editedValuesByItemName and
|
|
203
|
+
// the server apply boundary derives effectiveValue from it. Without this
|
|
204
|
+
// the edit lives only in browser state and never survives replay.
|
|
205
|
+
const editedValue = decision === "accept-proposed" ? session.editedValuesByItemName?.[item.metadata.name] : undefined;
|
|
206
|
+
const data = editedValue !== undefined
|
|
207
|
+
? { workbenchDecision: decision, workbenchEditedValue: editedValue }
|
|
208
|
+
: { workbenchDecision: decision };
|
|
201
209
|
events.push(buildReviewSessionEvent(session, {
|
|
202
210
|
sessionName,
|
|
203
211
|
sequence: events.length + 1,
|
|
@@ -252,24 +260,49 @@ export function replayReviewSessionEvents(startState, events) {
|
|
|
252
260
|
}
|
|
253
261
|
if ((event.spec.eventType === "decision-changed" || event.spec.eventType === "decision-submitted")
|
|
254
262
|
&& event.spec.reviewItemName) {
|
|
263
|
+
const itemName = event.spec.reviewItemName;
|
|
255
264
|
if (isClearedWorkbenchDecisionEvent(event)) {
|
|
256
|
-
const { [
|
|
257
|
-
|
|
265
|
+
const { [itemName]: _removedDecision, ...remainingDecisions } = session.decisionsByItemName;
|
|
266
|
+
const { [itemName]: _removedEdit, ...remainingEdits } = session.editedValuesByItemName ?? {};
|
|
267
|
+
return { ...session, decisionsByItemName: remainingDecisions, editedValuesByItemName: remainingEdits };
|
|
258
268
|
}
|
|
259
269
|
const decision = workbenchDecisionFromEvent(event);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
270
|
+
if (!decision) {
|
|
271
|
+
return session;
|
|
272
|
+
}
|
|
273
|
+
// Restore the inline edit the event carried (accept-proposed only); any
|
|
274
|
+
// other decision, or an accept with no carried edit, clears a stale edit
|
|
275
|
+
// for this item so effectiveValue can't fall back to an edit the
|
|
276
|
+
// reviewer moved away from.
|
|
277
|
+
const editedValue = workbenchEditedValueFromEvent(event);
|
|
278
|
+
const editedValuesByItemName = { ...session.editedValuesByItemName };
|
|
279
|
+
if (decision === "accept-proposed" && editedValue !== undefined) {
|
|
280
|
+
editedValuesByItemName[itemName] = editedValue;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
delete editedValuesByItemName[itemName];
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
...session,
|
|
287
|
+
decisionsByItemName: {
|
|
288
|
+
...session.decisionsByItemName,
|
|
289
|
+
[itemName]: decision,
|
|
290
|
+
},
|
|
291
|
+
editedValuesByItemName,
|
|
292
|
+
};
|
|
269
293
|
}
|
|
270
294
|
return session;
|
|
271
295
|
}, startState);
|
|
272
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Extracts a decision event's carried inline edit, or `undefined` when the
|
|
299
|
+
* event carries none. The edit rides `data.workbenchEditedValue`.
|
|
300
|
+
*/
|
|
301
|
+
function workbenchEditedValueFromEvent(event) {
|
|
302
|
+
return event.spec.data && "workbenchEditedValue" in event.spec.data
|
|
303
|
+
? event.spec.data.workbenchEditedValue
|
|
304
|
+
: undefined;
|
|
305
|
+
}
|
|
273
306
|
/**
|
|
274
307
|
* Detects the explicit "clear this ReviewItem's decision" replay signal (emitted
|
|
275
308
|
* by the workbench's "Change" / undo control): a decision event whose
|
|
@@ -6,149 +6,149 @@ export const REVIEW_WORKBENCH_CSS = `/* Bundled, scoped Survey Review Workbench
|
|
|
6
6
|
color-scheme: dark;
|
|
7
7
|
|
|
8
8
|
/* structure */
|
|
9
|
-
--k-bg: #0a0e13;
|
|
10
|
-
--k-panel: #111824;
|
|
11
|
-
--k-panel-raised: #16202d;
|
|
12
|
-
--k-line: rgba(150, 180, 210, 0.12);
|
|
13
|
-
--k-line-strong: rgba(150, 180, 210, 0.22);
|
|
14
|
-
--k-shadow: 0 26px 60px -42px rgba(0, 0, 0, 0.95);
|
|
9
|
+
--k-bg: var(--k-bg, #0a0e13);
|
|
10
|
+
--k-panel: var(--k-panel, #111824);
|
|
11
|
+
--k-panel-raised: var(--k-panel-raised, #16202d);
|
|
12
|
+
--k-line: var(--k-line, rgba(150, 180, 210, 0.12));
|
|
13
|
+
--k-line-strong: var(--k-line-strong, rgba(150, 180, 210, 0.22));
|
|
14
|
+
--k-shadow: var(--k-shadow, 0 26px 60px -42px rgba(0, 0, 0, 0.95));
|
|
15
15
|
|
|
16
16
|
/* text */
|
|
17
|
-
--k-text: #eef3f8;
|
|
18
|
-
--k-text-muted: #aebccb;
|
|
19
|
-
--k-text-faint: #72869b;
|
|
17
|
+
--k-text: var(--k-text, #eef3f8);
|
|
18
|
+
--k-text-muted: var(--k-text-muted, #aebccb);
|
|
19
|
+
--k-text-faint: var(--k-text-faint, #72869b);
|
|
20
20
|
|
|
21
21
|
/* brand */
|
|
22
|
-
--k-brand: #5ce0c6;
|
|
23
|
-
--k-brand-contrast: #06080b;
|
|
22
|
+
--k-brand: var(--k-brand, #5ce0c6);
|
|
23
|
+
--k-brand-contrast: var(--k-brand-contrast, #06080b);
|
|
24
24
|
|
|
25
25
|
/* semantic status scale */
|
|
26
|
-
--k-positive: #34d399;
|
|
27
|
-
--k-caution: #f3b14b;
|
|
28
|
-
--k-negative: #ff6f6f;
|
|
29
|
-
--k-neutral: #6f8095;
|
|
30
|
-
--k-active: #7aa2ff;
|
|
26
|
+
--k-positive: var(--k-positive, #34d399);
|
|
27
|
+
--k-caution: var(--k-caution, #f3b14b);
|
|
28
|
+
--k-negative: var(--k-negative, #ff6f6f);
|
|
29
|
+
--k-neutral: var(--k-neutral, #6f8095);
|
|
30
|
+
--k-active: var(--k-active, #7aa2ff);
|
|
31
31
|
--k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
|
|
32
32
|
--k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
|
|
33
33
|
--k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
|
|
34
34
|
--k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
|
|
35
35
|
|
|
36
36
|
/* spacing */
|
|
37
|
-
--k-space-1: 4px;
|
|
38
|
-
--k-space-2: 8px;
|
|
39
|
-
--k-space-3: 12px;
|
|
40
|
-
--k-space-4: 16px;
|
|
41
|
-
--k-space-5: 24px;
|
|
42
|
-
--k-space-6: 32px;
|
|
37
|
+
--k-space-1: var(--k-space-1, 4px);
|
|
38
|
+
--k-space-2: var(--k-space-2, 8px);
|
|
39
|
+
--k-space-3: var(--k-space-3, 12px);
|
|
40
|
+
--k-space-4: var(--k-space-4, 16px);
|
|
41
|
+
--k-space-5: var(--k-space-5, 24px);
|
|
42
|
+
--k-space-6: var(--k-space-6, 32px);
|
|
43
43
|
|
|
44
44
|
/* radius */
|
|
45
|
-
--k-radius-sm: 9px;
|
|
46
|
-
--k-radius-md: 14px;
|
|
45
|
+
--k-radius-sm: var(--k-radius-sm, 9px);
|
|
46
|
+
--k-radius-md: var(--k-radius-md, 14px);
|
|
47
47
|
|
|
48
48
|
/* type */
|
|
49
|
-
--k-text-xs: 11px;
|
|
50
|
-
--k-text-sm: 12.5px;
|
|
51
|
-
--k-text-md: 14px;
|
|
52
|
-
--k-text-lg: 18px;
|
|
53
|
-
--k-text-xl: 22px;
|
|
54
|
-
--k-text-2xl: clamp(26px, 3.4vw, 38px);
|
|
49
|
+
--k-text-xs: var(--k-text-xs, 11px);
|
|
50
|
+
--k-text-sm: var(--k-text-sm, 12.5px);
|
|
51
|
+
--k-text-md: var(--k-text-md, 14px);
|
|
52
|
+
--k-text-lg: var(--k-text-lg, 18px);
|
|
53
|
+
--k-text-xl: var(--k-text-xl, 22px);
|
|
54
|
+
--k-text-2xl: var(--k-text-2xl, clamp(26px, 3.4vw, 38px));
|
|
55
55
|
|
|
56
56
|
/* fonts */
|
|
57
|
-
--k-font-display: "Fraunces", Georgia, "Times New Roman", serif;
|
|
58
|
-
--k-font-ui: "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
59
|
-
--k-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
57
|
+
--k-font-display: var(--k-font-display, "Fraunces", Georgia, "Times New Roman", serif);
|
|
58
|
+
--k-font-ui: var(--k-font-ui, "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif);
|
|
59
|
+
--k-font-mono: var(--k-font-mono, "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
60
60
|
|
|
61
61
|
/* motion */
|
|
62
|
-
--k-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
63
|
-
--k-dur: 0.16s;
|
|
62
|
+
--k-ease: var(--k-ease, cubic-bezier(0.22, 1, 0.36, 1));
|
|
63
|
+
--k-dur: var(--k-dur, 0.16s);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.survey-workbench-embed[data-theme="light"]{
|
|
67
67
|
color-scheme: light;
|
|
68
|
-
--k-bg: #f5f4ef;
|
|
69
|
-
--k-panel: #ffffff;
|
|
70
|
-
--k-panel-raised: #fbfaf7;
|
|
71
|
-
--k-line: rgba(36, 40, 46, 0.12);
|
|
72
|
-
--k-line-strong: rgba(36, 40, 46, 0.20);
|
|
73
|
-
--k-shadow: 0 18px 50px -30px rgba(0, 0, 0, 0.25);
|
|
74
|
-
--k-text: #202124;
|
|
75
|
-
--k-text-muted: #5b626b;
|
|
76
|
-
--k-text-faint: #707782;
|
|
77
|
-
--k-brand-contrast: #ffffff;
|
|
78
|
-
--k-positive: #168257;
|
|
79
|
-
--k-caution: #8a5a00;
|
|
80
|
-
--k-negative: #c83b3b;
|
|
81
|
-
--k-neutral: #5f6975;
|
|
82
|
-
--k-active: #3f6fd6;
|
|
68
|
+
--k-bg: var(--k-bg, #f5f4ef);
|
|
69
|
+
--k-panel: var(--k-panel, #ffffff);
|
|
70
|
+
--k-panel-raised: var(--k-panel-raised, #fbfaf7);
|
|
71
|
+
--k-line: var(--k-line, rgba(36, 40, 46, 0.12));
|
|
72
|
+
--k-line-strong: var(--k-line-strong, rgba(36, 40, 46, 0.20));
|
|
73
|
+
--k-shadow: var(--k-shadow, 0 18px 50px -30px rgba(0, 0, 0, 0.25));
|
|
74
|
+
--k-text: var(--k-text, #202124);
|
|
75
|
+
--k-text-muted: var(--k-text-muted, #5b626b);
|
|
76
|
+
--k-text-faint: var(--k-text-faint, #707782);
|
|
77
|
+
--k-brand-contrast: var(--k-brand-contrast, #ffffff);
|
|
78
|
+
--k-positive: var(--k-positive, #168257);
|
|
79
|
+
--k-caution: var(--k-caution, #8a5a00);
|
|
80
|
+
--k-negative: var(--k-negative, #c83b3b);
|
|
81
|
+
--k-neutral: var(--k-neutral, #5f6975);
|
|
82
|
+
--k-active: var(--k-active, #3f6fd6);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
.survey-workbench-embed.theme-survey{
|
|
87
|
-
--k-bg: #06080b;
|
|
88
|
-
--k-brand: #5ce0c6;
|
|
89
|
-
--k-text-faint: #6f8095;
|
|
87
|
+
--k-bg: var(--k-bg, #06080b);
|
|
88
|
+
--k-brand: var(--k-brand, #5ce0c6);
|
|
89
|
+
--k-text-faint: var(--k-text-faint, #6f8095);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
.survey-workbench-embed.theme-console{
|
|
93
|
-
--k-font-ui: "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif;
|
|
94
|
-
--k-font-display: "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif;
|
|
95
|
-
--k-radius-sm: 0;
|
|
96
|
-
--k-radius-md: 0;
|
|
97
|
-
--k-brand: #c9ff4a;
|
|
98
|
-
--k-brand-contrast: #11120f;
|
|
99
|
-
--k-bg: #11120f;
|
|
100
|
-
--k-panel: #191b16;
|
|
101
|
-
--k-panel-raised: #20231e;
|
|
102
|
-
--k-line: #3a4035;
|
|
103
|
-
--k-line-strong: #8ea36e;
|
|
104
|
-
--k-text: #f2f0e8;
|
|
105
|
-
--k-text-muted: #a6ab9c;
|
|
106
|
-
--k-text-faint: #747a6c;
|
|
107
|
-
--k-positive: #a6d37b;
|
|
108
|
-
--k-caution: #e8c15f;
|
|
109
|
-
--k-negative: #ee776f;
|
|
110
|
-
--k-active: #84d8c8;
|
|
93
|
+
--k-font-ui: var(--k-font-ui, "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif);
|
|
94
|
+
--k-font-display: var(--k-font-display, "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif);
|
|
95
|
+
--k-radius-sm: var(--k-radius-sm, 0);
|
|
96
|
+
--k-radius-md: var(--k-radius-md, 0);
|
|
97
|
+
--k-brand: var(--k-brand, #c9ff4a);
|
|
98
|
+
--k-brand-contrast: var(--k-brand-contrast, #11120f);
|
|
99
|
+
--k-bg: var(--k-bg, #11120f);
|
|
100
|
+
--k-panel: var(--k-panel, #191b16);
|
|
101
|
+
--k-panel-raised: var(--k-panel-raised, #20231e);
|
|
102
|
+
--k-line: var(--k-line, #3a4035);
|
|
103
|
+
--k-line-strong: var(--k-line-strong, #8ea36e);
|
|
104
|
+
--k-text: var(--k-text, #f2f0e8);
|
|
105
|
+
--k-text-muted: var(--k-text-muted, #a6ab9c);
|
|
106
|
+
--k-text-faint: var(--k-text-faint, #747a6c);
|
|
107
|
+
--k-positive: var(--k-positive, #a6d37b);
|
|
108
|
+
--k-caution: var(--k-caution, #e8c15f);
|
|
109
|
+
--k-negative: var(--k-negative, #ee776f);
|
|
110
|
+
--k-active: var(--k-active, #84d8c8);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
.survey-workbench-embed.theme-flow{
|
|
114
|
-
--k-brand: #2f88a6;
|
|
114
|
+
--k-brand: var(--k-brand, #2f88a6);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
.survey-workbench-embed.theme-surface{
|
|
118
|
-
--k-brand: #14a37a;
|
|
118
|
+
--k-brand: var(--k-brand, #14a37a);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
.survey-workbench-embed[data-theme="light"].theme-survey,
|
|
122
122
|
.survey-workbench-embed[data-theme="light"] .theme-survey{
|
|
123
|
-
--k-brand: #16806f;
|
|
123
|
+
--k-brand: var(--k-brand, #16806f);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
.survey-workbench-embed[data-theme="light"].theme-console,
|
|
127
127
|
.survey-workbench-embed[data-theme="light"] .theme-console{
|
|
128
|
-
--k-brand: #6c9400;
|
|
129
|
-
--k-brand-contrast: #ffffff;
|
|
130
|
-
--k-bg: #f3f5eb;
|
|
131
|
-
--k-panel: #fbfcf7;
|
|
132
|
-
--k-panel-raised: #eef2e6;
|
|
133
|
-
--k-line: #ccd5bf;
|
|
134
|
-
--k-line-strong: #8fa36f;
|
|
135
|
-
--k-text: #1e2319;
|
|
136
|
-
--k-text-muted: #596250;
|
|
137
|
-
--k-text-faint: #77816d;
|
|
138
|
-
--k-positive: #2f7d32;
|
|
139
|
-
--k-caution: #8a6500;
|
|
140
|
-
--k-negative: #b93a36;
|
|
141
|
-
--k-active: #247f75;
|
|
128
|
+
--k-brand: var(--k-brand, #6c9400);
|
|
129
|
+
--k-brand-contrast: var(--k-brand-contrast, #ffffff);
|
|
130
|
+
--k-bg: var(--k-bg, #f3f5eb);
|
|
131
|
+
--k-panel: var(--k-panel, #fbfcf7);
|
|
132
|
+
--k-panel-raised: var(--k-panel-raised, #eef2e6);
|
|
133
|
+
--k-line: var(--k-line, #ccd5bf);
|
|
134
|
+
--k-line-strong: var(--k-line-strong, #8fa36f);
|
|
135
|
+
--k-text: var(--k-text, #1e2319);
|
|
136
|
+
--k-text-muted: var(--k-text-muted, #596250);
|
|
137
|
+
--k-text-faint: var(--k-text-faint, #77816d);
|
|
138
|
+
--k-positive: var(--k-positive, #2f7d32);
|
|
139
|
+
--k-caution: var(--k-caution, #8a6500);
|
|
140
|
+
--k-negative: var(--k-negative, #b93a36);
|
|
141
|
+
--k-active: var(--k-active, #247f75);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
.survey-workbench-embed[data-theme="light"].theme-flow,
|
|
145
145
|
.survey-workbench-embed[data-theme="light"] .theme-flow{
|
|
146
|
-
--k-brand: #1f6f88;
|
|
146
|
+
--k-brand: var(--k-brand, #1f6f88);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
.survey-workbench-embed[data-theme="light"].theme-surface,
|
|
150
150
|
.survey-workbench-embed[data-theme="light"] .theme-surface{
|
|
151
|
-
--k-brand: #0f6b52;
|
|
151
|
+
--k-brand: var(--k-brand, #0f6b52);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
|
|
@@ -3,149 +3,149 @@
|
|
|
3
3
|
color-scheme: dark;
|
|
4
4
|
|
|
5
5
|
/* structure */
|
|
6
|
-
--k-bg: #0a0e13;
|
|
7
|
-
--k-panel: #111824;
|
|
8
|
-
--k-panel-raised: #16202d;
|
|
9
|
-
--k-line: rgba(150, 180, 210, 0.12);
|
|
10
|
-
--k-line-strong: rgba(150, 180, 210, 0.22);
|
|
11
|
-
--k-shadow: 0 26px 60px -42px rgba(0, 0, 0, 0.95);
|
|
6
|
+
--k-bg: var(--k-bg, #0a0e13);
|
|
7
|
+
--k-panel: var(--k-panel, #111824);
|
|
8
|
+
--k-panel-raised: var(--k-panel-raised, #16202d);
|
|
9
|
+
--k-line: var(--k-line, rgba(150, 180, 210, 0.12));
|
|
10
|
+
--k-line-strong: var(--k-line-strong, rgba(150, 180, 210, 0.22));
|
|
11
|
+
--k-shadow: var(--k-shadow, 0 26px 60px -42px rgba(0, 0, 0, 0.95));
|
|
12
12
|
|
|
13
13
|
/* text */
|
|
14
|
-
--k-text: #eef3f8;
|
|
15
|
-
--k-text-muted: #aebccb;
|
|
16
|
-
--k-text-faint: #72869b;
|
|
14
|
+
--k-text: var(--k-text, #eef3f8);
|
|
15
|
+
--k-text-muted: var(--k-text-muted, #aebccb);
|
|
16
|
+
--k-text-faint: var(--k-text-faint, #72869b);
|
|
17
17
|
|
|
18
18
|
/* brand */
|
|
19
|
-
--k-brand: #5ce0c6;
|
|
20
|
-
--k-brand-contrast: #06080b;
|
|
19
|
+
--k-brand: var(--k-brand, #5ce0c6);
|
|
20
|
+
--k-brand-contrast: var(--k-brand-contrast, #06080b);
|
|
21
21
|
|
|
22
22
|
/* semantic status scale */
|
|
23
|
-
--k-positive: #34d399;
|
|
24
|
-
--k-caution: #f3b14b;
|
|
25
|
-
--k-negative: #ff6f6f;
|
|
26
|
-
--k-neutral: #6f8095;
|
|
27
|
-
--k-active: #7aa2ff;
|
|
23
|
+
--k-positive: var(--k-positive, #34d399);
|
|
24
|
+
--k-caution: var(--k-caution, #f3b14b);
|
|
25
|
+
--k-negative: var(--k-negative, #ff6f6f);
|
|
26
|
+
--k-neutral: var(--k-neutral, #6f8095);
|
|
27
|
+
--k-active: var(--k-active, #7aa2ff);
|
|
28
28
|
--k-positive-soft: color-mix(in oklab, var(--k-positive) 14%, transparent);
|
|
29
29
|
--k-caution-soft: color-mix(in oklab, var(--k-caution) 14%, transparent);
|
|
30
30
|
--k-negative-soft: color-mix(in oklab, var(--k-negative) 14%, transparent);
|
|
31
31
|
--k-active-soft: color-mix(in oklab, var(--k-active) 14%, transparent);
|
|
32
32
|
|
|
33
33
|
/* spacing */
|
|
34
|
-
--k-space-1: 4px;
|
|
35
|
-
--k-space-2: 8px;
|
|
36
|
-
--k-space-3: 12px;
|
|
37
|
-
--k-space-4: 16px;
|
|
38
|
-
--k-space-5: 24px;
|
|
39
|
-
--k-space-6: 32px;
|
|
34
|
+
--k-space-1: var(--k-space-1, 4px);
|
|
35
|
+
--k-space-2: var(--k-space-2, 8px);
|
|
36
|
+
--k-space-3: var(--k-space-3, 12px);
|
|
37
|
+
--k-space-4: var(--k-space-4, 16px);
|
|
38
|
+
--k-space-5: var(--k-space-5, 24px);
|
|
39
|
+
--k-space-6: var(--k-space-6, 32px);
|
|
40
40
|
|
|
41
41
|
/* radius */
|
|
42
|
-
--k-radius-sm: 9px;
|
|
43
|
-
--k-radius-md: 14px;
|
|
42
|
+
--k-radius-sm: var(--k-radius-sm, 9px);
|
|
43
|
+
--k-radius-md: var(--k-radius-md, 14px);
|
|
44
44
|
|
|
45
45
|
/* type */
|
|
46
|
-
--k-text-xs: 11px;
|
|
47
|
-
--k-text-sm: 12.5px;
|
|
48
|
-
--k-text-md: 14px;
|
|
49
|
-
--k-text-lg: 18px;
|
|
50
|
-
--k-text-xl: 22px;
|
|
51
|
-
--k-text-2xl: clamp(26px, 3.4vw, 38px);
|
|
46
|
+
--k-text-xs: var(--k-text-xs, 11px);
|
|
47
|
+
--k-text-sm: var(--k-text-sm, 12.5px);
|
|
48
|
+
--k-text-md: var(--k-text-md, 14px);
|
|
49
|
+
--k-text-lg: var(--k-text-lg, 18px);
|
|
50
|
+
--k-text-xl: var(--k-text-xl, 22px);
|
|
51
|
+
--k-text-2xl: var(--k-text-2xl, clamp(26px, 3.4vw, 38px));
|
|
52
52
|
|
|
53
53
|
/* fonts */
|
|
54
|
-
--k-font-display: "Fraunces", Georgia, "Times New Roman", serif;
|
|
55
|
-
--k-font-ui: "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
56
|
-
--k-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
54
|
+
--k-font-display: var(--k-font-display, "Fraunces", Georgia, "Times New Roman", serif);
|
|
55
|
+
--k-font-ui: var(--k-font-ui, "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif);
|
|
56
|
+
--k-font-mono: var(--k-font-mono, "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
57
57
|
|
|
58
58
|
/* motion */
|
|
59
|
-
--k-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
60
|
-
--k-dur: 0.16s;
|
|
59
|
+
--k-ease: var(--k-ease, cubic-bezier(0.22, 1, 0.36, 1));
|
|
60
|
+
--k-dur: var(--k-dur, 0.16s);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
.survey-workbench-embed[data-theme="light"]{
|
|
64
64
|
color-scheme: light;
|
|
65
|
-
--k-bg: #f5f4ef;
|
|
66
|
-
--k-panel: #ffffff;
|
|
67
|
-
--k-panel-raised: #fbfaf7;
|
|
68
|
-
--k-line: rgba(36, 40, 46, 0.12);
|
|
69
|
-
--k-line-strong: rgba(36, 40, 46, 0.20);
|
|
70
|
-
--k-shadow: 0 18px 50px -30px rgba(0, 0, 0, 0.25);
|
|
71
|
-
--k-text: #202124;
|
|
72
|
-
--k-text-muted: #5b626b;
|
|
73
|
-
--k-text-faint: #707782;
|
|
74
|
-
--k-brand-contrast: #ffffff;
|
|
75
|
-
--k-positive: #168257;
|
|
76
|
-
--k-caution: #8a5a00;
|
|
77
|
-
--k-negative: #c83b3b;
|
|
78
|
-
--k-neutral: #5f6975;
|
|
79
|
-
--k-active: #3f6fd6;
|
|
65
|
+
--k-bg: var(--k-bg, #f5f4ef);
|
|
66
|
+
--k-panel: var(--k-panel, #ffffff);
|
|
67
|
+
--k-panel-raised: var(--k-panel-raised, #fbfaf7);
|
|
68
|
+
--k-line: var(--k-line, rgba(36, 40, 46, 0.12));
|
|
69
|
+
--k-line-strong: var(--k-line-strong, rgba(36, 40, 46, 0.20));
|
|
70
|
+
--k-shadow: var(--k-shadow, 0 18px 50px -30px rgba(0, 0, 0, 0.25));
|
|
71
|
+
--k-text: var(--k-text, #202124);
|
|
72
|
+
--k-text-muted: var(--k-text-muted, #5b626b);
|
|
73
|
+
--k-text-faint: var(--k-text-faint, #707782);
|
|
74
|
+
--k-brand-contrast: var(--k-brand-contrast, #ffffff);
|
|
75
|
+
--k-positive: var(--k-positive, #168257);
|
|
76
|
+
--k-caution: var(--k-caution, #8a5a00);
|
|
77
|
+
--k-negative: var(--k-negative, #c83b3b);
|
|
78
|
+
--k-neutral: var(--k-neutral, #5f6975);
|
|
79
|
+
--k-active: var(--k-active, #3f6fd6);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
.survey-workbench-embed.theme-survey{
|
|
84
|
-
--k-bg: #06080b;
|
|
85
|
-
--k-brand: #5ce0c6;
|
|
86
|
-
--k-text-faint: #6f8095;
|
|
84
|
+
--k-bg: var(--k-bg, #06080b);
|
|
85
|
+
--k-brand: var(--k-brand, #5ce0c6);
|
|
86
|
+
--k-text-faint: var(--k-text-faint, #6f8095);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
.survey-workbench-embed.theme-console{
|
|
90
|
-
--k-font-ui: "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif;
|
|
91
|
-
--k-font-display: "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif;
|
|
92
|
-
--k-radius-sm: 0;
|
|
93
|
-
--k-radius-md: 0;
|
|
94
|
-
--k-brand: #c9ff4a;
|
|
95
|
-
--k-brand-contrast: #11120f;
|
|
96
|
-
--k-bg: #11120f;
|
|
97
|
-
--k-panel: #191b16;
|
|
98
|
-
--k-panel-raised: #20231e;
|
|
99
|
-
--k-line: #3a4035;
|
|
100
|
-
--k-line-strong: #8ea36e;
|
|
101
|
-
--k-text: #f2f0e8;
|
|
102
|
-
--k-text-muted: #a6ab9c;
|
|
103
|
-
--k-text-faint: #747a6c;
|
|
104
|
-
--k-positive: #a6d37b;
|
|
105
|
-
--k-caution: #e8c15f;
|
|
106
|
-
--k-negative: #ee776f;
|
|
107
|
-
--k-active: #84d8c8;
|
|
90
|
+
--k-font-ui: var(--k-font-ui, "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif);
|
|
91
|
+
--k-font-display: var(--k-font-display, "Aptos Narrow", "DIN Condensed", "IBM Plex Sans Condensed", "Gill Sans", sans-serif);
|
|
92
|
+
--k-radius-sm: var(--k-radius-sm, 0);
|
|
93
|
+
--k-radius-md: var(--k-radius-md, 0);
|
|
94
|
+
--k-brand: var(--k-brand, #c9ff4a);
|
|
95
|
+
--k-brand-contrast: var(--k-brand-contrast, #11120f);
|
|
96
|
+
--k-bg: var(--k-bg, #11120f);
|
|
97
|
+
--k-panel: var(--k-panel, #191b16);
|
|
98
|
+
--k-panel-raised: var(--k-panel-raised, #20231e);
|
|
99
|
+
--k-line: var(--k-line, #3a4035);
|
|
100
|
+
--k-line-strong: var(--k-line-strong, #8ea36e);
|
|
101
|
+
--k-text: var(--k-text, #f2f0e8);
|
|
102
|
+
--k-text-muted: var(--k-text-muted, #a6ab9c);
|
|
103
|
+
--k-text-faint: var(--k-text-faint, #747a6c);
|
|
104
|
+
--k-positive: var(--k-positive, #a6d37b);
|
|
105
|
+
--k-caution: var(--k-caution, #e8c15f);
|
|
106
|
+
--k-negative: var(--k-negative, #ee776f);
|
|
107
|
+
--k-active: var(--k-active, #84d8c8);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
.survey-workbench-embed.theme-flow{
|
|
111
|
-
--k-brand: #2f88a6;
|
|
111
|
+
--k-brand: var(--k-brand, #2f88a6);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
.survey-workbench-embed.theme-surface{
|
|
115
|
-
--k-brand: #14a37a;
|
|
115
|
+
--k-brand: var(--k-brand, #14a37a);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
.survey-workbench-embed[data-theme="light"].theme-survey,
|
|
119
119
|
.survey-workbench-embed[data-theme="light"] .theme-survey{
|
|
120
|
-
--k-brand: #16806f;
|
|
120
|
+
--k-brand: var(--k-brand, #16806f);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
.survey-workbench-embed[data-theme="light"].theme-console,
|
|
124
124
|
.survey-workbench-embed[data-theme="light"] .theme-console{
|
|
125
|
-
--k-brand: #6c9400;
|
|
126
|
-
--k-brand-contrast: #ffffff;
|
|
127
|
-
--k-bg: #f3f5eb;
|
|
128
|
-
--k-panel: #fbfcf7;
|
|
129
|
-
--k-panel-raised: #eef2e6;
|
|
130
|
-
--k-line: #ccd5bf;
|
|
131
|
-
--k-line-strong: #8fa36f;
|
|
132
|
-
--k-text: #1e2319;
|
|
133
|
-
--k-text-muted: #596250;
|
|
134
|
-
--k-text-faint: #77816d;
|
|
135
|
-
--k-positive: #2f7d32;
|
|
136
|
-
--k-caution: #8a6500;
|
|
137
|
-
--k-negative: #b93a36;
|
|
138
|
-
--k-active: #247f75;
|
|
125
|
+
--k-brand: var(--k-brand, #6c9400);
|
|
126
|
+
--k-brand-contrast: var(--k-brand-contrast, #ffffff);
|
|
127
|
+
--k-bg: var(--k-bg, #f3f5eb);
|
|
128
|
+
--k-panel: var(--k-panel, #fbfcf7);
|
|
129
|
+
--k-panel-raised: var(--k-panel-raised, #eef2e6);
|
|
130
|
+
--k-line: var(--k-line, #ccd5bf);
|
|
131
|
+
--k-line-strong: var(--k-line-strong, #8fa36f);
|
|
132
|
+
--k-text: var(--k-text, #1e2319);
|
|
133
|
+
--k-text-muted: var(--k-text-muted, #596250);
|
|
134
|
+
--k-text-faint: var(--k-text-faint, #77816d);
|
|
135
|
+
--k-positive: var(--k-positive, #2f7d32);
|
|
136
|
+
--k-caution: var(--k-caution, #8a6500);
|
|
137
|
+
--k-negative: var(--k-negative, #b93a36);
|
|
138
|
+
--k-active: var(--k-active, #247f75);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
.survey-workbench-embed[data-theme="light"].theme-flow,
|
|
142
142
|
.survey-workbench-embed[data-theme="light"] .theme-flow{
|
|
143
|
-
--k-brand: #1f6f88;
|
|
143
|
+
--k-brand: var(--k-brand, #1f6f88);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
.survey-workbench-embed[data-theme="light"].theme-surface,
|
|
147
147
|
.survey-workbench-embed[data-theme="light"] .theme-surface{
|
|
148
|
-
--k-brand: #0f6b52;
|
|
148
|
+
--k-brand: var(--k-brand, #0f6b52);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
|
|
@@ -567,7 +567,7 @@ function renderDiffRow(item, current, proposed, targetLabel, decided, effectiveP
|
|
|
567
567
|
<div class="val proposed">
|
|
568
568
|
<div class="vlbl">Proposed</div>
|
|
569
569
|
<div class="vtext" data-value data-testid="proposed-value">${escapeHtml(effectiveProposedText)}</div>
|
|
570
|
-
${decided ? "" : renderProposedValueEditor(item, proposed, targetLabel)}
|
|
570
|
+
${decided || item.spec.editable === false ? "" : renderProposedValueEditor(item, proposed, targetLabel)}
|
|
571
571
|
</div>
|
|
572
572
|
</div>
|
|
573
573
|
`;
|
|
@@ -968,6 +968,16 @@ function createReviewWorkbenchController(root, startState, options) {
|
|
|
968
968
|
const candidate = item && decision ? candidateForDecision(item, decision) : undefined;
|
|
969
969
|
const definition = decision ? workbenchDecisionDefinitions[decision] : undefined;
|
|
970
970
|
const note = itemName ? session.notesByItemName[itemName] : undefined;
|
|
971
|
+
// Carry the reviewer's inline edit in the event (accept-proposed only), so
|
|
972
|
+
// it survives replay and the server apply boundary derives the edited
|
|
973
|
+
// effectiveValue from snapshot + events alone. setDecision updates the
|
|
974
|
+
// session before this runs, so the edit is already in state.
|
|
975
|
+
const editedValue = itemName && decision === "accept-proposed" ? session.editedValuesByItemName?.[itemName] : undefined;
|
|
976
|
+
const defaultData = decision
|
|
977
|
+
? (editedValue !== undefined
|
|
978
|
+
? { workbenchDecision: decision, workbenchEditedValue: editedValue }
|
|
979
|
+
: { workbenchDecision: decision })
|
|
980
|
+
: undefined;
|
|
971
981
|
events = [
|
|
972
982
|
...events,
|
|
973
983
|
buildReviewSessionEvent(session, {
|
|
@@ -980,7 +990,7 @@ function createReviewWorkbenchController(root, startState, options) {
|
|
|
980
990
|
candidateId: candidate?.id,
|
|
981
991
|
status: definition?.status,
|
|
982
992
|
rationale: note,
|
|
983
|
-
data: dataOverride ??
|
|
993
|
+
data: dataOverride ?? defaultData,
|
|
984
994
|
}),
|
|
985
995
|
];
|
|
986
996
|
};
|
package/package.json
CHANGED