@narrative.io/jsonforms-provider-protocols 3.0.0-beta.10 → 3.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsonforms-provider-protocols.css +2 -2
- package/dist/vue/components/ProviderMultiSelect.vue.js +1 -1
- package/dist/vue/components/ProviderMultiSelect.vue2.js +1 -1
- package/dist/vue/components/ProviderMultiSelect.vue2.js.map +1 -1
- package/dist/vue/components/ProviderSelect.vue.js +1 -1
- package/dist/vue/components/ProviderSelect.vue2.js +1 -1
- package/dist/vue/components/ProviderSelect.vue2.js.map +1 -1
- package/dist/vue/composables/useProjection.d.ts +1 -0
- package/dist/vue/composables/useProjection.d.ts.map +1 -1
- package/dist/vue/composables/useProjection.js +33 -5
- package/dist/vue/composables/useProjection.js.map +1 -1
- package/dist/vue/composables/useProvider.d.ts +2 -2
- package/dist/vue/composables/useProvider.d.ts.map +1 -1
- package/dist/vue/composables/useProvider.js +14 -10
- package/dist/vue/composables/useProvider.js.map +1 -1
- package/dist/vue/primevue/JfEnum.vue.js +1 -1
- package/dist/vue/primevue/JfEnum.vue.js.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.js +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
- package/dist/vue/primevue/JfText.vue.js +1 -1
- package/dist/vue/primevue/JfText.vue.js.map +1 -1
- package/package.json +1 -1
- package/src/vue/components/ProviderMultiSelect.vue +1 -1
- package/src/vue/components/ProviderSelect.vue +1 -1
- package/src/vue/composables/useProjection.ts +55 -6
- package/src/vue/composables/useProvider.ts +28 -11
- package/src/vue/primevue/JfEnum.vue +1 -1
- package/src/vue/primevue/JfEnumArray.vue +1 -1
- package/src/vue/primevue/JfText.vue +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./ProviderMultiSelect.vue2.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
const ProviderMultiSelect = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const ProviderMultiSelect = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-18bc53f4"]]);
|
|
5
5
|
export {
|
|
6
6
|
ProviderMultiSelect as default
|
|
7
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderMultiSelect.vue2.js","sources":["../../../src/vue/components/ProviderMultiSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { shouldAutoSelectMulti } from \"../utils/autoSelect\";\nimport MultiSelect from \"primevue/multiselect\";\n\nconst props = defineProps<{\n uischema: ControlElement;\n schema: JsonSchema;\n path: string;\n}>();\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst { projectedData, handleProjectedChange: handleChange } = useProjection(\n control,\n rawHandleChange,\n);\n\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(() => deps.value.map(() => null)); // you can resolve actual values via control.value.data & pointers\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 { items, loading, error } = useProvider(binding, {\n data: rootData, // Pass the reactive reference\n path: control.value.path,\n dependsOnValues: depValues
|
|
1
|
+
{"version":3,"file":"ProviderMultiSelect.vue2.js","sources":["../../../src/vue/components/ProviderMultiSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { shouldAutoSelectMulti } from \"../utils/autoSelect\";\nimport MultiSelect from \"primevue/multiselect\";\n\nconst props = defineProps<{\n uischema: ControlElement;\n schema: JsonSchema;\n path: string;\n}>();\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst { projectedData, handleProjectedChange: handleChange } = useProjection(\n control,\n rawHandleChange,\n);\n\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(() => deps.value.map(() => null)); // you can resolve actual values via control.value.data & pointers\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 { items, loading, error } = useProvider(binding, {\n data: rootData, // Pass the reactive reference\n path: control.value.path,\n dependsOnValues: depValues,\n});\n\n// Provider will automatically reload when rootData changes due to reactive cache key\n\n// Auto-select when provider returns only one item (opt-in for multiselect)\nwatch(\n [items, loading],\n ([newItems, isLoading]) => {\n const valueToSelect = shouldAutoSelectMulti({\n autoSelectSingle:\n control.value.uischema?.options?.autoSelectSingle === true,\n isLoading,\n items: newItems,\n currentValue: Array.isArray(projectedData.value)\n ? projectedData.value\n : [],\n });\n\n if (valueToSelect !== null) {\n handleChange(control.value.path, valueToSelect);\n }\n },\n { immediate: true },\n);\n\n// order-insensitive shallow equality for primitive arrays\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 value = computed({\n get() {\n const curr = Array.isArray(projectedData.value) ? projectedData.value : [];\n // return a fresh copy so MultiSelect 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(projectedData.value) ? projectedData.value : [];\n if (!sameSet(curr, next)) handleChange(control.value.path, next);\n },\n});\n\nconst placeholder = computed(() => {\n if (loading.value) return \"Loading…\";\n // Check for placeholder in uischema options\n const uischemaPlaceholder = (\n control.value.uischema as { options?: { placeholder?: string } }\n )?.options?.placeholder;\n return uischemaPlaceholder || \"Select…\";\n});\n</script>\n\n<template>\n <div class=\"jf-control\">\n <label v-if=\"control.schema.title\" class=\"jf-label\">{{\n control.schema.title\n }}</label>\n <div v-if=\"control.description\" class=\"jf-description\">\n {{ control.description }}\n </div>\n <MultiSelect\n v-model=\"value\"\n class=\"w-full!\"\n :options=\"items\"\n option-label=\"label\"\n option-value=\"value\"\n data-key=\"value\"\n display=\"chip\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled || loading\"\n :show-clear=\"true\"\n />\n <small v-if=\"error\" class=\"p-error\" role=\"alert\"\n >Failed to load: {{ error }}</small\n >\n </div>\n</template>\n\n<style scoped>\n:deep(.p-multiselect-label) {\n text-align: left;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./ProviderSelect.vue2.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
const ProviderSelect = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const ProviderSelect = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6c0f5b2f"]]);
|
|
5
5
|
export {
|
|
6
6
|
ProviderSelect as default
|
|
7
7
|
};
|
|
@@ -50,7 +50,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
50
50
|
data: rootData,
|
|
51
51
|
// Pass the reactive reference
|
|
52
52
|
path: control.value.path,
|
|
53
|
-
dependsOnValues: depValues
|
|
53
|
+
dependsOnValues: depValues
|
|
54
54
|
});
|
|
55
55
|
useDeriveInitialValue({ control, handleChange });
|
|
56
56
|
watch(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderSelect.vue2.js","sources":["../../../src/vue/components/ProviderSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDeriveInitialValue } from \"../composables/useDeriveInitialValue\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { shouldAutoSelect } from \"../utils/autoSelect\";\nimport Dropdown from \"primevue/dropdown\";\n\nconst props = defineProps<{\n uischema: ControlElement;\n schema: JsonSchema;\n path: string;\n}>();\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst { projectedData, handleProjectedChange: handleChange } = useProjection(\n control,\n rawHandleChange,\n);\n\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(() => deps.value.map(() => null)); // you can resolve actual values via control.value.data & pointers\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 { items, loading, error } = useProvider(binding, {\n data: rootData, // Pass the reactive reference\n path: control.value.path,\n dependsOnValues: depValues
|
|
1
|
+
{"version":3,"file":"ProviderSelect.vue2.js","sources":["../../../src/vue/components/ProviderSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ControlElement, JsonSchema } from \"@jsonforms/core\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDeriveInitialValue } from \"../composables/useDeriveInitialValue\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { shouldAutoSelect } from \"../utils/autoSelect\";\nimport Dropdown from \"primevue/dropdown\";\n\nconst props = defineProps<{\n uischema: ControlElement;\n schema: JsonSchema;\n path: string;\n}>();\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst { projectedData, handleProjectedChange: handleChange } = useProjection(\n control,\n rawHandleChange,\n);\n\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(() => deps.value.map(() => null)); // you can resolve actual values via control.value.data & pointers\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 { items, loading, error } = useProvider(binding, {\n data: rootData, // Pass the reactive reference\n path: control.value.path,\n dependsOnValues: depValues,\n});\n\n// Provider will automatically reload when rootData changes due to reactive cache key\n\n// deriveInitialValue — async API-based initial value seeding\nuseDeriveInitialValue({ control, handleChange });\n\n// Auto-select when provider returns only one item (enabled by default)\nwatch(\n [items, loading],\n ([newItems, isLoading]) => {\n const valueToSelect = shouldAutoSelect({\n autoSelectSingle:\n control.value.uischema?.options?.autoSelectSingle !== false,\n isLoading,\n items: newItems,\n currentValue: projectedData.value,\n });\n\n if (valueToSelect !== null) {\n handleChange(control.value.path, valueToSelect);\n }\n },\n { immediate: true },\n);\n\nconst value = computed({\n get: () => projectedData.value,\n set: (v) => handleChange(control.value.path, v),\n});\n\nconst placeholder = computed(() => {\n if (loading.value) return \"Loading…\";\n // Check for placeholder in uischema options\n const uischemaPlaceholder = (\n control.value.uischema as { options?: { placeholder?: string } }\n )?.options?.placeholder;\n return uischemaPlaceholder || \"Select…\";\n});\n</script>\n\n<template>\n <div class=\"jf-control\">\n <label v-if=\"control.schema.title\" class=\"jf-label\">{{\n control.schema.title\n }}</label>\n <div v-if=\"control.description\" class=\"jf-description\">\n {{ control.description }}\n </div>\n <Dropdown\n v-model=\"value\"\n class=\"w-full!\"\n :options=\"items\"\n option-label=\"label\"\n option-value=\"value\"\n :placeholder=\"placeholder\"\n :disabled=\"!control.enabled || loading\"\n :show-clear=\"true\"\n />\n <small v-if=\"error\" class=\"p-error\" role=\"alert\"\n >Failed to load: {{ error }}</small\n >\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,UAAM,QAAQ;AAKd,UAAM,EAAE,SAAS,cAAc,gBAAA,IAAoB,oBAAoB,KAAK;AAC5E,UAAM,EAAE,eAAe,uBAAuB,aAAA,IAAiB;AAAA,MAC7D;AAAA,MACA;AAAA,IAAA;AAGF,UAAM,UAAU,SAAS,MAAM;AAC7B,YAAM,WAAW,QAAQ,MAAM,UAAU,SAAS;AAElD,UAAI,YAAY,OAAO,aAAa,YAAY,CAAC,SAAS,MAAM;AAC9D,eAAO,EAAE,GAAG,UAAU,MAAM,QAAA;AAAA,MAC9B;AACA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,OAAO;AAAA,MACX,MAEK,QAAQ,MAAM,SACb,YACF,GACC,aAA0B,CAAA;AAAA,IAAC;AAElC,UAAM,YAAY,SAAS,MAAM,KAAK,MAAM,IAAI,MAAM,IAAI,CAAC;AAG3D,UAAM,mBAAmB,OAA2B,YAAY,EAAE,OAAO,CAAA,GAAI;AAC7E,UAAM,WAAW,SAAS,MAAM,iBAAiB,SAAS,CAAA,CAAE;AAE5D,UAAM,EAAE,OAAO,SAAS,MAAA,IAAU,YAAY,SAAS;AAAA,MACrD,MAAM;AAAA;AAAA,MACN,MAAM,QAAQ,MAAM;AAAA,MACpB,iBAAiB;AAAA,IAAA,CAClB;AAKD,0BAAsB,EAAE,SAAS,cAAc;AAG/C;AAAA,MACE,CAAC,OAAO,OAAO;AAAA,MACf,CAAC,CAAC,UAAU,SAAS,MAAM;AACzB,cAAM,gBAAgB,iBAAiB;AAAA,UACrC,kBACE,QAAQ,MAAM,UAAU,SAAS,qBAAqB;AAAA,UACxD;AAAA,UACA,OAAO;AAAA,UACP,cAAc,cAAc;AAAA,QAAA,CAC7B;AAED,YAAI,kBAAkB,MAAM;AAC1B,uBAAa,QAAQ,MAAM,MAAM,aAAa;AAAA,QAChD;AAAA,MACF;AAAA,MACA,EAAE,WAAW,KAAA;AAAA,IAAK;AAGpB,UAAM,QAAQ,SAAS;AAAA,MACrB,KAAK,MAAM,cAAc;AAAA,MACzB,KAAK,CAAC,MAAM,aAAa,QAAQ,MAAM,MAAM,CAAC;AAAA,IAAA,CAC/C;AAED,UAAM,cAAc,SAAS,MAAM;AACjC,UAAI,QAAQ,MAAO,QAAO;AAE1B,YAAM,sBACJ,QAAQ,MAAM,UACb,SAAS;AACZ,aAAO,uBAAuB;AAAA,IAChC,CAAC;;AAIC,aAAAA,UAAA,GAAAC,mBAoBM,OApBN,YAoBM;AAAA,QAnBSC,MAAA,OAAA,EAAQ,OAAO,SAA5BF,aAAAC,mBAEU,SAFV,YAEUE,gBADRD,eAAQ,OAAO,KAAK,GAAA,CAAA;QAEXA,MAAA,OAAA,EAAQ,eAAnBF,UAAA,GAAAC,mBAEM,OAFN,YAEME,gBADDD,MAAA,OAAA,EAAQ,WAAW,GAAA,CAAA;QAExBE,YASEF,MAAA,QAAA,GAAA;AAAA,sBARS,MAAA;AAAA,uEAAA,MAAK,QAAA;AAAA,UACd,OAAM;AAAA,UACL,SAASA,MAAA,KAAA;AAAA,UACV,gBAAa;AAAA,UACb,gBAAa;AAAA,UACZ,aAAa,YAAA;AAAA,UACb,UAAQ,CAAGA,MAAA,OAAA,EAAQ,WAAWA,MAAA,OAAA;AAAA,UAC9B,cAAY;AAAA,QAAA;QAEFA,MAAA,KAAA,KAAbF,aAAAC,mBAEC,SAFD,YACG,qCAAmBC,MAAA,KAAA,CAAK,GAAA,CAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useProjection.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useProjection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"useProjection.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useProjection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAQnE,UAAU,iBAAiB;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CACzE;AA8FD,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,aAAa,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,gEAAgE;IAEhE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAClD,8DAA8D;IAC9D,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9D,mCAAmC;IACnC,aAAa,EAAE,OAAO,CAAC;IACvB,sFAAsF;IACtF,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAC/B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GACnD,gBAAgB,CAyFlB"}
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import { computed, inject } from "vue";
|
|
2
|
-
import { getProjectedValue, getProjectedSchema, setProjectedValue } from "../../core/projection.js";
|
|
3
|
-
function resolveLabel(ctrl, schemaTitle) {
|
|
4
|
-
|
|
2
|
+
import { getProjectedValue, getProjectedSchema, parseProjectionPath, setProjectedValue } from "../../core/projection.js";
|
|
3
|
+
function resolveLabel(ctrl, schemaTitle, required) {
|
|
4
|
+
const base = ctrl.uischema?.options?.label ?? schemaTitle ?? ctrl.label ?? "";
|
|
5
|
+
if (!base) return base;
|
|
6
|
+
return required ? `${base} *` : base;
|
|
7
|
+
}
|
|
8
|
+
function isProjectedFieldRequired(schema, path) {
|
|
9
|
+
const segments = parseProjectionPath(path);
|
|
10
|
+
if (segments.length === 0) return false;
|
|
11
|
+
let current = schema;
|
|
12
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
13
|
+
const seg = segments[i];
|
|
14
|
+
if (typeof seg === "number") {
|
|
15
|
+
current = current?.items;
|
|
16
|
+
} else {
|
|
17
|
+
current = current?.properties?.[seg];
|
|
18
|
+
}
|
|
19
|
+
if (!current) return false;
|
|
20
|
+
}
|
|
21
|
+
const last = segments[segments.length - 1];
|
|
22
|
+
if (typeof last !== "string") return false;
|
|
23
|
+
return Array.isArray(current?.required) && current.required.includes(last);
|
|
5
24
|
}
|
|
6
25
|
function normalizeErrors(errors) {
|
|
7
26
|
if (!errors) return errors;
|
|
@@ -21,7 +40,9 @@ function getErrorPath(error) {
|
|
|
21
40
|
function useProjection(control, handleChange) {
|
|
22
41
|
const projection = control.value.uischema?.options?.projection;
|
|
23
42
|
if (!projection) {
|
|
24
|
-
const label2 = computed(
|
|
43
|
+
const label2 = computed(
|
|
44
|
+
() => resolveLabel(control.value, void 0, control.value.required)
|
|
45
|
+
);
|
|
25
46
|
return {
|
|
26
47
|
projectedData: computed(() => control.value.data),
|
|
27
48
|
projectedSchema: computed(() => control.value.schema),
|
|
@@ -47,8 +68,15 @@ function useProjection(control, handleChange) {
|
|
|
47
68
|
const projectedSchema = computed(
|
|
48
69
|
() => getProjectedSchema(control.value.schema, projection)
|
|
49
70
|
);
|
|
71
|
+
const projectedRequired = computed(
|
|
72
|
+
() => isProjectedFieldRequired(control.value.schema, projection)
|
|
73
|
+
);
|
|
50
74
|
const label = computed(
|
|
51
|
-
() => resolveLabel(
|
|
75
|
+
() => resolveLabel(
|
|
76
|
+
control.value,
|
|
77
|
+
projectedSchema.value?.title,
|
|
78
|
+
projectedRequired.value
|
|
79
|
+
)
|
|
52
80
|
);
|
|
53
81
|
const projectedErrors = computed(() => {
|
|
54
82
|
const baseErrors = normalizeErrors(control.value.errors || "");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useProjection.js","sources":["../../../src/vue/composables/useProjection.ts"],"sourcesContent":["import { computed, inject, type ComputedRef, type Ref } from \"vue\";\nimport {\n getProjectedValue,\n setProjectedValue,\n getProjectedSchema,\n} from \"../../core/projection\";\n\ninterface ProjectionControl {\n data: unknown;\n path: string;\n errors: string;\n label?: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>;\n uischema: { options?: { projection?: string; [key: string]: unknown } };\n}\n\n// Minimal AJV ErrorObject shape for filtering\ninterface ErrorLike {\n instancePath?: string;\n keyword?: string;\n message?: string;\n params?: { missingProperty?: string };\n}\n\n/**\n * Resolve the display label for a control.\n * Priority: uischema options.label → schemaTitle (projected sub-schema) → control.label.\n */\nfunction resolveLabel(ctrl: ProjectionControl, schemaTitle?: string): string {\n return (\n (ctrl.uischema?.options?.label as string) ?? schemaTitle ?? ctrl.label ?? \"\"\n );\n}\n\n/**\n * Normalize AJV error message fragments into user-friendly text.\n * e.g. \"is a required property\" → \"is required\"\n */\nfunction normalizeErrors(errors: string): string {\n if (!errors) return errors;\n return errors\n .replace(/is a required property/g, \"is required\")\n .replace(/must have required property '[^']*'/g, \"is required\");\n}\n\n/**\n * Prefix each error message line with the field label so that AJV fragments\n * like \"is required\" become \"Name is required\".\n */\nfunction prefixErrors(label: string, errors: string): string {\n if (!label || !errors) return errors;\n return errors\n .split(\"\\n\")\n .map((line) => `${label} ${line}`)\n .join(\"\\n\");\n}\n\n/**\n * Convert an AJV ErrorObject's instancePath to a dot-separated control path.\n * Replicates the logic from @jsonforms/core getControlPath.\n */\nfunction getErrorPath(error: ErrorLike): string {\n let p = (error.instancePath || \"\").replace(/\\//g, \".\").replace(/^\\./, \"\");\n if (error.keyword === \"required\" && error.params?.missingProperty) {\n p = p\n ? p + \".\" + error.params.missingProperty\n : error.params.missingProperty;\n }\n return p;\n}\n\nexport interface ProjectionResult {\n /** The value at the projected path (for rendering) */\n projectedData: ComputedRef<unknown>;\n /** The schema at the projected path (for renderer selection) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n projectedSchema: ComputedRef<Record<string, any>>;\n /** Wrapped handleChange that writes through the projection */\n handleProjectedChange: (path: string, value: unknown) => void;\n /** Whether projection is active */\n hasProjection: boolean;\n /** Resolved display label (options.label → projected schema title → control.label) */\n projectedLabel: ComputedRef<string>;\n /** Error string combining base-path and projected sub-path errors */\n projectedErrors: ComputedRef<string>;\n}\n\n/**\n * Composable that wraps a JSON Forms control with projection support.\n *\n * When `options.projection` is set on the uischema, this composable:\n * - Reads the projected sub-value from the control data\n * - Resolves the projected sub-schema for renderer type resolution\n * - Wraps handleChange to write back through the projection path (preserving siblings)\n *\n * When no projection is set, it passes through control data/schema/handleChange unchanged.\n */\nexport function useProjection(\n control: Ref<ProjectionControl>,\n handleChange: (path: string, value: unknown) => void,\n): ProjectionResult {\n const projection = control.value.uischema?.options?.projection as\n | string\n | undefined;\n\n if (!projection) {\n const label = computed(() => resolveLabel(control.value));\n return {\n projectedData: computed(() => control.value.data),\n projectedSchema: computed(() => control.value.schema),\n handleProjectedChange: handleChange,\n hasProjection: false,\n projectedLabel: label,\n projectedErrors: computed(() =>\n prefixErrors(\n label.value.replace(/\\*$/, \"\").trim(),\n normalizeErrors(control.value.errors),\n ),\n ),\n };\n }\n\n // Inject JSONForms state to access raw AJV errors for projected sub-paths.\n // control.errors only contains errors at the exact control path (e.g. \"data_rates\"),\n // but projected fields need errors at the full path (e.g. \"data_rates.0.video_rate_usd\").\n const jsonforms = inject<{ core?: { errors?: ErrorLike[] } } | null>(\n \"jsonforms\",\n null,\n );\n\n const fullProjectedPath = control.value.path + \".\" + projection;\n\n const projectedData = computed(() =>\n getProjectedValue(control.value.data, projection),\n );\n\n const projectedSchema = computed(() =>\n getProjectedSchema(control.value.schema, projection),\n );\n\n const label = computed(() =>\n resolveLabel(control.value, projectedSchema.value?.title),\n );\n\n const projectedErrors = computed(() => {\n const baseErrors = normalizeErrors(control.value.errors || \"\");\n\n const rawErrors = jsonforms?.core?.errors ?? [];\n const matching = rawErrors.filter(\n (err) => getErrorPath(err) === fullProjectedPath,\n );\n\n let errStr: string;\n if (matching.length === 0) {\n errStr = baseErrors;\n } else {\n const projMsg = matching\n .map((e) => (e.keyword === \"required\" ? \"is required\" : e.message))\n .filter(Boolean)\n .join(\"\\n\");\n errStr = [baseErrors, projMsg].filter(Boolean).join(\"\\n\");\n }\n\n return prefixErrors(label.value.replace(/\\*$/, \"\").trim(), errStr);\n });\n\n const handleProjectedChange = (path: string, value: unknown) => {\n const fullValue = setProjectedValue(control.value.data, projection, value);\n handleChange(path, fullValue);\n };\n\n return {\n projectedData,\n projectedSchema,\n handleProjectedChange,\n hasProjection: true,\n projectedLabel: label,\n projectedErrors,\n };\n}\n"],"names":["label"],"mappings":";;AA6BA,SAAS,aAAa,MAAyB,aAA8B;AAC3E,SACG,KAAK,UAAU,SAAS,SAAoB,eAAe,KAAK,SAAS;AAE9E;AAMA,SAAS,gBAAgB,QAAwB;AAC/C,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,OACJ,QAAQ,2BAA2B,aAAa,EAChD,QAAQ,wCAAwC,aAAa;AAClE;AAMA,SAAS,aAAa,OAAe,QAAwB;AAC3D,MAAI,CAAC,SAAS,CAAC,OAAQ,QAAO;AAC9B,SAAO,OACJ,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,EAAE,EAChC,KAAK,IAAI;AACd;AAMA,SAAS,aAAa,OAA0B;AAC9C,MAAI,KAAK,MAAM,gBAAgB,IAAI,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,EAAE;AACxE,MAAI,MAAM,YAAY,cAAc,MAAM,QAAQ,iBAAiB;AACjE,QAAI,IACA,IAAI,MAAM,MAAM,OAAO,kBACvB,MAAM,OAAO;AAAA,EACnB;AACA,SAAO;AACT;AA4BO,SAAS,cACd,SACA,cACkB;AAClB,QAAM,aAAa,QAAQ,MAAM,UAAU,SAAS;AAIpD,MAAI,CAAC,YAAY;AACf,UAAMA,SAAQ,SAAS,MAAM,aAAa,QAAQ,KAAK,CAAC;AACxD,WAAO;AAAA,MACL,eAAe,SAAS,MAAM,QAAQ,MAAM,IAAI;AAAA,MAChD,iBAAiB,SAAS,MAAM,QAAQ,MAAM,MAAM;AAAA,MACpD,uBAAuB;AAAA,MACvB,eAAe;AAAA,MACf,gBAAgBA;AAAAA,MAChB,iBAAiB;AAAA,QAAS,MACxB;AAAA,UACEA,OAAM,MAAM,QAAQ,OAAO,EAAE,EAAE,KAAA;AAAA,UAC/B,gBAAgB,QAAQ,MAAM,MAAM;AAAA,QAAA;AAAA,MACtC;AAAA,IACF;AAAA,EAEJ;AAKA,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,EAAA;AAGF,QAAM,oBAAoB,QAAQ,MAAM,OAAO,MAAM;AAErD,QAAM,gBAAgB;AAAA,IAAS,MAC7B,kBAAkB,QAAQ,MAAM,MAAM,UAAU;AAAA,EAAA;AAGlD,QAAM,kBAAkB;AAAA,IAAS,MAC/B,mBAAmB,QAAQ,MAAM,QAAQ,UAAU;AAAA,EAAA;AAGrD,QAAM,QAAQ;AAAA,IAAS,MACrB,aAAa,QAAQ,OAAO,gBAAgB,OAAO,KAAK;AAAA,EAAA;AAG1D,QAAM,kBAAkB,SAAS,MAAM;AACrC,UAAM,aAAa,gBAAgB,QAAQ,MAAM,UAAU,EAAE;AAE7D,UAAM,YAAY,WAAW,MAAM,UAAU,CAAA;AAC7C,UAAM,WAAW,UAAU;AAAA,MACzB,CAAC,QAAQ,aAAa,GAAG,MAAM;AAAA,IAAA;AAGjC,QAAI;AACJ,QAAI,SAAS,WAAW,GAAG;AACzB,eAAS;AAAA,IACX,OAAO;AACL,YAAM,UAAU,SACb,IAAI,CAAC,MAAO,EAAE,YAAY,aAAa,gBAAgB,EAAE,OAAQ,EACjE,OAAO,OAAO,EACd,KAAK,IAAI;AACZ,eAAS,CAAC,YAAY,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,IAC1D;AAEA,WAAO,aAAa,MAAM,MAAM,QAAQ,OAAO,EAAE,EAAE,KAAA,GAAQ,MAAM;AAAA,EACnE,CAAC;AAED,QAAM,wBAAwB,CAAC,MAAc,UAAmB;AAC9D,UAAM,YAAY,kBAAkB,QAAQ,MAAM,MAAM,YAAY,KAAK;AACzE,iBAAa,MAAM,SAAS;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB;AAAA,EAAA;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"useProjection.js","sources":["../../../src/vue/composables/useProjection.ts"],"sourcesContent":["import { computed, inject, type ComputedRef, type Ref } from \"vue\";\nimport {\n getProjectedValue,\n setProjectedValue,\n getProjectedSchema,\n parseProjectionPath,\n} from \"../../core/projection\";\n\ninterface ProjectionControl {\n data: unknown;\n path: string;\n errors: string;\n label?: string;\n required?: boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>;\n uischema: { options?: { projection?: string; [key: string]: unknown } };\n}\n\n// Minimal AJV ErrorObject shape for filtering\ninterface ErrorLike {\n instancePath?: string;\n keyword?: string;\n message?: string;\n params?: { missingProperty?: string };\n}\n\n/**\n * Resolve the display label for a control.\n * Priority: uischema options.label → schemaTitle (projected sub-schema) → control.label.\n * Appends a trailing asterisk when the control is for a required property.\n */\nfunction resolveLabel(\n ctrl: ProjectionControl,\n schemaTitle?: string,\n required?: boolean,\n): string {\n const base =\n (ctrl.uischema?.options?.label as string) ??\n schemaTitle ??\n ctrl.label ??\n \"\";\n if (!base) return base;\n return required ? `${base} *` : base;\n}\n\n/**\n * Determine whether the leaf of a projection path is listed in its parent\n * schema's `required` array. Numeric leaf segments (array indices) are not\n * considered \"required properties\".\n */\nfunction isProjectedFieldRequired(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>,\n path: string,\n): boolean {\n const segments = parseProjectionPath(path);\n if (segments.length === 0) return false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: Record<string, any> = schema;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n if (typeof seg === \"number\") {\n current = current?.items;\n } else {\n current = current?.properties?.[seg];\n }\n if (!current) return false;\n }\n const last = segments[segments.length - 1];\n if (typeof last !== \"string\") return false;\n return Array.isArray(current?.required) && current.required.includes(last);\n}\n\n/**\n * Normalize AJV error message fragments into user-friendly text.\n * e.g. \"is a required property\" → \"is required\"\n */\nfunction normalizeErrors(errors: string): string {\n if (!errors) return errors;\n return errors\n .replace(/is a required property/g, \"is required\")\n .replace(/must have required property '[^']*'/g, \"is required\");\n}\n\n/**\n * Prefix each error message line with the field label so that AJV fragments\n * like \"is required\" become \"Name is required\".\n */\nfunction prefixErrors(label: string, errors: string): string {\n if (!label || !errors) return errors;\n return errors\n .split(\"\\n\")\n .map((line) => `${label} ${line}`)\n .join(\"\\n\");\n}\n\n/**\n * Convert an AJV ErrorObject's instancePath to a dot-separated control path.\n * Replicates the logic from @jsonforms/core getControlPath.\n */\nfunction getErrorPath(error: ErrorLike): string {\n let p = (error.instancePath || \"\").replace(/\\//g, \".\").replace(/^\\./, \"\");\n if (error.keyword === \"required\" && error.params?.missingProperty) {\n p = p\n ? p + \".\" + error.params.missingProperty\n : error.params.missingProperty;\n }\n return p;\n}\n\nexport interface ProjectionResult {\n /** The value at the projected path (for rendering) */\n projectedData: ComputedRef<unknown>;\n /** The schema at the projected path (for renderer selection) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n projectedSchema: ComputedRef<Record<string, any>>;\n /** Wrapped handleChange that writes through the projection */\n handleProjectedChange: (path: string, value: unknown) => void;\n /** Whether projection is active */\n hasProjection: boolean;\n /** Resolved display label (options.label → projected schema title → control.label) */\n projectedLabel: ComputedRef<string>;\n /** Error string combining base-path and projected sub-path errors */\n projectedErrors: ComputedRef<string>;\n}\n\n/**\n * Composable that wraps a JSON Forms control with projection support.\n *\n * When `options.projection` is set on the uischema, this composable:\n * - Reads the projected sub-value from the control data\n * - Resolves the projected sub-schema for renderer type resolution\n * - Wraps handleChange to write back through the projection path (preserving siblings)\n *\n * When no projection is set, it passes through control data/schema/handleChange unchanged.\n */\nexport function useProjection(\n control: Ref<ProjectionControl>,\n handleChange: (path: string, value: unknown) => void,\n): ProjectionResult {\n const projection = control.value.uischema?.options?.projection as\n | string\n | undefined;\n\n if (!projection) {\n const label = computed(() =>\n resolveLabel(control.value, undefined, control.value.required),\n );\n return {\n projectedData: computed(() => control.value.data),\n projectedSchema: computed(() => control.value.schema),\n handleProjectedChange: handleChange,\n hasProjection: false,\n projectedLabel: label,\n projectedErrors: computed(() =>\n prefixErrors(\n label.value.replace(/\\*$/, \"\").trim(),\n normalizeErrors(control.value.errors),\n ),\n ),\n };\n }\n\n // Inject JSONForms state to access raw AJV errors for projected sub-paths.\n // control.errors only contains errors at the exact control path (e.g. \"data_rates\"),\n // but projected fields need errors at the full path (e.g. \"data_rates.0.video_rate_usd\").\n const jsonforms = inject<{ core?: { errors?: ErrorLike[] } } | null>(\n \"jsonforms\",\n null,\n );\n\n const fullProjectedPath = control.value.path + \".\" + projection;\n\n const projectedData = computed(() =>\n getProjectedValue(control.value.data, projection),\n );\n\n const projectedSchema = computed(() =>\n getProjectedSchema(control.value.schema, projection),\n );\n\n const projectedRequired = computed(() =>\n isProjectedFieldRequired(control.value.schema, projection),\n );\n\n const label = computed(() =>\n resolveLabel(\n control.value,\n projectedSchema.value?.title,\n projectedRequired.value,\n ),\n );\n\n const projectedErrors = computed(() => {\n const baseErrors = normalizeErrors(control.value.errors || \"\");\n\n const rawErrors = jsonforms?.core?.errors ?? [];\n const matching = rawErrors.filter(\n (err) => getErrorPath(err) === fullProjectedPath,\n );\n\n let errStr: string;\n if (matching.length === 0) {\n errStr = baseErrors;\n } else {\n const projMsg = matching\n .map((e) => (e.keyword === \"required\" ? \"is required\" : e.message))\n .filter(Boolean)\n .join(\"\\n\");\n errStr = [baseErrors, projMsg].filter(Boolean).join(\"\\n\");\n }\n\n return prefixErrors(label.value.replace(/\\*$/, \"\").trim(), errStr);\n });\n\n const handleProjectedChange = (path: string, value: unknown) => {\n const fullValue = setProjectedValue(control.value.data, projection, value);\n handleChange(path, fullValue);\n };\n\n return {\n projectedData,\n projectedSchema,\n handleProjectedChange,\n hasProjection: true,\n projectedLabel: label,\n projectedErrors,\n };\n}\n"],"names":["label"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import type { ProviderBinding, ProviderItem } from "../../core/types";
|
|
|
3
3
|
export declare function useProvider(binding: ProviderBinding | Ref<ProviderBinding> | ComputedRef<ProviderBinding>, ctxBits: {
|
|
4
4
|
data: unknown | Ref<unknown> | ComputedRef<unknown>;
|
|
5
5
|
path: string;
|
|
6
|
-
dependsOnValues?: unknown[]
|
|
7
|
-
uiQuery?: string
|
|
6
|
+
dependsOnValues?: unknown[] | Ref<unknown[]> | ComputedRef<unknown[]>;
|
|
7
|
+
uiQuery?: string | Ref<string | undefined> | ComputedRef<string | undefined>;
|
|
8
8
|
}): {
|
|
9
9
|
items: Ref<{
|
|
10
10
|
label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useProvider.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAIhB,KAAK,GAAG,EAIT,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"useProvider.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAIhB,KAAK,GAAG,EAIT,MAAM,KAAK,CAAC;AAIb,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EAEb,MAAM,kBAAkB,CAAC;AAE1B,wBAAgB,WAAW,CACzB,OAAO,EACH,eAAe,GACf,GAAG,CAAC,eAAe,CAAC,GACpB,WAAW,CAAC,eAAe,CAAC,EAChC,OAAO,EAAE;IACP,IAAI,EAAE,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,EACJ,MAAM,GACN,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,GACvB,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACrC;;;;;;;;;;;;;EAmFF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { inject, ref, computed, unref, onBeforeUnmount, watch } from "vue";
|
|
2
2
|
import { cache } from "../../core/cache.js";
|
|
3
3
|
import { registry } from "../../core/registry.js";
|
|
4
|
+
import { renderObj } from "../../core/templating.js";
|
|
4
5
|
function useProvider(binding, ctxBits) {
|
|
5
6
|
const registry$1 = inject("providerRegistry", registry);
|
|
6
7
|
const cache$1 = inject("providerCache", cache);
|
|
@@ -9,15 +10,18 @@ function useProvider(binding, ctxBits) {
|
|
|
9
10
|
const loading = ref(false);
|
|
10
11
|
const error = ref(void 0);
|
|
11
12
|
const ac = new AbortController();
|
|
12
|
-
const cacheKey = computed(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
const cacheKey = computed(() => {
|
|
14
|
+
const b = unref(binding);
|
|
15
|
+
const renderedBinding = b ? {
|
|
16
|
+
...b,
|
|
17
|
+
config: renderObj(b.config ?? {}, { data: unref(ctxBits.data) })
|
|
18
|
+
} : b;
|
|
19
|
+
return JSON.stringify({
|
|
20
|
+
b: renderedBinding,
|
|
21
|
+
d: unref(ctxBits.dependsOnValues) ?? [],
|
|
22
|
+
q: unref(ctxBits.uiQuery) ?? ""
|
|
23
|
+
});
|
|
24
|
+
});
|
|
21
25
|
async function load() {
|
|
22
26
|
const bindingValue = unref(binding);
|
|
23
27
|
if (!bindingValue) return;
|
|
@@ -39,7 +43,7 @@ function useProvider(binding, ctxBits) {
|
|
|
39
43
|
const out = await driver.resolve(bindingValue.config ?? {}, {
|
|
40
44
|
data: unref(ctxBits.data),
|
|
41
45
|
path: ctxBits.path,
|
|
42
|
-
ui: { query: ctxBits.uiQuery },
|
|
46
|
+
ui: { query: unref(ctxBits.uiQuery) },
|
|
43
47
|
signal: ac.signal,
|
|
44
48
|
auth: resolveAuth(bindingValue.auth, auth)
|
|
45
49
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useProvider.js","sources":["../../../src/vue/composables/useProvider.ts"],"sourcesContent":["import {\n type ComputedRef,\n computed,\n inject,\n onBeforeUnmount,\n type Ref,\n ref,\n unref,\n watch,\n} from \"vue\";\nimport { cache as globalCache } from \"../../core/cache\";\nimport { registry as globalRegistry } from \"../../core/registry\";\nimport type {\n AuthConfig,\n ProviderBinding,\n ProviderItem,\n ProviderOutput,\n} from \"../../core/types\";\n\nexport function useProvider(\n binding:\n | ProviderBinding\n | Ref<ProviderBinding>\n | ComputedRef<ProviderBinding>,\n ctxBits: {\n data: unknown | Ref<unknown> | ComputedRef<unknown>;\n path: string;\n dependsOnValues?: unknown[]
|
|
1
|
+
{"version":3,"file":"useProvider.js","sources":["../../../src/vue/composables/useProvider.ts"],"sourcesContent":["import {\n type ComputedRef,\n computed,\n inject,\n onBeforeUnmount,\n type Ref,\n ref,\n unref,\n watch,\n} from \"vue\";\nimport { cache as globalCache } from \"../../core/cache\";\nimport { registry as globalRegistry } from \"../../core/registry\";\nimport { renderObj } from \"../../core/templating\";\nimport type {\n AuthConfig,\n ProviderBinding,\n ProviderItem,\n ProviderOutput,\n} from \"../../core/types\";\n\nexport function useProvider(\n binding:\n | ProviderBinding\n | Ref<ProviderBinding>\n | ComputedRef<ProviderBinding>,\n ctxBits: {\n data: unknown | Ref<unknown> | ComputedRef<unknown>;\n path: string;\n dependsOnValues?: unknown[] | Ref<unknown[]> | ComputedRef<unknown[]>;\n uiQuery?:\n | string\n | Ref<string | undefined>\n | ComputedRef<string | undefined>;\n },\n) {\n const registry = inject(\"providerRegistry\", globalRegistry);\n const cache = inject(\"providerCache\", globalCache);\n const auth = inject(\"providerAuth\", {}) as Record<\n string,\n (() => string) | string\n >;\n\n const items = ref<ProviderItem[]>([]);\n const loading = ref(false);\n const error = ref<string | undefined>(undefined);\n const ac = new AbortController();\n\n // Cache key keys on the *rendered* binding config (with template variables\n // substituted) plus dependsOnValues + uiQuery. This means:\n // - `{{data.country}}` in the URL → cache key changes when country changes,\n // auto-refetching without callers having to declare dependsOn.\n // - Unrelated form fields → rendered URL is unchanged → no refetch.\n // The protocol's resolve() still receives the raw config and current data,\n // so per-fetch URL rendering works as before.\n const cacheKey = computed(() => {\n const b = unref(binding);\n const renderedBinding = b\n ? {\n ...b,\n config: renderObj(b.config ?? {}, { data: unref(ctxBits.data) }),\n }\n : b;\n return JSON.stringify({\n b: renderedBinding,\n d: unref(ctxBits.dependsOnValues) ?? [],\n q: unref(ctxBits.uiQuery) ?? \"\",\n });\n });\n\n async function load() {\n const bindingValue = unref(binding);\n if (!bindingValue) return;\n loading.value = true;\n error.value = undefined;\n const hit = cache.get(cacheKey.value) as ProviderOutput | undefined;\n if (hit) {\n items.value = hit.items;\n loading.value = false;\n return;\n }\n try {\n const driver = registry.get(bindingValue.protocol);\n if (!driver) {\n throw new Error(\n `No provider registered for protocol: ${bindingValue.protocol}`,\n );\n }\n const out = await driver.resolve(bindingValue.config ?? {}, {\n data: unref(ctxBits.data),\n path: ctxBits.path,\n ui: { query: unref(ctxBits.uiQuery) },\n signal: ac.signal,\n auth: resolveAuth(bindingValue.auth, auth),\n });\n items.value = out.items;\n cache.set(cacheKey.value, out, bindingValue.cacheTTL ?? out.ttl ?? 0);\n } catch (e) {\n error.value = (e as Error)?.message ?? String(e);\n items.value = [];\n } finally {\n loading.value = false;\n }\n }\n\n onBeforeUnmount(() => ac.abort());\n watch(\n [cacheKey],\n () => {\n const bindingValue = unref(binding);\n if (bindingValue?.load === \"mount\" || bindingValue?.load === \"query\")\n load();\n },\n { immediate: unref(binding)?.load === \"mount\" },\n );\n\n return { items, loading, error, reload: load };\n}\n\nfunction resolveAuth(\n spec: AuthConfig | undefined,\n authBag: Record<string, (() => string) | string>,\n): AuthConfig {\n if (!spec) return {};\n if (spec.use && typeof authBag[spec.use] === \"function\") {\n const authFunc = authBag[spec.use] as () => string;\n return { [spec.use]: authFunc() };\n }\n return spec;\n}\n"],"names":["registry","globalRegistry","cache","globalCache"],"mappings":";;;;AAoBO,SAAS,YACd,SAIA,SASA;AACA,QAAMA,aAAW,OAAO,oBAAoBC,QAAc;AAC1D,QAAMC,UAAQ,OAAO,iBAAiBC,KAAW;AACjD,QAAM,OAAO,OAAO,gBAAgB,EAAE;AAKtC,QAAM,QAAQ,IAAoB,EAAE;AACpC,QAAM,UAAU,IAAI,KAAK;AACzB,QAAM,QAAQ,IAAwB,MAAS;AAC/C,QAAM,KAAK,IAAI,gBAAA;AASf,QAAM,WAAW,SAAS,MAAM;AAC9B,UAAM,IAAI,MAAM,OAAO;AACvB,UAAM,kBAAkB,IACpB;AAAA,MACE,GAAG;AAAA,MACH,QAAQ,UAAU,EAAE,UAAU,CAAA,GAAI,EAAE,MAAM,MAAM,QAAQ,IAAI,EAAA,CAAG;AAAA,IAAA,IAEjE;AACJ,WAAO,KAAK,UAAU;AAAA,MACpB,GAAG;AAAA,MACH,GAAG,MAAM,QAAQ,eAAe,KAAK,CAAA;AAAA,MACrC,GAAG,MAAM,QAAQ,OAAO,KAAK;AAAA,IAAA,CAC9B;AAAA,EACH,CAAC;AAED,iBAAe,OAAO;AACpB,UAAM,eAAe,MAAM,OAAO;AAClC,QAAI,CAAC,aAAc;AACnB,YAAQ,QAAQ;AAChB,UAAM,QAAQ;AACd,UAAM,MAAMD,QAAM,IAAI,SAAS,KAAK;AACpC,QAAI,KAAK;AACP,YAAM,QAAQ,IAAI;AAClB,cAAQ,QAAQ;AAChB;AAAA,IACF;AACA,QAAI;AACF,YAAM,SAASF,WAAS,IAAI,aAAa,QAAQ;AACjD,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,wCAAwC,aAAa,QAAQ;AAAA,QAAA;AAAA,MAEjE;AACA,YAAM,MAAM,MAAM,OAAO,QAAQ,aAAa,UAAU,IAAI;AAAA,QAC1D,MAAM,MAAM,QAAQ,IAAI;AAAA,QACxB,MAAM,QAAQ;AAAA,QACd,IAAI,EAAE,OAAO,MAAM,QAAQ,OAAO,EAAA;AAAA,QAClC,QAAQ,GAAG;AAAA,QACX,MAAM,YAAY,aAAa,MAAM,IAAI;AAAA,MAAA,CAC1C;AACD,YAAM,QAAQ,IAAI;AAClBE,cAAM,IAAI,SAAS,OAAO,KAAK,aAAa,YAAY,IAAI,OAAO,CAAC;AAAA,IACtE,SAAS,GAAG;AACV,YAAM,QAAS,GAAa,WAAW,OAAO,CAAC;AAC/C,YAAM,QAAQ,CAAA;AAAA,IAChB,UAAA;AACE,cAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AAEA,kBAAgB,MAAM,GAAG,OAAO;AAChC;AAAA,IACE,CAAC,QAAQ;AAAA,IACT,MAAM;AACJ,YAAM,eAAe,MAAM,OAAO;AAClC,UAAI,cAAc,SAAS,WAAW,cAAc,SAAS;AAC3D,aAAA;AAAA,IACJ;AAAA,IACA,EAAE,WAAW,MAAM,OAAO,GAAG,SAAS,QAAA;AAAA,EAAQ;AAGhD,SAAO,EAAE,OAAO,SAAS,OAAO,QAAQ,KAAA;AAC1C;AAEA,SAAS,YACP,MACA,SACY;AACZ,MAAI,CAAC,KAAM,QAAO,CAAA;AAClB,MAAI,KAAK,OAAO,OAAO,QAAQ,KAAK,GAAG,MAAM,YAAY;AACvD,UAAM,WAAW,QAAQ,KAAK,GAAG;AACjC,WAAO,EAAE,CAAC,KAAK,GAAG,GAAG,WAAS;AAAA,EAChC;AACA,SAAO;AACT;"}
|
|
@@ -119,7 +119,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
119
119
|
} = useProvider(binding, {
|
|
120
120
|
data: rootData,
|
|
121
121
|
path: control.value.path,
|
|
122
|
-
dependsOnValues: depValues
|
|
122
|
+
dependsOnValues: depValues
|
|
123
123
|
});
|
|
124
124
|
const placeholder = computed(() => {
|
|
125
125
|
if (loading.value) return "Loading…";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JfEnum.vue.js","sources":["../../../src/vue/primevue/JfEnum.vue"],"sourcesContent":["<script lang=\"ts\">\n// Define props manually to avoid any potential circular dependency issues\nexport default {\n name: \"JfEnum\",\n props: {\n uischema: {\n type: Object,\n required: true,\n },\n schema: {\n type: Object,\n required: true,\n },\n path: {\n type: String,\n required: true,\n },\n enabled: {\n type: Boolean,\n default: undefined,\n },\n renderers: {\n type: Array,\n required: false,\n default: undefined,\n },\n cells: {\n type: Array,\n required: false,\n default: undefined,\n },\n config: {\n type: Object,\n required: false,\n default: undefined,\n },\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport type { JsonSchema } from \"@jsonforms/core\";\nimport type { ControlProps } from \"@jsonforms/vue\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, getCurrentInstance, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport { useDeriveInitialValue } from \"../composables/useDeriveInitialValue\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { useDirtyValidation } from \"../composables/useDirtyValidation\";\nimport { shouldAutoSelect } from \"../utils/autoSelect\";\nimport Dropdown from \"primevue/dropdown\";\n\n// Access props from the component instance\nconst instance = getCurrentInstance()!;\nconst props = instance.props as unknown as ControlProps;\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst {\n projectedData,\n handleProjectedChange: handleChange,\n projectedErrors,\n projectedLabel,\n} = useProjection(control, rawHandleChange);\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
|
|
1
|
+
{"version":3,"file":"JfEnum.vue.js","sources":["../../../src/vue/primevue/JfEnum.vue"],"sourcesContent":["<script lang=\"ts\">\n// Define props manually to avoid any potential circular dependency issues\nexport default {\n name: \"JfEnum\",\n props: {\n uischema: {\n type: Object,\n required: true,\n },\n schema: {\n type: Object,\n required: true,\n },\n path: {\n type: String,\n required: true,\n },\n enabled: {\n type: Boolean,\n default: undefined,\n },\n renderers: {\n type: Array,\n required: false,\n default: undefined,\n },\n cells: {\n type: Array,\n required: false,\n default: undefined,\n },\n config: {\n type: Object,\n required: false,\n default: undefined,\n },\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport type { JsonSchema } from \"@jsonforms/core\";\nimport type { ControlProps } from \"@jsonforms/vue\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, getCurrentInstance, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport { useDeriveInitialValue } from \"../composables/useDeriveInitialValue\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { useDirtyValidation } from \"../composables/useDirtyValidation\";\nimport { shouldAutoSelect } from \"../utils/autoSelect\";\nimport Dropdown from \"primevue/dropdown\";\n\n// Access props from the component instance\nconst instance = getCurrentInstance()!;\nconst props = instance.props as unknown as ControlProps;\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst {\n projectedData,\n handleProjectedChange: handleChange,\n projectedErrors,\n projectedLabel,\n} = useProjection(control, rawHandleChange);\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,\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, data: projectedData });\n\n// Add deriveInitialValue — async API-based initial value seeding\nuseDeriveInitialValue({ control, handleChange });\n\n// Auto-select when provider returns only one item (enabled by default)\nwatch(\n [providerItems, loading],\n ([items, isLoading]) => {\n const valueToSelect = shouldAutoSelect({\n autoSelectSingle:\n control.value.uischema?.options?.autoSelectSingle !== false,\n isLoading,\n items,\n currentValue: projectedData.value,\n });\n\n if (valueToSelect !== null) {\n handleChange(control.value.path, valueToSelect);\n }\n },\n { immediate: true },\n);\n\n// Track user interaction — errors only show after blur\nconst { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);\n\nconst onSelect = (val: unknown) => {\n handleChange(control.value.path, val);\n};\n</script>\n\n<template>\n <div class=\"jf-control\">\n <label v-if=\"projectedLabel\" class=\"jf-label\">{{ projectedLabel }}</label>\n <div v-if=\"control.description\" class=\"jf-description\">\n {{ control.description }}\n </div>\n <Dropdown\n :class=\"['w-full!', { 'p-invalid': showErrors }]\"\n :options=\"options\"\n option-label=\"label\"\n option-value=\"value\"\n :model-value=\"projectedData ?? 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=\"markDirty\"\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\">{{ projectedErrors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":"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"}
|
|
@@ -118,7 +118,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
118
118
|
} = useProvider(binding, {
|
|
119
119
|
data: rootData,
|
|
120
120
|
path: control.value.path,
|
|
121
|
-
dependsOnValues: depValues
|
|
121
|
+
dependsOnValues: depValues
|
|
122
122
|
});
|
|
123
123
|
const options = computed(() => {
|
|
124
124
|
if (binding.value && providerItems.value.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JfEnumArray.vue.js","sources":["../../../src/vue/primevue/JfEnumArray.vue"],"sourcesContent":["<script lang=\"ts\">\nexport default {\n name: \"JfEnumArray\",\n props: {\n uischema: {\n type: Object,\n required: true,\n },\n schema: {\n type: Object,\n required: true,\n },\n path: {\n type: String,\n required: true,\n },\n enabled: {\n type: Boolean,\n default: undefined,\n },\n renderers: {\n type: Array,\n required: false,\n default: undefined,\n },\n cells: {\n type: Array,\n required: false,\n default: undefined,\n },\n config: {\n type: Object,\n required: false,\n default: undefined,\n },\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport type { JsonSchema } from \"@jsonforms/core\";\nimport type { ControlProps } from \"@jsonforms/vue\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, getCurrentInstance, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { useDirtyValidation } from \"../composables/useDirtyValidation\";\nimport { shouldAutoSelectMulti } from \"../utils/autoSelect\";\nimport MultiSelect from \"primevue/multiselect\";\n\n// Access props from the component instance\nconst instance = getCurrentInstance()!;\nconst props = instance.props as unknown as ControlProps;\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst {\n projectedData,\n handleProjectedChange: handleChange,\n projectedErrors,\n projectedLabel,\n} = useProjection(control, rawHandleChange);\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, data: projectedData });\n\n// Track user interaction — errors only show after first change\nconst { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);\n\n// Auto-select when provider returns only one item (opt-in for multiselect)\nwatch(\n [providerItems, loading],\n ([items, isLoading]) => {\n const valueToSelect = shouldAutoSelectMulti({\n autoSelectSingle:\n control.value.uischema?.options?.autoSelectSingle === true,\n isLoading,\n items,\n currentValue: Array.isArray(projectedData.value)\n ? projectedData.value\n : [],\n });\n\n if (valueToSelect !== null) {\n handleChange(control.value.path, valueToSelect);\n }\n },\n { immediate: true },\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\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(projectedData.value) ? projectedData.value : [];\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(projectedData.value) ? projectedData.value : [];\n if (!sameSet(curr, next)) {\n markDirty();\n handleChange(control.value.path, next);\n }\n },\n});\n</script>\n\n<template>\n <div class=\"jf-control\">\n <label v-if=\"projectedLabel\" class=\"jf-label\">{{ projectedLabel }}</label>\n <div v-if=\"control.description\" class=\"jf-description\">\n {{ control.description }}\n </div>\n\n <MultiSelect\n v-model=\"model\"\n :class=\"['w-full!', { 'p-invalid': showErrors }]\"\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=\"showErrors || 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=\"showErrors\" class=\"p-error\">{{ projectedErrors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JfEnumArray.vue.js","sources":["../../../src/vue/primevue/JfEnumArray.vue"],"sourcesContent":["<script lang=\"ts\">\nexport default {\n name: \"JfEnumArray\",\n props: {\n uischema: {\n type: Object,\n required: true,\n },\n schema: {\n type: Object,\n required: true,\n },\n path: {\n type: String,\n required: true,\n },\n enabled: {\n type: Boolean,\n default: undefined,\n },\n renderers: {\n type: Array,\n required: false,\n default: undefined,\n },\n cells: {\n type: Array,\n required: false,\n default: undefined,\n },\n config: {\n type: Object,\n required: false,\n default: undefined,\n },\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport type { JsonSchema } from \"@jsonforms/core\";\nimport type { ControlProps } from \"@jsonforms/vue\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, inject, getCurrentInstance, watch } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { useDirtyValidation } from \"../composables/useDirtyValidation\";\nimport { shouldAutoSelectMulti } from \"../utils/autoSelect\";\nimport MultiSelect from \"primevue/multiselect\";\n\n// Access props from the component instance\nconst instance = getCurrentInstance()!;\nconst props = instance.props as unknown as ControlProps;\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst {\n projectedData,\n handleProjectedChange: handleChange,\n projectedErrors,\n projectedLabel,\n} = useProjection(control, rawHandleChange);\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,\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, data: projectedData });\n\n// Track user interaction — errors only show after first change\nconst { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);\n\n// Auto-select when provider returns only one item (opt-in for multiselect)\nwatch(\n [providerItems, loading],\n ([items, isLoading]) => {\n const valueToSelect = shouldAutoSelectMulti({\n autoSelectSingle:\n control.value.uischema?.options?.autoSelectSingle === true,\n isLoading,\n items,\n currentValue: Array.isArray(projectedData.value)\n ? projectedData.value\n : [],\n });\n\n if (valueToSelect !== null) {\n handleChange(control.value.path, valueToSelect);\n }\n },\n { immediate: true },\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\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(projectedData.value) ? projectedData.value : [];\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(projectedData.value) ? projectedData.value : [];\n if (!sameSet(curr, next)) {\n markDirty();\n handleChange(control.value.path, next);\n }\n },\n});\n</script>\n\n<template>\n <div class=\"jf-control\">\n <label v-if=\"projectedLabel\" class=\"jf-label\">{{ projectedLabel }}</label>\n <div v-if=\"control.description\" class=\"jf-description\">\n {{ control.description }}\n </div>\n\n <MultiSelect\n v-model=\"model\"\n :class=\"['w-full!', { 'p-invalid': showErrors }]\"\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=\"showErrors || 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=\"showErrors\" class=\"p-error\">{{ projectedErrors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createVNode"],"mappings":"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"}
|
|
@@ -105,7 +105,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
105
105
|
data: rootData,
|
|
106
106
|
path: control.value.path,
|
|
107
107
|
uiQuery: query.value,
|
|
108
|
-
dependsOnValues: depValues
|
|
108
|
+
dependsOnValues: depValues
|
|
109
109
|
});
|
|
110
110
|
watch(query, () => {
|
|
111
111
|
if (binding.value?.load === "query") reload();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JfText.vue.js","sources":["../../../src/vue/primevue/JfText.vue"],"sourcesContent":["<script lang=\"ts\">\nexport default {\n name: \"JfText\",\n props: {\n uischema: {\n type: Object,\n required: true,\n },\n schema: {\n type: Object,\n required: true,\n },\n path: {\n type: String,\n required: true,\n },\n enabled: {\n type: Boolean,\n default: undefined,\n },\n renderers: {\n type: Array,\n required: false,\n default: undefined,\n },\n cells: {\n type: Array,\n required: false,\n default: undefined,\n },\n config: {\n type: Object,\n required: false,\n default: undefined,\n },\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport type { ControlProps } from \"@jsonforms/vue\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref, inject, watch, getCurrentInstance } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport { useDeriveInitialValue } from \"../composables/useDeriveInitialValue\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { useDirtyValidation } from \"../composables/useDirtyValidation\";\nimport InputText from \"primevue/inputtext\";\nimport AutoComplete from \"primevue/autocomplete\";\n\n// Access props from the component instance\nconst instance = getCurrentInstance()!;\nconst props = instance.props as unknown as ControlProps;\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst {\n projectedData,\n handleProjectedChange: handleChange,\n projectedErrors,\n projectedLabel,\n} = useProjection(control, rawHandleChange);\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
|
|
1
|
+
{"version":3,"file":"JfText.vue.js","sources":["../../../src/vue/primevue/JfText.vue"],"sourcesContent":["<script lang=\"ts\">\nexport default {\n name: \"JfText\",\n props: {\n uischema: {\n type: Object,\n required: true,\n },\n schema: {\n type: Object,\n required: true,\n },\n path: {\n type: String,\n required: true,\n },\n enabled: {\n type: Boolean,\n default: undefined,\n },\n renderers: {\n type: Array,\n required: false,\n default: undefined,\n },\n cells: {\n type: Array,\n required: false,\n default: undefined,\n },\n config: {\n type: Object,\n required: false,\n default: undefined,\n },\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport type { ControlProps } from \"@jsonforms/vue\";\nimport { useJsonFormsControl } from \"@jsonforms/vue\";\nimport { computed, ref, inject, watch, getCurrentInstance } from \"vue\";\nimport { useProvider } from \"../composables/useProvider\";\nimport { useDerive } from \"../composables/useDerive\";\nimport { useDeriveInitialValue } from \"../composables/useDeriveInitialValue\";\nimport { useProjection } from \"../composables/useProjection\";\nimport { useDirtyValidation } from \"../composables/useDirtyValidation\";\nimport InputText from \"primevue/inputtext\";\nimport AutoComplete from \"primevue/autocomplete\";\n\n// Access props from the component instance\nconst instance = getCurrentInstance()!;\nconst props = instance.props as unknown as ControlProps;\nconst { control, handleChange: rawHandleChange } = useJsonFormsControl(props);\nconst {\n projectedData,\n handleProjectedChange: handleChange,\n projectedErrors,\n projectedLabel,\n} = useProjection(control, rawHandleChange);\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,\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, data: projectedData });\n\n// Add deriveInitialValue — async API-based initial value seeding\nuseDeriveInitialValue({ control, handleChange });\n\n// Track user interaction — errors only show after blur\nconst { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);\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 (projectedData.value !== newValue) {\n handleChange(control.value.path, newValue);\n }\n}\n\nfunction onBlur() {\n markDirty();\n // Normalize empty strings to undefined so required validation fires\n const val = projectedData.value;\n if (typeof val === \"string\" && val.trim() === \"\") {\n handleChange(control.value.path, undefined);\n }\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=\"jf-control\">\n <label v-if=\"projectedLabel\" class=\"jf-label\">{{ projectedLabel }}</label>\n <div v-if=\"control.description\" class=\"jf-description\">\n {{ control.description }}\n </div>\n <AutoComplete\n v-if=\"isAutocomplete\"\n :class=\"['w-full!', { 'p-invalid': showErrors }]\"\n :model-value=\"projectedData ?? ''\"\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 />\n <InputText\n v-else\n :class=\"['w-full!', { 'p-invalid': showErrors }]\"\n :model-value=\"(projectedData as string) ?? ''\"\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 />\n <small v-if=\"error\" class=\"p-error\" role=\"alert\">Failed: {{ error }}</small>\n <small v-else-if=\"showErrors\" class=\"p-error\">{{ projectedErrors }}</small>\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_unref","_toDisplayString","_createBlock"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -44,7 +44,7 @@ const rootData = computed(() => injectedFormData.value || {});
|
|
|
44
44
|
const { items, loading, error } = useProvider(binding, {
|
|
45
45
|
data: rootData, // Pass the reactive reference
|
|
46
46
|
path: control.value.path,
|
|
47
|
-
dependsOnValues: depValues
|
|
47
|
+
dependsOnValues: depValues,
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
// Provider will automatically reload when rootData changes due to reactive cache key
|
|
@@ -45,7 +45,7 @@ const rootData = computed(() => injectedFormData.value || {});
|
|
|
45
45
|
const { items, loading, error } = useProvider(binding, {
|
|
46
46
|
data: rootData, // Pass the reactive reference
|
|
47
47
|
path: control.value.path,
|
|
48
|
-
dependsOnValues: depValues
|
|
48
|
+
dependsOnValues: depValues,
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
// Provider will automatically reload when rootData changes due to reactive cache key
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
getProjectedValue,
|
|
4
4
|
setProjectedValue,
|
|
5
5
|
getProjectedSchema,
|
|
6
|
+
parseProjectionPath,
|
|
6
7
|
} from "../../core/projection";
|
|
7
8
|
|
|
8
9
|
interface ProjectionControl {
|
|
@@ -10,6 +11,7 @@ interface ProjectionControl {
|
|
|
10
11
|
path: string;
|
|
11
12
|
errors: string;
|
|
12
13
|
label?: string;
|
|
14
|
+
required?: boolean;
|
|
13
15
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
16
|
schema: Record<string, any>;
|
|
15
17
|
uischema: { options?: { projection?: string; [key: string]: unknown } };
|
|
@@ -26,11 +28,48 @@ interface ErrorLike {
|
|
|
26
28
|
/**
|
|
27
29
|
* Resolve the display label for a control.
|
|
28
30
|
* Priority: uischema options.label → schemaTitle (projected sub-schema) → control.label.
|
|
31
|
+
* Appends a trailing asterisk when the control is for a required property.
|
|
29
32
|
*/
|
|
30
|
-
function resolveLabel(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
function resolveLabel(
|
|
34
|
+
ctrl: ProjectionControl,
|
|
35
|
+
schemaTitle?: string,
|
|
36
|
+
required?: boolean,
|
|
37
|
+
): string {
|
|
38
|
+
const base =
|
|
39
|
+
(ctrl.uischema?.options?.label as string) ??
|
|
40
|
+
schemaTitle ??
|
|
41
|
+
ctrl.label ??
|
|
42
|
+
"";
|
|
43
|
+
if (!base) return base;
|
|
44
|
+
return required ? `${base} *` : base;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Determine whether the leaf of a projection path is listed in its parent
|
|
49
|
+
* schema's `required` array. Numeric leaf segments (array indices) are not
|
|
50
|
+
* considered "required properties".
|
|
51
|
+
*/
|
|
52
|
+
function isProjectedFieldRequired(
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
+
schema: Record<string, any>,
|
|
55
|
+
path: string,
|
|
56
|
+
): boolean {
|
|
57
|
+
const segments = parseProjectionPath(path);
|
|
58
|
+
if (segments.length === 0) return false;
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
let current: Record<string, any> = schema;
|
|
61
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
62
|
+
const seg = segments[i]!;
|
|
63
|
+
if (typeof seg === "number") {
|
|
64
|
+
current = current?.items;
|
|
65
|
+
} else {
|
|
66
|
+
current = current?.properties?.[seg];
|
|
67
|
+
}
|
|
68
|
+
if (!current) return false;
|
|
69
|
+
}
|
|
70
|
+
const last = segments[segments.length - 1];
|
|
71
|
+
if (typeof last !== "string") return false;
|
|
72
|
+
return Array.isArray(current?.required) && current.required.includes(last);
|
|
34
73
|
}
|
|
35
74
|
|
|
36
75
|
/**
|
|
@@ -105,7 +144,9 @@ export function useProjection(
|
|
|
105
144
|
| undefined;
|
|
106
145
|
|
|
107
146
|
if (!projection) {
|
|
108
|
-
const label = computed(() =>
|
|
147
|
+
const label = computed(() =>
|
|
148
|
+
resolveLabel(control.value, undefined, control.value.required),
|
|
149
|
+
);
|
|
109
150
|
return {
|
|
110
151
|
projectedData: computed(() => control.value.data),
|
|
111
152
|
projectedSchema: computed(() => control.value.schema),
|
|
@@ -139,8 +180,16 @@ export function useProjection(
|
|
|
139
180
|
getProjectedSchema(control.value.schema, projection),
|
|
140
181
|
);
|
|
141
182
|
|
|
183
|
+
const projectedRequired = computed(() =>
|
|
184
|
+
isProjectedFieldRequired(control.value.schema, projection),
|
|
185
|
+
);
|
|
186
|
+
|
|
142
187
|
const label = computed(() =>
|
|
143
|
-
resolveLabel(
|
|
188
|
+
resolveLabel(
|
|
189
|
+
control.value,
|
|
190
|
+
projectedSchema.value?.title,
|
|
191
|
+
projectedRequired.value,
|
|
192
|
+
),
|
|
144
193
|
);
|
|
145
194
|
|
|
146
195
|
const projectedErrors = computed(() => {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "vue";
|
|
11
11
|
import { cache as globalCache } from "../../core/cache";
|
|
12
12
|
import { registry as globalRegistry } from "../../core/registry";
|
|
13
|
+
import { renderObj } from "../../core/templating";
|
|
13
14
|
import type {
|
|
14
15
|
AuthConfig,
|
|
15
16
|
ProviderBinding,
|
|
@@ -25,8 +26,11 @@ export function useProvider(
|
|
|
25
26
|
ctxBits: {
|
|
26
27
|
data: unknown | Ref<unknown> | ComputedRef<unknown>;
|
|
27
28
|
path: string;
|
|
28
|
-
dependsOnValues?: unknown[]
|
|
29
|
-
uiQuery?:
|
|
29
|
+
dependsOnValues?: unknown[] | Ref<unknown[]> | ComputedRef<unknown[]>;
|
|
30
|
+
uiQuery?:
|
|
31
|
+
| string
|
|
32
|
+
| Ref<string | undefined>
|
|
33
|
+
| ComputedRef<string | undefined>;
|
|
30
34
|
},
|
|
31
35
|
) {
|
|
32
36
|
const registry = inject("providerRegistry", globalRegistry);
|
|
@@ -41,14 +45,27 @@ export function useProvider(
|
|
|
41
45
|
const error = ref<string | undefined>(undefined);
|
|
42
46
|
const ac = new AbortController();
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
48
|
+
// Cache key keys on the *rendered* binding config (with template variables
|
|
49
|
+
// substituted) plus dependsOnValues + uiQuery. This means:
|
|
50
|
+
// - `{{data.country}}` in the URL → cache key changes when country changes,
|
|
51
|
+
// auto-refetching without callers having to declare dependsOn.
|
|
52
|
+
// - Unrelated form fields → rendered URL is unchanged → no refetch.
|
|
53
|
+
// The protocol's resolve() still receives the raw config and current data,
|
|
54
|
+
// so per-fetch URL rendering works as before.
|
|
55
|
+
const cacheKey = computed(() => {
|
|
56
|
+
const b = unref(binding);
|
|
57
|
+
const renderedBinding = b
|
|
58
|
+
? {
|
|
59
|
+
...b,
|
|
60
|
+
config: renderObj(b.config ?? {}, { data: unref(ctxBits.data) }),
|
|
61
|
+
}
|
|
62
|
+
: b;
|
|
63
|
+
return JSON.stringify({
|
|
64
|
+
b: renderedBinding,
|
|
65
|
+
d: unref(ctxBits.dependsOnValues) ?? [],
|
|
66
|
+
q: unref(ctxBits.uiQuery) ?? "",
|
|
67
|
+
});
|
|
68
|
+
});
|
|
52
69
|
|
|
53
70
|
async function load() {
|
|
54
71
|
const bindingValue = unref(binding);
|
|
@@ -71,7 +88,7 @@ export function useProvider(
|
|
|
71
88
|
const out = await driver.resolve(bindingValue.config ?? {}, {
|
|
72
89
|
data: unref(ctxBits.data),
|
|
73
90
|
path: ctxBits.path,
|
|
74
|
-
ui: { query: ctxBits.uiQuery },
|
|
91
|
+
ui: { query: unref(ctxBits.uiQuery) },
|
|
75
92
|
signal: ac.signal,
|
|
76
93
|
auth: resolveAuth(bindingValue.auth, auth),
|
|
77
94
|
});
|