@ai-matrx/content-ir-react 0.20.2 → 0.21.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 +23 -0
- package/dist/directives.cjs +57 -28
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +18 -3
- package/dist/directives.d.ts +18 -3
- package/dist/directives.js +38 -10
- package/dist/directives.js.map +1 -1
- package/dist/index.cjs +72 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +38 -10
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +71 -44
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +36 -10
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.21.0 — 2026-10-02
|
|
4
|
+
|
|
5
|
+
The G10B review of the action cards (nightly clone). Guard:
|
|
6
|
+
`__tests__/directive-card-g10b.test.tsx` (5 red on 0.20.2).
|
|
7
|
+
|
|
8
|
+
- **A nameless new item says so.** New `itemOwnName(item, titleColumn)` — the item's own
|
|
9
|
+
name, or null — and `NO_TITLE_WORD`. A create card whose title is empty reads "No title"
|
|
10
|
+
(muted), never "Item"; its copy control says "this Task". One rule for the card and a
|
|
11
|
+
host's confirm.
|
|
12
|
+
- **A record's id is never shown.** `recordFallbackName(nounLabel)` — the name used when a
|
|
13
|
+
record's own cannot be read — is the record's type ("Task"), never "Task a8a00001". It no
|
|
14
|
+
longer takes an id. A link to a missing record hovered "Open Task a8a00001".
|
|
15
|
+
- **The confirm opens with the record in hand.** Pointing at or focusing Apply on an update
|
|
16
|
+
or delete card calls `DirectiveHost.readRecord` for each target, so a host that keeps a
|
|
17
|
+
recent read answers the confirm's read without a second round trip.
|
|
18
|
+
|
|
19
|
+
### Consumer action
|
|
20
|
+
|
|
21
|
+
- Drop the second argument from any `recordFallbackName(label, id)` call.
|
|
22
|
+
- Name a new item in your confirm through `itemOwnName` (null → say it has no title).
|
|
23
|
+
- Keep a short-lived copy of a finished `readRecord` read (keyed by `recordRevision(id)`),
|
|
24
|
+
so the hover warm-up reaches the confirm.
|
|
25
|
+
|
|
3
26
|
## 0.20.2
|
|
4
27
|
|
|
5
28
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/directives.cjs
CHANGED
|
@@ -30,6 +30,7 @@ __export(directives_exports, {
|
|
|
30
30
|
DirectiveRender: () => DirectiveRender,
|
|
31
31
|
DirectiveScopeProvider: () => DirectiveScopeProvider,
|
|
32
32
|
EMPTY_VALUE_WORD: () => EMPTY_VALUE_WORD,
|
|
33
|
+
NO_TITLE_WORD: () => NO_TITLE_WORD,
|
|
33
34
|
SideEffectDirectiveCard: () => SideEffectDirectiveCard,
|
|
34
35
|
TARGETING_CLASSES: () => TARGETING_CLASSES,
|
|
35
36
|
defaultFailureWords: () => defaultFailureWords,
|
|
@@ -40,6 +41,7 @@ __export(directives_exports, {
|
|
|
40
41
|
fieldLabel: () => fieldLabel,
|
|
41
42
|
getDirectiveRenderer: () => getDirectiveRenderer,
|
|
42
43
|
itemChanges: () => itemChanges,
|
|
44
|
+
itemOwnName: () => itemOwnName,
|
|
43
45
|
itemRecordId: () => itemRecordId,
|
|
44
46
|
noteRecordChanged: () => noteRecordChanged,
|
|
45
47
|
provisionalDirectiveSlug: () => provisionalDirectiveSlug,
|
|
@@ -98,11 +100,11 @@ function resetDirectiveRenderers() {
|
|
|
98
100
|
|
|
99
101
|
// directives/ApplyDirectiveButton.tsx
|
|
100
102
|
var import_react3 = require("react");
|
|
101
|
-
var
|
|
103
|
+
var import_content_ir3 = require("@ai-matrx/content-ir");
|
|
102
104
|
|
|
103
105
|
// directives/item-changes.ts
|
|
104
|
-
var import_uuid = require("@ai-matrx/kit/uuid");
|
|
105
106
|
var import_text_case = require("@ai-matrx/kit/text-case");
|
|
107
|
+
var import_content_ir2 = require("@ai-matrx/content-ir");
|
|
106
108
|
var TARGETING_CLASSES = /* @__PURE__ */ new Set(["update", "delete"]);
|
|
107
109
|
var NOT_A_CHANGE = /* @__PURE__ */ new Set(["__kind", "id"]);
|
|
108
110
|
var CHANGE_VALUE_MAX = 280;
|
|
@@ -118,10 +120,14 @@ function fieldLabel(key) {
|
|
|
118
120
|
function directiveFieldLabel(key, titleColumn) {
|
|
119
121
|
return titleColumn && key === titleColumn ? "Title" : fieldLabel(key);
|
|
120
122
|
}
|
|
123
|
+
function itemOwnName(item, titleColumn) {
|
|
124
|
+
const probe = (0, import_content_ir2.itemTitle)(item, titleColumn, 0, 2);
|
|
125
|
+
return probe === "Item 1 of 2" ? null : probe;
|
|
126
|
+
}
|
|
127
|
+
var NO_TITLE_WORD = "No title";
|
|
121
128
|
var EMPTY_VALUE_WORD = "None";
|
|
122
|
-
function recordFallbackName(nounLabel3
|
|
123
|
-
|
|
124
|
-
return `${nounLabel3} ${short}`;
|
|
129
|
+
function recordFallbackName(nounLabel3) {
|
|
130
|
+
return nounLabel3.trim() || "Record";
|
|
125
131
|
}
|
|
126
132
|
function describeChangeValue(value, word) {
|
|
127
133
|
return describeValue(value, word);
|
|
@@ -443,7 +449,7 @@ function ApplyDirectiveButton({
|
|
|
443
449
|
(0, import_react3.useEffect)(() => {
|
|
444
450
|
currentIdentity.current = identity;
|
|
445
451
|
}, [identity]);
|
|
446
|
-
const nounText = (0,
|
|
452
|
+
const nounText = (0, import_content_ir3.nounLabel)(directive.noun, host.nouns);
|
|
447
453
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
448
454
|
const read = host.applyState;
|
|
449
455
|
const report = host.reportError;
|
|
@@ -623,7 +629,7 @@ function ApplyDirectiveButton({
|
|
|
623
629
|
) : null,
|
|
624
630
|
records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
625
631
|
...record,
|
|
626
|
-
fallback: recordFallbackName(label2
|
|
632
|
+
fallback: recordFallbackName(label2),
|
|
627
633
|
context: "applied",
|
|
628
634
|
trashed
|
|
629
635
|
}) }, `${record.noun}:${record.id}`)),
|
|
@@ -671,6 +677,14 @@ function ApplyDirectiveButton({
|
|
|
671
677
|
}
|
|
672
678
|
);
|
|
673
679
|
}
|
|
680
|
+
const warm = () => {
|
|
681
|
+
const read2 = host.readRecord;
|
|
682
|
+
if (!read2 || !TARGETING_CLASSES.has(directive.directiveClass)) return;
|
|
683
|
+
for (const item of items) {
|
|
684
|
+
const id = itemRecordId(item);
|
|
685
|
+
if (id) void read2({ noun: directive.noun, id }).catch(() => null);
|
|
686
|
+
}
|
|
687
|
+
};
|
|
674
688
|
const destructive = directive.directiveClass === "delete";
|
|
675
689
|
const muted = nothingToChange && view.status === "idle";
|
|
676
690
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "flex min-w-0 flex-wrap items-center justify-end gap-x-2 gap-y-1", children: [
|
|
@@ -680,6 +694,8 @@ function ApplyDirectiveButton({
|
|
|
680
694
|
{
|
|
681
695
|
type: "button",
|
|
682
696
|
onClick: () => void handleApply(),
|
|
697
|
+
onPointerEnter: warm,
|
|
698
|
+
onFocus: warm,
|
|
683
699
|
disabled: view.status === "applying" || view.status === "asking" || items.length === 0,
|
|
684
700
|
"data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
|
|
685
701
|
title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
|
|
@@ -753,7 +769,7 @@ function FailureNotice({
|
|
|
753
769
|
|
|
754
770
|
// directives/SideEffectDirectiveCard.tsx
|
|
755
771
|
var import_react4 = require("react");
|
|
756
|
-
var
|
|
772
|
+
var import_content_ir4 = require("@ai-matrx/content-ir");
|
|
757
773
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
758
774
|
function directiveValueWord(host, noun) {
|
|
759
775
|
const valueLabel = host.valueLabel;
|
|
@@ -776,20 +792,28 @@ function ItemRow({
|
|
|
776
792
|
if (recordId) {
|
|
777
793
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TargetRow, { directive, item, recordId, index, phase });
|
|
778
794
|
}
|
|
779
|
-
const titleColumn = (0,
|
|
780
|
-
const
|
|
781
|
-
const
|
|
795
|
+
const titleColumn = (0, import_content_ir4.nounTitleColumn)(directive.noun, host.nouns);
|
|
796
|
+
const ownName = itemOwnName(item, titleColumn);
|
|
797
|
+
const title = ownName ?? NO_TITLE_WORD;
|
|
798
|
+
const subtitle = (0, import_content_ir4.itemSubtitle)(item);
|
|
782
799
|
const valueWord = directiveValueWord(host, directive.noun);
|
|
783
|
-
const facts = (0,
|
|
800
|
+
const facts = (0, import_content_ir4.itemFacts)(titleColumn ? omitKey(item, titleColumn) : item).map((fact) => ({
|
|
784
801
|
...fact,
|
|
785
802
|
label: directiveFieldLabel(fact.key, titleColumn),
|
|
786
803
|
value: valueWord?.(fact.key, fact.value) ?? fact.value
|
|
787
804
|
}));
|
|
788
805
|
const kind = host.itemKind?.(directive.slug) ?? null;
|
|
789
|
-
const display = (0,
|
|
806
|
+
const display = (0, import_content_ir4.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
|
|
790
807
|
const openItem = host.openItem;
|
|
791
808
|
const body = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
792
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
809
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
810
|
+
"span",
|
|
811
|
+
{
|
|
812
|
+
className: `min-w-0 shrink-0 truncate font-medium ${ownName ? "text-foreground" : "italic text-muted-foreground"}`,
|
|
813
|
+
"data-item-untitled": ownName ? void 0 : "",
|
|
814
|
+
children: title
|
|
815
|
+
}
|
|
816
|
+
),
|
|
793
817
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "hidden min-w-0 flex-1 items-baseline gap-2 overflow-hidden sm:flex", children: facts.map((fact) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "truncate text-[11px] text-muted-foreground", "data-item-fact": fact.key, children: [
|
|
794
818
|
fact.label,
|
|
795
819
|
" ",
|
|
@@ -805,7 +829,7 @@ function ItemRow({
|
|
|
805
829
|
type: "button",
|
|
806
830
|
onClick: () => openItem({
|
|
807
831
|
// Stamped so the panel's kind pipeline types it from its own first key.
|
|
808
|
-
item: (0,
|
|
832
|
+
item: (0, import_content_ir4.asKindInstance)(item, kind) ?? item,
|
|
809
833
|
itemKind: kind,
|
|
810
834
|
title,
|
|
811
835
|
subtitle: `${display.title} \xB7 item ${index + 1} of ${total}`,
|
|
@@ -818,7 +842,12 @@ function ItemRow({
|
|
|
818
842
|
children: body
|
|
819
843
|
}
|
|
820
844
|
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5", children: body }),
|
|
821
|
-
host.renderCopy?.({
|
|
845
|
+
host.renderCopy?.({
|
|
846
|
+
label: ownName ?? `this ${(0, import_content_ir4.nounLabel)(directive.noun, host.nouns)}`,
|
|
847
|
+
value: item,
|
|
848
|
+
kind,
|
|
849
|
+
size: "xs"
|
|
850
|
+
})
|
|
822
851
|
] });
|
|
823
852
|
}
|
|
824
853
|
function DirectiveChangeList({
|
|
@@ -872,7 +901,7 @@ function TargetRow({
|
|
|
872
901
|
phase
|
|
873
902
|
}) {
|
|
874
903
|
const host = useDirectiveHost();
|
|
875
|
-
const fallback = recordFallbackName((0,
|
|
904
|
+
const fallback = recordFallbackName((0, import_content_ir4.nounLabel)(directive.noun, host.nouns));
|
|
876
905
|
const isUpdate = directive.directiveClass === "update";
|
|
877
906
|
const readsLive = isUpdate && phase.phase === "open";
|
|
878
907
|
const live = useRecordValues(
|
|
@@ -881,7 +910,7 @@ function TargetRow({
|
|
|
881
910
|
);
|
|
882
911
|
const compareTo = phase.phase === "applied" ? phase.before?.[index] ?? null : readsLive ? live.values : null;
|
|
883
912
|
const changes = isUpdate ? itemChanges(item, compareTo, {
|
|
884
|
-
titleColumn: (0,
|
|
913
|
+
titleColumn: (0, import_content_ir4.nounTitleColumn)(directive.noun, host.nouns),
|
|
885
914
|
valueWord: directiveValueWord(host, directive.noun)
|
|
886
915
|
}) : [];
|
|
887
916
|
const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate font-medium text-foreground", children: fallback });
|
|
@@ -889,7 +918,7 @@ function TargetRow({
|
|
|
889
918
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
890
919
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
|
|
891
920
|
host.renderCopy?.({
|
|
892
|
-
label: `this ${(0,
|
|
921
|
+
label: `this ${(0, import_content_ir4.nounLabel)(directive.noun, host.nouns).toLowerCase()}`,
|
|
893
922
|
value: item,
|
|
894
923
|
size: "xs",
|
|
895
924
|
record: { noun: directive.noun, id: recordId }
|
|
@@ -903,7 +932,7 @@ function SideEffectDirectiveCard({ directive }) {
|
|
|
903
932
|
const [expanded, setExpanded] = (0, import_react4.useState)(false);
|
|
904
933
|
const items = directive.items;
|
|
905
934
|
const total = items.length;
|
|
906
|
-
const display = (0,
|
|
935
|
+
const display = (0, import_content_ir4.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
|
|
907
936
|
const Icon = classIcon(directive.directiveClass, directive.noun);
|
|
908
937
|
const [phase, setPhase] = (0, import_react4.useState)(
|
|
909
938
|
() => readsApplyLedger(host, directive) ? { phase: "pending" } : { phase: "open" }
|
|
@@ -954,12 +983,12 @@ function SideEffectDirectiveCard({ directive }) {
|
|
|
954
983
|
}
|
|
955
984
|
|
|
956
985
|
// directives/DirectiveFallbackCard.tsx
|
|
957
|
-
var
|
|
986
|
+
var import_content_ir5 = require("@ai-matrx/content-ir");
|
|
958
987
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
959
988
|
function DirectiveFallbackCard({ directive, reason }) {
|
|
960
989
|
const host = useDirectiveHost();
|
|
961
990
|
const count = directive.items.length;
|
|
962
|
-
const display = (0,
|
|
991
|
+
const display = (0, import_content_ir5.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
|
|
963
992
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "my-3 inline-flex flex-wrap items-center gap-2 rounded-md border border-border bg-muted px-2.5 py-1 text-sm", children: [
|
|
964
993
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BoxesIcon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
965
994
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-foreground", children: display.title }),
|
|
@@ -982,7 +1011,7 @@ function DirectiveFallbackCard({ directive, reason }) {
|
|
|
982
1011
|
}
|
|
983
1012
|
|
|
984
1013
|
// directives/DirectiveProvisionalCard.tsx
|
|
985
|
-
var
|
|
1014
|
+
var import_content_ir6 = require("@ai-matrx/content-ir");
|
|
986
1015
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
987
1016
|
var COMPLETE_SLUG_RE = /^\{\s*"__kind"\s*:\s*"([^"]+)"/;
|
|
988
1017
|
function provisionalDirectiveSlug(content) {
|
|
@@ -992,8 +1021,8 @@ function provisionalDirectiveSlug(content) {
|
|
|
992
1021
|
function DirectiveProvisionalCard({ content, streaming, className }) {
|
|
993
1022
|
const host = useDirectiveHost();
|
|
994
1023
|
const slug = provisionalDirectiveSlug(content);
|
|
995
|
-
const known = slug ? (0,
|
|
996
|
-
const display = known ? (0,
|
|
1024
|
+
const known = slug ? (0, import_content_ir6.parseDirectiveSlug)(slug) : null;
|
|
1025
|
+
const display = known ? (0, import_content_ir6.directiveDisplay)(known.directiveClass, known.noun, host.nouns) : null;
|
|
997
1026
|
const Icon = known ? classIcon(known.directiveClass, known.noun) : BoxesIcon;
|
|
998
1027
|
const title = display?.title ?? "Structured action";
|
|
999
1028
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -1022,7 +1051,7 @@ function DirectiveProvisionalCard({ content, streaming, className }) {
|
|
|
1022
1051
|
}
|
|
1023
1052
|
|
|
1024
1053
|
// directives/DirectiveRender.tsx
|
|
1025
|
-
var
|
|
1054
|
+
var import_content_ir7 = require("@ai-matrx/content-ir");
|
|
1026
1055
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1027
1056
|
function isWholeJson(content) {
|
|
1028
1057
|
try {
|
|
@@ -1038,13 +1067,13 @@ function DirectiveRender({ conversationId, ...props }) {
|
|
|
1038
1067
|
}
|
|
1039
1068
|
function DirectiveRenderInner({ content, className, streaming }) {
|
|
1040
1069
|
const host = useDirectiveHost();
|
|
1041
|
-
const directive = (0,
|
|
1070
|
+
const directive = (0, import_content_ir7.tryDecodeDirectiveContent)(content, (message) => {
|
|
1042
1071
|
const line = `[kind-directives] ${message}`;
|
|
1043
1072
|
if (host.reportError) host.reportError(line);
|
|
1044
1073
|
else console.error(line);
|
|
1045
1074
|
});
|
|
1046
1075
|
if (!directive) {
|
|
1047
|
-
if (typeof content === "string" && (0,
|
|
1076
|
+
if (typeof content === "string" && (0, import_content_ir7.looksLikeDirectiveHead)(content) && !isWholeJson(content)) {
|
|
1048
1077
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DirectiveProvisionalCard, { content, streaming: streaming !== false, className });
|
|
1049
1078
|
}
|
|
1050
1079
|
const raw = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|