@almadar/std 4.0.0 → 5.0.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/behaviors/exports-reader.js +71 -122
- package/dist/behaviors/exports-reader.js.map +1 -1
- package/dist/behaviors/functions/index.d.ts +10 -4
- package/dist/behaviors/functions/index.js +71 -122
- package/dist/behaviors/functions/index.js.map +1 -1
- package/dist/behaviors/index.js +71 -122
- package/dist/behaviors/index.js.map +1 -1
- package/dist/behaviors/query.js +71 -122
- package/dist/behaviors/query.js.map +1 -1
- package/dist/index.js +71 -122
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -656,19 +656,14 @@ function buildTrait(c) {
|
|
|
656
656
|
const actionEvents = /* @__PURE__ */ new Set();
|
|
657
657
|
for (const a of c.headerActions) actionEvents.add(a.event);
|
|
658
658
|
for (const a of c.itemActions) actionEvents.add(a.event);
|
|
659
|
-
for (const re of c.refreshEvents) actionEvents.add(re);
|
|
660
659
|
const events = [
|
|
661
660
|
{ key: "INIT", name: "Initialize" },
|
|
662
661
|
...Array.from(actionEvents).map((e) => {
|
|
663
662
|
const needsId = c.itemActions.some((a) => a.event === e);
|
|
664
|
-
const isRefresh = c.refreshEvents.includes(e);
|
|
665
|
-
if (isRefresh) {
|
|
666
|
-
return { key: e, name: e, payload: [{ name: "data", type: "object", required: true }] };
|
|
667
|
-
}
|
|
668
663
|
return needsId ? { key: e, name: e, payload: [{ name: "id", type: "string", required: true }, { name: "row", type: "object" }] } : { key: e, name: e };
|
|
669
664
|
})
|
|
670
665
|
];
|
|
671
|
-
const listensDecl = c.refreshEvents.length > 0 ? c.refreshEvents.map((evt) => ({ event: evt, triggers:
|
|
666
|
+
const listensDecl = c.refreshEvents.length > 0 ? c.refreshEvents.map((evt) => ({ event: evt, triggers: "INIT" })) : void 0;
|
|
672
667
|
return {
|
|
673
668
|
name: c.traitName,
|
|
674
669
|
linkedEntity: entityName,
|
|
@@ -705,14 +700,7 @@ function buildTrait(c) {
|
|
|
705
700
|
]
|
|
706
701
|
}]
|
|
707
702
|
]
|
|
708
|
-
}
|
|
709
|
-
// Refresh self-loops: when modal atoms fire SAVE etc., re-fetch data
|
|
710
|
-
...c.refreshEvents.map((evt) => ({
|
|
711
|
-
from: "browsing",
|
|
712
|
-
to: "browsing",
|
|
713
|
-
event: evt,
|
|
714
|
-
effects: [["ref", entityName]]
|
|
715
|
-
}))
|
|
703
|
+
}
|
|
716
704
|
]
|
|
717
705
|
}
|
|
718
706
|
};
|
|
@@ -770,6 +758,8 @@ function resolve2(params) {
|
|
|
770
758
|
}
|
|
771
759
|
]
|
|
772
760
|
};
|
|
761
|
+
const saveEvent = params.saveEvent ?? "SAVE";
|
|
762
|
+
const emitOnSave = params.emitOnSave ?? saveEvent;
|
|
773
763
|
return {
|
|
774
764
|
entityName,
|
|
775
765
|
fields,
|
|
@@ -783,9 +773,9 @@ function resolve2(params) {
|
|
|
783
773
|
openPayload: params.openPayload ?? [],
|
|
784
774
|
closeEvent: params.closeEvent ?? "CLOSE",
|
|
785
775
|
openEffects: params.openEffects ?? [],
|
|
786
|
-
saveEvent
|
|
776
|
+
saveEvent,
|
|
787
777
|
saveEffects: params.saveEffects ?? [],
|
|
788
|
-
emitOnSave
|
|
778
|
+
emitOnSave,
|
|
789
779
|
standalone: params.standalone ?? true,
|
|
790
780
|
pageName: params.pageName ?? `${entityName}ModalPage`,
|
|
791
781
|
pagePath: params.pagePath ?? `/${p.toLowerCase()}/modal`,
|
|
@@ -799,11 +789,9 @@ function buildTrait2(c) {
|
|
|
799
789
|
const events = [
|
|
800
790
|
{ key: "INIT", name: "Initialize" },
|
|
801
791
|
{ key: c.openEvent, name: "Open", ...c.openPayload.length > 0 ? { payload: c.openPayload } : {} },
|
|
802
|
-
{ key: c.closeEvent, name: "Close" }
|
|
792
|
+
{ key: c.closeEvent, name: "Close" },
|
|
793
|
+
{ key: c.saveEvent, name: "Save", payload: [{ name: "data", type: "object", required: true }] }
|
|
803
794
|
];
|
|
804
|
-
if (c.saveEvent) {
|
|
805
|
-
events.push({ key: c.saveEvent, name: "Save", payload: [{ name: "data", type: "object", required: true }] });
|
|
806
|
-
}
|
|
807
795
|
const transitions = [
|
|
808
796
|
// INIT: closed → closed
|
|
809
797
|
{
|
|
@@ -856,41 +844,44 @@ function buildTrait2(c) {
|
|
|
856
844
|
}]] : []
|
|
857
845
|
] }
|
|
858
846
|
];
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
children: [
|
|
865
|
-
{ type: "stack", direction: "horizontal", gap: "md",
|
|
866
|
-
{ type: "
|
|
867
|
-
|
|
868
|
-
{ type: "typography", content: c.modalTitle, variant: "h2" }
|
|
869
|
-
] },
|
|
870
|
-
{ type: "button", label: "Open", event: c.openEvent, variant: "primary", icon: c.headerIcon }
|
|
847
|
+
const mainRefresh = c.standalone ? [["ref", c.entityName], ["render-ui", "main", {
|
|
848
|
+
type: "stack",
|
|
849
|
+
direction: "vertical",
|
|
850
|
+
gap: "lg",
|
|
851
|
+
children: [
|
|
852
|
+
{ type: "stack", direction: "horizontal", gap: "md", justify: "space-between", children: [
|
|
853
|
+
{ type: "stack", direction: "horizontal", gap: "md", children: [
|
|
854
|
+
{ type: "icon", name: c.headerIcon, size: "lg" },
|
|
855
|
+
{ type: "typography", content: c.modalTitle, variant: "h2" }
|
|
871
856
|
] },
|
|
872
|
-
{ type: "
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
857
|
+
{ type: "button", label: "Open", event: c.openEvent, variant: "primary", icon: c.headerIcon }
|
|
858
|
+
] },
|
|
859
|
+
{ type: "divider" },
|
|
860
|
+
{ type: "empty-state", icon: c.headerIcon, title: "Nothing open", description: "Click Open to view details in a modal overlay." }
|
|
861
|
+
]
|
|
862
|
+
}]] : [];
|
|
863
|
+
transitions.push({
|
|
864
|
+
from: "open",
|
|
865
|
+
to: "closed",
|
|
866
|
+
event: c.saveEvent,
|
|
867
|
+
effects: [
|
|
868
|
+
...c.saveEffects,
|
|
869
|
+
["render-ui", "modal", null],
|
|
870
|
+
// Emit after persist succeeds so browse traits can fetch fresh data.
|
|
871
|
+
// Skip the emit when emitOnSave equals saveEvent — that's a self-emit
|
|
872
|
+
// that the runtime would short-circuit anyway, and avoids double
|
|
873
|
+
// dispatch on every save.
|
|
874
|
+
...c.emitOnSave !== c.saveEvent ? [["emit", c.emitOnSave]] : [],
|
|
875
|
+
...mainRefresh
|
|
876
|
+
]
|
|
877
|
+
});
|
|
889
878
|
return {
|
|
890
879
|
name: c.traitName,
|
|
891
880
|
linkedEntity: c.entityName,
|
|
892
881
|
category: "interaction",
|
|
893
|
-
|
|
882
|
+
// Phase F.10: emits[] is always populated (default emitOnSave = saveEvent).
|
|
883
|
+
// If a molecule supplies a distinct emitOnSave, declare both events.
|
|
884
|
+
emits: c.emitOnSave === c.saveEvent ? [{ event: c.saveEvent }] : [{ event: c.saveEvent }, { event: c.emitOnSave }],
|
|
894
885
|
stateMachine: {
|
|
895
886
|
states: [{ name: "closed", isInitial: true }, { name: "open" }],
|
|
896
887
|
events,
|
|
@@ -919,6 +910,8 @@ function resolve3(params) {
|
|
|
919
910
|
const fields = ensureIdField(params.fields);
|
|
920
911
|
const nonIdFields = fields.filter((f) => f.name !== "id");
|
|
921
912
|
const p = plural(entityName);
|
|
913
|
+
const confirmEvent = params.confirmEvent ?? "CONFIRM";
|
|
914
|
+
const emitOnConfirm = params.emitOnConfirm ?? confirmEvent;
|
|
922
915
|
return {
|
|
923
916
|
entityName,
|
|
924
917
|
fields,
|
|
@@ -932,9 +925,9 @@ function resolve3(params) {
|
|
|
932
925
|
cancelLabel: params.cancelLabel ?? "Cancel",
|
|
933
926
|
headerIcon: params.headerIcon ?? "shield-check",
|
|
934
927
|
requestEvent: params.requestEvent ?? "REQUEST",
|
|
935
|
-
confirmEvent
|
|
928
|
+
confirmEvent,
|
|
936
929
|
confirmEffects: params.confirmEffects ?? [],
|
|
937
|
-
emitOnConfirm
|
|
930
|
+
emitOnConfirm,
|
|
938
931
|
standalone: params.standalone ?? true,
|
|
939
932
|
pageName: params.pageName ?? `${entityName}ConfirmPage`,
|
|
940
933
|
pagePath: params.pagePath ?? `/${p.toLowerCase()}/confirm`,
|
|
@@ -1014,7 +1007,9 @@ function buildTrait3(c) {
|
|
|
1014
1007
|
name: c.traitName,
|
|
1015
1008
|
linkedEntity: entityName,
|
|
1016
1009
|
category: "interaction",
|
|
1017
|
-
|
|
1010
|
+
// Phase F.10: emits[] always populated. When emitOnConfirm equals
|
|
1011
|
+
// confirmEvent, declare just the one. When they differ, declare both.
|
|
1012
|
+
emits: c.emitOnConfirm === c.confirmEvent ? [{ event: c.confirmEvent }] : [{ event: c.confirmEvent }, { event: c.emitOnConfirm }],
|
|
1018
1013
|
stateMachine: {
|
|
1019
1014
|
states: [
|
|
1020
1015
|
{ name: "idle", isInitial: true },
|
|
@@ -1051,7 +1046,9 @@ function buildTrait3(c) {
|
|
|
1051
1046
|
effects: [
|
|
1052
1047
|
...c.confirmEffects,
|
|
1053
1048
|
...dismissAndRefresh,
|
|
1054
|
-
|
|
1049
|
+
// Skip self-emit when emitOnConfirm == confirmEvent (the runtime
|
|
1050
|
+
// would short-circuit anyway).
|
|
1051
|
+
...c.emitOnConfirm !== c.confirmEvent ? [["emit", c.emitOnConfirm]] : []
|
|
1055
1052
|
]
|
|
1056
1053
|
},
|
|
1057
1054
|
{
|
|
@@ -8910,6 +8907,7 @@ function stdList(params) {
|
|
|
8910
8907
|
const UPPER = entityName.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase();
|
|
8911
8908
|
const CREATED = `${UPPER}_CREATED`;
|
|
8912
8909
|
const UPDATED = `${UPPER}_UPDATED`;
|
|
8910
|
+
const DELETED = `${UPPER}_DELETED`;
|
|
8913
8911
|
const browseTrait = extractTrait(stdBrowse({
|
|
8914
8912
|
entityName,
|
|
8915
8913
|
fields,
|
|
@@ -8930,7 +8928,7 @@ function stdList(params) {
|
|
|
8930
8928
|
{ label: "Edit", event: "EDIT" },
|
|
8931
8929
|
{ label: "Delete", event: "DELETE", variant: "danger" }
|
|
8932
8930
|
],
|
|
8933
|
-
refreshEvents: [CREATED, UPDATED]
|
|
8931
|
+
refreshEvents: [CREATED, UPDATED, DELETED]
|
|
8934
8932
|
}));
|
|
8935
8933
|
const createTrait = extractTrait(stdModal({
|
|
8936
8934
|
standalone: false,
|
|
@@ -8976,62 +8974,20 @@ function stdList(params) {
|
|
|
8976
8974
|
closeEvent: "CLOSE",
|
|
8977
8975
|
openEffects: [["fetch", entityName, { id: "@payload.id" }]]
|
|
8978
8976
|
}));
|
|
8979
|
-
const
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
);
|
|
8993
|
-
const browseMainView = initRenderEffect ? initRenderEffect[2] : null;
|
|
8994
|
-
sm.transitions.push(
|
|
8995
|
-
// DELETE: browsing → deleting (fetch entity by ID, show confirmation modal)
|
|
8996
|
-
{ from: "browsing", to: "deleting", event: "DELETE", effects: [
|
|
8997
|
-
["fetch", entityName, { id: "@payload.id" }],
|
|
8998
|
-
["render-ui", "modal", {
|
|
8999
|
-
type: "stack",
|
|
9000
|
-
direction: "vertical",
|
|
9001
|
-
gap: "md",
|
|
9002
|
-
children: [
|
|
9003
|
-
{ type: "stack", direction: "horizontal", gap: "sm", children: [
|
|
9004
|
-
{ type: "icon", name: "trash-2", size: "md" },
|
|
9005
|
-
{ type: "typography", content: `Delete ${entityName}`, variant: "h3" }
|
|
9006
|
-
] },
|
|
9007
|
-
{ type: "divider" },
|
|
9008
|
-
{ type: "typography", content: `@entity.${c.nonIdFields[0]?.name ?? "name"}`, variant: "h4" },
|
|
9009
|
-
{ type: "typography", content: c.deleteMessage, variant: "body" },
|
|
9010
|
-
{ type: "stack", direction: "horizontal", gap: "sm", justify: "end", children: [
|
|
9011
|
-
{ type: "button", label: "Cancel", event: "CANCEL", variant: "ghost" },
|
|
9012
|
-
{ type: "button", label: "Delete", event: "CONFIRM_DELETE", variant: "danger", icon: "trash" }
|
|
9013
|
-
] }
|
|
9014
|
-
]
|
|
9015
|
-
}]
|
|
9016
|
-
] },
|
|
9017
|
-
// CONFIRM_DELETE: deleting → browsing (persist delete, dismiss modal, re-render main)
|
|
9018
|
-
{ from: "deleting", to: "browsing", event: "CONFIRM_DELETE", effects: [
|
|
9019
|
-
["persist", "delete", entityName, "@entity.id"],
|
|
9020
|
-
["render-ui", "modal", null],
|
|
9021
|
-
["render-ui", "main", browseMainView]
|
|
9022
|
-
] },
|
|
9023
|
-
// CANCEL/CLOSE from deleting (dismiss modal, re-render main)
|
|
9024
|
-
{ from: "deleting", to: "browsing", event: "CANCEL", effects: [
|
|
9025
|
-
["render-ui", "modal", null],
|
|
9026
|
-
["fetch", entityName],
|
|
9027
|
-
["render-ui", "main", browseMainView]
|
|
9028
|
-
] },
|
|
9029
|
-
{ from: "deleting", to: "browsing", event: "CLOSE", effects: [
|
|
9030
|
-
["render-ui", "modal", null],
|
|
9031
|
-
["fetch", entityName],
|
|
9032
|
-
["render-ui", "main", browseMainView]
|
|
9033
|
-
] }
|
|
9034
|
-
);
|
|
8977
|
+
const deleteTrait = extractTrait(stdConfirmation({
|
|
8978
|
+
standalone: false,
|
|
8979
|
+
entityName,
|
|
8980
|
+
fields,
|
|
8981
|
+
traitName: `${entityName}Delete`,
|
|
8982
|
+
confirmTitle: `Delete ${entityName}`,
|
|
8983
|
+
confirmMessage: c.deleteMessage,
|
|
8984
|
+
confirmLabel: "Delete",
|
|
8985
|
+
headerIcon: "trash-2",
|
|
8986
|
+
requestEvent: "DELETE",
|
|
8987
|
+
confirmEvent: "CONFIRM_DELETE",
|
|
8988
|
+
confirmEffects: [["persist", "delete", entityName, "@entity.pendingId"]],
|
|
8989
|
+
emitOnConfirm: DELETED
|
|
8990
|
+
}));
|
|
9035
8991
|
const entity = makeEntity({ name: entityName, fields, persistence: c.persistence, collection: c.collection });
|
|
9036
8992
|
const page = {
|
|
9037
8993
|
name: c.pageName,
|
|
@@ -9041,13 +8997,14 @@ function stdList(params) {
|
|
|
9041
8997
|
{ ref: browseTrait.name },
|
|
9042
8998
|
{ ref: createTrait.name },
|
|
9043
8999
|
{ ref: editTrait.name },
|
|
9044
|
-
{ ref: viewTrait.name }
|
|
9000
|
+
{ ref: viewTrait.name },
|
|
9001
|
+
{ ref: deleteTrait.name }
|
|
9045
9002
|
]
|
|
9046
9003
|
};
|
|
9047
9004
|
return {
|
|
9048
9005
|
name: `${entityName}Orbital`,
|
|
9049
9006
|
entity,
|
|
9050
|
-
traits: [browseTrait, createTrait, editTrait, viewTrait],
|
|
9007
|
+
traits: [browseTrait, createTrait, editTrait, viewTrait, deleteTrait],
|
|
9051
9008
|
pages: [page]
|
|
9052
9009
|
};
|
|
9053
9010
|
}
|
|
@@ -9535,17 +9492,9 @@ function stdInventory(params) {
|
|
|
9535
9492
|
headerIcon: "trash-2",
|
|
9536
9493
|
requestEvent: "DROP",
|
|
9537
9494
|
confirmEvent: "CONFIRM_DROP",
|
|
9538
|
-
confirmEffects: [["persist", "delete", entityName, "@
|
|
9495
|
+
confirmEffects: [["persist", "delete", entityName, "@entity.pendingId"]],
|
|
9539
9496
|
emitOnConfirm: "CONFIRM_DROP"
|
|
9540
9497
|
}));
|
|
9541
|
-
const dropSm = dropTrait.stateMachine;
|
|
9542
|
-
if (dropSm && "events" in dropSm) {
|
|
9543
|
-
const events = dropSm.events;
|
|
9544
|
-
const confirmDropEvt = events.find((e) => e.key === "CONFIRM_DROP");
|
|
9545
|
-
if (confirmDropEvt && !confirmDropEvt.payload) {
|
|
9546
|
-
confirmDropEvt.payload = [{ name: "id", type: "string", required: true }];
|
|
9547
|
-
}
|
|
9548
|
-
}
|
|
9549
9498
|
const instances = [
|
|
9550
9499
|
{ id: "item-1", name: "Health Potion", description: "Restores 50 HP", status: "active", pendingId: "" },
|
|
9551
9500
|
{ id: "item-2", name: "Iron Sword", description: "A sturdy blade", status: "active", pendingId: "" },
|