@narrative.io/jsonforms-provider-protocols 1.1.0-beta.3 → 1.1.0-beta.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.
Files changed (31) hide show
  1. package/dist/jsonforms-provider-protocols.css +1 -1
  2. package/dist/vue/composables/useDerive.d.ts +13 -0
  3. package/dist/vue/composables/useDerive.d.ts.map +1 -0
  4. package/dist/vue/composables/useDerive.js +71 -0
  5. package/dist/vue/composables/useDerive.js.map +1 -0
  6. package/dist/vue/primevue/JfBoolean.vue.d.ts +1 -1
  7. package/dist/vue/primevue/JfEnum.vue.d.ts +1 -1
  8. package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
  9. package/dist/vue/primevue/JfEnum.vue.js +1 -1
  10. package/dist/vue/primevue/JfEnum.vue2.js +56 -6
  11. package/dist/vue/primevue/JfEnum.vue2.js.map +1 -1
  12. package/dist/vue/primevue/JfEnumArray.vue.d.ts +1 -1
  13. package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
  14. package/dist/vue/primevue/JfEnumArray.vue.js +56 -8
  15. package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
  16. package/dist/vue/primevue/JfNumber.vue.d.ts +1 -1
  17. package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
  18. package/dist/vue/primevue/JfNumber.vue.js +2 -0
  19. package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
  20. package/dist/vue/primevue/JfText.vue.d.ts +1 -1
  21. package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
  22. package/dist/vue/primevue/JfText.vue.js +77 -7
  23. package/dist/vue/primevue/JfText.vue.js.map +1 -1
  24. package/dist/vue/primevue/JfTextArea.vue.d.ts +1 -1
  25. package/dist/vue/primevue/index.d.ts +1 -1
  26. package/package.json +1 -1
  27. package/src/vue/composables/useDerive.ts +105 -0
  28. package/src/vue/primevue/JfEnum.vue +73 -7
  29. package/src/vue/primevue/JfEnumArray.vue +76 -9
  30. package/src/vue/primevue/JfNumber.vue +4 -0
  31. package/src/vue/primevue/JfText.vue +93 -5
@@ -7,6 +7,6 @@
7
7
  text-align: left;
8
8
  }
9
9
 
10
- [data-v-354307cd] .p-dropdown-label {
10
+ [data-v-feb82abc] .p-dropdown-label {
11
11
  text-align: left;
12
12
  }
@@ -0,0 +1,13 @@
1
+ import { type Ref } from "vue";
2
+ import { type ControlElement } from "@jsonforms/core";
3
+ interface DeriveOptions {
4
+ control: Ref<{
5
+ uischema: ControlElement;
6
+ path: string;
7
+ data: unknown;
8
+ }>;
9
+ handleChange: (path: string, value: unknown) => void;
10
+ }
11
+ export declare function useDerive({ control, handleChange }: DeriveOptions): void;
12
+ export {};
13
+ //# sourceMappingURL=useDerive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDerive.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useDerive.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACxD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,UAAU,aAAa;IACrB,OAAO,EAAE,GAAG,CAAC;QACX,QAAQ,EAAE,cAAc,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,OAAO,CAAC;KACf,CAAC,CAAC;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD;AAED,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,aAAa,QAkDjE"}
@@ -0,0 +1,71 @@
1
+ import { inject, computed, watch } from "vue";
2
+ import "@jsonforms/core";
3
+ function useDerive({ control, handleChange }) {
4
+ const injectedFormData = inject("formData", {
5
+ value: {}
6
+ });
7
+ const rootData = computed(() => injectedFormData.value || {});
8
+ const injectedExternalData = inject("externalData", {
9
+ value: {}
10
+ });
11
+ const externalData = computed(() => injectedExternalData.value || {});
12
+ const deriveConfig = computed(() => {
13
+ const options = control.value.uischema?.options;
14
+ return {
15
+ expression: options?.derive,
16
+ mode: options?.mode || "follow"
17
+ // 'follow' = auto-update, 'manual' = user controlled
18
+ };
19
+ });
20
+ watch(
21
+ [rootData, externalData, deriveConfig],
22
+ ([data, extData, config]) => {
23
+ if (!config.expression || config.mode !== "follow") {
24
+ return;
25
+ }
26
+ try {
27
+ const derivedValue = resolveDeriveExpression(
28
+ config.expression,
29
+ data,
30
+ extData
31
+ );
32
+ if (derivedValue !== control.value.data) {
33
+ handleChange(control.value.path, derivedValue);
34
+ }
35
+ } catch (error) {
36
+ console.warn(
37
+ `Failed to derive value for ${control.value.path}:`,
38
+ error
39
+ );
40
+ }
41
+ },
42
+ { deep: true, immediate: true }
43
+ );
44
+ }
45
+ function resolveDeriveExpression(expression, data, externalData) {
46
+ if (expression.startsWith("externalData(") && expression.endsWith(")")) {
47
+ const propertyPath = expression.slice(13, -1);
48
+ return resolvePropertyPath(propertyPath, externalData);
49
+ }
50
+ if (!expression.includes("(") && !expression.includes("+") && !expression.includes("?")) {
51
+ return resolvePropertyPath(expression, data);
52
+ }
53
+ return resolvePropertyPath(expression, data);
54
+ }
55
+ function resolvePropertyPath(path, data) {
56
+ if (!path || !data) return "";
57
+ const keys = path.split(".");
58
+ let value = data;
59
+ for (const key of keys) {
60
+ if (value && typeof value === "object" && key in value) {
61
+ value = value[key];
62
+ } else {
63
+ return null;
64
+ }
65
+ }
66
+ return value;
67
+ }
68
+ export {
69
+ useDerive
70
+ };
71
+ //# sourceMappingURL=useDerive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDerive.js","sources":["../../../src/vue/composables/useDerive.ts"],"sourcesContent":["import { computed, watch, inject, type Ref } from \"vue\";\nimport { type ControlElement } from \"@jsonforms/core\";\n\ninterface DeriveOptions {\n control: Ref<{\n uischema: ControlElement;\n path: string;\n data: unknown;\n }>;\n handleChange: (path: string, value: unknown) => void;\n}\n\nexport function useDerive({ control, handleChange }: DeriveOptions) {\n // Get the root form data from JSONForms context\n const injectedFormData = inject<{ value: unknown }>(\"formData\", {\n value: {},\n });\n const rootData = computed(() => injectedFormData.value || {});\n\n // Get external data from context if available\n const injectedExternalData = inject<{ value: unknown }>(\"externalData\", {\n value: {},\n });\n const externalData = computed(() => injectedExternalData.value || {});\n\n // Extract derive configuration from uischema options\n const deriveConfig = computed(() => {\n const options = control.value.uischema?.options as\n | { derive?: string; mode?: string }\n | undefined;\n return {\n expression: options?.derive,\n mode: options?.mode || \"follow\", // 'follow' = auto-update, 'manual' = user controlled\n };\n });\n\n // Watch for changes in form data and external data and update derived field\n watch(\n [rootData, externalData, deriveConfig],\n ([data, extData, config]) => {\n if (!config.expression || config.mode !== \"follow\") {\n return;\n }\n\n try {\n const derivedValue = resolveDeriveExpression(\n config.expression,\n data,\n extData,\n );\n if (derivedValue !== control.value.data) {\n handleChange(control.value.path, derivedValue);\n }\n } catch (error) {\n console.warn(\n `Failed to derive value for ${control.value.path}:`,\n error,\n );\n }\n },\n { deep: true, immediate: true },\n );\n}\n\nfunction resolveDeriveExpression(\n expression: string,\n data: unknown,\n externalData?: unknown,\n): unknown {\n // Handle externalData() syntax\n if (expression.startsWith(\"externalData(\") && expression.endsWith(\")\")) {\n const propertyPath = expression.slice(13, -1); // Remove \"externalData(\" and \")\"\n return resolvePropertyPath(propertyPath, externalData);\n }\n\n // Handle simple property paths like \"country.name\"\n if (\n !expression.includes(\"(\") &&\n !expression.includes(\"+\") &&\n !expression.includes(\"?\")\n ) {\n return resolvePropertyPath(expression, data);\n }\n\n // For now, we'll only support simple property paths and externalData() calls\n // Complex expressions would require a safe expression evaluator\n return resolvePropertyPath(expression, data);\n}\n\nfunction resolvePropertyPath(path: string, data: unknown): unknown {\n if (!path || !data) return \"\";\n\n const keys = path.split(\".\");\n let value: unknown = data;\n\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return null;\n }\n }\n\n return value;\n}\n"],"names":[],"mappings":";;AAYO,SAAS,UAAU,EAAE,SAAS,gBAA+B;AAElE,QAAM,mBAAmB,OAA2B,YAAY;AAAA,IAC9D,OAAO,CAAA;AAAA,EAAC,CACT;AACD,QAAM,WAAW,SAAS,MAAM,iBAAiB,SAAS,CAAA,CAAE;AAG5D,QAAM,uBAAuB,OAA2B,gBAAgB;AAAA,IACtE,OAAO,CAAA;AAAA,EAAC,CACT;AACD,QAAM,eAAe,SAAS,MAAM,qBAAqB,SAAS,CAAA,CAAE;AAGpE,QAAM,eAAe,SAAS,MAAM;AAClC,UAAM,UAAU,QAAQ,MAAM,UAAU;AAGxC,WAAO;AAAA,MACL,YAAY,SAAS;AAAA,MACrB,MAAM,SAAS,QAAQ;AAAA;AAAA,IAAA;AAAA,EAE3B,CAAC;AAGD;AAAA,IACE,CAAC,UAAU,cAAc,YAAY;AAAA,IACrC,CAAC,CAAC,MAAM,SAAS,MAAM,MAAM;AAC3B,UAAI,CAAC,OAAO,cAAc,OAAO,SAAS,UAAU;AAClD;AAAA,MACF;AAEA,UAAI;AACF,cAAM,eAAe;AAAA,UACnB,OAAO;AAAA,UACP;AAAA,UACA;AAAA,QAAA;AAEF,YAAI,iBAAiB,QAAQ,MAAM,MAAM;AACvC,uBAAa,QAAQ,MAAM,MAAM,YAAY;AAAA,QAC/C;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ;AAAA,UACN,8BAA8B,QAAQ,MAAM,IAAI;AAAA,UAChD;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAAA,IACA,EAAE,MAAM,MAAM,WAAW,KAAA;AAAA,EAAK;AAElC;AAEA,SAAS,wBACP,YACA,MACA,cACS;AAET,MAAI,WAAW,WAAW,eAAe,KAAK,WAAW,SAAS,GAAG,GAAG;AACtE,UAAM,eAAe,WAAW,MAAM,IAAI,EAAE;AAC5C,WAAO,oBAAoB,cAAc,YAAY;AAAA,EACvD;AAGA,MACE,CAAC,WAAW,SAAS,GAAG,KACxB,CAAC,WAAW,SAAS,GAAG,KACxB,CAAC,WAAW,SAAS,GAAG,GACxB;AACA,WAAO,oBAAoB,YAAY,IAAI;AAAA,EAC7C;AAIA,SAAO,oBAAoB,YAAY,IAAI;AAC7C;AAEA,SAAS,oBAAoB,MAAc,MAAwB;AACjE,MAAI,CAAC,QAAQ,CAAC,KAAM,QAAO;AAE3B,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,MAAI,QAAiB;AAErB,aAAW,OAAO,MAAM;AACtB,QAAI,SAAS,OAAO,UAAU,YAAY,OAAO,OAAO;AACtD,cAAS,MAAkC,GAAG;AAAA,IAChD,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;"}
@@ -66,10 +66,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
66
66
  default: undefined;
67
67
  };
