@timeax/digital-service-engine 0.3.4 → 0.3.5

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.
@@ -186,6 +186,75 @@ interface BaseFieldUI {
186
186
  /** Host-defined prop names → runtime default values (untyped base) */
187
187
  defaults?: Record<string, unknown>;
188
188
  }
189
+ type Ui = (UiString | UiNumber | UiBoolean | UiAnyOf | UiArray | UiObject) & {
190
+ description: string;
191
+ label: string;
192
+ };
193
+ /** string */
194
+ interface UiString {
195
+ type: "string";
196
+ enum?: string[];
197
+ minLength?: number;
198
+ maxLength?: number;
199
+ pattern?: string;
200
+ format?: string;
201
+ }
202
+ /** number */
203
+ interface UiNumber {
204
+ type: "number";
205
+ minimum?: number;
206
+ maximum?: number;
207
+ multipleOf?: number;
208
+ }
209
+ /** boolean */
210
+ interface UiBoolean {
211
+ type: "boolean";
212
+ }
213
+ /** enumerated choices */
214
+ interface UiAnyOf {
215
+ type: "anyOf";
216
+ multiple?: boolean;
217
+ items: Array<{
218
+ type: "string" | "number" | "boolean";
219
+ title?: string;
220
+ description?: string;
221
+ value: string | number | boolean;
222
+ }>;
223
+ }
224
+ /** arrays: homogeneous (item) or tuple (items) */
225
+ interface UiArray {
226
+ type: "array";
227
+ label: string;
228
+ description: string;
229
+ item?: Ui;
230
+ items?: Ui[];
231
+ editable?: boolean;
232
+ /**
233
+ * Optional: allowed shapes for new items.
234
+ * Key = label shown in UI picker
235
+ * Value = schema for the new element
236
+ */
237
+ shape?: Record<string, Ui>;
238
+ minItems?: number;
239
+ maxItems?: number;
240
+ uniqueItems?: boolean;
241
+ }
242
+ /** objects: nested props */
243
+ interface UiObject {
244
+ type: "object";
245
+ label: string;
246
+ description: string;
247
+ editable?: boolean;
248
+ fields: Record<string, Ui>;
249
+ /**
250
+ * Optional: allowed shapes for dynamically added keys.
251
+ * Key = human-readable name shown in UI picker
252
+ * Value = schema applied to the value of the new key
253
+ */
254
+ shape?: Record<string, Ui>;
255
+ required?: string[];
256
+ order?: string[];
257
+ }
189
258
  type FieldValidationValueBy = "value" | "length" | "eval";
190
259
  type FieldValidationOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "between" | "in" | "nin" | "truthy" | "falsy" | "match";
191
260
  type FieldValidationRule = {
@@ -1692,6 +1761,59 @@ type QuantityRule = {
1692
1761
  fallback?: number;
1693
1762
  };
1694
1763
 
1764
+ /** Matches your InputWrapper’s expectations */
1765
+ type InputKind = string;
1766
+ type InputVariant = "default" | (string & {});
1767
+ type AdapterCtx = {
1768
+ field: Field;
1769
+ props: ServiceProps;
1770
+ };
1771
+ type Adapter = {
1772
+ valueProp?: string;
1773
+ changeProp?: string;
1774
+ errorProp?: string;
1775
+ /** normalize what the host emitted into what we store in form-palette */
1776
+ getValue?: (next: unknown, current: unknown, ctx: AdapterCtx) => unknown;
1777
+ /** REQUIRED if field.options exists */
1778
+ getSelectedOptions?: (next: unknown, current: unknown, ctx: AdapterCtx) => string[];
1779
+ /** For option-less action buttons (button: true with no options) */
1780
+ isActive?: (stored: unknown, ctx: AdapterCtx) => boolean;
1781
+ getInputPropsFromField?: (props: AdapterCtx) => any;
1782
+ toValue?: (value: any) => any;
1783
+ };
1784
+ type InputOptionCapability = {
1785
+ supported?: boolean;
1786
+ autoCreate?: boolean;
1787
+ defaultLabel?: string;
1788
+ defaultValue?: string | number;
1789
+ };
1790
+ type InputMultiCapability = {
1791
+ supported?: boolean;
1792
+ autoEnable?: boolean;
1793
+ };
1794
+ type InputDescriptor = {
1795
+ Component: React__default.ComponentType<Record<string, unknown>>;
1796
+ adapter?: Adapter;
1797
+ defaultProps?: Record<string, unknown>;
1798
+ ui?: Record<string, Ui>;
1799
+ options?: InputOptionCapability;
1800
+ multi?: InputMultiCapability;
1801
+ };
1802
+ type VariantMap = Map<InputVariant, InputDescriptor>;
1803
+ type RegistryStore = Map<InputKind, VariantMap>;
1804
+ type Registry = {
1805
+ get(kind: InputKind, variant?: InputVariant): InputDescriptor | undefined;
1806
+ register(kind: InputKind, descriptor: InputDescriptor, variant?: InputVariant): void;
1807
+ unregister(kind: InputKind, variant?: InputVariant): void;
1808
+ registerMany(entries: Array<{
1809
+ kind: InputKind;
1810
+ descriptor: InputDescriptor;
1811
+ variant?: InputVariant;
1812
+ }>): void;
1813
+ /** low-level escape hatch */
1814
+ _store: RegistryStore;
1815
+ };
1816
+
1695
1817
  declare class Editor {
1696
1818
  private readonly builder;
1697
1819
  private readonly api;
@@ -1763,7 +1885,14 @@ declare class Editor {
1763
1885
  id?: string;
1764
1886
  label: string;
1765
1887
  type: Field["type"];
1766
- }): void;
1888
+ }): string;
1889
+ addFieldFromDescriptor(registry: Registry, partial: Omit<Field, "id" | "label" | "type"> & {
1890
+ id?: string;
1891
+ label: string;
1892
+ type: Field["type"];
1893
+ }, opts?: {
1894
+ variant?: InputVariant;
1895
+ }): string;
1767
1896
  updateField(id: string, patch: Partial<Field>): void;
