@almadar/ui 6.14.0 → 6.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/dist/{EntityBindingContext-BMz9xiBa.d.cts → EntityBindingContext-Dglbi9ks.d.cts} +8 -1
- package/dist/{EntityBindingContext-BMz9xiBa.d.ts → EntityBindingContext-Dglbi9ks.d.ts} +8 -1
- package/dist/avl/index.cjs +140 -80
- package/dist/avl/index.js +140 -80
- package/dist/{avl-schema-parser-B25PL-a8.d.cts → avl-schema-parser-dGHC5jUf.d.cts} +5 -5
- package/dist/{avl-schema-parser-CM0pQo8E.d.ts → avl-schema-parser-tzl7qXDY.d.ts} +5 -5
- package/dist/components/index.cjs +118 -57
- package/dist/components/index.d.cts +49 -19
- package/dist/components/index.d.ts +49 -19
- package/dist/components/index.js +118 -57
- package/dist/lib/drawable/three/index.cjs +25 -5
- package/dist/lib/drawable/three/index.d.cts +2 -2
- package/dist/lib/drawable/three/index.d.ts +2 -2
- package/dist/lib/drawable/three/index.js +25 -5
- package/dist/lib/index.cjs +22 -0
- package/dist/lib/index.d.cts +10 -2
- package/dist/lib/index.d.ts +10 -2
- package/dist/lib/index.js +20 -1
- package/dist/providers/index.cjs +153 -67
- package/dist/providers/index.d.cts +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +153 -67
- package/dist/runtime/index.cjs +138 -78
- package/dist/runtime/index.d.cts +7 -3
- package/dist/runtime/index.d.ts +7 -3
- package/dist/runtime/index.js +138 -78
- package/package.json +4 -4
package/dist/runtime/index.cjs
CHANGED
|
@@ -4061,7 +4061,7 @@ var init_Textarea = __esm({
|
|
|
4061
4061
|
init_cn();
|
|
4062
4062
|
init_useEventBus();
|
|
4063
4063
|
Textarea = React87__namespace.default.forwardRef(
|
|
4064
|
-
({ className, error, onChange, ...props }, ref) => {
|
|
4064
|
+
({ className, error, onChange, action, onKeyDown, ...props }, ref) => {
|
|
4065
4065
|
const eventBus = useEventBus();
|
|
4066
4066
|
const handleChange = (e) => {
|
|
4067
4067
|
if (typeof onChange === "string") {
|
|
@@ -4070,11 +4070,18 @@ var init_Textarea = __esm({
|
|
|
4070
4070
|
onChange?.(e);
|
|
4071
4071
|
}
|
|
4072
4072
|
};
|
|
4073
|
+
const handleKeyDown = (e) => {
|
|
4074
|
+
onKeyDown?.(e);
|
|
4075
|
+
if (!action || e.key !== "Enter" || !(e.metaKey || e.ctrlKey)) return;
|
|
4076
|
+
e.preventDefault();
|
|
4077
|
+
eventBus.emit(`UI:${action}`, { value: e.currentTarget.value });
|
|
4078
|
+
};
|
|
4073
4079
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4074
4080
|
"textarea",
|
|
4075
4081
|
{
|
|
4076
4082
|
ref,
|
|
4077
4083
|
onChange: handleChange,
|
|
4084
|
+
onKeyDown: handleKeyDown,
|
|
4078
4085
|
className: cn(
|
|
4079
4086
|
"block w-full border-[length:var(--border-width)] shadow-sm",
|
|
4080
4087
|
"px-3 py-2 text-sm text-foreground",
|
|
@@ -9467,6 +9474,29 @@ var init_useCamera = __esm({
|
|
|
9467
9474
|
}
|
|
9468
9475
|
});
|
|
9469
9476
|
|
|
9477
|
+
// lib/keyMapEvent.ts
|
|
9478
|
+
function isEditableTarget(target) {
|
|
9479
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
9480
|
+
const tag = target.tagName;
|
|
9481
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
9482
|
+
return target.isContentEditable || target.contentEditable === "true";
|
|
9483
|
+
}
|
|
9484
|
+
function keyMapCode(e) {
|
|
9485
|
+
let code = e.code;
|
|
9486
|
+
if (e.altKey) code = `Alt+${code}`;
|
|
9487
|
+
if (e.shiftKey) code = `Shift+${code}`;
|
|
9488
|
+
if (e.metaKey || e.ctrlKey) code = `Mod+${code}`;
|
|
9489
|
+
return code;
|
|
9490
|
+
}
|
|
9491
|
+
function resolveKeyMapEvent(map, e) {
|
|
9492
|
+
if (!map || isEditableTarget(e.target)) return void 0;
|
|
9493
|
+
return map[keyMapCode(e)] ?? map[e.code];
|
|
9494
|
+
}
|
|
9495
|
+
var init_keyMapEvent = __esm({
|
|
9496
|
+
"lib/keyMapEvent.ts"() {
|
|
9497
|
+
}
|
|
9498
|
+
});
|
|
9499
|
+
|
|
9470
9500
|
// lib/imageCache.ts
|
|
9471
9501
|
function startLoad(url, onReady, existing) {
|
|
9472
9502
|
const img = new Image();
|
|
@@ -11392,14 +11422,14 @@ function Canvas2D({
|
|
|
11392
11422
|
React87.useEffect(() => {
|
|
11393
11423
|
if (!keyMap && !keyUpMap) return;
|
|
11394
11424
|
const onDown = (e) => {
|
|
11395
|
-
const ev = keyMap
|
|
11425
|
+
const ev = resolveKeyMapEvent(keyMap, e);
|
|
11396
11426
|
if (ev) {
|
|
11397
11427
|
eventBus.emit(`UI:${ev}`, {});
|
|
11398
11428
|
e.preventDefault();
|
|
11399
11429
|
}
|
|
11400
11430
|
};
|
|
11401
11431
|
const onUp = (e) => {
|
|
11402
|
-
const ev = keyUpMap
|
|
11432
|
+
const ev = resolveKeyMapEvent(keyUpMap, e);
|
|
11403
11433
|
if (ev) eventBus.emit(`UI:${ev}`, {});
|
|
11404
11434
|
};
|
|
11405
11435
|
window.addEventListener("keydown", onDown);
|
|
@@ -11523,6 +11553,7 @@ var init_Canvas2D = __esm({
|
|
|
11523
11553
|
init_useCamera();
|
|
11524
11554
|
init_useCanvasGestures();
|
|
11525
11555
|
init_verificationRegistry();
|
|
11556
|
+
init_keyMapEvent();
|
|
11526
11557
|
init_webPainter2d();
|
|
11527
11558
|
init_projector();
|
|
11528
11559
|
init_paintDispatch();
|
|
@@ -27452,6 +27483,40 @@ var init_DashboardLayout = __esm({
|
|
|
27452
27483
|
NavLinkBottom.displayName = "NavLinkBottom";
|
|
27453
27484
|
}
|
|
27454
27485
|
});
|
|
27486
|
+
|
|
27487
|
+
// lib/relationLabel.ts
|
|
27488
|
+
function relationLabel(value) {
|
|
27489
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date)
|
|
27490
|
+
return null;
|
|
27491
|
+
for (const key of ["name", "title", "label"]) {
|
|
27492
|
+
const candidate = value[key];
|
|
27493
|
+
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
27494
|
+
}
|
|
27495
|
+
const id = value.id;
|
|
27496
|
+
return id !== void 0 && id !== null ? String(id) : null;
|
|
27497
|
+
}
|
|
27498
|
+
function relationDisplayLabels(value, options) {
|
|
27499
|
+
if (value === void 0 || value === null || value === "") return [];
|
|
27500
|
+
if (Array.isArray(value)) {
|
|
27501
|
+
return value.flatMap((item) => relationDisplayLabels(item, options));
|
|
27502
|
+
}
|
|
27503
|
+
const hydrated = relationLabel(value);
|
|
27504
|
+
if (hydrated !== null) return [hydrated];
|
|
27505
|
+
const raw = String(value);
|
|
27506
|
+
const match = options?.find((opt) => opt.value === raw);
|
|
27507
|
+
return [match ? match.label : raw];
|
|
27508
|
+
}
|
|
27509
|
+
function resolveRelationCellDisplay(value, options) {
|
|
27510
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
27511
|
+
const isObjectShaped = typeof value === "object" && !(value instanceof Date) || Array.isArray(value) && value.some((v) => v !== null && typeof v === "object" && !(v instanceof Date));
|
|
27512
|
+
if (!isObjectShaped && !options) return void 0;
|
|
27513
|
+
const labels = relationDisplayLabels(value, options);
|
|
27514
|
+
return labels.length > 0 ? labels.join(", ") : void 0;
|
|
27515
|
+
}
|
|
27516
|
+
var init_relationLabel = __esm({
|
|
27517
|
+
"lib/relationLabel.ts"() {
|
|
27518
|
+
}
|
|
27519
|
+
});
|
|
27455
27520
|
function downloadItemUrl(url, label) {
|
|
27456
27521
|
const a = document.createElement("a");
|
|
27457
27522
|
a.href = url;
|
|
@@ -28283,7 +28348,8 @@ function DataGrid({
|
|
|
28283
28348
|
positionEvent,
|
|
28284
28349
|
dndItemIdField,
|
|
28285
28350
|
dndRoot,
|
|
28286
|
-
look = "dense"
|
|
28351
|
+
look = "dense",
|
|
28352
|
+
relationsData
|
|
28287
28353
|
}) {
|
|
28288
28354
|
const eventBus = useEventBus();
|
|
28289
28355
|
const { t } = hooks.useTranslate();
|
|
@@ -28473,6 +28539,10 @@ function DataGrid({
|
|
|
28473
28539
|
);
|
|
28474
28540
|
}
|
|
28475
28541
|
const titleValue = core.getNestedValue(itemData, titleField?.name ?? "");
|
|
28542
|
+
const titleDisplay = resolveRelationCellDisplay(
|
|
28543
|
+
titleValue,
|
|
28544
|
+
titleField ? relationsData?.[titleField.name] : void 0
|
|
28545
|
+
) ?? (titleValue !== void 0 && titleValue !== null ? String(titleValue) : void 0);
|
|
28476
28546
|
return wrapDnd(
|
|
28477
28547
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
28478
28548
|
Box,
|
|
@@ -28497,7 +28567,7 @@ function DataGrid({
|
|
|
28497
28567
|
"img",
|
|
28498
28568
|
{
|
|
28499
28569
|
src: imgUrl,
|
|
28500
|
-
alt:
|
|
28570
|
+
alt: titleDisplay ?? "",
|
|
28501
28571
|
className: "w-full h-full object-cover",
|
|
28502
28572
|
loading: "lazy"
|
|
28503
28573
|
}
|
|
@@ -28512,18 +28582,18 @@ function DataGrid({
|
|
|
28512
28582
|
onChange: () => toggleSelection(id),
|
|
28513
28583
|
onClick: (e) => e.stopPropagation(),
|
|
28514
28584
|
className: "w-4 h-4 mt-1 flex-shrink-0 accent-primary",
|
|
28515
|
-
"aria-label": t("card.selectItem", { item:
|
|
28585
|
+
"aria-label": t("card.selectItem", { item: titleDisplay ?? t("card.itemFallback") })
|
|
28516
28586
|
}
|
|
28517
28587
|
),
|
|
28518
28588
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
|
|
28519
|
-
|
|
28589
|
+
titleDisplay !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center min-w-0", children: [
|
|
28520
28590
|
titleField?.icon && renderIconInput(titleField.icon, { size: "sm", className: "text-primary flex-shrink-0" }),
|
|
28521
28591
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28522
28592
|
Typography,
|
|
28523
28593
|
{
|
|
28524
28594
|
variant: titleField?.variant === "h3" ? "h3" : "h4",
|
|
28525
28595
|
className: "font-semibold truncate min-w-0",
|
|
28526
|
-
children:
|
|
28596
|
+
children: titleDisplay
|
|
28527
28597
|
}
|
|
28528
28598
|
)
|
|
28529
28599
|
] }),
|
|
@@ -28532,7 +28602,7 @@ function DataGrid({
|
|
|
28532
28602
|
if (val === void 0 || val === null || val === "") return null;
|
|
28533
28603
|
return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
28534
28604
|
field.icon && renderIconInput(field.icon, { size: "xs" }),
|
|
28535
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: humanizeEnumValue(formatValue(val, field.format)) })
|
|
28605
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: resolveRelationCellDisplay(val, relationsData?.[field.name]) ?? humanizeEnumValue(formatValue(val, field.format)) })
|
|
28536
28606
|
] }, field.name);
|
|
28537
28607
|
}) })
|
|
28538
28608
|
] }),
|
|
@@ -28571,7 +28641,7 @@ function DataGrid({
|
|
|
28571
28641
|
bodyFields.filter((f3) => f3.variant === "caption" && f3.format !== "boolean").map((field) => {
|
|
28572
28642
|
const value = core.getNestedValue(itemData, field.name);
|
|
28573
28643
|
if (value === void 0 || value === null || value === "") return null;
|
|
28574
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", className: "line-clamp-2", children: formatValue(value, field.format) }, field.name);
|
|
28644
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", className: "line-clamp-2", children: resolveRelationCellDisplay(value, relationsData?.[field.name]) ?? formatValue(value, field.format) }, field.name);
|
|
28575
28645
|
}),
|
|
28576
28646
|
/* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "flex-wrap gap-y-1", children: bodyFields.filter((f3) => f3.variant !== "caption" || f3.format === "boolean").map((field) => {
|
|
28577
28647
|
const value = core.getNestedValue(itemData, field.name);
|
|
@@ -28586,7 +28656,7 @@ function DataGrid({
|
|
|
28586
28656
|
return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
|
|
28587
28657
|
field.icon && renderIconInput(field.icon, { size: "xs", className: "text-muted-foreground" }),
|
|
28588
28658
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "sr-only", children: (field.label ?? fieldLabel2(field.name)) + ":" }),
|
|
28589
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: formatValue(value, field.format) })
|
|
28659
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: resolveRelationCellDisplay(value, relationsData?.[field.name]) ?? formatValue(value, field.format) })
|
|
28590
28660
|
] }, field.name);
|
|
28591
28661
|
}) })
|
|
28592
28662
|
] }) })
|
|
@@ -28630,6 +28700,7 @@ var init_DataGrid = __esm({
|
|
|
28630
28700
|
"use client";
|
|
28631
28701
|
init_cn();
|
|
28632
28702
|
init_format();
|
|
28703
|
+
init_relationLabel();
|
|
28633
28704
|
init_getNestedValue();
|
|
28634
28705
|
init_useEventBus();
|
|
28635
28706
|
init_Box();
|
|
@@ -28682,7 +28753,9 @@ function statusVariant3(value) {
|
|
|
28682
28753
|
if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
|
|
28683
28754
|
return "default";
|
|
28684
28755
|
}
|
|
28685
|
-
function formatValue2(value, format, boolLabels) {
|
|
28756
|
+
function formatValue2(value, format, boolLabels, relationOptions) {
|
|
28757
|
+
const relationDisplay = resolveRelationCellDisplay(value, relationOptions);
|
|
28758
|
+
if (relationDisplay !== void 0) return relationDisplay;
|
|
28686
28759
|
if (value !== void 0 && value !== null && (format === "boolean" || typeof value === "boolean")) {
|
|
28687
28760
|
const isNo = value === false || value === 0 || String(value) === "false";
|
|
28688
28761
|
return isNo ? boolLabels?.no ?? "No" : boolLabels?.yes ?? "Yes";
|
|
@@ -28742,7 +28815,8 @@ function DataList({
|
|
|
28742
28815
|
positionEvent,
|
|
28743
28816
|
dndItemIdField,
|
|
28744
28817
|
dndRoot,
|
|
28745
|
-
look = "dense"
|
|
28818
|
+
look = "dense",
|
|
28819
|
+
relationsData
|
|
28746
28820
|
}) {
|
|
28747
28821
|
const eventBus = useEventBus();
|
|
28748
28822
|
const { t } = hooks.useTranslate();
|
|
@@ -28930,13 +29004,13 @@ function DataList({
|
|
|
28930
29004
|
return f3.variant === "badge" ? (
|
|
28931
29005
|
// `format` applies here too — a boolean field badged
|
|
28932
29006
|
// without it renders the raw "false" instead of "No".
|
|
28933
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant3(String(v)), children: formatValue2(v, f3.format) }, f3.name)
|
|
29007
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant3(String(v)), children: formatValue2(v, f3.format, void 0, relationsData?.[f3.name]) }, f3.name)
|
|
28934
29008
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
28935
29009
|
Typography,
|
|
28936
29010
|
{
|
|
28937
29011
|
variant: "caption",
|
|
28938
29012
|
className: cn("text-xs", isSent ? "opacity-70" : "text-muted-foreground"),
|
|
28939
|
-
children: formatValue2(v, f3.format)
|
|
29013
|
+
children: formatValue2(v, f3.format, void 0, relationsData?.[f3.name])
|
|
28940
29014
|
},
|
|
28941
29015
|
f3.name
|
|
28942
29016
|
);
|
|
@@ -29014,6 +29088,10 @@ function DataList({
|
|
|
29014
29088
|
}
|
|
29015
29089
|
const id = itemData.id || String(index);
|
|
29016
29090
|
const titleValue = core.getNestedValue(itemData, titleField?.name ?? "");
|
|
29091
|
+
const titleDisplay = resolveRelationCellDisplay(
|
|
29092
|
+
titleValue,
|
|
29093
|
+
titleField ? relationsData?.[titleField.name] : void 0
|
|
29094
|
+
) ?? (titleValue !== void 0 && titleValue !== null ? String(titleValue) : void 0);
|
|
29017
29095
|
return wrapDnd(
|
|
29018
29096
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn(rowClickEvent && "cursor-pointer"), children: [
|
|
29019
29097
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -29038,7 +29116,7 @@ function DataList({
|
|
|
29038
29116
|
{
|
|
29039
29117
|
variant: titleField?.variant === "h3" ? "h3" : "h4",
|
|
29040
29118
|
className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
|
|
29041
|
-
children:
|
|
29119
|
+
children: titleDisplay
|
|
29042
29120
|
}
|
|
29043
29121
|
),
|
|
29044
29122
|
badgeFields.map((field) => {
|
|
@@ -29046,7 +29124,7 @@ function DataList({
|
|
|
29046
29124
|
if (val === void 0 || val === null) return null;
|
|
29047
29125
|
return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
|
|
29048
29126
|
field.icon && renderIconInput2(field.icon, { size: "xs" }),
|
|
29049
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant3(String(val)), children: formatValue2(val, field.format) })
|
|
29127
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant3(String(val)), children: formatValue2(val, field.format, void 0, relationsData?.[field.name]) })
|
|
29050
29128
|
] }, field.name);
|
|
29051
29129
|
})
|
|
29052
29130
|
] }),
|
|
@@ -29067,7 +29145,7 @@ function DataList({
|
|
|
29067
29145
|
]
|
|
29068
29146
|
}
|
|
29069
29147
|
),
|
|
29070
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: formatValue2(value, field.format, { yes: t("common.yes"), no: t("common.no") }) })
|
|
29148
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: formatValue2(value, field.format, { yes: t("common.yes"), no: t("common.no") }, relationsData?.[field.name]) })
|
|
29071
29149
|
] }, field.name);
|
|
29072
29150
|
}) }),
|
|
29073
29151
|
progressFields.map((field) => {
|
|
@@ -29147,6 +29225,7 @@ var init_DataList = __esm({
|
|
|
29147
29225
|
"use client";
|
|
29148
29226
|
init_cn();
|
|
29149
29227
|
init_format();
|
|
29228
|
+
init_relationLabel();
|
|
29150
29229
|
init_getNestedValue();
|
|
29151
29230
|
init_useEventBus();
|
|
29152
29231
|
init_Box();
|
|
@@ -32821,6 +32900,7 @@ var init_MathCanvas = __esm({
|
|
|
32821
32900
|
"use client";
|
|
32822
32901
|
init_useEventBus();
|
|
32823
32902
|
init_perf();
|
|
32903
|
+
init_keyMapEvent();
|
|
32824
32904
|
init_atoms();
|
|
32825
32905
|
init_Stack();
|
|
32826
32906
|
init_gameFonts();
|
|
@@ -32874,14 +32954,14 @@ var init_MathCanvas = __esm({
|
|
|
32874
32954
|
React87.useEffect(() => {
|
|
32875
32955
|
if (!stableKeyMap && !stableKeyUpMap) return;
|
|
32876
32956
|
const onDown = (e) => {
|
|
32877
|
-
const ev = stableKeyMap
|
|
32957
|
+
const ev = resolveKeyMapEvent(stableKeyMap, e);
|
|
32878
32958
|
if (ev) {
|
|
32879
32959
|
eventBus.emit(`UI:${ev}`, {});
|
|
32880
32960
|
e.preventDefault();
|
|
32881
32961
|
}
|
|
32882
32962
|
};
|
|
32883
32963
|
const onUp = (e) => {
|
|
32884
|
-
const ev = stableKeyUpMap
|
|
32964
|
+
const ev = resolveKeyMapEvent(stableKeyUpMap, e);
|
|
32885
32965
|
if (ev) eventBus.emit(`UI:${ev}`, {});
|
|
32886
32966
|
};
|
|
32887
32967
|
window.addEventListener("keydown", onDown);
|
|
@@ -35297,33 +35377,6 @@ var init_Lightbox = __esm({
|
|
|
35297
35377
|
Lightbox.displayName = "Lightbox";
|
|
35298
35378
|
}
|
|
35299
35379
|
});
|
|
35300
|
-
|
|
35301
|
-
// lib/relationLabel.ts
|
|
35302
|
-
function relationLabel(value) {
|
|
35303
|
-
if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Date)
|
|
35304
|
-
return null;
|
|
35305
|
-
for (const key of ["name", "title", "label"]) {
|
|
35306
|
-
const candidate = value[key];
|
|
35307
|
-
if (typeof candidate === "string" && candidate !== "") return candidate;
|
|
35308
|
-
}
|
|
35309
|
-
const id = value.id;
|
|
35310
|
-
return id !== void 0 && id !== null ? String(id) : null;
|
|
35311
|
-
}
|
|
35312
|
-
function relationDisplayLabels(value, options) {
|
|
35313
|
-
if (value === void 0 || value === null || value === "") return [];
|
|
35314
|
-
if (Array.isArray(value)) {
|
|
35315
|
-
return value.flatMap((item) => relationDisplayLabels(item, options));
|
|
35316
|
-
}
|
|
35317
|
-
const hydrated = relationLabel(value);
|
|
35318
|
-
if (hydrated !== null) return [hydrated];
|
|
35319
|
-
const raw = String(value);
|
|
35320
|
-
const match = options?.find((opt) => opt.value === raw);
|
|
35321
|
-
return [match ? match.label : raw];
|
|
35322
|
-
}
|
|
35323
|
-
var init_relationLabel = __esm({
|
|
35324
|
-
"lib/relationLabel.ts"() {
|
|
35325
|
-
}
|
|
35326
|
-
});
|
|
35327
35380
|
function renderIconInput3(icon, props) {
|
|
35328
35381
|
return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, ...props });
|
|
35329
35382
|
}
|
|
@@ -35387,7 +35440,8 @@ function TableView({
|
|
|
35387
35440
|
reorderEvent,
|
|
35388
35441
|
positionEvent,
|
|
35389
35442
|
dndItemIdField,
|
|
35390
|
-
dndRoot
|
|
35443
|
+
dndRoot,
|
|
35444
|
+
relationsData
|
|
35391
35445
|
}) {
|
|
35392
35446
|
const eventBus = useEventBus();
|
|
35393
35447
|
const { t } = hooks.useTranslate();
|
|
@@ -35472,7 +35526,7 @@ function TableView({
|
|
|
35472
35526
|
const colFloors = React87__namespace.default.useMemo(
|
|
35473
35527
|
() => colDefs.map((col) => {
|
|
35474
35528
|
const longest = data.reduce((widest, row) => {
|
|
35475
|
-
const cell = formatCell(asFieldValue(core.getNestedValue(row, col.field ?? col.key)), col.format);
|
|
35529
|
+
const cell = formatCell(asFieldValue(core.getNestedValue(row, col.field ?? col.key)), col.format, relationsData?.[col.field ?? col.key]);
|
|
35476
35530
|
return Math.max(widest, cell.length);
|
|
35477
35531
|
}, columnLabel(col).length);
|
|
35478
35532
|
const chrome = col.format === "badge" ? BADGE_CHROME_CH : 0;
|
|
@@ -35572,9 +35626,11 @@ function TableView({
|
|
|
35572
35626
|
col.className
|
|
35573
35627
|
);
|
|
35574
35628
|
if (col.format === "badge" && raw != null && raw !== "") {
|
|
35575
|
-
|
|
35629
|
+
const relationDisplay = resolveRelationCellDisplay(raw, relationsData?.[col.field ?? col.key]);
|
|
35630
|
+
const label = relationDisplay ?? humanizeEnumValue(String(raw));
|
|
35631
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: statusVariant4(String(raw)), size: "sm", className: "whitespace-nowrap", children: label }) }, col.key);
|
|
35576
35632
|
}
|
|
35577
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
|
|
35633
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format, relationsData?.[col.field ?? col.key]) }) }, col.key);
|
|
35578
35634
|
}),
|
|
35579
35635
|
hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
35580
35636
|
HStack,
|
|
@@ -35676,11 +35732,9 @@ var init_TableView = __esm({
|
|
|
35676
35732
|
init_Menu();
|
|
35677
35733
|
init_useDataDnd();
|
|
35678
35734
|
tableViewLog = logger.createLogger("almadar:ui:table-view");
|
|
35679
|
-
formatCell = (value, format) => {
|
|
35680
|
-
|
|
35681
|
-
|
|
35682
|
-
if (labels.length > 0) return labels.join(", ");
|
|
35683
|
-
}
|
|
35735
|
+
formatCell = (value, format, relationOptions) => {
|
|
35736
|
+
const relationDisplay = resolveRelationCellDisplay(value, relationOptions);
|
|
35737
|
+
if (relationDisplay !== void 0) return relationDisplay;
|
|
35684
35738
|
return formatValue(value, format);
|
|
35685
35739
|
};
|
|
35686
35740
|
MAX_MEASURED_COL_CH = 32;
|
|
@@ -44252,7 +44306,8 @@ function DataTable({
|
|
|
44252
44306
|
headerActions,
|
|
44253
44307
|
showTotal = true,
|
|
44254
44308
|
className,
|
|
44255
|
-
look = "dense"
|
|
44309
|
+
look = "dense",
|
|
44310
|
+
relationsData
|
|
44256
44311
|
}) {
|
|
44257
44312
|
const [openActionMenu, setOpenActionMenu] = React87.useState(
|
|
44258
44313
|
null
|
|
@@ -44547,6 +44602,11 @@ function DataTable({
|
|
|
44547
44602
|
"data-column": String(col.key),
|
|
44548
44603
|
className: "px-4 py-3 text-sm text-foreground whitespace-nowrap sm:whitespace-normal",
|
|
44549
44604
|
children: col.render ? col.render(cellValue, row, rowIndex) : (() => {
|
|
44605
|
+
const relationDisplay = resolveRelationCellDisplay(
|
|
44606
|
+
cellValue,
|
|
44607
|
+
relationsData?.[String(col.key)]
|
|
44608
|
+
);
|
|
44609
|
+
if (relationDisplay !== void 0) return relationDisplay;
|
|
44550
44610
|
const boolVal = asBooleanValue2(cellValue);
|
|
44551
44611
|
if (boolVal !== null) {
|
|
44552
44612
|
return boolVal ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "success", children: t("common.yes") }) : /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "neutral", children: t("common.no") });
|
|
@@ -44635,6 +44695,7 @@ var init_DataTable = __esm({
|
|
|
44635
44695
|
init_cn();
|
|
44636
44696
|
init_format();
|
|
44637
44697
|
init_getNestedValue();
|
|
44698
|
+
init_relationLabel();
|
|
44638
44699
|
init_atoms();
|
|
44639
44700
|
init_Box();
|
|
44640
44701
|
init_Stack();
|
|
@@ -52995,7 +53056,7 @@ function runTickFrame(entityId, orderedWriters, store) {
|
|
|
52995
53056
|
}
|
|
52996
53057
|
var log3 = logger.createLogger("almadar:ui:effects:client-handlers");
|
|
52997
53058
|
function createClientEffectHandlers(options) {
|
|
52998
|
-
const { eventBus, slotSetter, navigate, navigateBack, callService, liveEntity, persistDelegated } = options;
|
|
53059
|
+
const { eventBus, slotSetter, navigate, navigateBack, callService, liveEntity, persistDelegated, callServiceDelegated } = options;
|
|
52999
53060
|
return {
|
|
53000
53061
|
emit: (event, payload, source) => {
|
|
53001
53062
|
const prefixedEvent = event.startsWith("UI:") ? event : `UI:${event}`;
|
|
@@ -53008,6 +53069,7 @@ function createClientEffectHandlers(options) {
|
|
|
53008
53069
|
// carries its outcome — tell the executor so the placeholder above is
|
|
53009
53070
|
// never read as a denial (see `EffectHandlers.persistDelegated`).
|
|
53010
53071
|
...persistDelegated === true ? { persistDelegated: true } : {},
|
|
53072
|
+
...callServiceDelegated === true ? { callServiceDelegated: true } : {},
|
|
53011
53073
|
// @almadar/runtime EffectHandlers.set types value:unknown — should be FieldValue (upstream fix queued)
|
|
53012
53074
|
set: ((_entityId, field, value) => {
|
|
53013
53075
|
if (!liveEntity) {
|
|
@@ -53583,7 +53645,6 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
53583
53645
|
}, [traitStates]);
|
|
53584
53646
|
const traitSnapshotDataRef = React87.useRef(/* @__PURE__ */ new Map());
|
|
53585
53647
|
const traitFieldStatesRef = React87.useRef(/* @__PURE__ */ new Map());
|
|
53586
|
-
const bridgeEchoPendingRef = React87.useRef(/* @__PURE__ */ new Map());
|
|
53587
53648
|
const bindingSnapshotsRef = React87.useRef(/* @__PURE__ */ new Map());
|
|
53588
53649
|
const bindingListenersRef = React87.useRef(/* @__PURE__ */ new Map());
|
|
53589
53650
|
const publishBindingSnapshot = React87.useCallback((traitName, row) => {
|
|
@@ -53744,7 +53805,11 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
53744
53805
|
// No local persistence adapter (bridge mode, or a syncOnly tick):
|
|
53745
53806
|
// nothing persists client-side, the server owns the write and
|
|
53746
53807
|
// reports it — never read the placeholder as a denial.
|
|
53747
|
-
persistDelegated: (syncOnly ? void 0 : optionsRef.current?.persistence) === void 0
|
|
53808
|
+
persistDelegated: (syncOnly ? void 0 : optionsRef.current?.persistence) === void 0,
|
|
53809
|
+
// Bridge mode with no consumer-supplied callService: the server
|
|
53810
|
+
// runs every call-service and its cascade carries the result —
|
|
53811
|
+
// the client's mock must not also run one.
|
|
53812
|
+
callServiceDelegated: optionsRef.current?.callService === void 0 && (syncOnly ? void 0 : optionsRef.current?.persistence) === void 0
|
|
53748
53813
|
});
|
|
53749
53814
|
const persistence = syncOnly ? void 0 : optionsRef.current?.persistence;
|
|
53750
53815
|
let handlers = clientHandlers;
|
|
@@ -54060,6 +54125,11 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
54060
54125
|
const _perfT0 = ui.perfStart("processEvent:total");
|
|
54061
54126
|
const bindings = traitBindingsRef.current;
|
|
54062
54127
|
const currentManager = managerRef.current;
|
|
54128
|
+
if (sourceTrait === void 0 && tick === void 0) {
|
|
54129
|
+
for (const snap of traitSnapshotDataRef.current.values()) {
|
|
54130
|
+
snap.cascadeReceived = [];
|
|
54131
|
+
}
|
|
54132
|
+
}
|
|
54063
54133
|
crossTraitLog.debug("processEvent:enter", () => ({
|
|
54064
54134
|
event: normalizedEvent,
|
|
54065
54135
|
payload: JSON.stringify(payload ?? null),
|
|
@@ -54098,7 +54168,6 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
54098
54168
|
});
|
|
54099
54169
|
const emittedByTrait = /* @__PURE__ */ new Map();
|
|
54100
54170
|
const serverEffectResultsByTrait = /* @__PURE__ */ new Map();
|
|
54101
|
-
bridgeEchoPendingRef.current.clear();
|
|
54102
54171
|
for (const { traitName, result } of results) {
|
|
54103
54172
|
const binding = bindingMap.get(traitName);
|
|
54104
54173
|
const traitState = currentManager.getState(traitName);
|
|
@@ -54156,12 +54225,6 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
54156
54225
|
ui.perfEnd("processEvent:executeAll", _perfT2);
|
|
54157
54226
|
emittedByTrait.set(traitName, emittedDuringExec);
|
|
54158
54227
|
serverEffectResultsByTrait.set(traitName, transitionServerEffectResults);
|
|
54159
|
-
for (const emittedKey of emittedDuringExec) {
|
|
54160
|
-
bridgeEchoPendingRef.current.set(
|
|
54161
|
-
emittedKey,
|
|
54162
|
-
(bridgeEchoPendingRef.current.get(emittedKey) ?? 0) + 1
|
|
54163
|
-
);
|
|
54164
|
-
}
|
|
54165
54228
|
await reRenderCallsiteCaptureChildren(traitName, payload ?? {}, entityByTrait, stateLog);
|
|
54166
54229
|
} else if (!result.executed) {
|
|
54167
54230
|
if (result.guardResult === false) {
|
|
@@ -54235,6 +54298,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
54235
54298
|
// the verifier reads emittedEvents only.
|
|
54236
54299
|
orbitalName: "",
|
|
54237
54300
|
success: true,
|
|
54301
|
+
transitioned: true,
|
|
54238
54302
|
clientEffects: effectTraces.length,
|
|
54239
54303
|
dataEntities: {},
|
|
54240
54304
|
emittedEvents,
|
|
@@ -54256,7 +54320,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
54256
54320
|
if (orbital) dispatchedOrbitals.add(orbital);
|
|
54257
54321
|
}
|
|
54258
54322
|
const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
|
|
54259
|
-
|
|
54323
|
+
const locallyEmitted = Array.from(emittedByTrait.values()).flat();
|
|
54324
|
+
void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted);
|
|
54260
54325
|
}
|
|
54261
54326
|
ui.perfEnd("processEvent:total", _perfT0);
|
|
54262
54327
|
ui.perfEnd(`event:${normalizedEvent}`, _perfT0);
|
|
@@ -54323,14 +54388,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
54323
54388
|
subscribedBusKeys.add(selfBusKey);
|
|
54324
54389
|
crossTraitLog.debug("self:subscribe", { traitName, busKey: selfBusKey, eventKey });
|
|
54325
54390
|
const unsub = eventBus.on(selfBusKey, (event) => {
|
|
54326
|
-
if (event.source
|
|
54327
|
-
|
|
54328
|
-
|
|
54329
|
-
bridgeEchoPendingRef.current.set(eventKey, pendingEchoes - 1);
|
|
54330
|
-
crossTraitLog.debug("self:fire-skipped-bridge-echo", { traitName, busKey: selfBusKey, eventKey });
|
|
54331
|
-
return;
|
|
54332
|
-
}
|
|
54333
|
-
crossTraitLog.debug("self:fire-server-cascade", { traitName, busKey: selfBusKey, eventKey });
|
|
54391
|
+
if (event.source?.dispatched) {
|
|
54392
|
+
crossTraitLog.debug("self:fire-skipped-bridge-echo", { traitName, busKey: selfBusKey, eventKey });
|
|
54393
|
+
return;
|
|
54334
54394
|
}
|
|
54335
54395
|
crossTraitLog.debug("self:fire", { traitName, busKey: selfBusKey, eventKey });
|
|
54336
54396
|
enqueueAndDrain(eventKey, event.payload, traitName, event.source?.tick, event.source?.trait);
|
|
@@ -54699,7 +54759,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
54699
54759
|
[serverActiveTraits]
|
|
54700
54760
|
);
|
|
54701
54761
|
const uiSlots = context.useUISlots();
|
|
54702
|
-
const onEventProcessed = React87.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait) => {
|
|
54762
|
+
const onEventProcessed = React87.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted) => {
|
|
54703
54763
|
if (!bridge.connected || !orbitalNames?.length) return;
|
|
54704
54764
|
const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
|
|
54705
54765
|
xOrbitalLog.debug("TraitInitializer:fanout", () => ({
|
|
@@ -54713,7 +54773,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
54713
54773
|
void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
|
|
54714
54774
|
continue;
|
|
54715
54775
|
}
|
|
54716
|
-
void bridge.sendEvent(name, event, withActiveTraits(payload)).then(({ effects, meta }) => {
|
|
54776
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted).then(({ effects, meta }) => {
|
|
54717
54777
|
recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
|
|
54718
54778
|
applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
|
|
54719
54779
|
});
|
package/dist/runtime/index.d.cts
CHANGED
|
@@ -5,8 +5,8 @@ import * as _almadar_runtime from '@almadar/runtime';
|
|
|
5
5
|
import { TraitState, EffectHandlers } from '@almadar/runtime';
|
|
6
6
|
import { K as KeyCaptureTable } from '../useKeyboardRouter-CVn8lfiX.cjs';
|
|
7
7
|
import { c as useUISlots } from '../UISlotContext-BlRDbHDy.cjs';
|
|
8
|
-
import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-
|
|
9
|
-
export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-
|
|
8
|
+
import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-Dglbi9ks.cjs';
|
|
9
|
+
export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Dglbi9ks.cjs';
|
|
10
10
|
import '../verificationRegistry-DTrKDRoa.cjs';
|
|
11
11
|
export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
|
|
12
12
|
import React__default, { ReactNode } from 'react';
|
|
@@ -52,7 +52,9 @@ interface UseTraitStateMachineOptions {
|
|
|
52
52
|
* local state). `sourceTrait` is the emitting trait, for the
|
|
53
53
|
* server relay's BusEventSource.
|
|
54
54
|
*/
|
|
55
|
-
tick?: string, sourceTrait?: string
|
|
55
|
+
tick?: string, sourceTrait?: string,
|
|
56
|
+
/** Every event name this dispatch's local effect execution emitted, one entry per emit (multiplicity matters — see `stampLocallyDeliveredEchoes`). */
|
|
57
|
+
locallyEmitted?: readonly string[]) => void | Promise<void>;
|
|
56
58
|
/** Router navigate function for navigate effects. `crumb` labels the
|
|
57
59
|
* target page's navigation-stack entry (from the effect's options). */
|
|
58
60
|
navigate?: (path: string, params?: Record<string, string>, crumb?: string) => void;
|
|
@@ -220,6 +222,8 @@ interface CreateClientEffectHandlersOptions {
|
|
|
220
222
|
* it (the hook always binds one for `(set @entity.X)`).
|
|
221
223
|
*/
|
|
222
224
|
persistDelegated?: boolean;
|
|
225
|
+
/** Same bridge-mode delegation as `persistDelegated`, for `(call-service …)`: set when no consumer `callService` is wired, so the executor skips the mock fallback below and the server's cascade carries the result. */
|
|
226
|
+
callServiceDelegated?: boolean;
|
|
223
227
|
/**
|
|
224
228
|
* Optional consumer-supplied call-service handler. When set, it runs
|
|
225
229
|
* instead of the default mock fallback — use to wire the playground
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ import * as _almadar_runtime from '@almadar/runtime';
|
|
|
5
5
|
import { TraitState, EffectHandlers } from '@almadar/runtime';
|
|
6
6
|
import { K as KeyCaptureTable } from '../useKeyboardRouter-B1pIi9jo.js';
|
|
7
7
|
import { c as useUISlots } from '../UISlotContext-CB89mv7N.js';
|
|
8
|
-
import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-
|
|
9
|
-
export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-
|
|
8
|
+
import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-Dglbi9ks.js';
|
|
9
|
+
export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Dglbi9ks.js';
|
|
10
10
|
import '../verificationRegistry-Cwa52VyK.js';
|
|
11
11
|
export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
|
|
12
12
|
import React__default, { ReactNode } from 'react';
|
|
@@ -52,7 +52,9 @@ interface UseTraitStateMachineOptions {
|
|
|
52
52
|
* local state). `sourceTrait` is the emitting trait, for the
|
|
53
53
|
* server relay's BusEventSource.
|
|
54
54
|
*/
|
|
55
|
-
tick?: string, sourceTrait?: string
|
|
55
|
+
tick?: string, sourceTrait?: string,
|
|
56
|
+
/** Every event name this dispatch's local effect execution emitted, one entry per emit (multiplicity matters — see `stampLocallyDeliveredEchoes`). */
|
|
57
|
+
locallyEmitted?: readonly string[]) => void | Promise<void>;
|
|
56
58
|
/** Router navigate function for navigate effects. `crumb` labels the
|
|
57
59
|
* target page's navigation-stack entry (from the effect's options). */
|
|
58
60
|
navigate?: (path: string, params?: Record<string, string>, crumb?: string) => void;
|
|
@@ -220,6 +222,8 @@ interface CreateClientEffectHandlersOptions {
|
|
|
220
222
|
* it (the hook always binds one for `(set @entity.X)`).
|
|
221
223
|
*/
|
|
222
224
|
persistDelegated?: boolean;
|
|
225
|
+
/** Same bridge-mode delegation as `persistDelegated`, for `(call-service …)`: set when no consumer `callService` is wired, so the executor skips the mock fallback below and the server's cascade carries the result. */
|
|
226
|
+
callServiceDelegated?: boolean;
|
|
223
227
|
/**
|
|
224
228
|
* Optional consumer-supplied call-service handler. When set, it runs
|
|
225
229
|
* instead of the default mock fallback — use to wire the playground
|