68
68
  }>> & Readonly<{}>, {
69
+ config: Record<string, any>;
69
70
  enabled: boolean;
70
71
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
71
72
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
72
- config: Record<string, any>;
73
73
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
74
74
  export default _default;
75
75
  //# sourceMappingURL=JfBoolean.vue.d.ts.map
@@ -66,10 +66,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
66
66
  default: undefined;
67
67
  };
68
68
  }>> & Readonly<{}>, {
69
+ config: Record<string, any>;
69
70
  enabled: boolean;
70
71
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
71
72
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
72
- config: Record<string, any>;
73
73
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
74
74
  export default _default;
75
75
  //# sourceMappingURL=JfEnum.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JfEnum.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfEnum.vue"],"names":[],"mappings":"AAkFA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0KlE,wBAEG"}
1
+ {"version":3,"file":"JfEnum.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfEnum.vue"],"names":[],"mappings":"AAoJA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuPlE,wBAEG"}
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./JfEnum.vue2.js";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.js";
4
- const JfEnum = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-354307cd"]]);
4
+ const JfEnum = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-feb82abc"]]);
5
5
  export {
6
6
  JfEnum as default
7
7
  };
@@ -1,5 +1,7 @@
1
- import { defineComponent, computed, ref, createElementBlock, openBlock, createCommentVNode, createVNode, unref, toDisplayString } from "vue";
1
+ import { defineComponent, computed, inject, ref, createElementBlock, openBlock, createCommentVNode, createVNode, unref, toDisplayString } from "vue";
2
2
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
3
+ import { useProvider } from "../composables/useProvider.js";
4
+ import { useDerive } from "../composables/useDerive.js";
3
5
  import Dropdown from "primevue/dropdown";
4
6
  const _hoisted_1 = { class: "flex flex-column gap-2" };
5
7
  const _hoisted_2 = {
@@ -12,6 +14,11 @@ const _hoisted_3 = {
12
14
  };
13
15
  const _hoisted_4 = {
14
16
  key: 2,
17
+ class: "p-error",
18
+ role: "alert"
19
+ };
20
+ const _hoisted_5 = {
21
+ key: 3,
15
22
  class: "p-error"
16
23
  };
17
24
  const _sfc_main = /* @__PURE__ */ defineComponent({
@@ -33,10 +40,53 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
33
40
  }));
34
41
  return [];
35
42
  };
36
- const placeholder = computed(
37
- () => control.value.uischema?.options?.placeholder ?? control.value.description
43
+ const binding = computed(() => {
44
+ const provider = control.value.uischema?.options?.provider;
45
+ if (provider && typeof provider === "object" && !provider.load) {
46
+ return { ...provider, load: "mount" };
47
+ }
48
+ return provider;
49
+ });
50
+ const deps = computed(
51
+ () => control.value.schema?.["x-provider"]?.dependsOn ?? []
38
52
  );
39
- const options = computed(() => toOptions(control.value.schema));
53
+ const depValues = computed(() => {
54
+ return deps.value.map((dep) => {
55
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
56
+ const keys = path.replace(/\//g, ".").split(".");
57
+ let value = rootData.value;
58
+ for (const key of keys) {
59
+ if (value && typeof value === "object" && key in value) {
60
+ value = value[key];
61
+ } else {
62
+ return null;
63
+ }
64
+ }
65
+ return value;
66
+ });
67
+ });
68
+ const injectedFormData = inject("formData", { value: {} });
69
+ const rootData = computed(() => injectedFormData.value || {});
70
+ const {
71
+ items: providerItems,
72
+ loading,
73
+ error
74
+ } = useProvider(binding, {
75
+ data: rootData,
76
+ path: control.value.path,
77
+ dependsOnValues: depValues.value
78
+ });
79
+ const placeholder = computed(() => {
80
+ if (loading.value) return "Loading…";
81
+ return control.value.uischema?.options?.placeholder ?? control.value.description;
82
+ });
83
+ const options = computed(() => {
84
+ if (binding.value && providerItems.value.length > 0) {
85
+ return providerItems.value;
86
+ }
87
+ return toOptions(control.value.schema);
88
+ });
89
+ useDerive({ control, handleChange });
40
90
  const hasInteracted = ref(false);
41
91
  const showErrors = computed(() => hasInteracted.value && control.value.errors);
42
92
  const onSelect = (val) => {
@@ -56,13 +106,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
56
106
  "option-value": "value",
57
107
  "model-value": unref(control).data ?? null,
58
108
  placeholder: placeholder.value,
59
- disabled: !unref(control).enabled,
109
+ disabled: !unref(control).enabled || unref(loading),
60
110
  "aria-invalid": !!showErrors.value || void 0,
61
111
  "show-clear": true,
62
112
  "onUpdate:modelValue": onSelect,
63
113
  onBlur
64
114
  }, null, 8, ["options", "model-value", "placeholder", "disabled", "aria-invalid"]),
65
- showErrors.value ? (openBlock(), createElementBlock("small", _hoisted_4, toDisplayString(unref(control).errors), 1)) : createCommentVNode("", true)
115
+ unref(error) ? (openBlock(), createElementBlock("small", _hoisted_4, "Failed to load: " + toDisplayString(unref(error)), 1)) : showErrors.value ? (openBlock(), createElementBlock("small", _hoisted_5, toDisplayString(unref(control).errors), 1)) : createCommentVNode("", true)
66
116
  ]);
67
117
  };
68
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"JfEnum.vue2.js","sources":["../../../src/vue/primevue/JfEnum.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref } from \"vue\";\nimport Dropdown from \"primevue/dropdown\";\n\ndefineOptions({ name: \"JfEnum\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\ntype Opt = { label: string; value: unknown };\nconst toOptions = (schema?: JsonSchema): Opt[] => {\n if (!schema) return [];\n const s = schema as {\n enum?: unknown[];\n oneOf?: Array<{ title?: string; const: unknown }>;\n };\n if (Array.isArray(s.enum))\n return s.enum.map((v: unknown) => ({ label: String(v), value: v }));\n if (Array.isArray(s.oneOf))\n return s.oneOf.map((o) => ({\n label: o.title ?? String(o.const),\n value: o.const,\n }));\n return [];\n};\n\nconst placeholder = computed<string | undefined>(\n () =>\n (control.value.uischema as { options?: { placeholder?: string } })?.options\n ?.placeholder ?? control.value.description,\n);\n\nconst options = computed(() => toOptions(control.value.schema));\n\n// Track user interaction\nconst hasInteracted = ref(false);\n\nconst showErrors = computed(() => hasInteracted.value && control.value.errors);\n\nconst onSelect = (val: unknown) => {\n handleChange(control.value.path, val);\n};\n\nconst onBlur = () => {\n hasInteracted.value = true;\n};\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n <Dropdown\n class=\"w-full\"\n :options=\"options\"\n option-label=\"label\"\n option-value=\"value\"\n :model-value=\"control.data ?? null\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!showErrors || undefined\"\n :show-clear=\"true\"\n @update:model-value=\"onSelect\"\n @blur=\"onBlur\"\n />\n <small v-if=\"showErrors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n\n<style scoped>\n:deep(.p-dropdown-label) {\n text-align: left;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAM,QAAQ;AACd,UAAM,EAAE,SAAS,iBAAiB,oBAAoB,KAAK;AAG3D,UAAM,YAAY,CAAC,WAA+B;AAChD,UAAI,CAAC,OAAQ,QAAO,CAAA;AACpB,YAAM,IAAI;AAIV,UAAI,MAAM,QAAQ,EAAE,IAAI;AACtB,eAAO,EAAE,KAAK,IAAI,CAAC,OAAgB,EAAE,OAAO,OAAO,CAAC,GAAG,OAAO,EAAA,EAAI;AACpE,UAAI,MAAM,QAAQ,EAAE,KAAK;AACvB,eAAO,EAAE,MAAM,IAAI,CAAC,OAAO;AAAA,UACzB,OAAO,EAAE,SAAS,OAAO,EAAE,KAAK;AAAA,UAChC,OAAO,EAAE;AAAA,QAAA,EACT;AACJ,aAAO,CAAA;AAAA,IACT;AAEA,UAAM,cAAc;AAAA,MAClB,MACG,QAAQ,MAAM,UAAqD,SAChE,eAAe,QAAQ,MAAM;AAAA,IAAA;AAGrC,UAAM,UAAU,SAAS,MAAM,UAAU,QAAQ,MAAM,MAAM,CAAC;AAG9D,UAAM,gBAAgB,IAAI,KAAK;AAE/B,UAAM,aAAa,SAAS,MAAM,cAAc,SAAS,QAAQ,MAAM,MAAM;AAE7E,UAAM,WAAW,CAAC,QAAiB;AACjC,mBAAa,QAAQ,MAAM,MAAM,GAAG;AAAA,IACtC;AAEA,UAAM,SAAS,MAAM;AACnB,oBAAc,QAAQ;AAAA,IACxB;;AAIE,aAAAA,UAAA,GAAAC,mBAqBM,OArBN,YAqBM;AAAA,QApBSC,MAAA,OAAA,EAAQ,SAArBF,UAAA,GAAAC,mBAEU,SAFV,YAEUE,gBADRD,MAAA,OAAA,EAAQ,KAAK,GAAA,CAAA;QAEJA,MAAA,OAAA,EAAQ,eAAnBF,UAAA,GAAAC,mBAEM,OAFN,YAEME,gBADDD,MAAA,OAAA,EAAQ,WAAW,GAAA,CAAA;QAExBE,YAYEF,MAAA,QAAA,GAAA;AAAA,UAXA,OAAM;AAAA,UACL,SAAS,QAAA;AAAA,UACV,gBAAa;AAAA,UACb,gBAAa;AAAA,UACZ,eAAaA,MAAA,OAAA,EAAQ,QAAI;AAAA,UACzB,aAAa,YAAA;AAAA,UACb,UAAQ,CAAGA,MAAA,OAAA,EAAQ;AAAA,UACnB,gBAAY,CAAA,CAAI,WAAA,SAAc;AAAA,UAC9B,cAAY;AAAA,UACZ,uBAAoB;AAAA,UACpB;AAAA,QAAA;QAEU,WAAA,SAAbF,UAAA,GAAAC,mBAAqE,SAArE,YAAqEE,gBAAzBD,MAAA,OAAA,EAAQ,MAAM,GAAA,CAAA;;;;;"}
1
+ {"version":3,"file":"JfEnum.vue2.js","sources":["../../../src/vue/primevue/JfEnum.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref, inject } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport Dropdown from \"primevue/dropdown\";\n\ndefineOptions({ name: \"JfEnum\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\ntype Opt = { label: string; value: unknown };\nconst toOptions = (schema?: JsonSchema): Opt[] => {\n if (!schema) return [];\n const s = schema as {\n enum?: unknown[];\n oneOf?: Array<{ title?: string; const: unknown }>;\n };\n if (Array.isArray(s.enum))\n return s.enum.map((v: unknown) => ({ label: String(v), value: v }));\n if (Array.isArray(s.oneOf))\n return s.oneOf.map((o) => ({\n label: o.title ?? String(o.const),\n value: o.const,\n }));\n return [];\n};\n\n// Provider support\nconst binding = computed(() => {\n const provider = control.value.uischema?.options?.provider;\n // Ensure load property is set to 'mount' by default\n if (provider && typeof provider === \"object\" && !provider.load) {\n return { ...provider, load: \"mount\" };\n }\n return provider;\n});\n\nconst deps = computed(\n () =>\n ((\n (control.value.schema as Record<string, unknown>)?.[\n \"x-provider\"\n ] as Record<string, unknown>\n )?.dependsOn as string[]) ?? [],\n);\nconst depValues = computed(() => {\n return deps.value.map((dep) => {\n // Resolve dependency value from form data using JSON pointer-like path\n const path = dep.startsWith(\"#/\") ? dep.slice(2) : dep;\n const keys = path.replace(/\\//g, \".\").split(\".\");\n let value: unknown = rootData.value;\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return null;\n }\n }\n return value;\n });\n});\n\n// Get the root form data from JSONForms context for template URL resolution\nconst injectedFormData = inject<{ value: unknown }>(\"formData\", { value: {} });\nconst rootData = computed(() => injectedFormData.value || {});\n\n// Use provider if available, otherwise fall back to schema enum/oneOf\nconst {\n items: providerItems,\n loading,\n error,\n} = useProvider(binding, {\n data: rootData,\n path: control.value.path,\n dependsOnValues: depValues.value,\n});\n\nconst placeholder = computed<string | undefined>(() => {\n if (loading.value) return \"Loading…\";\n return (\n (control.value.uischema as { options?: { placeholder?: string } })?.options\n ?.placeholder ?? control.value.description\n );\n});\n\nconst options = computed(() => {\n // Use provider items if available, otherwise fall back to schema enum/oneOf\n if (binding.value && providerItems.value.length > 0) {\n return providerItems.value;\n }\n return toOptions(control.value.schema);\n});\n\n// Add derive functionality\nuseDerive({ control, handleChange });\n\n// Track user interaction\nconst hasInteracted = ref(false);\n\nconst showErrors = computed(() => hasInteracted.value && control.value.errors);\n\nconst onSelect = (val: unknown) => {\n handleChange(control.value.path, val);\n};\n\nconst onBlur = () => {\n hasInteracted.value = true;\n};\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n <Dropdown\n class=\"w-full\"\n :options=\"options\"\n option-label=\"label\"\n option-value=\"value\"\n :model-value=\"control.data ?? null\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled || loading\"\n :aria-invalid=\"!!showErrors || undefined\"\n :show-clear=\"true\"\n @update:model-value=\"onSelect\"\n @blur=\"onBlur\"\n />\n <small v-if=\"error\" class=\"p-error\" role=\"alert\"\n >Failed to load: {{ error }}</small\n >\n <small v-else-if=\"showErrors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n\n<style scoped>\n:deep(.p-dropdown-label) {\n text-align: left;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":"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"}
@@ -66,10 +66,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
66
66
  default: undefined;
67
67
  };