1768
1897
  removeField(id: string): void;
1769
1898
  remove(id: string): void;
@@ -1782,6 +1911,7 @@ declare class Editor {
1782
1911
  setPricingRoleMany(ids: readonly string[], role: "base" | "utility"): void;
1783
1912
  clearFieldDefaultsMany(ids: readonly string[]): void;
1784
1913
  clearFieldValidationMany(ids: readonly string[]): void;
1914
+ setFieldMulti(fieldId: string, enabled: boolean): void;
1785
1915
  autoCreateOptionsMany(ids: readonly string[], makeOption?: (fieldId: string) => {
1786
1916
  id?: string;
1787
1917
  label: string;
@@ -186,6 +186,75 @@ interface BaseFieldUI {
186
186
  /** Host-defined prop names → runtime default values (untyped base) */
187
187
  defaults?: Record<string, unknown>;
188
188
  }
189
+ type Ui = (UiString | UiNumber | UiBoolean | UiAnyOf | UiArray | UiObject) & {
190
+ description: string;
191
+ label: string;
192
+ };
193
+ /** string */
194
+ interface UiString {
195
+ type: "string";
196
+ enum?: string[];
197
+ minLength?: number;
198
+ maxLength?: number;
199
+ pattern?: string;
200
+ format?: string;
201
+ }
202
+ /** number */
203
+ interface UiNumber {
204
+ type: "number";
205
+ minimum?: number;
206
+ maximum?: number;
207
+ multipleOf?: number;
208
+ }
209
+ /** boolean */
210
+ interface UiBoolean {
211
+ type: "boolean";
212
+ }
213
+ /** enumerated choices */
214
+ interface UiAnyOf {
215
+ type: "anyOf";
216
+ multiple?: boolean;
217
+ items: Array<{
218
+ type: "string" | "number" | "boolean";
219
+ title?: string;
220
+ description?: string;
221
+ value: string | number | boolean;
222
+ }>;
223
+ }
224
+ /** arrays: homogeneous (item) or tuple (items) */
225
+ interface UiArray {
226
+ type: "array";
227
+ label: string;
228
+ description: string;
229
+ item?: Ui;
230
+ items?: Ui[];
231
+ editable?: boolean;
232
+ /**
233
+ * Optional: allowed shapes for new items.
234
+ * Key = label shown in UI picker
235
+ * Value = schema for the new element
236
+ */
237
+ shape?: Record<string, Ui>;
238
+ minItems?: number;
239
+ maxItems?: number;
240
+ uniqueItems?: boolean;
241
+ }
242
+ /** objects: nested props */
243
+ interface UiObject {
244
+ type: "object";
245
+ label: string;
246
+ description: string;
247
+ editable?: boolean;
248
+ fields: Record<string, Ui>;
249
+ /**
250
+ * Optional: allowed shapes for dynamically added keys.
251
+ * Key = human-readable name shown in UI picker
252
+ * Value = schema applied to the value of the new key
253
+ */
254
+ shape?: Record<string, Ui>;
255
+ required?: string[];
256
+ order?: string[];
257
+ }
189
258
  type FieldValidationValueBy = "value" | "length" | "eval";
190
259
  type FieldValidationOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "between" | "in" | "nin" | "truthy" | "falsy" | "match";
191
260
  type FieldValidationRule = {
@@ -1692,6 +1761,59 @@ type QuantityRule = {
1692
1761
  fallback?: number;
1693
1762
  };
1694
1763
 
1764
+ /** Matches your InputWrapper’s expectations */
1765
+ type InputKind = string;
1766
+ type InputVariant = "default" | (string & {});
1767
+ type AdapterCtx = {
1768
+ field: Field;
1769
+ props: ServiceProps;
1770
+ };
1771
+ type Adapter = {
1772
+ valueProp?: string;
1773
+ changeProp?: string;
1774
+ errorProp?: string;
1775
+ /** normalize what the host emitted into what we store in form-palette */
1776
+ getValue?: (next: unknown, current: unknown, ctx: AdapterCtx) => unknown;
1777
+ /** REQUIRED if field.options exists */
1778
+ getSelectedOptions?: (next: unknown, current: unknown, ctx: AdapterCtx) => string[];
1779
+ /** For option-less action buttons (button: true with no options) */
1780
+ isActive?: (stored: unknown, ctx: AdapterCtx) => boolean;
1781
+ getInputPropsFromField?: (props: AdapterCtx) => any;
1782
+ toValue?: (value: any) => any;
1783
+ };
1784
+ type InputOptionCapability = {
1785
+ supported?: boolean;
1786
+ autoCreate?: boolean;
1787
+ defaultLabel?: string;
1788
+ defaultValue?: string | number;
1789
+ };
1790
+ type InputMultiCapability = {
1791
+ supported?: boolean;
1792
+ autoEnable?: boolean;
1793
+ };
1794
+ type InputDescriptor = {
1795
+ Component: React__default.ComponentType<Record<string, unknown>>;
1796
+ adapter?: Adapter;
1797
+ defaultProps?: Record<string, unknown>;
1798
+ ui?: Record<string, Ui>;
1799
+ options?: InputOptionCapability;
1800
+ multi?: InputMultiCapability;
1801
+ };
1802
+ type VariantMap = Map<InputVariant, InputDescriptor>;
1803
+ type RegistryStore = Map<InputKind, VariantMap>;
1804
+ type Registry = {
1805
+ get(kind: InputKind, variant?: InputVariant): InputDescriptor | undefined;
1806
+ register(kind: InputKind, descriptor: InputDescriptor, variant?: InputVariant): void;
1807
+ unregister(kind: InputKind, variant?: InputVariant): void;
1808
+ registerMany(entries: Array<{
1809
+ kind: InputKind;
1810
+ descriptor: InputDescriptor;
1811
+ variant?: InputVariant;
1812
+ }>): void;
1813
+ /** low-level escape hatch */
1814
+ _store: RegistryStore;
1815
+ };
1816
+
1695
1817
  declare class Editor {
1696
1818
  private readonly builder;
1697
1819
  private readonly api;
@@ -1763,7 +1885,14 @@ declare class Editor {
1763
1885
  id?: string;
1764
1886
  label: string;
1765
1887
  type: Field["type"];
1766
- }): void;
1888
+ }): string;
1889
+ addFieldFromDescriptor(registry: Registry, partial: Omit<Field, "id" | "label" | "type"> & {
1890
+ id?: string;
1891
+ label: string;
1892
+ type: Field["type"];
1893
+ }, opts?: {
1894
+ variant?: InputVariant;
1895
+ }): string;
1767
1896
  updateField(id: string, patch: Partial<Field>): void;
1768
1897
  removeField(id: string): void;
1769
1898
  remove(id: string): void;
@@ -1782,6 +1911,7 @@ declare class Editor {
1782
1911
  setPricingRoleMany(ids: readonly string[], role: "base" | "utility"): void;
1783
1912
  clearFieldDefaultsMany(ids: readonly string[]): void;
1784
1913
  clearFieldValidationMany(ids: readonly string[]): void;
1914
+ setFieldMulti(fieldId: string, enabled: boolean): void;
1785
1915
  autoCreateOptionsMany(ids: readonly string[], makeOption?: (fieldId: string) => {
1786
1916
  id?: string;
1787
1917
  label: string;
@@ -7422,6 +7422,11 @@ function rateIssueAffectsCandidate(error, candidateId, candidateFieldId, primary
7422
7422
  });
7423
7423
  }
7424
7424
 
7425
+ // src/react/inputs/registry.ts
7426
+ function resolveInputDescriptor(registry, kind, variant) {
7427
+ return registry.get(kind, variant);
7428
+ }
7429
+
7425
7430
  // src/react/canvas/editor/editor-ids.ts
7426
7431
  function uniqueId(ctx, base) {
7427
7432
  var _a, _b;
@@ -8332,6 +8337,7 @@ function addField(ctx, partial) {
8332
8337
  p.fields = ((_a2 = p.fields) != null ? _a2 : []).filter((f) => f.id !== id);
8333
8338
  })
8334
8339
  });
8340
+ return id;
8335
8341
  }
