@ai-matrx/content-ir-react 0.15.1 → 0.16.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/CHANGELOG.md +30 -0
- package/dist/{directive-host-DJfF35FD.d.cts → directive-host-C4TcPpxX.d.cts} +19 -2
- package/dist/{directive-host-DJfF35FD.d.ts → directive-host-C4TcPpxX.d.ts} +19 -2
- package/dist/directives.cjs +150 -30
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +76 -41
- package/dist/directives.d.ts +76 -41
- package/dist/directives.js +150 -30
- package/dist/directives.js.map +1 -1
- package/dist/{host-types-9NfBeqrG.d.ts → host-types-CEc86R-v.d.ts} +1 -1
- package/dist/{host-types-DVIaaGR_.d.cts → host-types-a0XEr5b3.d.cts} +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +3 -3
- package/dist/host.d.ts +3 -3
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +156 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -42
- package/dist/index.d.ts +76 -42
- package/dist/index.js +153 -33
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +149 -35
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +146 -32
- package/dist/react.js.map +1 -1
- package/dist/{route-DDbgc-ID.d.ts → route-De9c5YgW.d.ts} +19 -2
- package/dist/{route-BCtPhF7W.d.cts → route-YcoyR3Fj.d.cts} +19 -2
- package/dist/route.d.cts +1 -1
- package/dist/route.d.ts +1 -1
- package/package.json +3 -3
package/dist/directives.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { D as DirectiveRecordRef } from './directive-host-C4TcPpxX.js';
|
|
2
|
+
export { a as DirectiveApplyResult, b as DirectiveApplyState, c as DirectiveAskRequest, d as DirectiveCopyProps, e as DirectiveHost, f as DirectiveHostProvider, g as DirectiveHostProviderProps, h as DirectiveOpenItemOptions, i as DirectiveRecordProps, j as DirectiveScope, k as DirectiveScopeProvider, l as DirectiveShell, u as useDirectiveHost, m as useDirectiveScope } from './directive-host-C4TcPpxX.js';
|
|
2
3
|
import * as react from 'react';
|
|
3
4
|
import { ComponentType } from 'react';
|
|
4
5
|
import { DecodedDirective, DirectiveClass } from '@ai-matrx/content-ir';
|
|
@@ -48,9 +49,75 @@ interface ApplyDirectiveButtonProps {
|
|
|
48
49
|
}
|
|
49
50
|
declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
|
|
54
|
+
* confirm dialog, and anything else that must say it before the click.
|
|
55
|
+
*
|
|
56
|
+
* WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item
|
|
57
|
+
* as "Item" — they never named the record they would change, and an Update card
|
|
58
|
+
* never said what it would change. The item-summary helpers name a thing to be
|
|
59
|
+
* CREATED from its own fields; an update or delete item carries the TARGET's id
|
|
60
|
+
* and, for an update, the NEW values — so its "title" field is the new title,
|
|
61
|
+
* not the name of the record being changed. Naming the target is the host's
|
|
62
|
+
* live lookup (`DirectiveHost.renderRecord`); what changes is right here.
|
|
63
|
+
*
|
|
64
|
+
* Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
|
|
65
|
+
* names what changes.
|
|
66
|
+
*/
|
|
67
|
+
/** Classes whose items point at an EXISTING record by `id`. */
|
|
68
|
+
declare const TARGETING_CLASSES: ReadonlySet<string>;
|
|
69
|
+
/** How long a changed value may read before it is shortened (full value on hover). */
|
|
70
|
+
declare const CHANGE_VALUE_MAX = 60;
|
|
71
|
+
/** The id of the existing record an update/delete item targets, or null. */
|
|
72
|
+
declare function itemRecordId(item: Record<string, unknown>): string | null;
|
|
73
|
+
/** "due_date" → "Due date". Underscores read as developer output. */
|
|
74
|
+
declare function fieldLabel(key: string): string;
|
|
75
|
+
/** A short, honest name for a record we could not look up: "Task 1a2b3c4d". */
|
|
76
|
+
declare function recordFallbackName(nounLabel: string, id: string): string;
|
|
77
|
+
/** One value as a row reads it: shortened, the whole of it, and whether it is empty. */
|
|
78
|
+
interface ChangeValue {
|
|
79
|
+
value: string;
|
|
80
|
+
full: string;
|
|
81
|
+
clears: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface ItemChange extends ChangeValue {
|
|
84
|
+
key: string;
|
|
85
|
+
/** "Due date". */
|
|
86
|
+
label: string;
|
|
87
|
+
/**
|
|
88
|
+
* What the field holds NOW, when the host could read the record — so an
|
|
89
|
+
* update reads "old → new", never just the new value (reviewer, 2026-10-02).
|
|
90
|
+
* Absent when the current record is unknown.
|
|
91
|
+
*/
|
|
92
|
+
before?: ChangeValue;
|
|
93
|
+
/** True when the record already holds exactly this value — nothing changes. */
|
|
94
|
+
same?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** One value, described for a change row (`value` shortened, `full` whole). */
|
|
97
|
+
declare function describeChangeValue(value: unknown): ChangeValue;
|
|
98
|
+
/**
|
|
99
|
+
* Every field an UPDATE item sets, in the order the item carries them — ALL of
|
|
100
|
+
* them, never a sample: a person approving an overwrite sees the whole of it.
|
|
101
|
+
*
|
|
102
|
+
* Pass `current` — the record as it is now (`DirectiveHost.readRecord`) — and
|
|
103
|
+
* each change also carries what it REPLACES (`before`) and whether it changes
|
|
104
|
+
* anything at all (`same`). A field the record does not carry gets no `before`.
|
|
105
|
+
*/
|
|
106
|
+
declare function itemChanges(item: Record<string, unknown>, current?: Record<string, unknown> | null): ItemChange[];
|
|
107
|
+
|
|
51
108
|
interface SideEffectDirectiveCardProps {
|
|
52
109
|
directive: DecodedDirective;
|
|
53
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* THE CHANGE LIST — every field an update sets, as "Label old → new" when the
|
|
113
|
+
* record's current value is known, "Label → new" when it is not. ONE component
|
|
114
|
+
* for the card row and the host's confirm dialog, so the two can never read
|
|
115
|
+
* differently (reviewer, 2026-10-02: the confirm showed only the new value).
|
|
116
|
+
*/
|
|
117
|
+
declare function DirectiveChangeList({ changes, className, }: {
|
|
118
|
+
changes: ItemChange[];
|
|
119
|
+
className?: string;
|
|
120
|
+
}): react.JSX.Element;
|
|
54
121
|
declare function SideEffectDirectiveCard({ directive }: SideEffectDirectiveCardProps): react.JSX.Element;
|
|
55
122
|
|
|
56
123
|
interface DirectiveFallbackCardProps {
|
|
@@ -94,45 +161,13 @@ interface DirectiveRenderProps {
|
|
|
94
161
|
}
|
|
95
162
|
declare function DirectiveRender({ conversationId, ...props }: DirectiveRenderProps): react.JSX.Element;
|
|
96
163
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
* as "Item" — they never named the record they would change, and an Update card
|
|
103
|
-
* never said what it would change. The item-summary helpers name a thing to be
|
|
104
|
-
* CREATED from its own fields; an update or delete item carries the TARGET's id
|
|
105
|
-
* and, for an update, the NEW values — so its "title" field is the new title,
|
|
106
|
-
* not the name of the record being changed. Naming the target is the host's
|
|
107
|
-
* live lookup (`DirectiveHost.renderRecord`); what changes is right here.
|
|
108
|
-
*
|
|
109
|
-
* Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
|
|
110
|
-
* names what changes.
|
|
111
|
-
*/
|
|
112
|
-
/** Classes whose items point at an EXISTING record by `id`. */
|
|
113
|
-
declare const TARGETING_CLASSES: ReadonlySet<string>;
|
|
114
|
-
/** How long a changed value may read before it is shortened (full value on hover). */
|
|
115
|
-
declare const CHANGE_VALUE_MAX = 60;
|
|
116
|
-
/** The id of the existing record an update/delete item targets, or null. */
|
|
117
|
-
declare function itemRecordId(item: Record<string, unknown>): string | null;
|
|
118
|
-
/** "due_date" → "Due date". Underscores read as developer output. */
|
|
119
|
-
declare function fieldLabel(key: string): string;
|
|
120
|
-
/** A short, honest name for a record we could not look up: "Task 1a2b3c4d". */
|
|
121
|
-
declare function recordFallbackName(nounLabel: string, id: string): string;
|
|
122
|
-
interface ItemChange {
|
|
123
|
-
key: string;
|
|
124
|
-
/** "Due date". */
|
|
125
|
-
label: string;
|
|
126
|
-
/** What it becomes, shortened for a row; `full` carries the whole value. */
|
|
127
|
-
value: string;
|
|
128
|
-
full: string;
|
|
129
|
-
/** True when the new value empties the field. */
|
|
130
|
-
clears: boolean;
|
|
164
|
+
type RecordValuesStatus = "idle" | "loading" | "ready" | "unavailable";
|
|
165
|
+
interface RecordValues {
|
|
166
|
+
/** The record's fields now, or null until (or unless) they are read. */
|
|
167
|
+
values: Record<string, unknown> | null;
|
|
168
|
+
status: RecordValuesStatus;
|
|
131
169
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
* them, never a sample: a person approving an overwrite sees the whole of it.
|
|
135
|
-
*/
|
|
136
|
-
declare function itemChanges(item: Record<string, unknown>): ItemChange[];
|
|
170
|
+
type RecordReader = (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
|
|
171
|
+
declare function useRecordValues(read: RecordReader | undefined, ref: DirectiveRecordRef | null): RecordValues;
|
|
137
172
|
|
|
138
|
-
export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, type ItemChange, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, fieldLabel, getDirectiveRenderer, itemChanges, itemRecordId, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers };
|
|
173
|
+
export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type ChangeValue, DirectiveChangeList, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, type ItemChange, type RecordReader, type RecordValues, type RecordValuesStatus, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, describeChangeValue, fieldLabel, getDirectiveRenderer, itemChanges, itemRecordId, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useRecordValues };
|
package/dist/directives.js
CHANGED
|
@@ -66,6 +66,9 @@ function recordFallbackName(nounLabel3, id) {
|
|
|
66
66
|
const short = isUuidShape(id) ? id.slice(0, 8) : id.length > 12 ? `${id.slice(0, 12)}\u2026` : id;
|
|
67
67
|
return `${nounLabel3} ${short}`;
|
|
68
68
|
}
|
|
69
|
+
function describeChangeValue(value) {
|
|
70
|
+
return describeValue(value);
|
|
71
|
+
}
|
|
69
72
|
function describeValue(value) {
|
|
70
73
|
if (value === null || value === void 0) return { value: "cleared", full: "cleared", clears: true };
|
|
71
74
|
if (typeof value === "string") {
|
|
@@ -94,11 +97,26 @@ function safeJson(value) {
|
|
|
94
97
|
return String(value);
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
|
-
function
|
|
100
|
+
function sameValue(a, b) {
|
|
101
|
+
if (a === b) return true;
|
|
102
|
+
if (a === null || a === void 0 || b === null || b === void 0) {
|
|
103
|
+
const emptyA = a === null || a === void 0 || a === "";
|
|
104
|
+
const emptyB = b === null || b === void 0 || b === "";
|
|
105
|
+
return emptyA && emptyB;
|
|
106
|
+
}
|
|
107
|
+
if (typeof a === "object" || typeof b === "object") return safeJson(a) === safeJson(b);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
function itemChanges(item, current) {
|
|
98
111
|
const out = [];
|
|
99
112
|
for (const [key, raw] of Object.entries(item)) {
|
|
100
113
|
if (NOT_A_CHANGE.has(key)) continue;
|
|
101
|
-
|
|
114
|
+
const change = { key, label: fieldLabel(key), ...describeValue(raw) };
|
|
115
|
+
if (current && Object.prototype.hasOwnProperty.call(current, key)) {
|
|
116
|
+
change.before = describeValue(current[key]);
|
|
117
|
+
change.same = sameValue(current[key], raw);
|
|
118
|
+
}
|
|
119
|
+
out.push(change);
|
|
102
120
|
}
|
|
103
121
|
return out;
|
|
104
122
|
}
|
|
@@ -211,11 +229,23 @@ function ApplyDirectiveButton({
|
|
|
211
229
|
const conversationId = scope.conversationId || void 0;
|
|
212
230
|
const items = directive.items;
|
|
213
231
|
const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
);
|
|
232
|
+
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
233
|
+
const [state, setState] = useState(initial);
|
|
217
234
|
const [elapsed, setElapsed] = useState(0);
|
|
235
|
+
const [askingAgain, setAskingAgain] = useState(false);
|
|
218
236
|
const startedAt = useRef(null);
|
|
237
|
+
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
238
|
+
const [stateFor, setStateFor] = useState(identity);
|
|
239
|
+
if (stateFor !== identity) {
|
|
240
|
+
setStateFor(identity);
|
|
241
|
+
setState(initial);
|
|
242
|
+
setAskingAgain(false);
|
|
243
|
+
setElapsed(0);
|
|
244
|
+
}
|
|
245
|
+
const currentIdentity = useRef(identity);
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
currentIdentity.current = identity;
|
|
248
|
+
}, [identity]);
|
|
219
249
|
const nounText = nounLabel(directive.noun, host.nouns);
|
|
220
250
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
221
251
|
const read = host.applyState;
|
|
@@ -238,7 +268,8 @@ function ApplyDirectiveButton({
|
|
|
238
268
|
applied: shellItems.length,
|
|
239
269
|
failed: 0,
|
|
240
270
|
message: answer.message?.trim() ? answer.message.trim() : null,
|
|
241
|
-
records: answer.records ?? []
|
|
271
|
+
records: answer.records ?? [],
|
|
272
|
+
copies: Math.max(1, answer.copies ?? 1)
|
|
242
273
|
} : prev
|
|
243
274
|
);
|
|
244
275
|
} else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
|
|
@@ -278,8 +309,12 @@ function ApplyDirectiveButton({
|
|
|
278
309
|
async function handleApply(again = false) {
|
|
279
310
|
if (!confirm) return;
|
|
280
311
|
const before = state;
|
|
312
|
+
const askedFor = identity;
|
|
313
|
+
const stillHere = () => currentIdentity.current === askedFor;
|
|
314
|
+
const priorCopies = state.status === "applied" ? state.copies : 0;
|
|
281
315
|
if (host.ask) {
|
|
282
|
-
|
|
316
|
+
if (again) setAskingAgain(true);
|
|
317
|
+
else setState({ status: "asking" });
|
|
283
318
|
let ok = false;
|
|
284
319
|
try {
|
|
285
320
|
ok = await host.ask({
|
|
@@ -289,12 +324,16 @@ function ApplyDirectiveButton({
|
|
|
289
324
|
...again ? { again: true } : {}
|
|
290
325
|
});
|
|
291
326
|
} catch (error) {
|
|
327
|
+
if (!stillHere()) return;
|
|
328
|
+
setAskingAgain(false);
|
|
292
329
|
setState({
|
|
293
330
|
status: "error",
|
|
294
331
|
message: error instanceof Error && error.message ? error.message : "We could not ask you to confirm this, so nothing was done."
|
|
295
332
|
});
|
|
296
333
|
return;
|
|
297
334
|
}
|
|
335
|
+
if (!stillHere()) return;
|
|
336
|
+
setAskingAgain(false);
|
|
298
337
|
if (!ok) {
|
|
299
338
|
setState(again ? before : { status: "idle" });
|
|
300
339
|
return;
|
|
@@ -307,15 +346,19 @@ function ApplyDirectiveButton({
|
|
|
307
346
|
if (conversationId) shell.conversationId = conversationId;
|
|
308
347
|
if (again) shell.force = true;
|
|
309
348
|
const result = await confirm(shell);
|
|
349
|
+
if (!stillHere()) return;
|
|
310
350
|
setState({
|
|
311
351
|
status: "applied",
|
|
312
352
|
applied: result.applied,
|
|
313
353
|
failed: result.failed,
|
|
314
354
|
message: result.message?.trim() ? result.message.trim() : null,
|
|
315
|
-
records: result.records ?? []
|
|
355
|
+
records: result.records ?? [],
|
|
356
|
+
// "Run again" made one more; a first apply (or a replay of one) is one.
|
|
357
|
+
copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
|
|
316
358
|
});
|
|
317
359
|
onApplied?.();
|
|
318
360
|
} catch (error) {
|
|
361
|
+
if (!stillHere()) return;
|
|
319
362
|
setState({
|
|
320
363
|
status: "error",
|
|
321
364
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
@@ -340,6 +383,15 @@ function ApplyDirectiveButton({
|
|
|
340
383
|
bad && !state.message ? ` \xB7 ${state.failed} failed` : ""
|
|
341
384
|
] })
|
|
342
385
|
] }),
|
|
386
|
+
state.copies > 1 ? /* @__PURE__ */ jsx3(
|
|
387
|
+
"span",
|
|
388
|
+
{
|
|
389
|
+
className: "shrink-0 text-muted-foreground",
|
|
390
|
+
"data-apply-copies": state.copies,
|
|
391
|
+
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
392
|
+
children: directive.directiveClass === "create" ? `${state.copies} copies` : `Ran ${state.copies} times`
|
|
393
|
+
}
|
|
394
|
+
) : null,
|
|
343
395
|
records.map((record) => /* @__PURE__ */ jsx3("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
344
396
|
...record,
|
|
345
397
|
fallback: recordFallbackName(label2, record.id),
|
|
@@ -350,8 +402,9 @@ function ApplyDirectiveButton({
|
|
|
350
402
|
"button",
|
|
351
403
|
{
|
|
352
404
|
type: "button",
|
|
405
|
+
disabled: askingAgain,
|
|
353
406
|
onClick: () => void handleApply(!bad),
|
|
354
|
-
className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
407
|
+
className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-50",
|
|
355
408
|
"data-apply-action": bad ? "retry" : "run-again",
|
|
356
409
|
children: [
|
|
357
410
|
/* @__PURE__ */ jsx3(RotateCcwIcon, { className: "h-3 w-3" }),
|
|
@@ -389,6 +442,7 @@ function ApplyDirectiveButton({
|
|
|
389
442
|
}
|
|
390
443
|
);
|
|
391
444
|
}
|
|
445
|
+
const destructive = directive.directiveClass === "delete";
|
|
392
446
|
return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
|
|
393
447
|
/* @__PURE__ */ jsxs2(
|
|
394
448
|
"button",
|
|
@@ -396,7 +450,8 @@ function ApplyDirectiveButton({
|
|
|
396
450
|
type: "button",
|
|
397
451
|
onClick: () => void handleApply(),
|
|
398
452
|
disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
|
|
399
|
-
|
|
453
|
+
"data-apply-tone": destructive ? "destructive" : "default",
|
|
454
|
+
className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium disabled:opacity-50 ${destructive ? "border-destructive/50 bg-background text-destructive hover:bg-destructive/10" : "border-border bg-background hover:bg-accent"}`,
|
|
400
455
|
children: [
|
|
401
456
|
state.status === "applying" ? /* @__PURE__ */ jsx3(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx3(PlayIcon, { className: "h-3.5 w-3.5" }),
|
|
402
457
|
state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
@@ -411,7 +466,7 @@ function ApplyDirectiveButton({
|
|
|
411
466
|
}
|
|
412
467
|
|
|
413
468
|
// directives/SideEffectDirectiveCard.tsx
|
|
414
|
-
import { useState as
|
|
469
|
+
import { useState as useState3 } from "react";
|
|
415
470
|
import {
|
|
416
471
|
asKindInstance,
|
|
417
472
|
directiveDisplay,
|
|
@@ -421,6 +476,39 @@ import {
|
|
|
421
476
|
nounLabel as nounLabel2,
|
|
422
477
|
nounTitleColumn
|
|
423
478
|
} from "@ai-matrx/content-ir";
|
|
479
|
+
|
|
480
|
+
// directives/record-values.ts
|
|
481
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
482
|
+
function useRecordValues(read, ref) {
|
|
483
|
+
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
484
|
+
const [result, setResult] = useState2({
|
|
485
|
+
key: "",
|
|
486
|
+
values: null,
|
|
487
|
+
status: "idle"
|
|
488
|
+
});
|
|
489
|
+
useEffect2(() => {
|
|
490
|
+
if (!key || !read) return;
|
|
491
|
+
const split = key.indexOf(":");
|
|
492
|
+
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
493
|
+
let live = true;
|
|
494
|
+
setResult({ key, values: null, status: "loading" });
|
|
495
|
+
read(target).then((values) => {
|
|
496
|
+
if (!live) return;
|
|
497
|
+
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
498
|
+
}).catch(() => {
|
|
499
|
+
if (!live) return;
|
|
500
|
+
setResult({ key, values: null, status: "unavailable" });
|
|
501
|
+
});
|
|
502
|
+
return () => {
|
|
503
|
+
live = false;
|
|
504
|
+
};
|
|
505
|
+
}, [key, read]);
|
|
506
|
+
if (!key) return { values: null, status: "idle" };
|
|
507
|
+
if (result.key !== key) return { values: null, status: "loading" };
|
|
508
|
+
return { values: result.values, status: result.status };
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// directives/SideEffectDirectiveCard.tsx
|
|
424
512
|
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
425
513
|
var ROWS_BEFORE_FOLD = 3;
|
|
426
514
|
function ItemRow({
|
|
@@ -474,44 +562,73 @@ function ItemRow({
|
|
|
474
562
|
host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
|
|
475
563
|
] });
|
|
476
564
|
}
|
|
477
|
-
function
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
recordId
|
|
565
|
+
function DirectiveChangeList({
|
|
566
|
+
changes,
|
|
567
|
+
className
|
|
481
568
|
}) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
490
|
-
] }),
|
|
491
|
-
directive.directiveClass === "update" ? changes.length === 0 ? /* @__PURE__ */ jsx4("p", { className: "px-1 text-[11px] text-muted-foreground", children: "Sets no fields \u2014 nothing would change." }) : /* @__PURE__ */ jsx4("ul", { className: "mt-0.5 space-y-0.5 px-1", children: changes.map((change) => /* @__PURE__ */ jsxs3(
|
|
569
|
+
if (changes.length === 0) {
|
|
570
|
+
return /* @__PURE__ */ jsx4("p", { className: `text-[11px] text-muted-foreground${className ? ` ${className}` : ""}`, children: "Sets no fields \u2014 nothing would change." });
|
|
571
|
+
}
|
|
572
|
+
return /* @__PURE__ */ jsx4("ul", { className: `space-y-0.5${className ? ` ${className}` : ""}`, "data-directive-changes": "", children: changes.map((change) => {
|
|
573
|
+
const before = change.before && !change.same ? change.before : null;
|
|
574
|
+
const was = before ? before.clears ? "empty" : before.value : null;
|
|
575
|
+
return /* @__PURE__ */ jsxs3(
|
|
492
576
|
"li",
|
|
493
577
|
{
|
|
494
578
|
className: "flex min-w-0 items-baseline gap-1.5 text-[11px]",
|
|
495
|
-
title: `${change.label} \u2192 ${change.full}`,
|
|
579
|
+
title: before ? `${change.label}: ${before.clears ? "empty" : before.full} \u2192 ${change.full}` : `${change.label} \u2192 ${change.full}`,
|
|
580
|
+
"data-change-key": change.key,
|
|
496
581
|
children: [
|
|
497
582
|
/* @__PURE__ */ jsx4("span", { className: "shrink-0 text-muted-foreground", children: change.label }),
|
|
583
|
+
was !== null ? /* @__PURE__ */ jsx4(
|
|
584
|
+
"span",
|
|
585
|
+
{
|
|
586
|
+
className: "min-w-0 max-w-[40%] shrink truncate text-muted-foreground line-through",
|
|
587
|
+
"data-change-before": "",
|
|
588
|
+
children: was
|
|
589
|
+
}
|
|
590
|
+
) : null,
|
|
498
591
|
/* @__PURE__ */ jsx4("span", { "aria-hidden": true, className: "shrink-0 text-muted-foreground", children: "\u2192" }),
|
|
499
592
|
/* @__PURE__ */ jsx4(
|
|
500
593
|
"span",
|
|
501
594
|
{
|
|
502
595
|
className: `min-w-0 truncate ${change.clears ? "italic text-muted-foreground" : "text-foreground"}`,
|
|
596
|
+
"data-change-after": "",
|
|
503
597
|
children: change.value
|
|
504
598
|
}
|
|
505
|
-
)
|
|
599
|
+
),
|
|
600
|
+
change.same ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-muted-foreground", children: "(no change)" }) : null
|
|
506
601
|
]
|
|
507
602
|
},
|
|
508
603
|
change.key
|
|
509
|
-
)
|
|
604
|
+
);
|
|
605
|
+
}) });
|
|
606
|
+
}
|
|
607
|
+
function TargetRow({
|
|
608
|
+
directive,
|
|
609
|
+
item,
|
|
610
|
+
recordId
|
|
611
|
+
}) {
|
|
612
|
+
const host = useDirectiveHost();
|
|
613
|
+
const fallback = recordFallbackName(nounLabel2(directive.noun, host.nouns), recordId);
|
|
614
|
+
const isUpdate = directive.directiveClass === "update";
|
|
615
|
+
const current = useRecordValues(
|
|
616
|
+
isUpdate ? host.readRecord : void 0,
|
|
617
|
+
isUpdate ? { noun: directive.noun, id: recordId } : null
|
|
618
|
+
);
|
|
619
|
+
const changes = isUpdate ? itemChanges(item, current.values) : [];
|
|
620
|
+
const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ jsx4("span", { className: "truncate font-medium text-foreground", children: fallback });
|
|
621
|
+
return /* @__PURE__ */ jsxs3("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
|
|
622
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
623
|
+
/* @__PURE__ */ jsx4("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
|
|
624
|
+
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
625
|
+
] }),
|
|
626
|
+
isUpdate ? /* @__PURE__ */ jsx4(DirectiveChangeList, { changes, className: "mt-0.5 px-1" }) : null
|
|
510
627
|
] });
|
|
511
628
|
}
|
|
512
629
|
function SideEffectDirectiveCard({ directive }) {
|
|
513
630
|
const host = useDirectiveHost();
|
|
514
|
-
const [expanded, setExpanded] =
|
|
631
|
+
const [expanded, setExpanded] = useState3(false);
|
|
515
632
|
const items = directive.items;
|
|
516
633
|
const total = items.length;
|
|
517
634
|
const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);
|
|
@@ -663,6 +780,7 @@ function DirectiveRenderInner({ content, className, streaming }) {
|
|
|
663
780
|
export {
|
|
664
781
|
ApplyDirectiveButton,
|
|
665
782
|
CHANGE_VALUE_MAX,
|
|
783
|
+
DirectiveChangeList,
|
|
666
784
|
DirectiveFallbackCard,
|
|
667
785
|
DirectiveHostProvider,
|
|
668
786
|
DirectiveProvisionalCard,
|
|
@@ -670,6 +788,7 @@ export {
|
|
|
670
788
|
DirectiveScopeProvider,
|
|
671
789
|
SideEffectDirectiveCard,
|
|
672
790
|
TARGETING_CLASSES,
|
|
791
|
+
describeChangeValue,
|
|
673
792
|
fieldLabel,
|
|
674
793
|
getDirectiveRenderer,
|
|
675
794
|
itemChanges,
|
|
@@ -679,6 +798,7 @@ export {
|
|
|
679
798
|
registerDirectiveRenderer,
|
|
680
799
|
resetDirectiveRenderers,
|
|
681
800
|
useDirectiveHost,
|
|
682
|
-
useDirectiveScope
|
|
801
|
+
useDirectiveScope,
|
|
802
|
+
useRecordValues
|
|
683
803
|
};
|
|
684
804
|
//# sourceMappingURL=directives.js.map
|