@fuaran-ui/ops 0.1.0 → 0.2.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/README.md +2 -2
- package/dist/index.cjs +19 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -2
- package/dist/index.d.ts +0 -2
- package/dist/index.js +19 -132
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Canonical-JSON codec (encoder + structural decoder) and tree-op apply engine for
|
|
4
4
|
the Fuaran UI wire format — a conformant **TypeScript host** of the
|
|
5
5
|
language-neutral contract specified in
|
|
6
|
-
[`fuaran/docs/WIRE_FORMAT.md`](../../../fuaran/docs/WIRE_FORMAT.md), sibling to the
|
|
6
|
+
[`fuaran-dotnet/docs/WIRE_FORMAT.md`](../../../fuaran-dotnet/docs/WIRE_FORMAT.md), sibling to the
|
|
7
7
|
F# host. Built on the typed shapes from
|
|
8
8
|
[`@fuaran-ui/schema`](../schema/) (a peer dependency).
|
|
9
9
|
|
|
@@ -73,7 +73,7 @@ of the erased payloads is the host's responsibility.
|
|
|
73
73
|
## Conformance is the stability contract
|
|
74
74
|
|
|
75
75
|
Per the wire-format **forward-coupling rule**
|
|
76
|
-
([`WIRE_FORMAT.md` §11](../../../fuaran/docs/WIRE_FORMAT.md)), adding a `NodeKind` / `Spec`
|
|
76
|
+
([`WIRE_FORMAT.md` §11](../../../fuaran-dotnet/docs/WIRE_FORMAT.md)), adding a `NodeKind` / `Spec`
|
|
77
77
|
/ `TreeOp` / `Binding` / `Action` case updates the F# encoder + decoder + the corpus
|
|
78
78
|
**and** this TS codec + `@fuaran-ui/schema` in the same commit. Byte-equality against the
|
|
79
79
|
corpus — not just API non-breakage — is the contract.
|
package/dist/index.cjs
CHANGED
|
@@ -362,8 +362,10 @@ var flushTrigger = (t) => {
|
|
|
362
362
|
};
|
|
363
363
|
var binding = (b, staticEnc = objValue) => {
|
|
364
364
|
switch (b.kind) {
|
|
365
|
-
case "Static":
|
|
366
|
-
|
|
365
|
+
case "Static": {
|
|
366
|
+
const valueFields = b.value === null || b.value === void 0 ? [] : [["value", staticEnc(b.value)]];
|
|
367
|
+
return caseObj("Static", valueFields);
|
|
368
|
+
}
|
|
367
369
|
case "Query": {
|
|
368
370
|
const dependsOnFields = b.dependsOn !== void 0 && b.dependsOn.length > 0 ? [["dependsOn", jArray(b.dependsOn.map((s) => str(s)))]] : [];
|
|
369
371
|
return caseObj("Query", [...dependsOnFields, ["name", str(b.name)]]);
|
|
@@ -377,11 +379,10 @@ var binding = (b, staticEnc = objValue) => {
|
|
|
377
379
|
const fieldField = b.field !== void 0 ? [["field", str(b.field)]] : [];
|
|
378
380
|
return caseObj("Selection", [...defaultField, ...fieldField, ["nodeId", str(b.nodeId)]]);
|
|
379
381
|
}
|
|
380
|
-
case "State":
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
]);
|
|
382
|
+
case "State": {
|
|
383
|
+
const defaultFields = b.defaultValue === null || b.defaultValue === void 0 ? [] : [["defaultValue", staticEnc(b.defaultValue)]];
|
|
384
|
+
return caseObj("State", [...defaultFields, ["key", str(b.key)]]);
|
|
385
|
+
}
|
|
385
386
|
case "Computed":
|
|
386
387
|
return caseObj("Computed", [["fn", CLOSURE]]);
|
|
387
388
|
case "I18n": {
|
|
@@ -1517,15 +1518,13 @@ var treeOp = (op) => {
|
|
|
1517
1518
|
case "InsertChild":
|
|
1518
1519
|
return caseObj("InsertChild", [
|
|
1519
1520
|
["child", node(op.child)],
|
|
1520
|
-
["parentId", str(op.parentId)]
|
|
1521
|
-
["position", num(op.position)]
|
|
1521
|
+
["parentId", str(op.parentId)]
|
|
1522
1522
|
]);
|
|
1523
1523
|
case "RemoveNode":
|
|
1524
1524
|
return caseObj("RemoveNode", [["target", str(op.target)]]);
|
|
1525
1525
|
case "MoveNode":
|
|
1526
1526
|
return caseObj("MoveNode", [
|
|
1527
1527
|
["newParentId", str(op.newParentId)],
|
|
1528
|
-
["newPosition", num(op.newPosition)],
|
|
1529
1528
|
["target", str(op.target)]
|
|
1530
1529
|
]);
|
|
1531
1530
|
case "ReorderChildren":
|
|
@@ -4034,9 +4033,8 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
|
|
|
4034
4033
|
if (!d.ok) return d;
|
|
4035
4034
|
switch (d.value) {
|
|
4036
4035
|
case "Static": {
|
|
4037
|
-
const
|
|
4038
|
-
|
|
4039
|
-
const parsed = parseStatic(`${path}.value`, v.value);
|
|
4036
|
+
const raw = f.get("value") ?? { kind: "JNull" };
|
|
4037
|
+
const parsed = parseStatic(`${path}.value`, raw);
|
|
4040
4038
|
return parsed.ok ? ok({ kind: "Static", value: parsed.value }) : parsed;
|
|
4041
4039
|
}
|
|
4042
4040
|
case "Query": {
|
|
@@ -4113,7 +4111,7 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
|
|
|
4113
4111
|
case "State": {
|
|
4114
4112
|
const key = reqField(path, f, "key", "state key string", requireString);
|
|
4115
4113
|
if (!key.ok) return key;
|
|
4116
|
-
const dv = fieldAliased(f, "defaultValue", ["initialValue", "default"]);
|
|
4114
|
+
const dv = fieldAliased(f, "defaultValue", ["initialValue", "default"]) ?? { kind: "JNull" };
|
|
4117
4115
|
let defaultValue = placeholder;
|
|
4118
4116
|
if (dv !== void 0) {
|
|
4119
4117
|
const parsed = parseStatic(`${path}.defaultValue`, dv);
|
|
@@ -5828,23 +5826,6 @@ var decodeVisKind = (path, j) => {
|
|
|
5828
5826
|
const r = decodeChartSpec(path, j);
|
|
5829
5827
|
return r.ok ? ok({ kind: "Chart", spec: r.value }) : r;
|
|
5830
5828
|
}
|
|
5831
|
-
// Phase 393 — legacy decode-upgrade: a `Table` tag folds into a read-only `Grid`
|
|
5832
|
-
// (the `staticRows` mode). Accepted on read but NEVER re-encodes as `Table` (the
|
|
5833
|
-
// encoder has no `Table` arm), riding the Phase 390 retired-kind seam.
|
|
5834
|
-
case "Table": {
|
|
5835
|
-
const r = decodeStaticRows(path, j);
|
|
5836
|
-
return r.ok ? ok({
|
|
5837
|
-
kind: "Grid",
|
|
5838
|
-
spec: {
|
|
5839
|
-
// An opaque Static source re-encodes to {"$type":"Static","value":"<opaque>"} —
|
|
5840
|
-
// byte-identical to the F# static grid's `Binding.Static Seq.empty`.
|
|
5841
|
-
source: { kind: "Static", value: OPAQUE2 },
|
|
5842
|
-
columns: [],
|
|
5843
|
-
editable: false,
|
|
5844
|
-
staticRows: r.value
|
|
5845
|
-
}
|
|
5846
|
-
}) : r;
|
|
5847
|
-
}
|
|
5848
5829
|
case "Map": {
|
|
5849
5830
|
const r = decodeMapSpec(path, j);
|
|
5850
5831
|
return r.ok ? ok({ kind: "Map", spec: r.value }) : r;
|
|
@@ -5936,64 +5917,6 @@ var decodeBox = (path, j) => {
|
|
|
5936
5917
|
role: role.value
|
|
5937
5918
|
});
|
|
5938
5919
|
};
|
|
5939
|
-
var decodeLegacyDashboard = (path, j) => {
|
|
5940
|
-
const fo = requireObject(path, j);
|
|
5941
|
-
if (!fo.ok) return fo;
|
|
5942
|
-
const children = decodeChildren(path, fo.value);
|
|
5943
|
-
if (!children.ok) return children;
|
|
5944
|
-
return ok({ children: children.value, layout: { kind: "Auto" }, role: "Dashboard" });
|
|
5945
|
-
};
|
|
5946
|
-
var decodeLegacyStack = (path, j) => {
|
|
5947
|
-
const fo = requireObject(path, j);
|
|
5948
|
-
if (!fo.ok) return fo;
|
|
5949
|
-
const f = fo.value;
|
|
5950
|
-
const children = decodeChildren(path, f);
|
|
5951
|
-
if (!children.ok) return children;
|
|
5952
|
-
const orientation = reqField(path, f, "orientation", "Orientation", decodeOrientation);
|
|
5953
|
-
if (!orientation.ok) return orientation;
|
|
5954
|
-
const wrap = reqField(path, f, "wrap", "wrap bool", requireBool);
|
|
5955
|
-
if (!wrap.ok) return wrap;
|
|
5956
|
-
return ok({
|
|
5957
|
-
children: children.value,
|
|
5958
|
-
layout: { kind: "Flex", direction: orientation.value, wrap: wrap.value },
|
|
5959
|
-
role: "Group"
|
|
5960
|
-
});
|
|
5961
|
-
};
|
|
5962
|
-
var decodeLegacyGridLayout = (path, j) => {
|
|
5963
|
-
const fo = requireObject(path, j);
|
|
5964
|
-
if (!fo.ok) return fo;
|
|
5965
|
-
const f = fo.value;
|
|
5966
|
-
const children = decodeChildren(path, f);
|
|
5967
|
-
if (!children.ok) return children;
|
|
5968
|
-
const cols = reqFieldAliased(path, f, "cols", ["columns"], "cols integer", requireInt);
|
|
5969
|
-
if (!cols.ok) return cols;
|
|
5970
|
-
const templateColumns = optField(path, f, "templateColumns", requireString);
|
|
5971
|
-
if (!templateColumns.ok) return templateColumns;
|
|
5972
|
-
return ok({
|
|
5973
|
-
children: children.value,
|
|
5974
|
-
layout: {
|
|
5975
|
-
kind: "Grid",
|
|
5976
|
-
cols: cols.value,
|
|
5977
|
-
...templateColumns.value !== void 0 ? { templateColumns: templateColumns.value } : {}
|
|
5978
|
-
},
|
|
5979
|
-
role: "Group"
|
|
5980
|
-
});
|
|
5981
|
-
};
|
|
5982
|
-
var decodeLegacyCard = (path, j) => {
|
|
5983
|
-
const fo = requireObject(path, j);
|
|
5984
|
-
if (!fo.ok) return fo;
|
|
5985
|
-
const f = fo.value;
|
|
5986
|
-
const children = decodeChildren(path, f);
|
|
5987
|
-
if (!children.ok) return children;
|
|
5988
|
-
const heading = optFieldAliased(path, f, "heading", ["title"], decodeTextSource);
|
|
5989
|
-
if (!heading.ok) return heading;
|
|
5990
|
-
return ok({
|
|
5991
|
-
children: children.value,
|
|
5992
|
-
...heading.value !== void 0 ? { heading: heading.value } : {},
|
|
5993
|
-
layout: { kind: "Flex", direction: "Vertical", wrap: false },
|
|
5994
|
-
role: "Card"
|
|
5995
|
-
});
|
|
5996
|
-
};
|
|
5997
5920
|
var decodeSplitPanelSpec = (path, j) => {
|
|
5998
5921
|
const fo = requireObject(path, j);
|
|
5999
5922
|
if (!fo.ok) return fo;
|
|
@@ -6183,22 +6106,6 @@ var decodeLayoutKind = (path, j) => {
|
|
|
6183
6106
|
const r = decodeBox(path, j);
|
|
6184
6107
|
return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
|
|
6185
6108
|
}
|
|
6186
|
-
case "Dashboard": {
|
|
6187
|
-
const r = decodeLegacyDashboard(path, j);
|
|
6188
|
-
return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
|
|
6189
|
-
}
|
|
6190
|
-
case "Stack": {
|
|
6191
|
-
const r = decodeLegacyStack(path, j);
|
|
6192
|
-
return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
|
|
6193
|
-
}
|
|
6194
|
-
case "GridLayout": {
|
|
6195
|
-
const r = decodeLegacyGridLayout(path, j);
|
|
6196
|
-
return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
|
|
6197
|
-
}
|
|
6198
|
-
case "Card": {
|
|
6199
|
-
const r = decodeLegacyCard(path, j);
|
|
6200
|
-
return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
|
|
6201
|
-
}
|
|
6202
6109
|
case "SplitPanel": {
|
|
6203
6110
|
const r = decodeSplitPanelSpec(path, j);
|
|
6204
6111
|
return r.ok ? ok({ kind: "SplitPanel", spec: r.value }) : r;
|
|
@@ -6231,7 +6138,7 @@ var decodeLayoutKind = (path, j) => {
|
|
|
6231
6138
|
return unknownDuCase(
|
|
6232
6139
|
path,
|
|
6233
6140
|
d.value,
|
|
6234
|
-
"Box |
|
|
6141
|
+
"Box | SplitPanel | Tabs | Stepper | SummaryList | Disclosure | Modal | ScrollArea"
|
|
6235
6142
|
);
|
|
6236
6143
|
}
|
|
6237
6144
|
};
|
|
@@ -6407,12 +6314,8 @@ var decodeNodeKind = (path, j) => {
|
|
|
6407
6314
|
// each primitive to its inner decoder and recover the category here. These
|
|
6408
6315
|
// name-sets MUST stay in sync with the four inner decoders + the encoder.
|
|
6409
6316
|
case "Box":
|
|
6410
|
-
case "Dashboard":
|
|
6411
|
-
case "Stack":
|
|
6412
|
-
case "GridLayout":
|
|
6413
6317
|
case "SplitPanel":
|
|
6414
6318
|
case "Tabs":
|
|
6415
|
-
case "Card":
|
|
6416
6319
|
case "Stepper":
|
|
6417
6320
|
case "SummaryList":
|
|
6418
6321
|
case "Disclosure":
|
|
@@ -6451,7 +6354,6 @@ var decodeNodeKind = (path, j) => {
|
|
|
6451
6354
|
}
|
|
6452
6355
|
case "DataGrid":
|
|
6453
6356
|
case "Chart":
|
|
6454
|
-
case "Table":
|
|
6455
6357
|
case "Map": {
|
|
6456
6358
|
const k = decodeVisKind(path, j);
|
|
6457
6359
|
return k.ok ? ok({ kind: "Visualisation", visualisation: k.value }) : k;
|
|
@@ -6654,7 +6556,7 @@ var decodeNodeKind = (path, j) => {
|
|
|
6654
6556
|
"WRONG_NODE_KIND",
|
|
6655
6557
|
`${path}.$type`,
|
|
6656
6558
|
`unknown NodeKind discriminator '${d.value}'`,
|
|
6657
|
-
"a Layout primitive (
|
|
6559
|
+
"a Layout primitive (Box | SplitPanel | Tabs | Stepper | SummaryList | Disclosure | Modal | ScrollArea), a Display primitive (Heading | Markdown | Metric | Badge | Sparkline | Callout | Progress | Skeleton | LabelValueRow | Link | Image | List | Toast), an Input primitive (Form | Filters | Button | FileUpload | Select), a Visualisation primitive (DataGrid | Chart | Map), or Custom | ErrorBoundary | FragmentDecl | FragmentRef | Mount"
|
|
6658
6560
|
);
|
|
6659
6561
|
}
|
|
6660
6562
|
};
|
|
@@ -6825,13 +6727,10 @@ var decodeTreeOpAst = (path, j) => {
|
|
|
6825
6727
|
case "InsertChild": {
|
|
6826
6728
|
const parentJ = reqField(path, f, "parentId", "parent NodeId", requireString);
|
|
6827
6729
|
if (!parentJ.ok) return parentJ;
|
|
6828
|
-
const position = reqField(path, f, "position", "position integer", requireInt);
|
|
6829
|
-
if (!position.ok) return position;
|
|
6830
6730
|
const child = reqField(path, f, "child", "child Node object", decodeNodeAst);
|
|
6831
6731
|
return child.ok ? ok({
|
|
6832
6732
|
kind: "InsertChild",
|
|
6833
6733
|
parentId: parentJ.value,
|
|
6834
|
-
position: position.value,
|
|
6835
6734
|
child: child.value
|
|
6836
6735
|
}) : child;
|
|
6837
6736
|
}
|
|
@@ -6843,14 +6742,11 @@ var decodeTreeOpAst = (path, j) => {
|
|
|
6843
6742
|
const t = target();
|
|
6844
6743
|
if (!t.ok) return t;
|
|
6845
6744
|
const newParent = reqField(path, f, "newParentId", "new parent NodeId", requireString);
|
|
6846
|
-
|
|
6847
|
-
const newPosition = reqField(path, f, "newPosition", "new position integer", requireInt);
|
|
6848
|
-
return newPosition.ok ? ok({
|
|
6745
|
+
return newParent.ok ? ok({
|
|
6849
6746
|
kind: "MoveNode",
|
|
6850
6747
|
target: t.value,
|
|
6851
|
-
newParentId: newParent.value
|
|
6852
|
-
|
|
6853
|
-
}) : newPosition;
|
|
6748
|
+
newParentId: newParent.value
|
|
6749
|
+
}) : newParent;
|
|
6854
6750
|
}
|
|
6855
6751
|
case "ReorderChildren": {
|
|
6856
6752
|
const parentJ = reqField(path, f, "parentId", "parent NodeId", requireString);
|
|
@@ -7858,11 +7754,6 @@ var applyOne = (op, root, telem) => {
|
|
|
7858
7754
|
"ChildlessKind",
|
|
7859
7755
|
`Node '${op.parentId}' (kind=${parent.kind.kind}) has no children field \u2014 only Layout kinds accept structural child ops.`
|
|
7860
7756
|
);
|
|
7861
|
-
if (op.position < 0 || op.position > children.length)
|
|
7862
|
-
return fail2(
|
|
7863
|
-
"PositionOutOfRange",
|
|
7864
|
-
`Position ${op.position} is out of range for parent '${op.parentId}' (valid: 0..${children.length}).`
|
|
7865
|
-
);
|
|
7866
7757
|
const existing = new Set(allNodeIds(root));
|
|
7867
7758
|
const duplicate = allNodeIds(op.child).find((id) => existing.has(id));
|
|
7868
7759
|
if (duplicate !== void 0)
|
|
@@ -7870,11 +7761,7 @@ var applyOne = (op, root, telem) => {
|
|
|
7870
7761
|
"DuplicateNodeId",
|
|
7871
7762
|
`NodeId '${duplicate}' is already present in the tree; ids must be unique.`
|
|
7872
7763
|
);
|
|
7873
|
-
const newChildren = [
|
|
7874
|
-
...children.slice(0, op.position),
|
|
7875
|
-
op.child,
|
|
7876
|
-
...children.slice(op.position)
|
|
7877
|
-
];
|
|
7764
|
+
const newChildren = [...children, op.child];
|
|
7878
7765
|
const newTree = mapNode(op.parentId, (n) => withLayoutChildren(n, newChildren), root);
|
|
7879
7766
|
if (newTree === void 0)
|
|
7880
7767
|
return fail2("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
|
|
@@ -7922,7 +7809,7 @@ var applyOne = (op, root, telem) => {
|
|
|
7922
7809
|
const afterRemove = applyOne({ kind: "RemoveNode", target: op.target }, root, []);
|
|
7923
7810
|
if (!afterRemove.ok) return afterRemove;
|
|
7924
7811
|
const inserted = applyOne(
|
|
7925
|
-
{ kind: "InsertChild", parentId: op.newParentId,
|
|
7812
|
+
{ kind: "InsertChild", parentId: op.newParentId, child: moving },
|
|
7926
7813
|
afterRemove.value,
|
|
7927
7814
|
[]
|
|
7928
7815
|
);
|