68
68
  }>> & Readonly<{}>, {
69
+ config: Record<string, any>;
69
70
  enabled: boolean;
70
71
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
71
72
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
72
- config: Record<string, any>;
73
73
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
74
74
  export default _default;
75
75
  //# sourceMappingURL=JfEnumArray.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JfEnumArray.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfEnumArray.vue"],"names":[],"mappings":"AAuFA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmKlE,wBAEG"}
1
+ {"version":3,"file":"JfEnumArray.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfEnumArray.vue"],"names":[],"mappings":"AA0JA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiPlE,wBAEG"}
@@ -1,5 +1,7 @@
1
- import { defineComponent, computed, createElementBlock, openBlock, createCommentVNode, createVNode, unref, toDisplayString } from "vue";
1
+ import { defineComponent, computed, inject, createElementBlock, openBlock, createCommentVNode, createVNode, unref, toDisplayString } from "vue";
2
2
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
3
+ import { useProvider } from "../composables/useProvider.js";
4
+ import { useDerive } from "../composables/useDerive.js";
3
5
  import MultiSelect from "primevue/multiselect";
4
6
  const _hoisted_1 = { class: "flex flex-column gap-2" };
5
7
  const _hoisted_2 = {
@@ -12,6 +14,11 @@ const _hoisted_3 = {
12
14
  };
13
15
  const _hoisted_4 = {
14
16
  key: 2,
17
+ class: "p-error",
18
+ role: "alert"
19
+ };
20
+ const _hoisted_5 = {
21
+ key: 3,
15
22
  class: "p-error"
16
23
  };
17
24
  const _sfc_main = /* @__PURE__ */ defineComponent({
@@ -33,12 +40,53 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
33
40
  }));
34
41
  return [];
35
42
  };
36
- const options = computed(
37
- () => toOptions(control.value.schema?.items)
38
- );
39
- const placeholder = computed(
40
- () => control.value.uischema?.options?.placeholder ?? control.value.description
43
+ const binding = computed(() => {
44
+ const provider = control.value.uischema?.options?.provider;
45
+ if (provider && typeof provider === "object" && !provider.load) {
46
+ return { ...provider, load: "mount" };
47
+ }
48
+ return provider;
49
+ });
50
+ const deps = computed(
51
+ () => control.value.schema?.["x-provider"]?.dependsOn ?? []
41
52
  );
53
+ const depValues = computed(() => {
54
+ return deps.value.map((dep) => {
55
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
56
+ const keys = path.replace(/\//g, ".").split(".");
57
+ let value = rootData.value;
58
+ for (const key of keys) {
59
+ if (value && typeof value === "object" && key in value) {
60
+ value = value[key];
61
+ } else {
62
+ return null;
63
+ }
64
+ }
65
+ return value;
66
+ });
67
+ });
68
+ const injectedFormData = inject("formData", { value: {} });
69
+ const rootData = computed(() => injectedFormData.value || {});
70
+ const {
71
+ items: providerItems,
72
+ loading,
73
+ error
74
+ } = useProvider(binding, {
75
+ data: rootData,
76
+ path: control.value.path,
77
+ dependsOnValues: depValues.value
78
+ });
79
+ const options = computed(() => {
80
+ if (binding.value && providerItems.value.length > 0) {
81
+ return providerItems.value;
82
+ }
83
+ return toOptions(control.value.schema?.items);
84
+ });
85
+ useDerive({ control, handleChange });
86
+ const placeholder = computed(() => {
87
+ if (loading.value) return "Loading…";
88
+ return control.value.uischema?.options?.placeholder ?? control.value.description;
89
+ });
42
90
  const sameSet = (a, b) => {
43
91
  if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
44
92
  return false;
@@ -69,11 +117,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
69
117
  "option-value": "value",
70
118
  "data-key": "value",
71
119
  display: "chip",
72
- disabled: !unref(control).enabled,
120
+ disabled: !unref(control).enabled || unref(loading),
73
121
  "aria-invalid": !!unref(control).errors || void 0,
74
122
  placeholder: placeholder.value
75
123
  }, null, 8, ["modelValue", "options", "disabled", "aria-invalid", "placeholder"]),
76
- unref(control).errors ? (openBlock(), createElementBlock("small", _hoisted_4, toDisplayString(unref(control).errors), 1)) : createCommentVNode("", true)
124
+ unref(error) ? (openBlock(), createElementBlock("small", _hoisted_4, "Failed to load: " + toDisplayString(unref(error)), 1)) : unref(control).errors ? (openBlock(), createElementBlock("small", _hoisted_5, toDisplayString(unref(control).errors), 1)) : createCommentVNode("", true)
77
125
  ]);
78
126
  };
79
127
  }
