@fuaran-ui/ops 0.1.0 → 0.3.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/index.d.cts CHANGED
@@ -59,7 +59,6 @@ type TreeOp<TMsg> = {
59
59
  } | {
60
60
  readonly kind: 'InsertChild';
61
61
  readonly parentId: NodeId;
62
- readonly position: number;
63
62
  readonly child: Node<TMsg>;
64
63
  } | {
65
64
  readonly kind: 'RemoveNode';
@@ -68,7 +67,6 @@ type TreeOp<TMsg> = {
68
67
  readonly kind: 'MoveNode';
69
68
  readonly target: NodeId;
70
69
  readonly newParentId: NodeId;
71
- readonly newPosition: number;
72
70
  } | {
73
71
  readonly kind: 'ReorderChildren';
74
72
  readonly parentId: NodeId;
package/dist/index.d.ts CHANGED
@@ -59,7 +59,6 @@ type TreeOp<TMsg> = {
59
59
  } | {
60
60
  readonly kind: 'InsertChild';
61
61
  readonly parentId: NodeId;
62
- readonly position: number;
63
62
  readonly child: Node<TMsg>;
64
63
  } | {
65
64
  readonly kind: 'RemoveNode';
@@ -68,7 +67,6 @@ type TreeOp<TMsg> = {
68
67
  readonly kind: 'MoveNode';
69
68
  readonly target: NodeId;
70
69
  readonly newParentId: NodeId;
71
- readonly newPosition: number;
72
70
  } | {
73
71
  readonly kind: 'ReorderChildren';
74
72
  readonly parentId: NodeId;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { defaults, projectSelectionField, controlValueDefaults } from '@fuaran-ui/schema';
1
+ import { FORM_FIELD_KIND_NAMES, NODE_KIND_GROUPS, defaults, projectSelectionField, controlValueDefaults } from '@fuaran-ui/schema';
2
2
 
3
3
  // src/encode.ts
4
4
  var assertNever = (x) => {
@@ -360,8 +360,10 @@ var flushTrigger = (t) => {
360
360
  };
361
361
  var binding = (b, staticEnc = objValue) => {
362
362
  switch (b.kind) {
363
- case "Static":
364
- return caseObj("Static", [["value", staticEnc(b.value)]]);
363
+ case "Static": {
364
+ const valueFields = b.value === null || b.value === void 0 ? [] : [["value", staticEnc(b.value)]];
365
+ return caseObj("Static", valueFields);
366
+ }
365
367
  case "Query": {
366
368
  const dependsOnFields = b.dependsOn !== void 0 && b.dependsOn.length > 0 ? [["dependsOn", jArray(b.dependsOn.map((s) => str(s)))]] : [];
367
369
  return caseObj("Query", [...dependsOnFields, ["name", str(b.name)]]);
@@ -375,11 +377,10 @@ var binding = (b, staticEnc = objValue) => {
375
377
  const fieldField = b.field !== void 0 ? [["field", str(b.field)]] : [];
376
378
  return caseObj("Selection", [...defaultField, ...fieldField, ["nodeId", str(b.nodeId)]]);
377
379
  }
378
- case "State":
379
- return caseObj("State", [
380
- ["defaultValue", staticEnc(b.defaultValue)],
381
- ["key", str(b.key)]
382
- ]);
380
+ case "State": {
381
+ const defaultFields = b.defaultValue === null || b.defaultValue === void 0 ? [] : [["defaultValue", staticEnc(b.defaultValue)]];
382
+ return caseObj("State", [...defaultFields, ["key", str(b.key)]]);
383
+ }
383
384
  case "Computed":
384
385
  return caseObj("Computed", [["fn", CLOSURE]]);
385
386
  case "I18n": {
@@ -934,6 +935,25 @@ var formFieldKind = (autoBind, k) => {
934
935
  if (k.constraints.step !== void 0) fields.push(["step", num(k.constraints.step)]);
935
936
  return caseObj("Date", fields);
936
937
  }
938
+ case "DateRange": {
939
+ const staticPair = (p) => jObject([
940
+ ["from", str(p[0])],
941
+ ["to", str(p[1])]
942
+ ]);
943
+ const fields = [
944
+ ...handlerField("onChange", k.onChange),
945
+ ...valueField(
946
+ k.value,
947
+ controlValueDefaults.dateRange,
948
+ (v) => v.kind === "Static" ? staticPair(v.value) : binding(v, staticPair)
949
+ ),
950
+ ["variant", str(k.variant)]
951
+ ];
952
+ if (k.constraints.min !== void 0) fields.push(["min", str(k.constraints.min)]);
953
+ if (k.constraints.max !== void 0) fields.push(["max", str(k.constraints.max)]);
954
+ if (k.constraints.step !== void 0) fields.push(["step", num(k.constraints.step)]);
955
+ return caseObj("DateRange", fields);
956
+ }
937
957
  default:
938
958
  return assertNever(k);
939
959
  }
@@ -1515,15 +1535,13 @@ var treeOp = (op) => {
1515
1535
  case "InsertChild":
1516
1536
  return caseObj("InsertChild", [
1517
1537
  ["child", node(op.child)],
1518
- ["parentId", str(op.parentId)],
1519
- ["position", num(op.position)]
1538
+ ["parentId", str(op.parentId)]
1520
1539
  ]);
1521
1540
  case "RemoveNode":
1522
1541
  return caseObj("RemoveNode", [["target", str(op.target)]]);
1523
1542
  case "MoveNode":
1524
1543
  return caseObj("MoveNode", [
1525
1544
  ["newParentId", str(op.newParentId)],
1526
- ["newPosition", num(op.newPosition)],
1527
1545
  ["target", str(op.target)]
1528
1546
  ]);
1529
1547
  case "ReorderChildren":
@@ -4032,9 +4050,8 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4032
4050
  if (!d.ok) return d;
4033
4051
  switch (d.value) {
4034
4052
  case "Static": {
4035
- const v = requireField(path, f, "value", "Binding.Static value of the slot's expected type");
4036
- if (!v.ok) return v;
4037
- const parsed = parseStatic(`${path}.value`, v.value);
4053
+ const raw = f.get("value") ?? { kind: "JNull" };
4054
+ const parsed = parseStatic(`${path}.value`, raw);
4038
4055
  return parsed.ok ? ok({ kind: "Static", value: parsed.value }) : parsed;
4039
4056
  }
4040
4057
  case "Query": {
@@ -4111,7 +4128,7 @@ var decodeBinding = (path, j, parseStatic = (_p, v) => ok(decodeAstValue(v)), pl
4111
4128
  case "State": {
4112
4129
  const key = reqField(path, f, "key", "state key string", requireString);
4113
4130
  if (!key.ok) return key;
4114
- const dv = fieldAliased(f, "defaultValue", ["initialValue", "default"]);
4131
+ const dv = fieldAliased(f, "defaultValue", ["initialValue", "default"]) ?? { kind: "JNull" };
4115
4132
  let defaultValue = placeholder;
4116
4133
  if (dv !== void 0) {
4117
4134
  const parsed = parseStatic(`${path}.defaultValue`, dv);
@@ -4339,6 +4356,41 @@ var decodeBindingFloatPair = (p, j) => {
4339
4356
  }
4340
4357
  return decodeBinding(p, j, parseStaticFloatPair, [0, 0]);
4341
4358
  };
4359
+ var parseStaticStringPair = (p, v) => {
4360
+ const ordered = (a, b) => a > b ? makeError(
4361
+ "WRONG_TYPE",
4362
+ p,
4363
+ `date-range start '${a}' is after end '${b}' \u2014 a DateRange pair is ordered (from <= to); ISO-8601 strings of one variant compare lexicographically, so swap the two values`,
4364
+ 'ordered ISO-8601 pair ({"from": <iso>, "to": <iso>} with from <= to)'
4365
+ ) : ok([a, b]);
4366
+ if (v.kind === "JObject") {
4367
+ const from = v.fields.get("from");
4368
+ const to = v.fields.get("to");
4369
+ if (from !== void 0 && to !== void 0) {
4370
+ const a = requireString(`${p}.from`, from);
4371
+ if (!a.ok) return a;
4372
+ const b = requireString(`${p}.to`, to);
4373
+ if (!b.ok) return b;
4374
+ return ordered(a.value, b.value);
4375
+ }
4376
+ return wrongType(p, "object with from and to ISO-8601 strings");
4377
+ }
4378
+ if (v.kind === "JArray" && v.items.length === 2) {
4379
+ const a = requireString(`${p}[0]`, v.items[0]);
4380
+ if (!a.ok) return a;
4381
+ const b = requireString(`${p}[1]`, v.items[1]);
4382
+ if (!b.ok) return b;
4383
+ return ordered(a.value, b.value);
4384
+ }
4385
+ return wrongType(p, "date-range pair ({from, to} object or [from, to] array)");
4386
+ };
4387
+ var decodeBindingStringPair = (p, j) => {
4388
+ if (j.kind === "JObject" && j.fields.get("$type") === void 0 && j.fields.get("from") !== void 0 && j.fields.get("to") !== void 0) {
4389
+ const parsed = parseStaticStringPair(p, j);
4390
+ return parsed.ok ? ok({ kind: "Static", value: parsed.value }) : parsed;
4391
+ }
4392
+ return decodeBinding(p, j, parseStaticStringPair, ["", ""]);
4393
+ };
4342
4394
  var parseStaticStringList = (p, v) => {
4343
4395
  if (v.kind === "JNull") return ok([]);
4344
4396
  if (v.kind === "JString" && v.value === OPAQUE2) return ok([OPAQUE2]);
@@ -5186,6 +5238,7 @@ var decodeDisplayKind = (path, j) => {
5186
5238
  );
5187
5239
  }
5188
5240
  };
5241
+ var WRONG_FORM_FIELD_KIND_HINT = FORM_FIELD_KIND_NAMES.join(" | ");
5189
5242
  var decodeFormFieldKind = (autoBind, path, j) => {
5190
5243
  const fo = requireObject(path, j);
5191
5244
  if (!fo.ok) return fo;
@@ -5335,12 +5388,35 @@ var decodeFormFieldKind = (autoBind, path, j) => {
5335
5388
  }
5336
5389
  });
5337
5390
  }
5338
- default:
5339
- return unknownDuCase(
5340
- path,
5341
- d.value,
5342
- "Text | Number | Checkbox | Choice | Range | RangedNumber | SegmentedChoice | TextArea | Date"
5391
+ case "DateRange": {
5392
+ const value = valueOr(
5393
+ decodeBindingStringPair,
5394
+ controlValueDefaults.dateRange,
5395
+ "Binding<[from, to]> ISO-8601 pair value"
5343
5396
  );
5397
+ if (!value.ok) return value;
5398
+ const variant = reqField(path, f, "variant", "DateVariant", decodeDateVariant);
5399
+ if (!variant.ok) return variant;
5400
+ const min = optField(path, f, "min", requireString);
5401
+ if (!min.ok) return min;
5402
+ const max = optField(path, f, "max", requireString);
5403
+ if (!max.ok) return max;
5404
+ const step = optField(path, f, "step", requireFloat);
5405
+ if (!step.ok) return step;
5406
+ return ok({
5407
+ kind: "DateRange",
5408
+ value: value.value,
5409
+ ...onChangeField,
5410
+ variant: variant.value,
5411
+ constraints: {
5412
+ ...min.value !== void 0 ? { min: min.value } : {},
5413
+ ...max.value !== void 0 ? { max: max.value } : {},
5414
+ ...step.value !== void 0 ? { step: step.value } : {}
5415
+ }
5416
+ });
5417
+ }
5418
+ default:
5419
+ return unknownDuCase(path, d.value, WRONG_FORM_FIELD_KIND_HINT);
5344
5420
  }
5345
5421
  };
5346
5422
  var decodeFormField = (path, j) => {
@@ -5826,23 +5902,6 @@ var decodeVisKind = (path, j) => {
5826
5902
  const r = decodeChartSpec(path, j);
5827
5903
  return r.ok ? ok({ kind: "Chart", spec: r.value }) : r;
5828
5904
  }
5829
- // Phase 393 — legacy decode-upgrade: a `Table` tag folds into a read-only `Grid`
5830
- // (the `staticRows` mode). Accepted on read but NEVER re-encodes as `Table` (the
5831
- // encoder has no `Table` arm), riding the Phase 390 retired-kind seam.
5832
- case "Table": {
5833
- const r = decodeStaticRows(path, j);
5834
- return r.ok ? ok({
5835
- kind: "Grid",
5836
- spec: {
5837
- // An opaque Static source re-encodes to {"$type":"Static","value":"<opaque>"} —
5838
- // byte-identical to the F# static grid's `Binding.Static Seq.empty`.
5839
- source: { kind: "Static", value: OPAQUE2 },
5840
- columns: [],
5841
- editable: false,
5842
- staticRows: r.value
5843
- }
5844
- }) : r;
5845
- }
5846
5905
  case "Map": {
5847
5906
  const r = decodeMapSpec(path, j);
5848
5907
  return r.ok ? ok({ kind: "Map", spec: r.value }) : r;
@@ -5934,64 +5993,6 @@ var decodeBox = (path, j) => {
5934
5993
  role: role.value
5935
5994
  });
5936
5995
  };
5937
- var decodeLegacyDashboard = (path, j) => {
5938
- const fo = requireObject(path, j);
5939
- if (!fo.ok) return fo;
5940
- const children = decodeChildren(path, fo.value);
5941
- if (!children.ok) return children;
5942
- return ok({ children: children.value, layout: { kind: "Auto" }, role: "Dashboard" });
5943
- };
5944
- var decodeLegacyStack = (path, j) => {
5945
- const fo = requireObject(path, j);
5946
- if (!fo.ok) return fo;
5947
- const f = fo.value;
5948
- const children = decodeChildren(path, f);
5949
- if (!children.ok) return children;
5950
- const orientation = reqField(path, f, "orientation", "Orientation", decodeOrientation);
5951
- if (!orientation.ok) return orientation;
5952
- const wrap = reqField(path, f, "wrap", "wrap bool", requireBool);
5953
- if (!wrap.ok) return wrap;
5954
- return ok({
5955
- children: children.value,
5956
- layout: { kind: "Flex", direction: orientation.value, wrap: wrap.value },
5957
- role: "Group"
5958
- });
5959
- };
5960
- var decodeLegacyGridLayout = (path, j) => {
5961
- const fo = requireObject(path, j);
5962
- if (!fo.ok) return fo;
5963
- const f = fo.value;
5964
- const children = decodeChildren(path, f);
5965
- if (!children.ok) return children;
5966
- const cols = reqFieldAliased(path, f, "cols", ["columns"], "cols integer", requireInt);
5967
- if (!cols.ok) return cols;
5968
- const templateColumns = optField(path, f, "templateColumns", requireString);
5969
- if (!templateColumns.ok) return templateColumns;
5970
- return ok({
5971
- children: children.value,
5972
- layout: {
5973
- kind: "Grid",
5974
- cols: cols.value,
5975
- ...templateColumns.value !== void 0 ? { templateColumns: templateColumns.value } : {}
5976
- },
5977
- role: "Group"
5978
- });
5979
- };
5980
- var decodeLegacyCard = (path, j) => {
5981
- const fo = requireObject(path, j);
5982
- if (!fo.ok) return fo;
5983
- const f = fo.value;
5984
- const children = decodeChildren(path, f);
5985
- if (!children.ok) return children;
5986
- const heading = optFieldAliased(path, f, "heading", ["title"], decodeTextSource);
5987
- if (!heading.ok) return heading;
5988
- return ok({
5989
- children: children.value,
5990
- ...heading.value !== void 0 ? { heading: heading.value } : {},
5991
- layout: { kind: "Flex", direction: "Vertical", wrap: false },
5992
- role: "Card"
5993
- });
5994
- };
5995
5996
  var decodeSplitPanelSpec = (path, j) => {
5996
5997
  const fo = requireObject(path, j);
5997
5998
  if (!fo.ok) return fo;
@@ -6181,22 +6182,6 @@ var decodeLayoutKind = (path, j) => {
6181
6182
  const r = decodeBox(path, j);
6182
6183
  return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
6183
6184
  }
6184
- case "Dashboard": {
6185
- const r = decodeLegacyDashboard(path, j);
6186
- return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
6187
- }
6188
- case "Stack": {
6189
- const r = decodeLegacyStack(path, j);
6190
- return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
6191
- }
6192
- case "GridLayout": {
6193
- const r = decodeLegacyGridLayout(path, j);
6194
- return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
6195
- }
6196
- case "Card": {
6197
- const r = decodeLegacyCard(path, j);
6198
- return r.ok ? ok({ kind: "Box", spec: r.value }) : r;
6199
- }
6200
6185
  case "SplitPanel": {
6201
6186
  const r = decodeSplitPanelSpec(path, j);
6202
6187
  return r.ok ? ok({ kind: "SplitPanel", spec: r.value }) : r;
@@ -6229,7 +6214,7 @@ var decodeLayoutKind = (path, j) => {
6229
6214
  return unknownDuCase(
6230
6215
  path,
6231
6216
  d.value,
6232
- "Box | Dashboard | Stack | GridLayout | SplitPanel | Tabs | Card | Stepper | SummaryList | Disclosure | Modal | ScrollArea"
6217
+ "Box | SplitPanel | Tabs | Stepper | SummaryList | Disclosure | Modal | ScrollArea"
6233
6218
  );
6234
6219
  }
6235
6220
  };
@@ -6393,6 +6378,13 @@ var decodeEffectClass = (path, j) => {
6393
6378
  );
6394
6379
  return ok({ hostEffect: host.value, determinism: det.value });
6395
6380
  };
6381
+ var WRONG_NODE_KIND_HINT = (() => {
6382
+ const primitives = NODE_KIND_GROUPS.filter((g) => g.label !== "Structural").map(
6383
+ (g) => `${"AEIOU".includes(g.label[0]) ? "an" : "a"} ${g.label} primitive (${g.kinds.join(" | ")})`
6384
+ ).join(", ");
6385
+ const structural = NODE_KIND_GROUPS.find((g) => g.label === "Structural")?.kinds ?? [];
6386
+ return `${primitives}, or ${structural.join(" | ")}`;
6387
+ })();
6396
6388
  var decodeNodeKind = (path, j) => {
6397
6389
  const fo = requireObject(path, j);
6398
6390
  if (!fo.ok) return fo;
@@ -6405,12 +6397,8 @@ var decodeNodeKind = (path, j) => {
6405
6397
  // each primitive to its inner decoder and recover the category here. These
6406
6398
  // name-sets MUST stay in sync with the four inner decoders + the encoder.
6407
6399
  case "Box":
6408
- case "Dashboard":
6409
- case "Stack":
6410
- case "GridLayout":
6411
6400
  case "SplitPanel":
6412
6401
  case "Tabs":
6413
- case "Card":
6414
6402
  case "Stepper":
6415
6403
  case "SummaryList":
6416
6404
  case "Disclosure":
@@ -6449,7 +6437,6 @@ var decodeNodeKind = (path, j) => {
6449
6437
  }
6450
6438
  case "DataGrid":
6451
6439
  case "Chart":
6452
- case "Table":
6453
6440
  case "Map": {
6454
6441
  const k = decodeVisKind(path, j);
6455
6442
  return k.ok ? ok({ kind: "Visualisation", visualisation: k.value }) : k;
@@ -6652,7 +6639,7 @@ var decodeNodeKind = (path, j) => {
6652
6639
  "WRONG_NODE_KIND",
6653
6640
  `${path}.$type`,
6654
6641
  `unknown NodeKind discriminator '${d.value}'`,
6655
- "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"
6642
+ WRONG_NODE_KIND_HINT
6656
6643
  );
6657
6644
  }
6658
6645
  };
@@ -6823,13 +6810,10 @@ var decodeTreeOpAst = (path, j) => {
6823
6810
  case "InsertChild": {
6824
6811
  const parentJ = reqField(path, f, "parentId", "parent NodeId", requireString);
6825
6812
  if (!parentJ.ok) return parentJ;
6826
- const position = reqField(path, f, "position", "position integer", requireInt);
6827
- if (!position.ok) return position;
6828
6813
  const child = reqField(path, f, "child", "child Node object", decodeNodeAst);
6829
6814
  return child.ok ? ok({
6830
6815
  kind: "InsertChild",
6831
6816
  parentId: parentJ.value,
6832
- position: position.value,
6833
6817
  child: child.value
6834
6818
  }) : child;
6835
6819
  }
@@ -6841,14 +6825,11 @@ var decodeTreeOpAst = (path, j) => {
6841
6825
  const t = target();
6842
6826
  if (!t.ok) return t;
6843
6827
  const newParent = reqField(path, f, "newParentId", "new parent NodeId", requireString);
6844
- if (!newParent.ok) return newParent;
6845
- const newPosition = reqField(path, f, "newPosition", "new position integer", requireInt);
6846
- return newPosition.ok ? ok({
6828
+ return newParent.ok ? ok({
6847
6829
  kind: "MoveNode",
6848
6830
  target: t.value,
6849
- newParentId: newParent.value,
6850
- newPosition: newPosition.value
6851
- }) : newPosition;
6831
+ newParentId: newParent.value
6832
+ }) : newParent;
6852
6833
  }
6853
6834
  case "ReorderChildren": {
6854
6835
  const parentJ = reqField(path, f, "parentId", "parent NodeId", requireString);
@@ -7856,11 +7837,6 @@ var applyOne = (op, root, telem) => {
7856
7837
  "ChildlessKind",
7857
7838
  `Node '${op.parentId}' (kind=${parent.kind.kind}) has no children field \u2014 only Layout kinds accept structural child ops.`
7858
7839
  );
7859
- if (op.position < 0 || op.position > children.length)
7860
- return fail2(
7861
- "PositionOutOfRange",
7862
- `Position ${op.position} is out of range for parent '${op.parentId}' (valid: 0..${children.length}).`
7863
- );
7864
7840
  const existing = new Set(allNodeIds(root));
7865
7841
  const duplicate = allNodeIds(op.child).find((id) => existing.has(id));
7866
7842
  if (duplicate !== void 0)
@@ -7868,11 +7844,7 @@ var applyOne = (op, root, telem) => {
7868
7844
  "DuplicateNodeId",
7869
7845
  `NodeId '${duplicate}' is already present in the tree; ids must be unique.`
7870
7846
  );
7871
- const newChildren = [
7872
- ...children.slice(0, op.position),
7873
- op.child,
7874
- ...children.slice(op.position)
7875
- ];
7847
+ const newChildren = [...children, op.child];
7876
7848
  const newTree = mapNode(op.parentId, (n) => withLayoutChildren(n, newChildren), root);
7877
7849
  if (newTree === void 0)
7878
7850
  return fail2("ParentNotFound", `Parent node '${op.parentId}' not found in tree.`);
@@ -7920,7 +7892,7 @@ var applyOne = (op, root, telem) => {
7920
7892
  const afterRemove = applyOne({ kind: "RemoveNode", target: op.target }, root, []);
7921
7893
  if (!afterRemove.ok) return afterRemove;
7922
7894
  const inserted = applyOne(
7923
- { kind: "InsertChild", parentId: op.newParentId, position: op.newPosition, child: moving },
7895
+ { kind: "InsertChild", parentId: op.newParentId, child: moving },
7924
7896
  afterRemove.value,
7925
7897
  []
7926
7898
  );