@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.
Files changed (35) hide show
  1. package/dist/jsonforms-provider-protocols.css +1 -1
  2. package/dist/vue/composables/useDerive.d.ts +13 -0
  3. package/dist/vue/composables/useDerive.d.ts.map +1 -0
  4. package/dist/vue/composables/useDerive.js +59 -0
  5. package/dist/vue/composables/useDerive.js.map +1 -0
  6. package/dist/vue/primevue/JfBoolean.vue.d.ts +1 -1
  7. package/dist/vue/primevue/JfEnum.vue.d.ts +1 -1
  8. package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
  9. package/dist/vue/primevue/JfEnum.vue.js +1 -1
  10. package/dist/vue/primevue/JfEnum.vue2.js +67 -9
  11. package/dist/vue/primevue/JfEnum.vue2.js.map +1 -1
  12. package/dist/vue/primevue/JfEnumArray.vue.d.ts +1 -1
  13. package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
  14. package/dist/vue/primevue/JfEnumArray.vue.js +56 -8
  15. package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
  16. package/dist/vue/primevue/JfNumber.vue.d.ts +1 -1
  17. package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
  18. package/dist/vue/primevue/JfNumber.vue.js +15 -5
  19. package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
  20. package/dist/vue/primevue/JfText.vue.d.ts +1 -1
  21. package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
  22. package/dist/vue/primevue/JfText.vue.js +94 -11
  23. package/dist/vue/primevue/JfText.vue.js.map +1 -1
  24. package/dist/vue/primevue/JfTextArea.vue.d.ts +1 -1
  25. package/dist/vue/primevue/JfTextArea.vue.d.ts.map +1 -1
  26. package/dist/vue/primevue/JfTextArea.vue.js +12 -6
  27. package/dist/vue/primevue/JfTextArea.vue.js.map +1 -1
  28. package/dist/vue/primevue/index.d.ts +1 -1
  29. package/package.json +1 -1
  30. package/src/vue/composables/useDerive.ts +85 -0
  31. package/src/vue/primevue/JfEnum.vue +88 -9
  32. package/src/vue/primevue/JfEnumArray.vue +76 -9
  33. package/src/vue/primevue/JfNumber.vue +19 -4
  34. package/src/vue/primevue/JfText.vue +115 -8
  35. 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
- const placeholder = computed<string | undefined>(
15
+ // Provider support for autocomplete functionality
16
+ const binding = computed(() => {
17
+ const provider = control.value.uischema?.options?.provider;
18
+ // Ensure load property is set to 'query' by default for autocomplete
19
+ if (provider && typeof provider === "object" && !provider.load) {
20
+ return { ...provider, load: "query" };
21
+ }
22
+ return provider;
23
+ });
24
+
25
+ const deps = computed(
13
26
  () =>
14
- (control.value.uischema as { options?: { placeholder?: string } })?.options
15
- ?.placeholder ?? control.value.description,
27
+ ((
28
+ (control.value.schema as Record<string, unknown>)?.[
29
+ "x-provider"
30
+ ] as Record<string, unknown>
31
+ )?.dependsOn as string[]) ?? [],
16
32
  );
33
+ const depValues = computed(() => {
34
+ return deps.value.map((dep) => {
35
+ // Resolve dependency value from form data using JSON pointer-like path
36
+ const path = dep.startsWith("#/") ? dep.slice(2) : dep;
37
+ const keys = path.replace(/\//g, ".").split(".");
38
+ let value: unknown = rootData.value;
39
+ for (const key of keys) {
40
+ if (value && typeof value === "object" && key in value) {
41
+ value = (value as Record<string, unknown>)[key];
42
+ } else {
43
+ return null;
44
+ }
45
+ }
46
+ return value;
47
+ });
48
+ });
49
+
50
+ // Get the root form data from JSONForms context for template URL resolution
51
+ const injectedFormData = inject<{ value: unknown }>("formData", { value: {} });
52
+ const rootData = computed(() => injectedFormData.value || {});
53
+
54
+ const query = ref("");
55
+ const { items, loading, error, reload } = useProvider(binding, {
56
+ data: rootData,
57
+ path: control.value.path,
58
+ uiQuery: query.value,
59
+ dependsOnValues: depValues.value,
60
+ });
61
+
62
+ watch(query, () => {
63
+ if (binding.value?.load === "query") reload();
64
+ });
65
+
66
+ const placeholder = computed<string | undefined>(() => {
67
+ if (loading.value) return "Loading…";
68
+ return (
69
+ (control.value.uischema as { options?: { placeholder?: string } })?.options
70
+ ?.placeholder ?? control.value.description
71
+ );
72
+ });
73
+
74
+ const isAutocomplete = computed(() => !!binding.value);
75
+
76
+ // Add derive functionality
77
+ useDerive({ control, handleChange });
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
- const newValue = val ?? "";
20
- if ((control.value.data ?? "") !== newValue) {
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="!!control.errors || undefined"
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="control.errors" class="p-error">{{ control.errors }}</small>
151
+ <small v-if="error" class="p-error" role="alert">Failed: {{ error }}</small>
152
+ <small v-else-if="showErrors" class="p-error">{{ control.errors }}</small>
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
- const newValue = val ?? "";
20
- if ((control.value.data ?? "") !== newValue) {
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="!!control.errors || undefined"
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="control.errors" class="p-error">{{ control.errors }}</small>
55
+ <small v-if="showErrors" class="p-error">{{ control.errors }}</small>
45
56
  </div>
46
57
  </template>