@@ -1 +1 @@
1
- {"version":3,"file":"JfEnumArray.vue.js","sources":["../../../src/vue/primevue/JfEnumArray.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed } from \"vue\";\nimport MultiSelect from \"primevue/multiselect\";\n\ndefineOptions({ name: \"JfEnumArray\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\ntype Opt = { label: string; value: unknown };\nconst toOptions = (schema?: JsonSchema): Opt[] => {\n if (!schema) return [];\n const s = schema as {\n enum?: unknown[];\n oneOf?: Array<{ title?: string; const: unknown }>;\n };\n if (Array.isArray(s.enum))\n return s.enum.map((v: unknown) => ({ label: String(v), value: v }));\n if (Array.isArray(s.oneOf))\n return s.oneOf.map((o) => ({\n label: o.title ?? String(o.const),\n value: o.const,\n }));\n return [];\n};\n\nconst options = computed(() =>\n toOptions((control.value.schema as { items?: JsonSchema })?.items),\n);\nconst placeholder = computed<string | undefined>(\n () =>\n (control.value.uischema as { options?: { placeholder?: string } })?.options\n ?.placeholder ?? control.value.description,\n);\n\n// order-insensitive shallow equality for primitive enums\nconst sameSet = (a: unknown[], b: unknown[]) => {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)\n return false;\n const s = new Set(b);\n return a.every((v) => s.has(v));\n};\n\n// v-model with guard to avoid recursive updates\nconst model = computed<unknown[]>({\n get() {\n const curr = Array.isArray(control.value.data) ? control.value.data : [];\n // return a fresh copy so PrimeMultiSelect can't mutate JSONForms' array in place\n return [...curr];\n },\n set(val) {\n const next = Array.isArray(val) ? [...val] : [];\n const curr = Array.isArray(control.value.data) ? control.value.data : [];\n if (!sameSet(curr, next)) handleChange(control.value.path, next);\n },\n});\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n\n <MultiSelect\n v-model=\"model\"\n class=\"w-full\"\n :options=\"options\"\n option-label=\"label\"\n option-value=\"value\"\n data-key=\"value\"\n display=\"chip\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!control.errors || undefined\"\n :placeholder=\"placeholder\"\n />\n\n <small v-if=\"control.errors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAM,QAAQ;AACd,UAAM,EAAE,SAAS,iBAAiB,oBAAoB,KAAK;AAG3D,UAAM,YAAY,CAAC,WAA+B;AAChD,UAAI,CAAC,OAAQ,QAAO,CAAA;AACpB,YAAM,IAAI;AAIV,UAAI,MAAM,QAAQ,EAAE,IAAI;AACtB,eAAO,EAAE,KAAK,IAAI,CAAC,OAAgB,EAAE,OAAO,OAAO,CAAC,GAAG,OAAO,EAAA,EAAI;AACpE,UAAI,MAAM,QAAQ,EAAE,KAAK;AACvB,eAAO,EAAE,MAAM,IAAI,CAAC,OAAO;AAAA,UACzB,OAAO,EAAE,SAAS,OAAO,EAAE,KAAK;AAAA,UAChC,OAAO,EAAE;AAAA,QAAA,EACT;AACJ,aAAO,CAAA;AAAA,IACT;AAEA,UAAM,UAAU;AAAA,MAAS,MACvB,UAAW,QAAQ,MAAM,QAAmC,KAAK;AAAA,IAAA;AAEnE,UAAM,cAAc;AAAA,MAClB,MACG,QAAQ,MAAM,UAAqD,SAChE,eAAe,QAAQ,MAAM;AAAA,IAAA;AAIrC,UAAM,UAAU,CAAC,GAAc,MAAiB;AAC9C,UAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE;AAC3D,eAAO;AACT,YAAM,IAAI,IAAI,IAAI,CAAC;AACnB,aAAO,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAAA,IAChC;AAGA,UAAM,QAAQ,SAAoB;AAAA,MAChC,MAAM;AACJ,cAAM,OAAO,MAAM,QAAQ,QAAQ,MAAM,IAAI,IAAI,QAAQ,MAAM,OAAO,CAAA;AAEtE,eAAO,CAAC,GAAG,IAAI;AAAA,MACjB;AAAA,MACA,IAAI,KAAK;AACP,cAAM,OAAO,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAA;AAC7C,cAAM,OAAO,MAAM,QAAQ,QAAQ,MAAM,IAAI,IAAI,QAAQ,MAAM,OAAO,CAAA;AACtE,YAAI,CAAC,QAAQ,MAAM,IAAI,EAAG,cAAa,QAAQ,MAAM,MAAM,IAAI;AAAA,MACjE;AAAA,IAAA,CACD;;AAIC,aAAAA,UAAA,GAAAC,mBAsBM,OAtBN,YAsBM;AAAA,QArBSC,MAAA,OAAA,EAAQ,SAArBF,UAAA,GAAAC,mBAEU,SAFV,YAEUE,gBADRD,MAAA,OAAA,EAAQ,KAAK,GAAA,CAAA;QAEJA,MAAA,OAAA,EAAQ,eAAnBF,UAAA,GAAAC,mBAEM,OAFN,YAEME,gBADDD,MAAA,OAAA,EAAQ,WAAW,GAAA,CAAA;QAGxBE,YAWEF,MAAA,WAAA,GAAA;AAAA,sBAVS,MAAA;AAAA,uEAAA,MAAK,QAAA;AAAA,UACd,OAAM;AAAA,UACL,SAAS,QAAA;AAAA,UACV,gBAAa;AAAA,UACb,gBAAa;AAAA,UACb,YAAS;AAAA,UACT,SAAQ;AAAA,UACP,UAAQ,CAAGA,MAAA,OAAA,EAAQ;AAAA,UACnB,gBAAY,CAAA,CAAIA,MAAA,OAAA,EAAQ,UAAU;AAAA,UAClC,aAAa,YAAA;AAAA,QAAA;QAGHA,MAAA,OAAA,EAAQ,UAArBF,UAAA,GAAAC,mBAAyE,SAAzE,YAAyEE,gBAAzBD,MAAA,OAAA,EAAQ,MAAM,GAAA,CAAA;;;;;"}
1
+ {"version":3,"file":"JfEnumArray.vue.js","sources":["../../../src/vue/primevue/JfEnumArray.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport MultiSelect from \"primevue/multiselect\";\n\ndefineOptions({ name: \"JfEnumArray\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\ntype Opt = { label: string; value: unknown };\nconst toOptions = (schema?: JsonSchema): Opt[] => {\n if (!schema) return [];\n const s = schema as {\n enum?: unknown[];\n oneOf?: Array<{ title?: string; const: unknown }>;\n };\n if (Array.isArray(s.enum))\n return s.enum.map((v: unknown) => ({ label: String(v), value: v }));\n if (Array.isArray(s.oneOf))\n return s.oneOf.map((o) => ({\n label: o.title ?? String(o.const),\n value: o.const,\n }));\n return [];\n};\n\n// Provider support\nconst binding = computed(() => {\n const provider = control.value.uischema?.options?.provider;\n // Ensure load property is set to 'mount' by default\n if (provider && typeof provider === \"object\" && !provider.load) {\n return { ...provider, load: \"mount\" };\n }\n return provider;\n});\n\nconst deps = computed(\n () =>\n ((\n (control.value.schema as Record<string, unknown>)?.[\n \"x-provider\"\n ] as Record<string, unknown>\n )?.dependsOn as string[]) ?? [],\n);\nconst depValues = computed(() => {\n return deps.value.map((dep) => {\n // Resolve dependency value from form data using JSON pointer-like path\n const path = dep.startsWith(\"#/\") ? dep.slice(2) : dep;\n const keys = path.replace(/\\//g, \".\").split(\".\");\n let value: unknown = rootData.value;\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return null;\n }\n }\n return value;\n });\n});\n\n// Get the root form data from JSONForms context for template URL resolution\nconst injectedFormData = inject<{ value: unknown }>(\"formData\", { value: {} });\nconst rootData = computed(() => injectedFormData.value || {});\n\n// Use provider if available, otherwise fall back to schema enum/oneOf\nconst {\n items: providerItems,\n loading,\n error,\n} = useProvider(binding, {\n data: rootData,\n path: control.value.path,\n dependsOnValues: depValues.value,\n});\n\nconst options = computed(() => {\n // Use provider items if available, otherwise fall back to schema enum/oneOf\n if (binding.value && providerItems.value.length > 0) {\n return providerItems.value;\n }\n return toOptions((control.value.schema as { items?: JsonSchema })?.items);\n});\n\n// Add derive functionality\nuseDerive({ control, handleChange });\n\nconst placeholder = computed<string | undefined>(() => {\n if (loading.value) return \"Loading…\";\n return (\n (control.value.uischema as { options?: { placeholder?: string } })?.options\n ?.placeholder ?? control.value.description\n );\n});\n\n// order-insensitive shallow equality for primitive enums\nconst sameSet = (a: unknown[], b: unknown[]) => {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)\n return false;\n const s = new Set(b);\n return a.every((v) => s.has(v));\n};\n\n// v-model with guard to avoid recursive updates\nconst model = computed<unknown[]>({\n get() {\n const curr = Array.isArray(control.value.data) ? control.value.data : [];\n // return a fresh copy so PrimeMultiSelect can't mutate JSONForms' array in place\n return [...curr];\n },\n set(val) {\n const next = Array.isArray(val) ? [...val] : [];\n const curr = Array.isArray(control.value.data) ? control.value.data : [];\n if (!sameSet(curr, next)) handleChange(control.value.path, next);\n },\n});\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n\n <MultiSelect\n v-model=\"model\"\n class=\"w-full\"\n :options=\"options\"\n option-label=\"label\"\n option-value=\"value\"\n data-key=\"value\"\n display=\"chip\"\n :disabled=\"!control.enabled || loading\"\n :aria-invalid=\"!!control.errors || undefined\"\n :placeholder=\"placeholder\"\n />\n\n <small v-if=\"error\" class=\"p-error\" role=\"alert\"\n >Failed to load: {{ error }}</small\n >\n <small v-else-if=\"control.errors\" class=\"p-error\">{{\n control.errors\n }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":"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"}
@@ -66,10 +66,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
66
66
  default: undefined;
67
67
  };
68
68
  }>> & Readonly<{}>, {
69
+ config: Record<string, any>;
69
70
  enabled: boolean;
70
71
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
71
72
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
72
- config: Record<string, any>;
73
73
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
74
74
  export default _default;
75
75
  //# sourceMappingURL=JfNumber.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JfNumber.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfNumber.vue"],"names":[],"mappings":"AA+FA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+LtD,wBAEG"}
1
+ {"version":3,"file":"JfNumber.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfNumber.vue"],"names":[],"mappings":"AAmGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmMtD,wBAEG"}
@@ -1,5 +1,6 @@
1
1
  import { defineComponent, computed, ref, createElementBlock, openBlock, createCommentVNode, createVNode, unref, toDisplayString } from "vue";
2
2
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
3
+ import { useDerive } from "../composables/useDerive.js";
3
4
  import InputNumber from "primevue/inputnumber";
4
5
  const _hoisted_1 = { class: "flex flex-column gap-2" };
