@narrative.io/jsonforms-provider-protocols 1.1.0-beta.2 → 1.1.0-beta.4
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 +1 -1
- package/dist/vue/composables/useDerive.d.ts +13 -0
- package/dist/vue/composables/useDerive.d.ts.map +1 -0
- package/dist/vue/composables/useDerive.js +59 -0
- package/dist/vue/composables/useDerive.js.map +1 -0
- package/dist/vue/primevue/JfBoolean.vue.d.ts +1 -1
- package/dist/vue/primevue/JfEnum.vue.d.ts +1 -1
- package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfEnum.vue.js +1 -1
- package/dist/vue/primevue/JfEnum.vue2.js +67 -9
- package/dist/vue/primevue/JfEnum.vue2.js.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.d.ts +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.js +56 -8
- package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
- package/dist/vue/primevue/JfNumber.vue.d.ts +1 -1
- package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfNumber.vue.js +15 -5
- package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
- package/dist/vue/primevue/JfText.vue.d.ts +1 -1
- package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfText.vue.js +94 -11
- package/dist/vue/primevue/JfText.vue.js.map +1 -1
- package/dist/vue/primevue/JfTextArea.vue.d.ts +1 -1
- package/dist/vue/primevue/JfTextArea.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfTextArea.vue.js +12 -6
- package/dist/vue/primevue/JfTextArea.vue.js.map +1 -1
- package/dist/vue/primevue/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/vue/composables/useDerive.ts +85 -0
- package/src/vue/primevue/JfEnum.vue +88 -9
- package/src/vue/primevue/JfEnumArray.vue +76 -9
- package/src/vue/primevue/JfNumber.vue +19 -4
- package/src/vue/primevue/JfText.vue +115 -8
- package/src/vue/primevue/JfTextArea.vue +16 -5
|
@@ -1,26 +1,114 @@
|
|
|
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 } 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
|
-
|
|
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
|
-
(
|
|
15
|
-
|
|
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 });
|
|
78
|
+
|
|
79
|
+
// Track user interaction
|
|
80
|
+
const hasInteracted = ref(false);
|
|
81
|
+
const hasFocused = ref(false);
|
|
82
|
+
|
|
83
|
+
const showErrors = computed(() => hasInteracted.value && control.value.errors);
|
|
17
84
|
|
|
18
85
|
function onInput(val: string | undefined) {
|
|
19
|
-
|
|
20
|
-
|
|
86
|
+
// Convert empty strings to undefined for proper required field validation
|
|
87
|
+
const newValue = val && val.trim() !== "" ? val : undefined;
|
|
88
|
+
if (control.value.data !== newValue) {
|
|
21
89
|
handleChange(control.value.path, newValue);
|
|
22
90
|
}
|
|
23
91
|
}
|
|
92
|
+
|
|
93
|
+
function onBlur() {
|
|
94
|
+
if (hasFocused.value) {
|
|
95
|
+
hasInteracted.value = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function onFocus() {
|
|
100
|
+
hasFocused.value = true;
|
|
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
|
+
};
|
|
24
112
|
</script>
|
|
25
113
|
|
|
26
114
|
<template>
|
|
@@ -31,17 +119,36 @@ function onInput(val: string | undefined) {
|
|
|
31
119
|
<div v-if="control.description" class="text-color-secondary text-left">
|
|
32
120
|
{{ control.description }}
|
|
33
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
|
+
/>
|
|
34
137
|
<InputText
|
|
138
|
+
v-else
|
|
35
139
|
class="w-full"
|
|
36
140
|
:model-value="control.data ?? ''"
|
|
37
141
|
:disabled="!control.enabled"
|
|
38
|
-
:aria-invalid="!!
|
|
142
|
+
:aria-invalid="!!showErrors || undefined"
|
|
39
143
|
:placeholder="placeholder"
|
|
40
144
|
autocapitalize="off"
|
|
41
145
|
autocomplete="off"
|
|
42
146
|
spellcheck="false"
|
|
43
147
|
@update:model-value="onInput"
|
|
148
|
+
@blur="onBlur"
|
|
149
|
+
@focus="onFocus"
|
|
44
150
|
/>
|
|
45
|
-
<small v-if="
|
|
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>
|
|
46
153
|
</div>
|
|
47
154
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
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 } from "vue";
|
|
4
|
+
import { computed, ref } from "vue";
|
|
5
5
|
import Textarea from "primevue/textarea";
|
|
6
6
|
|
|
7
7
|
defineOptions({ name: "JfTextArea" });
|
|
@@ -15,12 +15,22 @@ const placeholder = computed<string | undefined>(
|
|
|
15
15
|
?.placeholder ?? control.value.description,
|
|
16
16
|
);
|
|
17
17
|
|
|
18
|
+
// Track user interaction
|
|
19
|
+
const hasInteracted = ref(false);
|
|
20
|
+
|
|
21
|
+
const showErrors = computed(() => hasInteracted.value && control.value.errors);
|
|
22
|
+
|
|
18
23
|
function onInput(val: string | undefined) {
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
// Convert empty strings to undefined for proper required field validation
|
|
25
|
+
const newValue = val && val.trim() !== "" ? val : undefined;
|
|
26
|
+
if (control.value.data !== newValue) {
|
|
21
27
|
handleChange(control.value.path, newValue);
|
|
22
28
|
}
|
|
23
29
|
}
|
|
30
|
+
|
|
31
|
+
function onBlur() {
|
|
32
|
+
hasInteracted.value = true;
|
|
33
|
+
}
|
|
24
34
|
</script>
|
|
25
35
|
|
|
26
36
|
<template>
|
|
@@ -35,12 +45,13 @@ function onInput(val: string | undefined) {
|
|
|
35
45
|
class="w-full"
|
|
36
46
|
:model-value="control.data ?? ''"
|
|
37
47
|
:disabled="!control.enabled"
|
|
38
|
-
:aria-invalid="!!
|
|
48
|
+
:aria-invalid="!!showErrors || undefined"
|
|
39
49
|
:placeholder="placeholder"
|
|
40
50
|
:rows="4"
|
|
41
51
|
:auto-resize="true"
|
|
42
52
|
@update:model-value="onInput"
|
|
53
|
+
@blur="onBlur"
|
|
43
54
|
/>
|
|
44
|
-
<small v-if="
|
|
55
|
+
<small v-if="showErrors" class="p-error">{{ control.errors }}</small>
|
|
45
56
|
</div>
|
|
46
57
|
</template>
|