@ai-matrx/content-ir-react 0.15.2 → 0.16.1
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 +35 -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 +145 -28
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +85 -41
- package/dist/directives.d.ts +85 -41
- package/dist/directives.js +145 -28
- 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 +151 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -42
- package/dist/index.d.ts +85 -42
- package/dist/index.js +148 -31
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +144 -33
- 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 +141 -30
- 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,84 @@ 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
|
+
interface ItemChangesOptions {
|
|
107
|
+
/**
|
|
108
|
+
* The noun's title column (catalog `title_column` — `nounTitleColumn`). It is
|
|
109
|
+
* labelled "Title" whatever it is called: a note's title is stored in
|
|
110
|
+
* `label`, and the confirm said "Label" while the form said "Title"
|
|
111
|
+
* (reviewer, 2026-10-02). The same rule the directive builder's form uses.
|
|
112
|
+
*/
|
|
113
|
+
titleColumn?: string | null;
|
|
114
|
+
}
|
|
115
|
+
declare function itemChanges(item: Record<string, unknown>, current?: Record<string, unknown> | null, options?: ItemChangesOptions): ItemChange[];
|
|
116
|
+
|
|
51
117
|
interface SideEffectDirectiveCardProps {
|
|
52
118
|
directive: DecodedDirective;
|
|
53
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* THE CHANGE LIST — every field an update sets, as "Label old → new" when the
|
|
122
|
+
* record's current value is known, "Label → new" when it is not. ONE component
|
|
123
|
+
* for the card row and the host's confirm dialog, so the two can never read
|
|
124
|
+
* differently (reviewer, 2026-10-02: the confirm showed only the new value).
|
|
125
|
+
*/
|
|
126
|
+
declare function DirectiveChangeList({ changes, className, }: {
|
|
127
|
+
changes: ItemChange[];
|
|
128
|
+
className?: string;
|
|
129
|
+
}): react.JSX.Element;
|
|
54
130
|
declare function SideEffectDirectiveCard({ directive }: SideEffectDirectiveCardProps): react.JSX.Element;
|
|
55
131
|
|
|
56
132
|
interface DirectiveFallbackCardProps {
|
|
@@ -94,45 +170,13 @@ interface DirectiveRenderProps {
|
|
|
94
170
|
}
|
|
95
171
|
declare function DirectiveRender({ conversationId, ...props }: DirectiveRenderProps): react.JSX.Element;
|
|
96
172
|
|
|
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;
|
|
173
|
+
type RecordValuesStatus = "idle" | "loading" | "ready" | "unavailable";
|
|
174
|
+
interface RecordValues {
|
|
175
|
+
/** The record's fields now, or null until (or unless) they are read. */
|
|
176
|
+
values: Record<string, unknown> | null;
|
|
177
|
+
status: RecordValuesStatus;
|
|
131
178
|
}
|
|
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[];
|
|
179
|
+
type RecordReader = (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
|
|
180
|
+
declare function useRecordValues(read: RecordReader | undefined, ref: DirectiveRecordRef | null): RecordValues;
|
|
137
181
|
|
|
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 };
|
|
182
|
+
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 ItemChangesOptions, 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,28 @@ 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, options = {}) {
|
|
98
111
|
const out = [];
|
|
112
|
+
const titleColumn = options.titleColumn ?? null;
|
|
99
113
|
for (const [key, raw] of Object.entries(item)) {
|
|
100
114
|
if (NOT_A_CHANGE.has(key)) continue;
|
|
101
|
-
|
|
115
|
+
const label = key === titleColumn ? "Title" : fieldLabel(key);
|
|
116
|
+
const change = { key, label, ...describeValue(raw) };
|
|
117
|
+
if (current && Object.prototype.hasOwnProperty.call(current, key)) {
|
|
118
|
+
change.before = describeValue(current[key]);
|
|
119
|
+
change.same = sameValue(current[key], raw);
|
|
120
|
+
}
|
|
121
|
+
out.push(change);
|
|
102
122
|
}
|
|
103
123
|
return out;
|
|
104
124
|
}
|
|
@@ -211,12 +231,23 @@ function ApplyDirectiveButton({
|
|
|
211
231
|
const conversationId = scope.conversationId || void 0;
|
|
212
232
|
const items = directive.items;
|
|
213
233
|
const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
);
|
|
234
|
+
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
235
|
+
const [state, setState] = useState(initial);
|
|
217
236
|
const [elapsed, setElapsed] = useState(0);
|
|
218
237
|
const [askingAgain, setAskingAgain] = useState(false);
|
|
219
238
|
const startedAt = useRef(null);
|
|
239
|
+
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
240
|
+
const [stateFor, setStateFor] = useState(identity);
|
|
241
|
+
if (stateFor !== identity) {
|
|
242
|
+
setStateFor(identity);
|
|
243
|
+
setState(initial);
|
|
244
|
+
setAskingAgain(false);
|
|
245
|
+
setElapsed(0);
|
|
246
|
+
}
|
|
247
|
+
const currentIdentity = useRef(identity);
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
currentIdentity.current = identity;
|
|
250
|
+
}, [identity]);
|
|
220
251
|
const nounText = nounLabel(directive.noun, host.nouns);
|
|
221
252
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
222
253
|
const read = host.applyState;
|
|
@@ -239,7 +270,8 @@ function ApplyDirectiveButton({
|
|
|
239
270
|
applied: shellItems.length,
|
|
240
271
|
failed: 0,
|
|
241
272
|
message: answer.message?.trim() ? answer.message.trim() : null,
|
|
242
|
-
records: answer.records ?? []
|
|
273
|
+
records: answer.records ?? [],
|
|
274
|
+
copies: Math.max(1, answer.copies ?? 1)
|
|
243
275
|
} : prev
|
|
244
276
|
);
|
|
245
277
|
} else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
|
|
@@ -279,6 +311,9 @@ function ApplyDirectiveButton({
|
|
|
279
311
|
async function handleApply(again = false) {
|
|
280
312
|
if (!confirm) return;
|
|
281
313
|
const before = state;
|
|
314
|
+
const askedFor = identity;
|
|
315
|
+
const stillHere = () => currentIdentity.current === askedFor;
|
|
316
|
+
const priorCopies = state.status === "applied" ? state.copies : 0;
|
|
282
317
|
if (host.ask) {
|
|
283
318
|
if (again) setAskingAgain(true);
|
|
284
319
|
else setState({ status: "asking" });
|
|
@@ -291,6 +326,7 @@ function ApplyDirectiveButton({
|
|
|
291
326
|
...again ? { again: true } : {}
|
|
292
327
|
});
|
|
293
328
|
} catch (error) {
|
|
329
|
+
if (!stillHere()) return;
|
|
294
330
|
setAskingAgain(false);
|
|
295
331
|
setState({
|
|
296
332
|
status: "error",
|
|
@@ -298,6 +334,7 @@ function ApplyDirectiveButton({
|
|
|
298
334
|
});
|
|
299
335
|
return;
|
|
300
336
|
}
|
|
337
|
+
if (!stillHere()) return;
|
|
301
338
|
setAskingAgain(false);
|
|
302
339
|
if (!ok) {
|
|
303
340
|
setState(again ? before : { status: "idle" });
|
|
@@ -311,15 +348,19 @@ function ApplyDirectiveButton({
|
|
|
311
348
|
if (conversationId) shell.conversationId = conversationId;
|
|
312
349
|
if (again) shell.force = true;
|
|
313
350
|
const result = await confirm(shell);
|
|
351
|
+
if (!stillHere()) return;
|
|
314
352
|
setState({
|
|
315
353
|
status: "applied",
|
|
316
354
|
applied: result.applied,
|
|
317
355
|
failed: result.failed,
|
|
318
356
|
message: result.message?.trim() ? result.message.trim() : null,
|
|
319
|
-
records: result.records ?? []
|
|
357
|
+
records: result.records ?? [],
|
|
358
|
+
// "Run again" made one more; a first apply (or a replay of one) is one.
|
|
359
|
+
copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
|
|
320
360
|
});
|
|
321
361
|
onApplied?.();
|
|
322
362
|
} catch (error) {
|
|
363
|
+
if (!stillHere()) return;
|
|
323
364
|
setState({
|
|
324
365
|
status: "error",
|
|
325
366
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
@@ -344,6 +385,15 @@ function ApplyDirectiveButton({
|
|
|
344
385
|
bad && !state.message ? ` \xB7 ${state.failed} failed` : ""
|
|
345
386
|
] })
|
|
346
387
|
] }),
|
|
388
|
+
state.copies > 1 ? /* @__PURE__ */ jsx3(
|
|
389
|
+
"span",
|
|
390
|
+
{
|
|
391
|
+
className: "shrink-0 text-muted-foreground",
|
|
392
|
+
"data-apply-copies": state.copies,
|
|
393
|
+
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
394
|
+
children: directive.directiveClass === "create" ? `${state.copies} copies` : `Ran ${state.copies} times`
|
|
395
|
+
}
|
|
396
|
+
) : null,
|
|
347
397
|
records.map((record) => /* @__PURE__ */ jsx3("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
348
398
|
...record,
|
|
349
399
|
fallback: recordFallbackName(label2, record.id),
|
|
@@ -394,6 +444,7 @@ function ApplyDirectiveButton({
|
|
|
394
444
|
}
|
|
395
445
|
);
|
|
396
446
|
}
|
|
447
|
+
const destructive = directive.directiveClass === "delete";
|
|
397
448
|
return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
|
|
398
449
|
/* @__PURE__ */ jsxs2(
|
|
399
450
|
"button",
|
|
@@ -401,7 +452,8 @@ function ApplyDirectiveButton({
|
|
|
401
452
|
type: "button",
|
|
402
453
|
onClick: () => void handleApply(),
|
|
403
454
|
disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
|
|
404
|
-
|
|
455
|
+
"data-apply-tone": destructive ? "destructive" : "default",
|
|
456
|
+
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"}`,
|
|
405
457
|
children: [
|
|
406
458
|
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" }),
|
|
407
459
|
state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
@@ -416,7 +468,7 @@ function ApplyDirectiveButton({
|
|
|
416
468
|
}
|
|
417
469
|
|
|
418
470
|
// directives/SideEffectDirectiveCard.tsx
|
|
419
|
-
import { useState as
|
|
471
|
+
import { useState as useState3 } from "react";
|
|
420
472
|
import {
|
|
421
473
|
asKindInstance,
|
|
422
474
|
directiveDisplay,
|
|
@@ -426,6 +478,39 @@ import {
|
|
|
426
478
|
nounLabel as nounLabel2,
|
|
427
479
|
nounTitleColumn
|
|
428
480
|
} from "@ai-matrx/content-ir";
|
|
481
|
+
|
|
482
|
+
// directives/record-values.ts
|
|
483
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
484
|
+
function useRecordValues(read, ref) {
|
|
485
|
+
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
486
|
+
const [result, setResult] = useState2({
|
|
487
|
+
key: "",
|
|
488
|
+
values: null,
|
|
489
|
+
status: "idle"
|
|
490
|
+
});
|
|
491
|
+
useEffect2(() => {
|
|
492
|
+
if (!key || !read) return;
|
|
493
|
+
const split = key.indexOf(":");
|
|
494
|
+
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
495
|
+
let live = true;
|
|
496
|
+
setResult({ key, values: null, status: "loading" });
|
|
497
|
+
read(target).then((values) => {
|
|
498
|
+
if (!live) return;
|
|
499
|
+
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
500
|
+
}).catch(() => {
|
|
501
|
+
if (!live) return;
|
|
502
|
+
setResult({ key, values: null, status: "unavailable" });
|
|
503
|
+
});
|
|
504
|
+
return () => {
|
|
505
|
+
live = false;
|
|
506
|
+
};
|
|
507
|
+
}, [key, read]);
|
|
508
|
+
if (!key) return { values: null, status: "idle" };
|
|
509
|
+
if (result.key !== key) return { values: null, status: "loading" };
|
|
510
|
+
return { values: result.values, status: result.status };
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// directives/SideEffectDirectiveCard.tsx
|
|
429
514
|
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
430
515
|
var ROWS_BEFORE_FOLD = 3;
|
|
431
516
|
function ItemRow({
|
|
@@ -479,44 +564,73 @@ function ItemRow({
|
|
|
479
564
|
host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
|
|
480
565
|
] });
|
|
481
566
|
}
|
|
482
|
-
function
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
recordId
|
|
567
|
+
function DirectiveChangeList({
|
|
568
|
+
changes,
|
|
569
|
+
className
|
|
486
570
|
}) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
495
|
-
] }),
|
|
496
|
-
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(
|
|
571
|
+
if (changes.length === 0) {
|
|
572
|
+
return /* @__PURE__ */ jsx4("p", { className: `text-[11px] text-muted-foreground${className ? ` ${className}` : ""}`, children: "Sets no fields \u2014 nothing would change." });
|
|
573
|
+
}
|
|
574
|
+
return /* @__PURE__ */ jsx4("ul", { className: `space-y-0.5${className ? ` ${className}` : ""}`, "data-directive-changes": "", children: changes.map((change) => {
|
|
575
|
+
const before = change.before && !change.same ? change.before : null;
|
|
576
|
+
const was = before ? before.clears ? "empty" : before.value : null;
|
|
577
|
+
return /* @__PURE__ */ jsxs3(
|
|
497
578
|
"li",
|
|
498
579
|
{
|
|
499
580
|
className: "flex min-w-0 items-baseline gap-1.5 text-[11px]",
|
|
500
|
-
title: `${change.label} \u2192 ${change.full}`,
|
|
581
|
+
title: before ? `${change.label}: ${before.clears ? "empty" : before.full} \u2192 ${change.full}` : `${change.label} \u2192 ${change.full}`,
|
|
582
|
+
"data-change-key": change.key,
|
|
501
583
|
children: [
|
|
502
584
|
/* @__PURE__ */ jsx4("span", { className: "shrink-0 text-muted-foreground", children: change.label }),
|
|
585
|
+
was !== null ? /* @__PURE__ */ jsx4(
|
|
586
|
+
"span",
|
|
587
|
+
{
|
|
588
|
+
className: "min-w-0 max-w-[40%] shrink truncate text-muted-foreground line-through",
|
|
589
|
+
"data-change-before": "",
|
|
590
|
+
children: was
|
|
591
|
+
}
|
|
592
|
+
) : null,
|
|
503
593
|
/* @__PURE__ */ jsx4("span", { "aria-hidden": true, className: "shrink-0 text-muted-foreground", children: "\u2192" }),
|
|
504
594
|
/* @__PURE__ */ jsx4(
|
|
505
595
|
"span",
|
|
506
596
|
{
|
|
507
597
|
className: `min-w-0 truncate ${change.clears ? "italic text-muted-foreground" : "text-foreground"}`,
|
|
598
|
+
"data-change-after": "",
|
|
508
599
|
children: change.value
|
|
509
600
|
}
|
|
510
|
-
)
|
|
601
|
+
),
|
|
602
|
+
change.same ? /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-muted-foreground", children: "(no change)" }) : null
|
|
511
603
|
]
|
|
512
604
|
},
|
|
513
605
|
change.key
|
|
514
|
-
)
|
|
606
|
+
);
|
|
607
|
+
}) });
|
|
608
|
+
}
|
|
609
|
+
function TargetRow({
|
|
610
|
+
directive,
|
|
611
|
+
item,
|
|
612
|
+
recordId
|
|
613
|
+
}) {
|
|
614
|
+
const host = useDirectiveHost();
|
|
615
|
+
const fallback = recordFallbackName(nounLabel2(directive.noun, host.nouns), recordId);
|
|
616
|
+
const isUpdate = directive.directiveClass === "update";
|
|
617
|
+
const current = useRecordValues(
|
|
618
|
+
isUpdate ? host.readRecord : void 0,
|
|
619
|
+
isUpdate ? { noun: directive.noun, id: recordId } : null
|
|
620
|
+
);
|
|
621
|
+
const changes = isUpdate ? itemChanges(item, current.values, { titleColumn: nounTitleColumn(directive.noun, host.nouns) }) : [];
|
|
622
|
+
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 });
|
|
623
|
+
return /* @__PURE__ */ jsxs3("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
|
|
624
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
625
|
+
/* @__PURE__ */ jsx4("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
|
|
626
|
+
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
627
|
+
] }),
|
|
628
|
+
isUpdate ? /* @__PURE__ */ jsx4(DirectiveChangeList, { changes, className: "mt-0.5 px-1" }) : null
|
|
515
629
|
] });
|
|
516
630
|
}
|
|
517
631
|
function SideEffectDirectiveCard({ directive }) {
|
|
518
632
|
const host = useDirectiveHost();
|
|
519
|
-
const [expanded, setExpanded] =
|
|
633
|
+
const [expanded, setExpanded] = useState3(false);
|
|
520
634
|
const items = directive.items;
|
|
521
635
|
const total = items.length;
|
|
522
636
|
const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);
|
|
@@ -668,6 +782,7 @@ function DirectiveRenderInner({ content, className, streaming }) {
|
|
|
668
782
|
export {
|
|
669
783
|
ApplyDirectiveButton,
|
|
670
784
|
CHANGE_VALUE_MAX,
|
|
785
|
+
DirectiveChangeList,
|
|
671
786
|
DirectiveFallbackCard,
|
|
672
787
|
DirectiveHostProvider,
|
|
673
788
|
DirectiveProvisionalCard,
|
|
@@ -675,6 +790,7 @@ export {
|
|
|
675
790
|
DirectiveScopeProvider,
|
|
676
791
|
SideEffectDirectiveCard,
|
|
677
792
|
TARGETING_CLASSES,
|
|
793
|
+
describeChangeValue,
|
|
678
794
|
fieldLabel,
|
|
679
795
|
getDirectiveRenderer,
|
|
680
796
|
itemChanges,
|
|
@@ -684,6 +800,7 @@ export {
|
|
|
684
800
|
registerDirectiveRenderer,
|
|
685
801
|
resetDirectiveRenderers,
|
|
686
802
|
useDirectiveHost,
|
|
687
|
-
useDirectiveScope
|
|
803
|
+
useDirectiveScope,
|
|
804
|
+
useRecordValues
|
|
688
805
|
};
|
|
689
806
|
//# sourceMappingURL=directives.js.map
|