8336
8342
  function updateField(ctx, id, patch) {
8337
8343
  let prev;
@@ -9768,6 +9774,36 @@ var Editor = class {
9768
9774
  addField(partial) {
9769
9775
  return addField(this.moduleCtx(), partial);
9770
9776
  }
9777
+ addFieldFromDescriptor(registry, partial, opts) {
9778
+ var _a, _b, _c, _d, _e;
9779
+ const variant = (_b = opts == null ? void 0 : opts.variant) != null ? _b : typeof ((_a = partial == null ? void 0 : partial.meta) == null ? void 0 : _a.variant) === "string" ? partial.meta.variant : void 0;
9780
+ const descriptor = resolveInputDescriptor(
9781
+ registry,
9782
+ String(partial.type),
9783
+ variant
9784
+ );
9785
+ const nextMeta = {
9786
+ ...(_c = partial.meta) != null ? _c : {}
9787
+ };
9788
+ if (((_d = descriptor == null ? void 0 : descriptor.multi) == null ? void 0 : _d.autoEnable) === true) {
9789
+ nextMeta.multi = true;
9790
+ }
9791
+ const fieldInput = {
9792
+ ...partial,
9793
+ ...Object.keys(nextMeta).length ? { meta: nextMeta } : {}
9794
+ };
9795
+ const fieldId = this.addField(fieldInput);
9796
+ if (((_e = descriptor == null ? void 0 : descriptor.options) == null ? void 0 : _e.autoCreate) === true) {
9797
+ this.autoCreateOptionsMany([fieldId], () => {
9798
+ var _a2, _b2, _c2, _d2;
9799
+ return {
9800
+ label: (_b2 = (_a2 = descriptor.options) == null ? void 0 : _a2.defaultLabel) != null ? _b2 : "Option label",
9801
+ value: (_d2 = (_c2 = descriptor.options) == null ? void 0 : _c2.defaultValue) != null ? _d2 : "option"
9802
+ };
9803
+ });
9804
+ }
9805
+ return fieldId;
9806
+ }
9771
9807
  updateField(id, patch) {
9772
9808
  return updateField(this.moduleCtx(), id, patch);
9773
9809
  }
@@ -9963,6 +9999,28 @@ var Editor = class {
9963
9999
  });
9964
10000
  });
9965
10001
  }
10002
+ setFieldMulti(fieldId, enabled) {
10003
+ const flag = enabled === true;
10004
+ this.transact("setFieldMulti", () => {
10005
+ this.patchProps((p) => {
10006
+ var _a, _b;
10007
+ const f = ((_a = p.fields) != null ? _a : []).find((x) => x.id === fieldId);
10008
+ if (!f) return;
10009
+ const currentMeta = (_b = f.meta) != null ? _b : {};
10010
+ const nextMeta = { ...currentMeta };
10011
+ if (flag) {
10012
+ nextMeta.multi = true;
10013
+ } else {
10014
+ delete nextMeta.multi;
10015
+ }
10016
+ if (Object.keys(nextMeta).length === 0) {
10017
+ delete f.meta;
10018
+ } else {
10019
+ f.meta = nextMeta;
10020
+ }
10021
+ });
10022
+ });
10023
+ }
9966
10024
  autoCreateOptionsMany(ids, makeOption) {
9967
10025
  const ordered = Array.from(new Set((ids != null ? ids : []).map((id) => String(id))));
9968
10026
  if (!ordered.length) return;