@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 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
- return caseObj("Static", [["value", staticEnc(b.value)]]);
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
- return caseObj("State", [
382
- ["defaultValue", staticEnc(b.defaultValue)],
383
- ["key", str(b.key)]
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 v = requireField(path, f, "value", "Binding.Static value of the slot's expected type");
4038
- if (!v.ok) return v;
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 | Dashboard | Stack | GridLayout | SplitPanel | Tabs | Card | Stepper | SummaryList | Disclosure | Modal | ScrollArea"
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 (Dashboard | Stack | GridLayout | SplitPanel | Tabs | Card | 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 | Table | Map), or Custom | ErrorBoundary | FragmentDecl | FragmentRef | Mount"
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
- if (!newParent.ok) return newParent;
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
- newPosition: newPosition.value
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, position: op.newPosition, child: moving },
7812
+ { kind: "InsertChild", parentId: op.newParentId, child: moving },
7926
7813
  afterRemove.value,
7927
7814
  []
7928
7815
  );