5
6
  const _hoisted_2 = {
@@ -27,6 +28,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
27
28
  const placeholder = computed(
28
29
  () => options.value.placeholder ?? control.value.description
29
30
  );
31
+ useDerive({ control, handleChange });
30
32
  const mode = computed(() => {
31
33
  if (options.value.currency) return "currency";
32
34
  if (options.value.decimal || typeof options.value.precision === "number")
@@ -1 +1 @@
1
- {"version":3,"file":"JfNumber.vue.js","sources":["../../../src/vue/primevue/JfNumber.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref } from \"vue\";\nimport InputNumber from \"primevue/inputnumber\";\n\ndefineOptions({ name: \"JfNumber\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\nconst options = computed(\n () =>\n (control.value.uischema as { options?: Record<string, unknown> })\n ?.options ?? {},\n);\n\nconst placeholder = computed<string | undefined>(\n () => (options.value.placeholder as string) ?? control.value.description,\n);\n\n// Currency and decimal configuration\nconst mode = computed(() => {\n if (options.value.currency) return \"currency\";\n if (options.value.decimal || typeof options.value.precision === \"number\")\n return \"decimal\";\n return undefined;\n});\n\nconst currency = computed(() =>\n typeof options.value.currency === \"string\" ? options.value.currency : \"USD\",\n);\n\nconst minFractionDigits = computed(() => {\n if (mode.value === \"currency\") return 2;\n if (typeof options.value.precision === \"number\")\n return options.value.precision;\n return undefined;\n});\n\nconst maxFractionDigits = computed(() => {\n if (mode.value === \"currency\") return 2;\n if (typeof options.value.precision === \"number\")\n return options.value.precision;\n return undefined;\n});\n\nconst useGrouping = computed(() => {\n // Enable grouping for currency by default, or if explicitly set\n if (mode.value === \"currency\") return true;\n return options.value.useGrouping === true;\n});\n\n// Track user interaction\nconst hasInteracted = ref(false);\n\nconst showErrors = computed(() => hasInteracted.value && control.value.errors);\n\nconst onNumber = (val: number | null) => {\n handleChange(control.value.path, val ?? undefined);\n};\n\nconst onBlur = () => {\n hasInteracted.value = true;\n};\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n <InputNumber\n class=\"w-full\"\n input-class=\"w-full\"\n :use-grouping=\"useGrouping\"\n :mode=\"mode\"\n :currency=\"currency\"\n :min-fraction-digits=\"minFractionDigits\"\n :max-fraction-digits=\"maxFractionDigits\"\n :model-value=\"typeof control.data === 'number' ? control.data : null\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!showErrors || undefined\"\n @update:model-value=\"onNumber\"\n @blur=\"onBlur\"\n />\n <small v-if=\"showErrors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAM,QAAQ;AACd,UAAM,EAAE,SAAS,iBAAiB,oBAAoB,KAAK;AAE3D,UAAM,UAAU;AAAA,MACd,MACG,QAAQ,MAAM,UACX,WAAW,CAAA;AAAA,IAAC;AAGpB,UAAM,cAAc;AAAA,MAClB,MAAO,QAAQ,MAAM,eAA0B,QAAQ,MAAM;AAAA,IAAA;AAI/D,UAAM,OAAO,SAAS,MAAM;AAC1B,UAAI,QAAQ,MAAM,SAAU,QAAO;AACnC,UAAI,QAAQ,MAAM,WAAW,OAAO,QAAQ,MAAM,cAAc;AAC9D,eAAO;AACT,aAAO;AAAA,IACT,CAAC;AAED,UAAM,WAAW;AAAA,MAAS,MACxB,OAAO,QAAQ,MAAM,aAAa,WAAW,QAAQ,MAAM,WAAW;AAAA,IAAA;AAGxE,UAAM,oBAAoB,SAAS,MAAM;AACvC,UAAI,KAAK,UAAU,WAAY,QAAO;AACtC,UAAI,OAAO,QAAQ,MAAM,cAAc;AACrC,eAAO,QAAQ,MAAM;AACvB,aAAO;AAAA,IACT,CAAC;AAED,UAAM,oBAAoB,SAAS,MAAM;AACvC,UAAI,KAAK,UAAU,WAAY,QAAO;AACtC,UAAI,OAAO,QAAQ,MAAM,cAAc;AACrC,eAAO,QAAQ,MAAM;AACvB,aAAO;AAAA,IACT,CAAC;AAED,UAAM,cAAc,SAAS,MAAM;AAEjC,UAAI,KAAK,UAAU,WAAY,QAAO;AACtC,aAAO,QAAQ,MAAM,gBAAgB;AAAA,IACvC,CAAC;AAGD,UAAM,gBAAgB,IAAI,KAAK;AAE/B,UAAM,aAAa,SAAS,MAAM,cAAc,SAAS,QAAQ,MAAM,MAAM;AAE7E,UAAM,WAAW,CAAC,QAAuB;AACvC,mBAAa,QAAQ,MAAM,MAAM,OAAO,MAAS;AAAA,IACnD;AAEA,UAAM,SAAS,MAAM;AACnB,oBAAc,QAAQ;AAAA,IACxB;;AAIE,aAAAA,UAAA,GAAAC,mBAuBM,OAvBN,YAuBM;AAAA,QAtBSC,MAAA,OAAA,EAAQ,SAArBF,UAAA,GAAAC,mBAEU,SAFV,YAEUE,gBADRD,MAAA,OAAA,EAAQ,KAAK,GAAA,CAAA;QAEJA,MAAA,OAAA,EAAQ,eAAnBF,UAAA,GAAAC,mBAEM,OAFN,YAEME,gBADDD,MAAA,OAAA,EAAQ,WAAW,GAAA,CAAA;QAExBE,YAcEF,MAAA,WAAA,GAAA;AAAA,UAbA,OAAM;AAAA,UACN,eAAY;AAAA,UACX,gBAAc,YAAA;AAAA,UACd,MAAM,KAAA;AAAA,UACN,UAAU,SAAA;AAAA,UACV,uBAAqB,kBAAA;AAAA,UACrB,uBAAqB,kBAAA;AAAA,UACrB,sBAAoBA,MAAA,OAAA,EAAQ,SAAI,WAAgBA,MAAA,OAAA,EAAQ,OAAI;AAAA,UAC5D,aAAa,YAAA;AAAA,UACb,UAAQ,CAAGA,MAAA,OAAA,EAAQ;AAAA,UACnB,gBAAY,CAAA,CAAI,WAAA,SAAc;AAAA,UAC9B,uBAAoB;AAAA,UACpB;AAAA,QAAA;QAEU,WAAA,SAAbF,UAAA,GAAAC,mBAAqE,SAArE,YAAqEE,gBAAzBD,MAAA,OAAA,EAAQ,MAAM,GAAA,CAAA;;;;;"}
1
+ {"version":3,"file":"JfNumber.vue.js","sources":["../../../src/vue/primevue/JfNumber.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref } from \"vue\";\nimport { useDerive } from \"../composables/useDerive\";\nimport InputNumber from \"primevue/inputnumber\";\n\ndefineOptions({ name: \"JfNumber\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\nconst options = computed(\n () =>\n (control.value.uischema as { options?: Record<string, unknown> })\n ?.options ?? {},\n);\n\nconst placeholder = computed<string | undefined>(\n () => (options.value.placeholder as string) ?? control.value.description,\n);\n\n// Add derive functionality\nuseDerive({ control, handleChange });\n\n// Currency and decimal configuration\nconst mode = computed(() => {\n if (options.value.currency) return \"currency\";\n if (options.value.decimal || typeof options.value.precision === \"number\")\n return \"decimal\";\n return undefined;\n});\n\nconst currency = computed(() =>\n typeof options.value.currency === \"string\" ? options.value.currency : \"USD\",\n);\n\nconst minFractionDigits = computed(() => {\n if (mode.value === \"currency\") return 2;\n if (typeof options.value.precision === \"number\")\n return options.value.precision;\n return undefined;\n});\n\nconst maxFractionDigits = computed(() => {\n if (mode.value === \"currency\") return 2;\n if (typeof options.value.precision === \"number\")\n return options.value.precision;\n return undefined;\n});\n\nconst useGrouping = computed(() => {\n // Enable grouping for currency by default, or if explicitly set\n if (mode.value === \"currency\") return true;\n return options.value.useGrouping === true;\n});\n\n// Track user interaction\nconst hasInteracted = ref(false);\n\nconst showErrors = computed(() => hasInteracted.value && control.value.errors);\n\nconst onNumber = (val: number | null) => {\n handleChange(control.value.path, val ?? undefined);\n};\n\nconst onBlur = () => {\n hasInteracted.value = true;\n};\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n <InputNumber\n class=\"w-full\"\n input-class=\"w-full\"\n :use-grouping=\"useGrouping\"\n :mode=\"mode\"\n :currency=\"currency\"\n :min-fraction-digits=\"minFractionDigits\"\n :max-fraction-digits=\"maxFractionDigits\"\n :model-value=\"typeof control.data === 'number' ? control.data : null\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!showErrors || undefined\"\n @update:model-value=\"onNumber\"\n @blur=\"onBlur\"\n />\n <small v-if=\"showErrors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AASA,UAAM,QAAQ;AACd,UAAM,EAAE,SAAS,iBAAiB,oBAAoB,KAAK;AAE3D,UAAM,UAAU;AAAA,MACd,MACG,QAAQ,MAAM,UACX,WAAW,CAAA;AAAA,IAAC;AAGpB,UAAM,cAAc;AAAA,MAClB,MAAO,QAAQ,MAAM,eAA0B,QAAQ,MAAM;AAAA,IAAA;AAI/D,cAAU,EAAE,SAAS,cAAc;AAGnC,UAAM,OAAO,SAAS,MAAM;AAC1B,UAAI,QAAQ,MAAM,SAAU,QAAO;AACnC,UAAI,QAAQ,MAAM,WAAW,OAAO,QAAQ,MAAM,cAAc;AAC9D,eAAO;AACT,aAAO;AAAA,IACT,CAAC;AAED,UAAM,WAAW;AAAA,MAAS,MACxB,OAAO,QAAQ,MAAM,aAAa,WAAW,QAAQ,MAAM,WAAW;AAAA,IAAA;AAGxE,UAAM,oBAAoB,SAAS,MAAM;AACvC,UAAI,KAAK,UAAU,WAAY,QAAO;AACtC,UAAI,OAAO,QAAQ,MAAM,cAAc;AACrC,eAAO,QAAQ,MAAM;AACvB,aAAO;AAAA,IACT,CAAC;AAED,UAAM,oBAAoB,SAAS,MAAM;AACvC,UAAI,KAAK,UAAU,WAAY,QAAO;AACtC,UAAI,OAAO,QAAQ,MAAM,cAAc;AACrC,eAAO,QAAQ,MAAM;AACvB,aAAO;AAAA,IACT,CAAC;AAED,UAAM,cAAc,SAAS,MAAM;AAEjC,UAAI,KAAK,UAAU,WAAY,QAAO;AACtC,aAAO,QAAQ,MAAM,gBAAgB;AAAA,IACvC,CAAC;AAGD,UAAM,gBAAgB,IAAI,KAAK;AAE/B,UAAM,aAAa,SAAS,MAAM,cAAc,SAAS,QAAQ,MAAM,MAAM;AAE7E,UAAM,WAAW,CAAC,QAAuB;AACvC,mBAAa,QAAQ,MAAM,MAAM,OAAO,MAAS;AAAA,IACnD;AAEA,UAAM,SAAS,MAAM;AACnB,oBAAc,QAAQ;AAAA,IACxB;;AAIE,aAAAA,UAAA,GAAAC,mBAuBM,OAvBN,YAuBM;AAAA,QAtBSC,MAAA,OAAA,EAAQ,SAArBF,UAAA,GAAAC,mBAEU,SAFV,YAEUE,gBADRD,MAAA,OAAA,EAAQ,KAAK,GAAA,CAAA;QAEJA,MAAA,OAAA,EAAQ,eAAnBF,UAAA,GAAAC,mBAEM,OAFN,YAEME,gBADDD,MAAA,OAAA,EAAQ,WAAW,GAAA,CAAA;QAExBE,YAcEF,MAAA,WAAA,GAAA;AAAA,UAbA,OAAM;AAAA,UACN,eAAY;AAAA,UACX,gBAAc,YAAA;AAAA,UACd,MAAM,KAAA;AAAA,UACN,UAAU,SAAA;AAAA,UACV,uBAAqB,kBAAA;AAAA,UACrB,uBAAqB,kBAAA;AAAA,UACrB,sBAAoBA,MAAA,OAAA,EAAQ,SAAI,WAAgBA,MAAA,OAAA,EAAQ,OAAI;AAAA,UAC5D,aAAa,YAAA;AAAA,UACb,UAAQ,CAAGA,MAAA,OAAA,EAAQ;AAAA,UACnB,gBAAY,CAAA,CAAI,WAAA,SAAc;AAAA,UAC9B,uBAAoB;AAAA,UACpB;AAAA,QAAA;QAEU,WAAA,SAAbF,UAAA,GAAAC,mBAAqE,SAArE,YAAqEE,gBAAzBD,MAAA,OAAA,EAAQ,MAAM,GAAA,CAAA;;;;;"}
@@ -66,10 +66,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
66
66
  default: undefined;
67
67
  };
68
68
  }>> & Readonly<{}>, {
69
+ config: Record<string, any>;
69
70
  enabled: boolean;
70
71
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
71
72
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
72
- config: Record<string, any>;
73
73
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
74
74
  export default _default;
75
75
  //# sourceMappingURL=JfText.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JfText.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfText.vue"],"names":[],"mappings":"AAoEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiKtD,wBAEG"}
1
+ {"version":3,"file":"JfText.vue.d.ts","sourceRoot":"","sources":["../../../src/vue/primevue/JfText.vue"],"names":[],"mappings":"AA4JA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsTtD,wBAEG"}
@@ -1,6 +1,9 @@
1
- import { defineComponent, computed, ref, createElementBlock, openBlock, createCommentVNode, createVNode, unref, toDisplayString } from "vue";
1
+ import { defineComponent, computed, inject, ref, watch, createElementBlock, openBlock, createCommentVNode, createBlock, unref, toDisplayString } from "vue";
2
2
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
3
+ import { useProvider } from "../composables/useProvider.js";
4
+ import { useDerive } from "../composables/useDerive.js";
3
5
  import InputText from "primevue/inputtext";
6
+ import AutoComplete from "primevue/autocomplete";
4
7
  const _hoisted_1 = { class: "flex flex-column gap-2" };
5
8
  const _hoisted_2 = {
6
9
  key: 0,
@@ -11,7 +14,12 @@ const _hoisted_3 = {
11
14
  class: "text-color-secondary text-left"
12
15
  };
13
16
  const _hoisted_4 = {
14
- key: 2,
17
+ key: 4,
18
+ class: "p-error",
19
+ role: "alert"
20
+ };
21
+ const _hoisted_5 = {
22
+ key: 5,
15
23
  class: "p-error"
16
24
  };
17
25
  const _sfc_main = /* @__PURE__ */ defineComponent({
@@ -21,9 +29,49 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
21
29
  setup(__props) {
22
30
  const props = __props;
23
31
  const { control, handleChange } = useJsonFormsControl(props);
24
- const placeholder = computed(
25
- () => control.value.uischema?.options?.placeholder ?? control.value.description
32
+ const binding = computed(() => {
33
+ const provider = control.value.uischema?.options?.provider;
34
+ if (provider && typeof provider === "object" && !provider.load) {
35
+ return { ...provider, load: "query" };
36
+ }
37
+ return provider;
38
+ });
39
+ const deps = computed(
40
+ () => control.value.schema?.["x-provider"]?.dependsOn ?? []
26
41
  );
42
+ const depValues = computed(() => {
43
+ return deps.value.map((dep) => {
44
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
45
+ const keys = path.replace(/\//g, ".").split(".");
46
+ let value = rootData.value;
47
+ for (const key of keys) {
48
+ if (value && typeof value === "object" && key in value) {
49
+ value = value[key];
50
+ } else {
51
+ return null;
52
+ }
53
+ }
54
+ return value;
55
+ });
56
+ });
57
+ const injectedFormData = inject("formData", { value: {} });
58
+ const rootData = computed(() => injectedFormData.value || {});
59
+ const query = ref("");
60
+ const { items, loading, error, reload } = useProvider(binding, {
61
+ data: rootData,
62
+ path: control.value.path,
63
+ uiQuery: query.value,
64
+ dependsOnValues: depValues.value
65
+ });
66
+ watch(query, () => {
67
+ if (binding.value?.load === "query") reload();
68
+ });
69
+ const placeholder = computed(() => {
70
+ if (loading.value) return "Loading…";
71
+ return control.value.uischema?.options?.placeholder ?? control.value.description;
72
+ });
73
+ const isAutocomplete = computed(() => !!binding.value);
74
+ useDerive({ control, handleChange });
27
75
  const hasInteracted = ref(false);
28
76
  const hasFocused = ref(false);
29
77
  const showErrors = computed(() => hasInteracted.value && control.value.errors);
@@ -41,11 +89,33 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
41
89
  function onFocus() {
42
90
  hasFocused.value = true;
43
91
  }
92
+ const onComplete = (event) => {
93
+ query.value = event.query;
94
+ };
95
+ const onSelect = (event) => {
96
+ const newValue = event.value?.value ?? event.value;
97
+ handleChange(control.value.path, newValue);
98
+ };
44
99
  return (_ctx, _cache) => {
45
100
  return openBlock(), createElementBlock("div", _hoisted_1, [
46
101
  unref(control).label ? (openBlock(), createElementBlock("label", _hoisted_2, toDisplayString(unref(control).label), 1)) : createCommentVNode("", true),
47
102
  unref(control).description ? (openBlock(), createElementBlock("div", _hoisted_3, toDisplayString(unref(control).description), 1)) : createCommentVNode("", true),
48
- createVNode(unref(InputText), {
103
+ isAutocomplete.value ? (openBlock(), createBlock(unref(AutoComplete), {
104
+ key: 2,
105
+ class: "w-full",
106
+ "model-value": unref(control).data ?? "",
107
+ suggestions: unref(items),
108
+ "option-label": "label",
109
+ placeholder: placeholder.value,
110
+ disabled: !unref(control).enabled,
111
+ "aria-invalid": !!showErrors.value || void 0,
112
+ onComplete,
113
+ onItemSelect: onSelect,
114
+ "onUpdate:modelValue": onInput,
115
+ onBlur,
116
+ onFocus
117
+ }, null, 8, ["model-value", "suggestions", "placeholder", "disabled", "aria-invalid"])) : (openBlock(), createBlock(unref(InputText), {
118
+ key: 3,
49
119
  class: "w-full",
50
120
  "model-value": unref(control).data ?? "",
51
121
  disabled: !unref(control).enabled,
@@ -57,8 +127,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
57
127
  "onUpdate:modelValue": onInput,
58
128
  onBlur,
59
129
  onFocus
60
- }, null, 8, ["model-value", "disabled", "aria-invalid", "placeholder"]),
61
- showErrors.value ? (openBlock(), createElementBlock("small", _hoisted_4, toDisplayString(unref(control).errors), 1)) : createCommentVNode("", true)
130
+ }, null, 8, ["model-value", "disabled", "aria-invalid", "placeholder"])),
131
+ unref(error) ? (openBlock(), createElementBlock("small", _hoisted_4, "Failed: " + toDisplayString(unref(error)), 1)) : showErrors.value ? (openBlock(), createElementBlock("small", _hoisted_5, toDisplayString(unref(control).errors), 1)) : createCommentVNode("", true)
62
132
  ]);
63
133
  };
64
134
  }
@@ -1 +1 @@
1
- {"version":3,"file":"JfText.vue.js","sources":["../../../src/vue/primevue/JfText.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref } from \"vue\";\nimport InputText from \"primevue/inputtext\";\n\ndefineOptions({ name: \"JfText\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\nconst placeholder = computed<string | undefined>(\n () =>\n (control.value.uischema as { options?: { placeholder?: string } })?.options\n ?.placeholder ?? control.value.description,\n);\n\n// Track user interaction\nconst hasInteracted = ref(false);\nconst hasFocused = ref(false);\n\nconst showErrors = computed(() => hasInteracted.value && control.value.errors);\n\nfunction onInput(val: string | undefined) {\n // Convert empty strings to undefined for proper required field validation\n const newValue = val && val.trim() !== \"\" ? val : undefined;\n if (control.value.data !== newValue) {\n handleChange(control.value.path, newValue);\n }\n}\n\nfunction onBlur() {\n if (hasFocused.value) {\n hasInteracted.value = true;\n }\n}\n\nfunction onFocus() {\n hasFocused.value = true;\n}\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n <InputText\n class=\"w-full\"\n :model-value=\"control.data ?? ''\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!showErrors || undefined\"\n :placeholder=\"placeholder\"\n autocapitalize=\"off\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @update:model-value=\"onInput\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n />\n <small v-if=\"showErrors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAM,QAAQ;AACd,UAAM,EAAE,SAAS,iBAAiB,oBAAoB,KAAK;AAE3D,UAAM,cAAc;AAAA,MAClB,MACG,QAAQ,MAAM,UAAqD,SAChE,eAAe,QAAQ,MAAM;AAAA,IAAA;AAIrC,UAAM,gBAAgB,IAAI,KAAK;AAC/B,UAAM,aAAa,IAAI,KAAK;AAE5B,UAAM,aAAa,SAAS,MAAM,cAAc,SAAS,QAAQ,MAAM,MAAM;AAE7E,aAAS,QAAQ,KAAyB;AAExC,YAAM,WAAW,OAAO,IAAI,KAAA,MAAW,KAAK,MAAM;AAClD,UAAI,QAAQ,MAAM,SAAS,UAAU;AACnC,qBAAa,QAAQ,MAAM,MAAM,QAAQ;AAAA,MAC3C;AAAA,IACF;AAEA,aAAS,SAAS;AAChB,UAAI,WAAW,OAAO;AACpB,sBAAc,QAAQ;AAAA,MACxB;AAAA,IACF;AAEA,aAAS,UAAU;AACjB,iBAAW,QAAQ;AAAA,IACrB;;AAIE,aAAAA,UAAA,GAAAC,mBAqBM,OArBN,YAqBM;AAAA,QApBSC,MAAA,OAAA,EAAQ,SAArBF,UAAA,GAAAC,mBAEU,SAFV,YAEUE,gBADRD,MAAA,OAAA,EAAQ,KAAK,GAAA,CAAA;QAEJA,MAAA,OAAA,EAAQ,eAAnBF,UAAA,GAAAC,mBAEM,OAFN,YAEME,gBADDD,MAAA,OAAA,EAAQ,WAAW,GAAA,CAAA;QAExBE,YAYEF,MAAA,SAAA,GAAA;AAAA,UAXA,OAAM;AAAA,UACL,eAAaA,MAAA,OAAA,EAAQ,QAAI;AAAA,UACzB,UAAQ,CAAGA,MAAA,OAAA,EAAQ;AAAA,UACnB,gBAAY,CAAA,CAAI,WAAA,SAAc;AAAA,UAC9B,aAAa,YAAA;AAAA,UACd,gBAAe;AAAA,UACf,cAAa;AAAA,UACb,YAAW;AAAA,UACV,uBAAoB;AAAA,UACpB;AAAA,UACA;AAAA,QAAA;QAEU,WAAA,SAAbF,UAAA,GAAAC,mBAAqE,SAArE,YAAqEE,gBAAzBD,MAAA,OAAA,EAAQ,MAAM,GAAA,CAAA;;;;;"}
1
+ {"version":3,"file":"JfText.vue.js","sources":["../../../src/vue/primevue/JfText.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement } from \"@jsonforms/core\";\nimport { rendererProps, useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref, inject, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport InputText from \"primevue/inputtext\";\nimport AutoComplete from \"primevue/autocomplete\";\n\ndefineOptions({ name: \"JfText\" });\n\nconst props = defineProps(rendererProps<ControlElement>());\nconst { control, handleChange } = useJsonFormsControl(props);\n\n// Provider support for autocomplete functionality\nconst binding = computed(() => {\n const provider = control.value.uischema?.options?.provider;\n // Ensure load property is set to 'query' by default for autocomplete\n if (provider && typeof provider === \"object\" && !provider.load) {\n return { ...provider, load: \"query\" };\n }\n return provider;\n});\n\nconst deps = computed(\n () =>\n ((\n (control.value.schema as Record<string, unknown>)?.[\n \"x-provider\"\n ] as Record<string, unknown>\n )?.dependsOn as string[]) ?? [],\n);\nconst depValues = computed(() => {\n return deps.value.map((dep) => {\n // Resolve dependency value from form data using JSON pointer-like path\n const path = dep.startsWith(\"#/\") ? dep.slice(2) : dep;\n const keys = path.replace(/\\//g, \".\").split(\".\");\n let value: unknown = rootData.value;\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return null;\n }\n }\n return value;\n });\n});\n\n// Get the root form data from JSONForms context for template URL resolution\nconst injectedFormData = inject<{ value: unknown }>(\"formData\", { value: {} });\nconst rootData = computed(() => injectedFormData.value || {});\n\nconst query = ref(\"\");\nconst { items, loading, error, reload } = useProvider(binding, {\n data: rootData,\n path: control.value.path,\n uiQuery: query.value,\n dependsOnValues: depValues.value,\n});\n\nwatch(query, () => {\n if (binding.value?.load === \"query\") reload();\n});\n\nconst placeholder = computed<string | undefined>(() => {\n if (loading.value) return \"Loading…\";\n return (\n (control.value.uischema as { options?: { placeholder?: string } })?.options\n ?.placeholder ?? control.value.description\n );\n});\n\nconst isAutocomplete = computed(() => !!binding.value);\n\n// Add derive functionality\nuseDerive({ control, handleChange });\n\n// Track user interaction\nconst hasInteracted = ref(false);\nconst hasFocused = ref(false);\n\nconst showErrors = computed(() => hasInteracted.value && control.value.errors);\n\nfunction onInput(val: string | undefined) {\n // Convert empty strings to undefined for proper required field validation\n const newValue = val && val.trim() !== \"\" ? val : undefined;\n if (control.value.data !== newValue) {\n handleChange(control.value.path, newValue);\n }\n}\n\nfunction onBlur() {\n if (hasFocused.value) {\n hasInteracted.value = true;\n }\n}\n\nfunction onFocus() {\n hasFocused.value = true;\n}\n\n// Autocomplete specific handlers\nconst onComplete = (event: { query: string }) => {\n query.value = event.query;\n};\n\nconst onSelect = (event: { value?: { value?: unknown } | unknown }) => {\n const newValue = (event.value as { value?: unknown })?.value ?? event.value;\n handleChange(control.value.path, newValue);\n};\n</script>\n\n<template>\n <div class=\"flex flex-column gap-2\">\n <label v-if=\"control.label\" class=\"text-color text-left\">{{\n control.label\n }}</label>\n <div v-if=\"control.description\" class=\"text-color-secondary text-left\">\n {{ control.description }}\n </div>\n <AutoComplete\n v-if=\"isAutocomplete\"\n class=\"w-full\"\n :model-value=\"control.data ?? ''\"\n :suggestions=\"items\"\n option-label=\"label\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!showErrors || undefined\"\n @complete=\"onComplete\"\n @item-select=\"onSelect\"\n @update:model-value=\"onInput\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n />\n <InputText\n v-else\n class=\"w-full\"\n :model-value=\"control.data ?? ''\"\n :disabled=\"!control.enabled\"\n :aria-invalid=\"!!showErrors || undefined\"\n :placeholder=\"placeholder\"\n autocapitalize=\"off\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @update:model-value=\"onInput\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n />\n <small v-if=\"error\" class=\"p-error\" role=\"alert\">Failed: {{ error }}</small>\n <small v-else-if=\"showErrors\" class=\"p-error\">{{ control.errors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createBlock"],"mappings":"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"}
@@ -66,10 +66,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
66
66
  default: undefined;
67
67
  };
68
68
  }>> & Readonly<{}>, {
69
+ config: Record<string, any>;
69
70
  enabled: boolean;
70
71
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
71
72
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
72
- config: Record<string, any>;
73
73
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
74
74
  export default _default;
75
75
  //# sourceMappingURL=JfTextArea.vue.d.ts.map
@@ -73,10 +73,10 @@ export declare const primevueRenderers: {
73
73
  default: undefined;
74
74
  };
75
75
  }>> & Readonly<{}>, {
76
+ config: Record<string, any>;
76
77
  enabled: boolean;
77
78
  renderers: import("@jsonforms/core").JsonFormsRendererRegistryEntry[];
78
79
  cells: import("@jsonforms/core").JsonFormsCellRendererRegistryEntry[];
79
- config: Record<string, any>;
80
80
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
81
81
  }[];
82
82
  export { JfText, JfTextArea, JfNumber, JfEnum, JfEnumArray, JfBoolean };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narrative.io/jsonforms-provider-protocols",
3
- "version": "1.1.0-beta.3",
3
+ "version": "1.1.0-beta.5",
4
4
  "description": "Dynamic data provider capabilities for JSONForms with Vue 3 integration",
5
5
  "type": "module",
6
6
  "author": "Narrative I/O",
@@ -0,0 +1,105 @@
1
+ import { computed, watch, inject, type Ref } from "vue";
2
+ import { type ControlElement } from "@jsonforms/core";
3
+
4
+ interface DeriveOptions {
5
+ control: Ref<{
6
+ uischema: ControlElement;
7
+ path: string;
8
+ data: unknown;
9
+ }>;
10
+ handleChange: (path: string, value: unknown) => void;
11
+ }
12
+
13
+ export function useDerive({ control, handleChange }: DeriveOptions) {
14
+ // Get the root form data from JSONForms context
15
+ const injectedFormData = inject<{ value: unknown }>("formData", {
16
+ value: {},
17
+ });
18
+ const rootData = computed(() => injectedFormData.value || {});
19
+
20
+ // Get external data from context if available
21
+ const injectedExternalData = inject<{ value: unknown }>("externalData", {
22
+ value: {},
23
+ });
24
+ const externalData = computed(() => injectedExternalData.value || {});
25
+
26
+ // Extract derive configuration from uischema options
27
+ const deriveConfig = computed(() => {
28
+ const options = control.value.uischema?.options as
29
+ | { derive?: string; mode?: string }
30
+ | undefined;
31
+ return {
32
+ expression: options?.derive,
33
+ mode: options?.mode || "follow", // 'follow' = auto-update, 'manual' = user controlled
34
+ };
35
+ });
36
+
37
+ // Watch for changes in form data and external data and update derived field
38
+ watch(
39
+ [rootData, externalData, deriveConfig],
40
+ ([data, extData, config]) => {
41
+ if (!config.expression || config.mode !== "follow") {
42
+ return;
43
+ }
44
+
45
+ try {
46
+ const derivedValue = resolveDeriveExpression(
47
+ config.expression,
48
+ data,
49
+ extData,
50
+ );
51
+ if (derivedValue !== control.value.data) {
52
+ handleChange(control.value.path, derivedValue);
53
+ }
54
+ } catch (error) {
55
+ console.warn(
56
+ `Failed to derive value for ${control.value.path}:`,
57
+ error,
58
+ );
59
+ }
60
+ },
61
+ { deep: true, immediate: true },
62
+ );
63
+ }
64
+
65
+ function resolveDeriveExpression(
66
+ expression: string,
67
+ data: unknown,
68
+ externalData?: unknown,
69
+ ): unknown {
70
+ // Handle externalData() syntax
71
+ if (expression.startsWith("externalData(") && expression.endsWith(")")) {
72
+ const propertyPath = expression.slice(13, -1); // Remove "externalData(" and ")"
73
+ return resolvePropertyPath(propertyPath, externalData);
74
+ }
75
+
76
+ // Handle simple property paths like "country.name"
77
+ if (
78
+ !expression.includes("(") &&
79
+ !expression.includes("+") &&
80
+ !expression.includes("?")
81
+ ) {
82
+ return resolvePropertyPath(expression, data);
83
+ }
84
+
85
+ // For now, we'll only support simple property paths and externalData() calls
86
+ // Complex expressions would require a safe expression evaluator
87
+ return resolvePropertyPath(expression, data);
88
+ }
89
+
90
+ function resolvePropertyPath(path: string, data: unknown): unknown {
91
+ if (!path || !data) return "";
92
+
93
+ const keys = path.split(".");
94
+ let value: unknown = data;
95
+
96
+ for (const key of keys) {
97
+ if (value && typeof value === "object" && key in value) {
98
+ value = (value as Record<string, unknown>)[key];
99
+ } else {
100
+ return null;
101
+ }
102
+ }
103
+
104
+ return value;
105
+ }
@@ -1,7 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import type { ControlElement, JsonSchema } from "@jsonforms/core";
3
3
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
4
- import { computed, ref } from "vue";
4
+ import { computed, ref, inject } from "vue";
5
+ import { useProvider } from "../composables/useProvider";
6
+ import { useDerive } from "../composables/useDerive";
5
7
  import Dropdown from "primevue/dropdown";
6
8
 
7
9
  defineOptions({ name: "JfEnum" });
@@ -26,13 +28,74 @@ const toOptions = (schema?: JsonSchema): Opt[] => {
26
28
  return [];
27
29
  };
28
30
 
29
- const placeholder = computed<string | undefined>(
31
+ // Provider support
32
+ const binding = computed(() => {
33
+ const provider = control.value.uischema?.options?.provider;
34
+ // Ensure load property is set to 'mount' by default
35
+ if (provider && typeof provider === "object" && !provider.load) {
36
+ return { ...provider, load: "mount" };
37
+ }
38
+ return provider;
39
+ });
40
+
41
+ const deps = computed(
30
42
  () =>
31
- (control.value.uischema as { options?: { placeholder?: string } })?.options
32
- ?.placeholder ?? control.value.description,
43
+ ((
44
+ (control.value.schema as Record<string, unknown>)?.[
45
+ "x-provider"
46
+ ] as Record<string, unknown>
47
+ )?.dependsOn as string[]) ?? [],
33
48
  );
49
+ const depValues = computed(() => {
50
+ return deps.value.map((dep) => {
51
+ // Resolve dependency value from form data using JSON pointer-like path
52
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
53
+ const keys = path.replace(/\//g, ".").split(".");
54
+ let value: unknown = rootData.value;
55
+ for (const key of keys) {
56
+ if (value && typeof value === "object" && key in value) {
57
+ value = (value as Record<string, unknown>)[key];
58
+ } else {
59
+ return null;
60
+ }
61
+ }
62
+ return value;
63
+ });
64
+ });
65
+
66
+ // Get the root form data from JSONForms context for template URL resolution
67
+ const injectedFormData = inject<{ value: unknown }>("formData", { value: {} });
68
+ const rootData = computed(() => injectedFormData.value || {});
69
+
70
+ // Use provider if available, otherwise fall back to schema enum/oneOf
71
+ const {
72
+ items: providerItems,
73
+ loading,
74
+ error,
75
+ } = useProvider(binding, {
76
+ data: rootData,
77
+ path: control.value.path,
78
+ dependsOnValues: depValues.value,
79
+ });
80
+
81
+ const placeholder = computed<string | undefined>(() => {
82
+ if (loading.value) return "Loading…";
83
+ return (
84
+ (control.value.uischema as { options?: { placeholder?: string } })?.options
85
+ ?.placeholder ?? control.value.description
86
+ );
87
+ });
88
+
89
+ const options = computed(() => {
90
+ // Use provider items if available, otherwise fall back to schema enum/oneOf
91
+ if (binding.value && providerItems.value.length > 0) {
92
+ return providerItems.value;
93
+ }
94
+ return toOptions(control.value.schema);
95
+ });
34
96
 
35
- const options = computed(() => toOptions(control.value.schema));
97
+ // Add derive functionality
98
+ useDerive({ control, handleChange });
36
99
 
37
100
  // Track user interaction
38
101
  const hasInteracted = ref(false);
@@ -63,13 +126,16 @@ const onBlur = () => {
63
126
  option-value="value"
64
127
  :model-value="control.data ?? null"
65
128
  :placeholder="placeholder"
66
- :disabled="!control.enabled"
129
+ :disabled="!control.enabled || loading"
67
130
  :aria-invalid="!!showErrors || undefined"
68
131
  :show-clear="true"
69
132
  @update:model-value="onSelect"
70
133
  @blur="onBlur"
71
134
  />
72
- <small v-if="showErrors" class="p-error">{{ control.errors }}</small>
135
+ <small v-if="error" class="p-error" role="alert"
136
+ >Failed to load: {{ error }}</small
137
+ >
138
+ <small v-else-if="showErrors" class="p-error">{{ control.errors }}</small>
73
139
  </div>
74
140
  </template>
75
141
 
@@ -1,7 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import type { ControlElement, JsonSchema } from "@jsonforms/core";
3
3
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
4
- import { computed } from "vue";
4
+ import { computed, inject } from "vue";
5
+ import { useProvider } from "../composables/useProvider";
6
+ import { useDerive } from "../composables/useDerive";
5
7
  import MultiSelect from "primevue/multiselect";
6
8
 
7
9
  defineOptions({ name: "JfEnumArray" });
@@ -26,14 +28,74 @@ const toOptions = (schema?: JsonSchema): Opt[] => {
26
28
  return [];
27
29
  };
28
30
 
29
- const options = computed(() =>
30
- toOptions((control.value.schema as { items?: JsonSchema })?.items),
31
- );
32
- const placeholder = computed<string | undefined>(
31
+ // Provider support
32
+ const binding = computed(() => {
33
+ const provider = control.value.uischema?.options?.provider;
34
+ // Ensure load property is set to 'mount' by default
35
+ if (provider && typeof provider === "object" && !provider.load) {
36
+ return { ...provider, load: "mount" };
37
+ }
38
+ return provider;
39
+ });
40
+
41
+ const deps = computed(
33
42
  () =>
34
- (control.value.uischema as { options?: { placeholder?: string } })?.options
35
- ?.placeholder ?? control.value.description,
43
+ ((
44
+ (control.value.schema as Record<string, unknown>)?.[
45
+ "x-provider"
46
+ ] as Record<string, unknown>
47
+ )?.dependsOn as string[]) ?? [],
36
48
  );
49
+ const depValues = computed(() => {
50
+ return deps.value.map((dep) => {
51
+ // Resolve dependency value from form data using JSON pointer-like path
52
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
53
+ const keys = path.replace(/\//g, ".").split(".");
54
+ let value: unknown = rootData.value;
55
+ for (const key of keys) {
56
+ if (value && typeof value === "object" && key in value) {
57
+ value = (value as Record<string, unknown>)[key];
58
+ } else {
59
+ return null;
60
+ }
61
+ }
62
+ return value;
63
+ });
64
+ });
65
+
66
+ // Get the root form data from JSONForms context for template URL resolution
67
+ const injectedFormData = inject<{ value: unknown }>("formData", { value: {} });
68
+ const rootData = computed(() => injectedFormData.value || {});
69
+
70
+ // Use provider if available, otherwise fall back to schema enum/oneOf
71
+ const {
72
+ items: providerItems,
73
+ loading,
74
+ error,
75
+ } = useProvider(binding, {
76
+ data: rootData,
77
+ path: control.value.path,
78
+ dependsOnValues: depValues.value,
79
+ });
80
+
81
+ const options = computed(() => {
82
+ // Use provider items if available, otherwise fall back to schema enum/oneOf
83
+ if (binding.value && providerItems.value.length > 0) {
84
+ return providerItems.value;
85
+ }
86
+ return toOptions((control.value.schema as { items?: JsonSchema })?.items);
87
+ });
88
+
89
+ // Add derive functionality
90
+ useDerive({ control, handleChange });
91
+
92
+ const placeholder = computed<string | undefined>(() => {
93
+ if (loading.value) return "Loading…";
94
+ return (
95
+ (control.value.uischema as { options?: { placeholder?: string } })?.options
96
+ ?.placeholder ?? control.value.description
97
+ );
98
+ });
37
99
 
38
100
  // order-insensitive shallow equality for primitive enums
39
101
  const sameSet = (a: unknown[], b: unknown[]) => {
@@ -75,11 +137,16 @@ const model = computed<unknown[]>({
75
137
  option-value="value"
76
138
  data-key="value"
77
139
  display="chip"
78
- :disabled="!control.enabled"
140
+ :disabled="!control.enabled || loading"
79
141
  :aria-invalid="!!control.errors || undefined"
80
142
  :placeholder="placeholder"
81
143
  />
82
144
 
83
- <small v-if="control.errors" class="p-error">{{ control.errors }}</small>
145
+ <small v-if="error" class="p-error" role="alert"
146
+ >Failed to load: {{ error }}</small
147
+ >
148
+ <small v-else-if="control.errors" class="p-error">{{
149
+ control.errors
150
+ }}</small>
84
151
  </div>
85
152
  </template>
@@ -2,6 +2,7 @@
2
2
  import type { ControlElement } from "@jsonforms/core";
3
3
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
4
4
  import { computed, ref } from "vue";
5
+ import { useDerive } from "../composables/useDerive";
5
6
  import InputNumber from "primevue/inputnumber";
6
7
 
7
8
  defineOptions({ name: "JfNumber" });
@@ -19,6 +20,9 @@ const placeholder = computed<string | undefined>(
19
20
  () => (options.value.placeholder as string) ?? control.value.description,
20
21
  );
21
22
 
23
+ // Add derive functionality
24
+ useDerive({ control, handleChange });
25
+
22
26
  // Currency and decimal configuration
23
27
  const mode = computed(() => {
24
28
  if (options.value.currency) return "currency";
@@ -1,19 +1,80 @@
1
1
  <script setup lang="ts">
2
2
  import type { ControlElement } from "@jsonforms/core";
3
3
  import { rendererProps, useJsonFormsControl } from "@jsonforms/vue";
4
- import { computed, ref } from "vue";
4
+ import { computed, ref, inject, watch } from "vue";
5
+ import { useProvider } from "../composables/useProvider";
6
+ import { useDerive } from "../composables/useDerive";
5
7
  import InputText from "primevue/inputtext";
8
+ import AutoComplete from "primevue/autocomplete";
6
9
 
7
10
  defineOptions({ name: "JfText" });
8
11
 
9
12
  const props = defineProps(rendererProps<ControlElement>());
10
13
  const { control, handleChange } = useJsonFormsControl(props);
11
14
 
12
- const placeholder = computed<string | undefined>(
15
+ // Provider support for autocomplete functionality
16
+ const binding = computed(() => {
17
+ const provider = control.value.uischema?.options?.provider;
18
+ // Ensure load property is set to 'query' by default for autocomplete
19
+ if (provider && typeof provider === "object" && !provider.load) {
20
+ return { ...provider, load: "query" };
21
+ }
22
+ return provider;
23
+ });
24
+
25
+ const deps = computed(
13
26
  () =>
14
- (control.value.uischema as { options?: { placeholder?: string } })?.options
15
- ?.placeholder ?? control.value.description,
27
+ ((
28
+ (control.value.schema as Record<string, unknown>)?.[
29
+ "x-provider"
30
+ ] as Record<string, unknown>
31
+ )?.dependsOn as string[]) ?? [],
16
32
  );
33
+ const depValues = computed(() => {
34
+ return deps.value.map((dep) => {
35
+ // Resolve dependency value from form data using JSON pointer-like path
36
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
37
+ const keys = path.replace(/\//g, ".").split(".");
38
+ let value: unknown = rootData.value;
39
+ for (const key of keys) {
40
+ if (value && typeof value === "object" && key in value) {
41
+ value = (value as Record<string, unknown>)[key];
42
+ } else {
43
+ return null;
44
+ }
45
+ }
46
+ return value;
47
+ });
48
+ });
49
+
50
+ // Get the root form data from JSONForms context for template URL resolution
51
+ const injectedFormData = inject<{ value: unknown }>("formData", { value: {} });
52
+ const rootData = computed(() => injectedFormData.value || {});
53
+
54
+ const query = ref("");
55
+ const { items, loading, error, reload } = useProvider(binding, {
56
+ data: rootData,
57
+ path: control.value.path,
58
+ uiQuery: query.value,
59
+ dependsOnValues: depValues.value,
60
+ });
61
+
62
+ watch(query, () => {
63
+ if (binding.value?.load === "query") reload();
64
+ });
65
+
66
+ const placeholder = computed<string | undefined>(() => {
67
+ if (loading.value) return "Loading…";
68
+ return (
69
+ (control.value.uischema as { options?: { placeholder?: string } })?.options
70
+ ?.placeholder ?? control.value.description
71
+ );
72
+ });
73
+
74
+ const isAutocomplete = computed(() => !!binding.value);
75
+
76
+ // Add derive functionality
77
+ useDerive({ control, handleChange });
17
78
 
18
79
  // Track user interaction
19
80
  const hasInteracted = ref(false);
@@ -38,6 +99,16 @@ function onBlur() {
38
99
  function onFocus() {
39
100
  hasFocused.value = true;
40
101
  }
102
+
103
+ // Autocomplete specific handlers
104
+ const onComplete = (event: { query: string }) => {
105
+ query.value = event.query;
106
+ };
107
+
108
+ const onSelect = (event: { value?: { value?: unknown } | unknown }) => {
109
+ const newValue = (event.value as { value?: unknown })?.value ?? event.value;
110
+ handleChange(control.value.path, newValue);
111
+ };
41
112
  </script>
42
113
 
43
114
  <template>
@@ -48,7 +119,23 @@ function onFocus() {
48
119
  <div v-if="control.description" class="text-color-secondary text-left">
49
120
  {{ control.description }}
50
121
  </div>
122
+ <AutoComplete
123
+ v-if="isAutocomplete"
124
+ class="w-full"
125
+ :model-value="control.data ?? ''"
126
+ :suggestions="items"
127
+ option-label="label"
128
+ :placeholder="placeholder"
129
+ :disabled="!control.enabled"
130
+ :aria-invalid="!!showErrors || undefined"
131
+ @complete="onComplete"
132
+ @item-select="onSelect"
133
+ @update:model-value="onInput"
134
+ @blur="onBlur"
135
+ @focus="onFocus"
136
+ />
51
137
  <InputText
138
+ v-else
52
139
  class="w-full"
53
140
  :model-value="control.data ?? ''"
54
141
  :disabled="!control.enabled"
@@ -61,6 +148,7 @@ function onFocus() {
61
148
  @blur="onBlur"
62
149
  @focus="onFocus"
63
150
  />
64
- <small v-if="showErrors" class="p-error">{{ control.errors }}</small>
151
+ <small v-if="error" class="p-error" role="alert">Failed: {{ error }}</small>
152
+ <small v-else-if="showErrors" class="p-error">{{ control.errors }}</small>
65
153
  </div>
66
154
  </template>