@narrative.io/jsonforms-provider-protocols 3.0.0-beta.3 → 3.0.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 (67) hide show
  1. package/dist/core/projection.d.ts.map +1 -1
  2. package/dist/core/projection.js.map +1 -1
  3. package/dist/core/transforms.d.ts.map +1 -1
  4. package/dist/core/transforms.js +3 -1
  5. package/dist/core/transforms.js.map +1 -1
  6. package/dist/jsonforms-provider-protocols.css +2 -2
  7. package/dist/vue/components/ProviderAutocomplete.vue.d.ts.map +1 -1
  8. package/dist/vue/components/ProviderAutocomplete.vue.js +8 -5
  9. package/dist/vue/components/ProviderAutocomplete.vue.js.map +1 -1
  10. package/dist/vue/components/ProviderMultiSelect.vue.d.ts.map +1 -1
  11. package/dist/vue/components/ProviderMultiSelect.vue.js +1 -1
  12. package/dist/vue/components/ProviderMultiSelect.vue2.js +8 -5
  13. package/dist/vue/components/ProviderMultiSelect.vue2.js.map +1 -1
  14. package/dist/vue/components/ProviderSelect.vue.d.ts.map +1 -1
  15. package/dist/vue/components/ProviderSelect.vue.js +1 -1
  16. package/dist/vue/components/ProviderSelect.vue2.js +8 -5
  17. package/dist/vue/components/ProviderSelect.vue2.js.map +1 -1
  18. package/dist/vue/composables/useDerive.d.ts +1 -1
  19. package/dist/vue/composables/useDerive.d.ts.map +1 -1
  20. package/dist/vue/composables/useDerive.js +5 -1
  21. package/dist/vue/composables/useDerive.js.map +1 -1
  22. package/dist/vue/composables/useProjection.d.ts.map +1 -1
  23. package/dist/vue/composables/useProjection.js +1 -3
  24. package/dist/vue/composables/useProjection.js.map +1 -1
  25. package/dist/vue/index.d.ts.map +1 -1
  26. package/dist/vue/index.js +10 -2
  27. package/dist/vue/index.js.map +1 -1
  28. package/dist/vue/primevue/JfBoolean.vue.d.ts.map +1 -1
  29. package/dist/vue/primevue/JfBoolean.vue.js +14 -3
  30. package/dist/vue/primevue/JfBoolean.vue.js.map +1 -1
  31. package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
  32. package/dist/vue/primevue/JfEnum.vue.js +10 -5
  33. package/dist/vue/primevue/JfEnum.vue.js.map +1 -1
  34. package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
  35. package/dist/vue/primevue/JfEnumArray.vue.js +10 -5
  36. package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
  37. package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
  38. package/dist/vue/primevue/JfNumber.vue.js +11 -6
  39. package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
  40. package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
  41. package/dist/vue/primevue/JfText.vue.js +11 -6
  42. package/dist/vue/primevue/JfText.vue.js.map +1 -1
  43. package/dist/vue/primevue/JfTextArea.vue.d.ts.map +1 -1
  44. package/dist/vue/primevue/JfTextArea.vue.js +10 -5
  45. package/dist/vue/primevue/JfTextArea.vue.js.map +1 -1
  46. package/dist/vue/primevue/index.d.ts.map +1 -1
  47. package/dist/vue/primevue/index.js +93 -16
  48. package/dist/vue/primevue/index.js.map +1 -1
  49. package/dist/vue/utils/autoSelect.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/core/projection.ts +5 -5
  52. package/src/core/transforms.ts +33 -6
  53. package/src/vue/components/ProviderAutocomplete.vue +8 -5
  54. package/src/vue/components/ProviderMultiSelect.vue +12 -7
  55. package/src/vue/components/ProviderSelect.vue +9 -6
  56. package/src/vue/composables/useDerive.ts +16 -3
  57. package/src/vue/composables/useProjection.ts +6 -12
  58. package/src/vue/index.ts +10 -4
  59. package/src/vue/primevue/JfBoolean.vue +8 -3
  60. package/src/vue/primevue/JfEnum.vue +11 -8
  61. package/src/vue/primevue/JfEnumArray.vue +15 -12
  62. package/src/vue/primevue/JfNumber.vue +11 -8
  63. package/src/vue/primevue/JfText.vue +11 -8
  64. package/src/vue/primevue/JfTextArea.vue +10 -7
  65. package/src/vue/primevue/index.ts +104 -23
  66. package/src/vue/styles.css +26 -1
  67. package/src/vue/utils/autoSelect.ts +2 -2
@@ -17,13 +17,38 @@ const injectLayoutStyles = () => {
17
17
  display: flex;
18
18
  flex-direction: column;
19
19
  align-items: flex-start;
20
- gap: 1rem;
20
+ gap: 24px;
21
21
  width: 100%;
22
22
  }
23
23
 
24
24
  .vertical-layout-item {
25
25
  width: 100%;
26
26
  }
27
+
28
+ /* Form control wrapper */
29
+ .jf-control {
30
+ display: flex;
31
+ flex-direction: column;
32
+ gap: 12px;
33
+ }
34
+
35
+ /* Form control label typography */
36
+ .jf-label {
37
+ font-weight: 600;
38
+ font-size: 14px;
39
+ line-height: 14px;
40
+ color: #031553;
41
+ text-align: left;
42
+ }
43
+
44
+ /* Form control description typography */
45
+ .jf-description {
46
+ font-weight: 400;
47
+ font-size: 14px;
48
+ line-height: 14px;
49
+ color: #415290;
50
+ text-align: left;
51
+ }
27
52
  `;
28
53
  document.head.appendChild(style);
29
54
  }
@@ -64,39 +89,91 @@ function registerPrimevueRenderers(jsonformsCore) {
64
89
  {}
65
90
  );
66
91
  };
67
- const projectedSchemaMatches = (check) => (uischema, schema) => {
68
- const ui = uischema;
69
- const projection = ui?.options?.projection;
70
- if (!projection || ui?.type !== "Control" || !ui?.scope) return false;
71
- const propertySchema = resolveScopeSchema(ui.scope, schema);
72
- if (!propertySchema) return false;
73
- return check(getProjectedSchema(propertySchema, projection));
74
- };
92
+ const projectedSchemaMatches = (
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ ((check) => (uischema, schema) => {
95
+ const ui = uischema;
96
+ const projection = ui?.options?.projection;
97
+ if (!projection || ui?.type !== "Control" || !ui?.scope) return false;
98
+ const propertySchema = resolveScopeSchema(
99
+ ui.scope,
100
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
+ schema
102
+ );
103
+ if (!propertySchema) return false;
104
+ return check(getProjectedSchema(propertySchema, projection));
105
+ })
106
+ );
75
107
  const isMultilineProjection = (uischema, schema) => {
76
108
  const ui = uischema;
77
109
  return ui?.options?.multi === true && projectedSchemaMatches((s) => s?.type === "string")(uischema, schema);
78
110
  };
79
111
  const renderers = [
80
112
  // Multiline text has higher priority than regular text
81
- { tester: rankWith(PRIME + 4, or(isMultilineString, isMultilineProjection)), renderer: _sfc_main },
82
- { tester: rankWith(PRIME + 3, or(isStringControl, projectedSchemaMatches((s) => s?.type === "string"))), renderer: _sfc_main$1 },
83
113
  {
84
- tester: rankWith(PRIME + 6, or(isIntegerControl, projectedSchemaMatches((s) => s?.type === "integer"))),
114
+ tester: rankWith(PRIME + 4, or(isMultilineString, isMultilineProjection)),
115
+ renderer: _sfc_main
116
+ },
117
+ {
118
+ tester: rankWith(
119
+ PRIME + 3,
120
+ or(
121
+ isStringControl,
122
+ projectedSchemaMatches((s) => s?.type === "string")
123
+ )
124
+ ),
125
+ renderer: _sfc_main$1
126
+ },
127
+ {
128
+ tester: rankWith(
129
+ PRIME + 6,
130
+ or(
131
+ isIntegerControl,
132
+ projectedSchemaMatches((s) => s?.type === "integer")
133
+ )
134
+ ),
85
135
  renderer: _sfc_main$2
86
136
  },
87
137
  {
88
- tester: rankWith(PRIME + 4, or(isNumberControl, projectedSchemaMatches((s) => s?.type === "number"))),
138
+ tester: rankWith(
139
+ PRIME + 4,
140
+ or(
141
+ isNumberControl,
142
+ projectedSchemaMatches((s) => s?.type === "number")
143
+ )
144
+ ),
89
145
  renderer: _sfc_main$2
90
146
  },
91
147
  {
92
- tester: rankWith(PRIME + 7, or(and(isControl, schemaMatches(isScalarEnum)), and(isControl, projectedSchemaMatches(isScalarEnum)))),
148
+ tester: rankWith(
149
+ PRIME + 7,
150
+ or(
151
+ and(isControl, schemaMatches(isScalarEnum)),
152
+ and(isControl, projectedSchemaMatches(isScalarEnum))
153
+ )
154
+ ),
93
155
  renderer: _sfc_main$3
94
156
  },
95
157
  {
96
- tester: rankWith(PRIME + 8, or(and(isControl, schemaMatches(isEnumArray)), and(isControl, projectedSchemaMatches(isEnumArray)))),
158
+ tester: rankWith(
159
+ PRIME + 8,
160
+ or(
161
+ and(isControl, schemaMatches(isEnumArray)),
162
+ and(isControl, projectedSchemaMatches(isEnumArray))
163
+ )
164
+ ),
97
165
  renderer: _sfc_main$4
98
166
  },
99
- { tester: rankWith(PRIME + 3, or(isBooleanControl, projectedSchemaMatches((s) => s?.type === "boolean"))), renderer: _sfc_main$5 }
167
+ {
168
+ tester: rankWith(
169
+ PRIME + 3,
170
+ or(
171
+ isBooleanControl,
172
+ projectedSchemaMatches((s) => s?.type === "boolean")
173
+ )
174
+ ),
175
+ renderer: _sfc_main$5
176
+ }
100
177
  ];
101
178
  primevueRenderers.splice(0, primevueRenderers.length, ...renderers);
102
179
  renderersInitialized = true;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/vue/primevue/index.ts"],"sourcesContent":["import JfText from \"./JfText.vue\";\nimport JfTextArea from \"./JfTextArea.vue\";\nimport JfNumber from \"./JfNumber.vue\";\nimport JfEnum from \"./JfEnum.vue\";\nimport JfEnumArray from \"./JfEnumArray.vue\";\nimport JfBoolean from \"./JfBoolean.vue\";\nimport { getProjectedSchema } from \"../../core/projection\";\nimport { resolveScopeSchema } from \"../../core/resolveScope\";\n\n// Auto-inject layout styles\nconst injectLayoutStyles = () => {\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n if (!document.getElementById(\"jsonforms-primevue-styles\")) {\n const style = document.createElement(\"style\");\n style.id = \"jsonforms-primevue-styles\";\n style.textContent = `\n/* JSONForms PrimeVue Provider Protocols Layout Styles */\n.vertical-layout {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1rem;\n width: 100%;\n}\n\n.vertical-layout-item {\n width: 100%;\n}\n `;\n document.head.appendChild(style);\n }\n }\n};\n\n// Inject styles when this module is imported\ninjectLayoutStyles();\n\n// Track whether renderers have been registered to avoid duplicate registrations\nlet renderersInitialized = false;\n\n// Return empty renderers array initially\nexport const primevueRenderers: unknown[] = [];\n\n// Export a function that can be called by the consumer to register renderers\n// This should only be called once during application initialization\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function registerPrimevueRenderers(jsonformsCore: any): unknown[] {\n // Prevent duplicate registration which causes AJV schema recompilation\n if (renderersInitialized) {\n return primevueRenderers as unknown[];\n }\n\n const {\n rankWith,\n isStringControl,\n isNumberControl,\n isIntegerControl,\n and,\n or,\n isControl,\n schemaMatches,\n isBooleanControl,\n } = jsonformsCore;\n\n // Give PrimeVue renderers a high base rank; vanilla commonly uses small ranks (2–5)\n const PRIME = 100;\n\n // helpers for enum detection - using simple schema checks instead of JSONForms internal functions\n const isScalarEnum = (s?: object) => {\n const schema = s as {\n type?: string;\n enum?: unknown[];\n oneOf?: unknown[];\n };\n return (\n schema &&\n schema.type !== \"array\" &&\n (Array.isArray(schema.enum) || Array.isArray(schema.oneOf))\n );\n };\n\n const isEnumArray = (s?: object) => {\n const schema = s as {\n type?: string;\n items?: { enum?: unknown[]; oneOf?: unknown[] };\n };\n return (\n schema?.type === \"array\" &&\n (Array.isArray(schema.items?.enum) || Array.isArray(schema.items?.oneOf))\n );\n };\n\n // helper for multiline detection\n const isMultilineString = (uischema: unknown, schema: unknown) => {\n const controlUischema = uischema as { options?: { multi?: boolean } };\n return and(isStringControl, () => controlUischema?.options?.multi === true)(\n uischema as Parameters<typeof isStringControl>[0],\n schema as Parameters<typeof isStringControl>[1],\n {} as Parameters<typeof isStringControl>[2],\n );\n };\n\n // Projection-aware schema check: when options.projection is set,\n // resolve the projected schema and test against it instead of the original\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const projectedSchemaMatches = (check: (schema: any) => boolean) =>\n (uischema: unknown, schema: unknown): boolean => {\n const ui = uischema as { type?: string; scope?: string; options?: { projection?: string } };\n const projection = ui?.options?.projection;\n if (!projection || ui?.type !== \"Control\" || !ui?.scope) return false;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const propertySchema = resolveScopeSchema(ui.scope, schema as Record<string, any>);\n if (!propertySchema) return false;\n\n return check(getProjectedSchema(propertySchema, projection));\n };\n\n const isMultilineProjection = (uischema: unknown, schema: unknown) => {\n const ui = uischema as { options?: { multi?: boolean } };\n return ui?.options?.multi === true &&\n projectedSchemaMatches((s) => s?.type === \"string\")(uischema, schema);\n };\n\n const renderers = [\n // Multiline text has higher priority than regular text\n { tester: rankWith(PRIME + 4, or(isMultilineString, isMultilineProjection)), renderer: JfTextArea },\n { tester: rankWith(PRIME + 3, or(isStringControl, projectedSchemaMatches((s) => s?.type === \"string\"))), renderer: JfText },\n {\n tester: rankWith(PRIME + 6, or(isIntegerControl, projectedSchemaMatches((s) => s?.type === \"integer\"))),\n renderer: JfNumber,\n },\n {\n tester: rankWith(PRIME + 4, or(isNumberControl, projectedSchemaMatches((s) => s?.type === \"number\"))),\n renderer: JfNumber,\n },\n {\n tester: rankWith(PRIME + 7, or(and(isControl, schemaMatches(isScalarEnum)), and(isControl, projectedSchemaMatches(isScalarEnum)))),\n renderer: JfEnum,\n },\n {\n tester: rankWith(PRIME + 8, or(and(isControl, schemaMatches(isEnumArray)), and(isControl, projectedSchemaMatches(isEnumArray)))),\n renderer: JfEnumArray,\n },\n { tester: rankWith(PRIME + 3, or(isBooleanControl, projectedSchemaMatches((s) => s?.type === \"boolean\"))), renderer: JfBoolean },\n ];\n\n // Update the exported array\n primevueRenderers.splice(0, primevueRenderers.length, ...renderers);\n\n // Mark as initialized to prevent duplicate registrations\n renderersInitialized = true;\n\n return renderers;\n}\n\nexport { JfText, JfTextArea, JfNumber, JfEnum, JfEnumArray, JfBoolean };\n"],"names":["JfTextArea","JfText","JfNumber","JfEnum","JfEnumArray","JfBoolean"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/vue/primevue/index.ts"],"sourcesContent":["import JfText from \"./JfText.vue\";\nimport JfTextArea from \"./JfTextArea.vue\";\nimport JfNumber from \"./JfNumber.vue\";\nimport JfEnum from \"./JfEnum.vue\";\nimport JfEnumArray from \"./JfEnumArray.vue\";\nimport JfBoolean from \"./JfBoolean.vue\";\nimport { getProjectedSchema } from \"../../core/projection\";\nimport { resolveScopeSchema } from \"../../core/resolveScope\";\n\n// Auto-inject layout styles\nconst injectLayoutStyles = () => {\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n if (!document.getElementById(\"jsonforms-primevue-styles\")) {\n const style = document.createElement(\"style\");\n style.id = \"jsonforms-primevue-styles\";\n style.textContent = `\n/* JSONForms PrimeVue Provider Protocols Layout Styles */\n.vertical-layout {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 24px;\n width: 100%;\n}\n\n.vertical-layout-item {\n width: 100%;\n}\n\n/* Form control wrapper */\n.jf-control {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n/* Form control label typography */\n.jf-label {\n font-weight: 600;\n font-size: 14px;\n line-height: 14px;\n color: #031553;\n text-align: left;\n}\n\n/* Form control description typography */\n.jf-description {\n font-weight: 400;\n font-size: 14px;\n line-height: 14px;\n color: #415290;\n text-align: left;\n}\n `;\n document.head.appendChild(style);\n }\n }\n};\n\n// Inject styles when this module is imported\ninjectLayoutStyles();\n\n// Track whether renderers have been registered to avoid duplicate registrations\nlet renderersInitialized = false;\n\n// Return empty renderers array initially\nexport const primevueRenderers: unknown[] = [];\n\n// Export a function that can be called by the consumer to register renderers\n// This should only be called once during application initialization\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function registerPrimevueRenderers(jsonformsCore: any): unknown[] {\n // Prevent duplicate registration which causes AJV schema recompilation\n if (renderersInitialized) {\n return primevueRenderers as unknown[];\n }\n\n const {\n rankWith,\n isStringControl,\n isNumberControl,\n isIntegerControl,\n and,\n or,\n isControl,\n schemaMatches,\n isBooleanControl,\n } = jsonformsCore;\n\n // Give PrimeVue renderers a high base rank; vanilla commonly uses small ranks (2–5)\n const PRIME = 100;\n\n // helpers for enum detection - using simple schema checks instead of JSONForms internal functions\n const isScalarEnum = (s?: object) => {\n const schema = s as {\n type?: string;\n enum?: unknown[];\n oneOf?: unknown[];\n };\n return (\n schema &&\n schema.type !== \"array\" &&\n (Array.isArray(schema.enum) || Array.isArray(schema.oneOf))\n );\n };\n\n const isEnumArray = (s?: object) => {\n const schema = s as {\n type?: string;\n items?: { enum?: unknown[]; oneOf?: unknown[] };\n };\n return (\n schema?.type === \"array\" &&\n (Array.isArray(schema.items?.enum) || Array.isArray(schema.items?.oneOf))\n );\n };\n\n // helper for multiline detection\n const isMultilineString = (uischema: unknown, schema: unknown) => {\n const controlUischema = uischema as { options?: { multi?: boolean } };\n return and(isStringControl, () => controlUischema?.options?.multi === true)(\n uischema as Parameters<typeof isStringControl>[0],\n schema as Parameters<typeof isStringControl>[1],\n {} as Parameters<typeof isStringControl>[2],\n );\n };\n\n // Projection-aware schema check: when options.projection is set,\n // resolve the projected schema and test against it instead of the original\n\n const projectedSchemaMatches =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (check: (schema: any) => boolean) =>\n (uischema: unknown, schema: unknown): boolean => {\n const ui = uischema as {\n type?: string;\n scope?: string;\n options?: { projection?: string };\n };\n const projection = ui?.options?.projection;\n if (!projection || ui?.type !== \"Control\" || !ui?.scope) return false;\n\n const propertySchema = resolveScopeSchema(\n ui.scope,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema as Record<string, any>,\n );\n if (!propertySchema) return false;\n\n return check(getProjectedSchema(propertySchema, projection));\n };\n\n const isMultilineProjection = (uischema: unknown, schema: unknown) => {\n const ui = uischema as { options?: { multi?: boolean } };\n return (\n ui?.options?.multi === true &&\n projectedSchemaMatches((s) => s?.type === \"string\")(uischema, schema)\n );\n };\n\n const renderers = [\n // Multiline text has higher priority than regular text\n {\n tester: rankWith(PRIME + 4, or(isMultilineString, isMultilineProjection)),\n renderer: JfTextArea,\n },\n {\n tester: rankWith(\n PRIME + 3,\n or(\n isStringControl,\n projectedSchemaMatches((s) => s?.type === \"string\"),\n ),\n ),\n renderer: JfText,\n },\n {\n tester: rankWith(\n PRIME + 6,\n or(\n isIntegerControl,\n projectedSchemaMatches((s) => s?.type === \"integer\"),\n ),\n ),\n renderer: JfNumber,\n },\n {\n tester: rankWith(\n PRIME + 4,\n or(\n isNumberControl,\n projectedSchemaMatches((s) => s?.type === \"number\"),\n ),\n ),\n renderer: JfNumber,\n },\n {\n tester: rankWith(\n PRIME + 7,\n or(\n and(isControl, schemaMatches(isScalarEnum)),\n and(isControl, projectedSchemaMatches(isScalarEnum)),\n ),\n ),\n renderer: JfEnum,\n },\n {\n tester: rankWith(\n PRIME + 8,\n or(\n and(isControl, schemaMatches(isEnumArray)),\n and(isControl, projectedSchemaMatches(isEnumArray)),\n ),\n ),\n renderer: JfEnumArray,\n },\n {\n tester: rankWith(\n PRIME + 3,\n or(\n isBooleanControl,\n projectedSchemaMatches((s) => s?.type === \"boolean\"),\n ),\n ),\n renderer: JfBoolean,\n },\n ];\n\n // Update the exported array\n primevueRenderers.splice(0, primevueRenderers.length, ...renderers);\n\n // Mark as initialized to prevent duplicate registrations\n renderersInitialized = true;\n\n return renderers;\n}\n\nexport { JfText, JfTextArea, JfNumber, JfEnum, JfEnumArray, JfBoolean };\n"],"names":["JfTextArea","JfText","JfNumber","JfEnum","JfEnumArray","JfBoolean"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"autoSelect.js","sources":["../../../src/vue/utils/autoSelect.ts"],"sourcesContent":["import type { ProviderItem } from \"../../core/types\";\n\nexport interface AutoSelectParams {\n autoSelectSingle: boolean;\n isLoading: boolean;\n items: ProviderItem[];\n currentValue: unknown;\n}\n\n/**\n * Determines if auto-select should trigger for single-select dropdowns.\n * Returns null if auto-select should not trigger.\n *\n * Auto-select triggers when:\n * - autoSelectSingle option is enabled (default: true for single-select)\n * - Provider has finished loading\n * - Exactly one item is available\n * - Current value is empty (undefined/null) OR not in the current options\n */\nexport function shouldAutoSelect(params: AutoSelectParams): unknown | null {\n const { autoSelectSingle, isLoading, items, currentValue } = params;\n\n if (!autoSelectSingle || isLoading || items.length !== 1) {\n return null;\n }\n\n const singleItem = items[0];\n if (!singleItem) {\n return null;\n }\n\n const isValueEmpty = currentValue === undefined || currentValue === null;\n const isValueInOptions = items.some((item) => item.value === currentValue);\n\n if (isValueEmpty || !isValueInOptions) {\n return singleItem.value;\n }\n\n return null;\n}\n\nexport interface AutoSelectMultiParams {\n autoSelectSingle: boolean;\n isLoading: boolean;\n items: ProviderItem[];\n currentValue: unknown[];\n}\n\n/**\n * Determines if auto-select should trigger for multiselect dropdowns.\n * Returns null if auto-select should not trigger, otherwise returns an array with the single value.\n *\n * Auto-select triggers when:\n * - autoSelectSingle option is explicitly enabled (default: false for multiselect)\n * - Provider has finished loading\n * - Exactly one item is available\n * - Current value is empty array OR current selection is not in the current options\n */\nexport function shouldAutoSelectMulti(\n params: AutoSelectMultiParams\n): unknown[] | null {\n const { autoSelectSingle, isLoading, items, currentValue } = params;\n\n if (!autoSelectSingle || isLoading || items.length !== 1) {\n return null;\n }\n\n const singleItem = items[0];\n if (!singleItem) {\n return null;\n }\n\n const currentArray = Array.isArray(currentValue) ? currentValue : [];\n const isValueEmpty = currentArray.length === 0;\n const hasValidSelection = currentArray.some((val) =>\n items.some((item) => item.value === val)\n );\n\n if (isValueEmpty || !hasValidSelection) {\n return [singleItem.value];\n }\n\n return null;\n}\n"],"names":[],"mappings":"AAmBO,SAAS,iBAAiB,QAA0C;AACzE,QAAM,EAAE,kBAAkB,WAAW,OAAO,iBAAiB;AAE7D,MAAI,CAAC,oBAAoB,aAAa,MAAM,WAAW,GAAG;AACxD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,CAAC;AAC1B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,iBAAiB,UAAa,iBAAiB;AACpE,QAAM,mBAAmB,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,YAAY;AAEzE,MAAI,gBAAgB,CAAC,kBAAkB;AACrC,WAAO,WAAW;AAAA,EACpB;AAEA,SAAO;AACT;AAmBO,SAAS,sBACd,QACkB;AAClB,QAAM,EAAE,kBAAkB,WAAW,OAAO,iBAAiB;AAE7D,MAAI,CAAC,oBAAoB,aAAa,MAAM,WAAW,GAAG;AACxD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,CAAC;AAC1B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,MAAM,QAAQ,YAAY,IAAI,eAAe,CAAA;AAClE,QAAM,eAAe,aAAa,WAAW;AAC7C,QAAM,oBAAoB,aAAa;AAAA,IAAK,CAAC,QAC3C,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,GAAG;AAAA,EAAA;AAGzC,MAAI,gBAAgB,CAAC,mBAAmB;AACtC,WAAO,CAAC,WAAW,KAAK;AAAA,EAC1B;AAEA,SAAO;AACT;"}
1
+ {"version":3,"file":"autoSelect.js","sources":["../../../src/vue/utils/autoSelect.ts"],"sourcesContent":["import type { ProviderItem } from \"../../core/types\";\n\nexport interface AutoSelectParams {\n autoSelectSingle: boolean;\n isLoading: boolean;\n items: ProviderItem[];\n currentValue: unknown;\n}\n\n/**\n * Determines if auto-select should trigger for single-select dropdowns.\n * Returns null if auto-select should not trigger.\n *\n * Auto-select triggers when:\n * - autoSelectSingle option is enabled (default: true for single-select)\n * - Provider has finished loading\n * - Exactly one item is available\n * - Current value is empty (undefined/null) OR not in the current options\n */\nexport function shouldAutoSelect(params: AutoSelectParams): unknown | null {\n const { autoSelectSingle, isLoading, items, currentValue } = params;\n\n if (!autoSelectSingle || isLoading || items.length !== 1) {\n return null;\n }\n\n const singleItem = items[0];\n if (!singleItem) {\n return null;\n }\n\n const isValueEmpty = currentValue === undefined || currentValue === null;\n const isValueInOptions = items.some((item) => item.value === currentValue);\n\n if (isValueEmpty || !isValueInOptions) {\n return singleItem.value;\n }\n\n return null;\n}\n\nexport interface AutoSelectMultiParams {\n autoSelectSingle: boolean;\n isLoading: boolean;\n items: ProviderItem[];\n currentValue: unknown[];\n}\n\n/**\n * Determines if auto-select should trigger for multiselect dropdowns.\n * Returns null if auto-select should not trigger, otherwise returns an array with the single value.\n *\n * Auto-select triggers when:\n * - autoSelectSingle option is explicitly enabled (default: false for multiselect)\n * - Provider has finished loading\n * - Exactly one item is available\n * - Current value is empty array OR current selection is not in the current options\n */\nexport function shouldAutoSelectMulti(\n params: AutoSelectMultiParams,\n): unknown[] | null {\n const { autoSelectSingle, isLoading, items, currentValue } = params;\n\n if (!autoSelectSingle || isLoading || items.length !== 1) {\n return null;\n }\n\n const singleItem = items[0];\n if (!singleItem) {\n return null;\n }\n\n const currentArray = Array.isArray(currentValue) ? currentValue : [];\n const isValueEmpty = currentArray.length === 0;\n const hasValidSelection = currentArray.some((val) =>\n items.some((item) => item.value === val),\n );\n\n if (isValueEmpty || !hasValidSelection) {\n return [singleItem.value];\n }\n\n return null;\n}\n"],"names":[],"mappings":"AAmBO,SAAS,iBAAiB,QAA0C;AACzE,QAAM,EAAE,kBAAkB,WAAW,OAAO,iBAAiB;AAE7D,MAAI,CAAC,oBAAoB,aAAa,MAAM,WAAW,GAAG;AACxD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,CAAC;AAC1B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,iBAAiB,UAAa,iBAAiB;AACpE,QAAM,mBAAmB,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,YAAY;AAEzE,MAAI,gBAAgB,CAAC,kBAAkB;AACrC,WAAO,WAAW;AAAA,EACpB;AAEA,SAAO;AACT;AAmBO,SAAS,sBACd,QACkB;AAClB,QAAM,EAAE,kBAAkB,WAAW,OAAO,iBAAiB;AAE7D,MAAI,CAAC,oBAAoB,aAAa,MAAM,WAAW,GAAG;AACxD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,CAAC;AAC1B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,MAAM,QAAQ,YAAY,IAAI,eAAe,CAAA;AAClE,QAAM,eAAe,aAAa,WAAW;AAC7C,QAAM,oBAAoB,aAAa;AAAA,IAAK,CAAC,QAC3C,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,GAAG;AAAA,EAAA;AAGzC,MAAI,gBAAgB,CAAC,mBAAmB;AACtC,WAAO,CAAC,WAAW,KAAK;AAAA,EAC1B;AAEA,SAAO;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narrative.io/jsonforms-provider-protocols",
3
- "version": "3.0.0-beta.3",
3
+ "version": "3.0.0-beta.4",
4
4
  "description": "Dynamic data provider capabilities for JSONForms with Vue 3 integration",
5
5
  "type": "module",
6
6
  "author": "Narrative I/O",
@@ -26,10 +26,7 @@ export function parseProjectionPath(path: string): ProjectionSegment[] {
26
26
  * Read a value from `data` by following the projection path.
27
27
  * Returns `undefined` if any segment along the path is missing.
28
28
  */
29
- export function getProjectedValue(
30
- data: unknown,
31
- path: string,
32
- ): unknown {
29
+ export function getProjectedValue(data: unknown, path: string): unknown {
33
30
  const segments = parseProjectionPath(path);
34
31
  let current: unknown = data;
35
32
 
@@ -85,7 +82,10 @@ function setAtPath(
85
82
  } else {
86
83
  // Object key — ensure we have an object
87
84
  const obj: Record<string, unknown> =
88
- current !== null && current !== undefined && typeof current === "object" && !Array.isArray(current)
85
+ current !== null &&
86
+ current !== undefined &&
87
+ typeof current === "object" &&
88
+ !Array.isArray(current)
89
89
  ? { ...(current as Record<string, unknown>) }
90
90
  : {};
91
91
  obj[seg] = setAtPath(obj[seg], segments, index + 1, value);
@@ -14,7 +14,16 @@ export interface FlattenTransform extends Transform {
14
14
  labelFormat?: string; // Optional format string like "{parent.name} → {name}"
15
15
  }
16
16
 
17
- export type FilterOperator = "eq" | "neq" | "empty" | "notEmpty" | "gt" | "gte" | "lt" | "lte" | "contains";
17
+ export type FilterOperator =
18
+ | "eq"
19
+ | "neq"
20
+ | "empty"
21
+ | "notEmpty"
22
+ | "gt"
23
+ | "gte"
24
+ | "lt"
25
+ | "lte"
26
+ | "contains";
18
27
 
19
28
  export interface FilterCondition {
20
29
  key: string;
@@ -153,13 +162,29 @@ function evaluateCondition(
153
162
  case "notEmpty":
154
163
  return !isEmpty(value);
155
164
  case "gt":
156
- return typeof value === "number" && condition.values !== undefined && value > (condition.values[0] as number);
165
+ return (
166
+ typeof value === "number" &&
167
+ condition.values !== undefined &&
168
+ value > (condition.values[0] as number)
169
+ );
157
170
  case "gte":
158
- return typeof value === "number" && condition.values !== undefined && value >= (condition.values[0] as number);
171
+ return (
172
+ typeof value === "number" &&
173
+ condition.values !== undefined &&
174
+ value >= (condition.values[0] as number)
175
+ );
159
176
  case "lt":
160
- return typeof value === "number" && condition.values !== undefined && value < (condition.values[0] as number);
177
+ return (
178
+ typeof value === "number" &&
179
+ condition.values !== undefined &&
180
+ value < (condition.values[0] as number)
181
+ );
161
182
  case "lte":
162
- return typeof value === "number" && condition.values !== undefined && value <= (condition.values[0] as number);
183
+ return (
184
+ typeof value === "number" &&
185
+ condition.values !== undefined &&
186
+ value <= (condition.values[0] as number)
187
+ );
163
188
  case "contains":
164
189
  if (typeof value === "string" && condition.values) {
165
190
  return condition.values.some((v) => value.includes(String(v)));
@@ -208,7 +233,9 @@ function filterTransform(items: unknown[], config: Transform): unknown[] {
208
233
  return items.filter((item) => {
209
234
  if (typeof item !== "object" || item === null) return false;
210
235
  const itemObj = item as Record<string, unknown>;
211
- return conditions.every((condition) => evaluateCondition(itemObj, condition));
236
+ return conditions.every((condition) =>
237
+ evaluateCondition(itemObj, condition),
238
+ );
212
239
  });
213
240
  }
214
241
 
@@ -12,7 +12,10 @@ const props = defineProps<{
12
12
  path: string;
13
13
  }>();
14
14
  const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
15
- const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
15
+ const { projectedData, handleProjectedChange: handleChange } = useProjection(
16
+ control,
17
+ rawHandleChange,
18
+ );
16
19
 
17
20
  const binding = computed(() => {
18
21
  const provider = control.value.uischema?.options?.provider;
@@ -53,16 +56,16 @@ const onSelect = (event: { value?: { value?: unknown } | unknown }) => {
53
56
  </script>
54
57
 
55
58
  <template>
56
- <div class="flex flex-column gap-1">
57
- <label v-if="control.schema.title" class="text-color text-left">{{
59
+ <div class="jf-control">
60
+ <label v-if="control.schema.title" class="jf-label">{{
58
61
  control.schema.title
59
62
  }}</label>
60
- <div v-if="control.description" class="text-color-secondary text-left">
63
+ <div v-if="control.description" class="jf-description">
61
64
  {{ control.description }}
62
65
  </div>
63
66
  <AutoComplete
64
67
  v-model="value"
65
- class="w-full"
68
+ class="w-full!"
66
69
  :suggestions="items"
67
70
  option-label="label"
68
71
  :placeholder="placeholder"
@@ -13,7 +13,10 @@ const props = defineProps<{
13
13
  path: string;
14
14
  }>();
15
15
  const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
16
- const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
16
+ const { projectedData, handleProjectedChange: handleChange } = useProjection(
17
+ control,
18
+ rawHandleChange,
19
+ );
17
20
 
18
21
  const binding = computed(() => {
19
22
  const provider = control.value.uischema?.options?.provider;
@@ -55,14 +58,16 @@ watch(
55
58
  control.value.uischema?.options?.autoSelectSingle === true,
56
59
  isLoading,
57
60
  items: newItems,
58
- currentValue: Array.isArray(projectedData.value) ? projectedData.value : [],
61
+ currentValue: Array.isArray(projectedData.value)
62
+ ? projectedData.value
63
+ : [],
59
64
  });
60
65
 
61
66
  if (valueToSelect !== null) {
62
67
  handleChange(control.value.path, valueToSelect);
63
68
  }
64
69
  },
65
- { immediate: true }
70
+ { immediate: true },
66
71
  );
67
72
 
68
73
  // order-insensitive shallow equality for primitive arrays
@@ -98,16 +103,16 @@ const placeholder = computed(() => {
98
103
  </script>
99
104
 
100
105
  <template>
101
- <div class="flex flex-column gap-2">
102
- <label v-if="control.schema.title" class="text-color text-left">{{
106
+ <div class="jf-control">
107
+ <label v-if="control.schema.title" class="jf-label">{{
103
108
  control.schema.title
104
109
  }}</label>
105
- <div v-if="control.description" class="text-color-secondary text-left">
110
+ <div v-if="control.description" class="jf-description">
106
111
  {{ control.description }}
107
112
  </div>
108
113
  <MultiSelect
109
114
  v-model="value"
110
- class="w-full"
115
+ class="w-full!"
111
116
  :options="items"
112
117
  option-label="label"
113
118
  option-value="value"
@@ -13,7 +13,10 @@ const props = defineProps<{
13
13
  path: string;
14
14
  }>();
15
15
  const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
16
- const { projectedData, handleProjectedChange: handleChange } = useProjection(control, rawHandleChange);
16
+ const { projectedData, handleProjectedChange: handleChange } = useProjection(
17
+ control,
18
+ rawHandleChange,
19
+ );
17
20
 
18
21
  const binding = computed(() => {
19
22
  const provider = control.value.uischema?.options?.provider;
@@ -62,7 +65,7 @@ watch(
62
65
  handleChange(control.value.path, valueToSelect);
63
66
  }
64
67
  },
65
- { immediate: true }
68
+ { immediate: true },
66
69
  );
67
70
 
68
71
  const value = computed({
@@ -81,16 +84,16 @@ const placeholder = computed(() => {
81
84
  </script>
82
85
 
83
86
  <template>
84
- <div class="flex flex-column gap-2">
85
- <label v-if="control.schema.title" class="text-color text-left">{{
87
+ <div class="jf-control">
88
+ <label v-if="control.schema.title" class="jf-label">{{
86
89
  control.schema.title
87
90
  }}</label>
88
- <div v-if="control.description" class="text-color-secondary text-left">
91
+ <div v-if="control.description" class="jf-description">
89
92
  {{ control.description }}
90
93
  </div>
91
94
  <Dropdown
92
95
  v-model="value"
93
- class="w-full"
96
+ class="w-full!"
94
97
  :options="items"
95
98
  option-label="label"
96
99
  option-value="value"
@@ -1,4 +1,11 @@
1
- import { computed, watch, unref, inject, type Ref, type ComputedRef } from "vue";
1
+ import {
2
+ computed,
3
+ watch,
4
+ unref,
5
+ inject,
6
+ type Ref,
7
+ type ComputedRef,
8
+ } from "vue";
2
9
  import { type ControlElement } from "@jsonforms/core";
3
10
  import { useDataLayer } from "./useDataLayer";
4
11
 
@@ -14,7 +21,11 @@ interface DeriveOptions {
14
21
  data?: Ref<unknown> | ComputedRef<unknown>;
15
22
  }
16
23
 
17
- export function useDerive({ control, handleChange, data: dataOverride }: DeriveOptions) {
24
+ export function useDerive({
25
+ control,
26
+ handleChange,
27
+ data: dataOverride,
28
+ }: DeriveOptions) {
18
29
  // Get the root form data from JSONForms context
19
30
  const injectedFormData = inject<{ value: unknown }>("formData", {
20
31
  value: {},
@@ -50,7 +61,9 @@ export function useDerive({ control, handleChange, data: dataOverride }: DeriveO
50
61
  data,
51
62
  extData,
52
63
  );
53
- const compareData = dataOverride ? unref(dataOverride) : control.value.data;
64
+ const compareData = dataOverride
65
+ ? unref(dataOverride)
66
+ : control.value.data;
54
67
  if (derivedValue !== compareData) {
55
68
  handleChange(control.value.path, derivedValue);
56
69
  }
@@ -27,15 +27,9 @@ interface ErrorLike {
27
27
  * Resolve the display label for a control.
28
28
  * Priority: uischema options.label → schemaTitle (projected sub-schema) → control.label.
29
29
  */
30
- function resolveLabel(
31
- ctrl: ProjectionControl,
32
- schemaTitle?: string,
33
- ): string {
30
+ function resolveLabel(ctrl: ProjectionControl, schemaTitle?: string): string {
34
31
  return (
35
- (ctrl.uischema?.options?.label as string) ??
36
- schemaTitle ??
37
- ctrl.label ??
38
- ""
32
+ (ctrl.uischema?.options?.label as string) ?? schemaTitle ?? ctrl.label ?? ""
39
33
  );
40
34
  }
41
35
 
@@ -69,7 +63,9 @@ function prefixErrors(label: string, errors: string): string {
69
63
  function getErrorPath(error: ErrorLike): string {
70
64
  let p = (error.instancePath || "").replace(/\//g, ".").replace(/^\./, "");
71
65
  if (error.keyword === "required" && error.params?.missingProperty) {
72
- p = p ? p + "." + error.params.missingProperty : error.params.missingProperty;
66
+ p = p
67
+ ? p + "." + error.params.missingProperty
68
+ : error.params.missingProperty;
73
69
  }
74
70
  return p;
75
71
  }
@@ -160,9 +156,7 @@ export function useProjection(
160
156
  errStr = baseErrors;
161
157
  } else {
162
158
  const projMsg = matching
163
- .map((e) =>
164
- e.keyword === "required" ? "is required" : e.message,
165
- )
159
+ .map((e) => (e.keyword === "required" ? "is required" : e.message))
166
160
  .filter(Boolean)
167
161
  .join("\n");
168
162
  errStr = [baseErrors, projMsg].filter(Boolean).join("\n");
package/src/vue/index.ts CHANGED
@@ -22,8 +22,11 @@ const isIntegerScope = (uischema: unknown, schema: unknown) => {
22
22
  const ui = uischema as { type?: string; scope?: string };
23
23
  if (ui?.type !== "Control" || !ui?.scope) return false;
24
24
 
25
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
- const propertySchema = resolveScopeSchema(ui.scope, schema as Record<string, any>);
25
+ const propertySchema = resolveScopeSchema(
26
+ ui.scope,
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ schema as Record<string, any>,
29
+ );
27
30
  return propertySchema?.type === "integer";
28
31
  };
29
32
 
@@ -53,8 +56,11 @@ const isArrayControl = (uischema: UISchemaElement, schema: unknown) => {
53
56
  return false;
54
57
  }
55
58
 
56
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
- const propertySchema = resolveScopeSchema(controlSchema.scope, schema as Record<string, any>);
59
+ const propertySchema = resolveScopeSchema(
60
+ controlSchema.scope,
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ schema as Record<string, any>,
63
+ );
58
64
  return propertySchema?.type === "array";
59
65
  };
60
66
 
@@ -49,7 +49,12 @@ import Checkbox from "primevue/checkbox";
49
49
  const instance = getCurrentInstance()!;
50
50
  const props = instance.props as unknown as ControlProps;
51
51
  const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
52
- const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
52
+ const {
53
+ projectedData,
54
+ handleProjectedChange: handleChange,
55
+ projectedErrors,
56
+ projectedLabel,
57
+ } = useProjection(control, rawHandleChange);
53
58
 
54
59
  // Track user interaction — errors only show after first toggle
55
60
  const { showErrors, markDirty } = useDirtyValidation(control, projectedErrors);
@@ -61,7 +66,7 @@ const onToggle = (val: boolean) => {
61
66
  </script>
62
67
 
63
68
  <template>
64
- <div class="flex items-center gap-2">
69
+ <div class="jf-control" style="flex-direction: row; align-items: center">
65
70
  <Checkbox
66
71
  :binary="true"
67
72
  :model-value="!!projectedData"
@@ -70,7 +75,7 @@ const onToggle = (val: boolean) => {
70
75
  :aria-invalid="showErrors || undefined"
71
76
  @update:model-value="onToggle"
72
77
  />
73
- <label v-if="projectedLabel">{{ projectedLabel }}</label>
78
+ <label v-if="projectedLabel" class="jf-label">{{ projectedLabel }}</label>
74
79
  <small v-if="showErrors" class="p-error">{{ projectedErrors }}</small>
75
80
  </div>
76
81
  </template>
@@ -54,7 +54,12 @@ import Dropdown from "primevue/dropdown";
54
54
  const instance = getCurrentInstance()!;
55
55
  const props = instance.props as unknown as ControlProps;
56
56
  const { control, handleChange: rawHandleChange } = useJsonFormsControl(props);
57
- const { projectedData, handleProjectedChange: handleChange, projectedErrors, projectedLabel } = useProjection(control, rawHandleChange);
57
+ const {
58
+ projectedData,
59
+ handleProjectedChange: handleChange,
60
+ projectedErrors,
61
+ projectedLabel,
62
+ } = useProjection(control, rawHandleChange);
58
63
 
59
64
  type Opt = { label: string; value: unknown };
60
65
  const toOptions = (schema?: JsonSchema): Opt[] => {
@@ -158,7 +163,7 @@ watch(
158
163
  handleChange(control.value.path, valueToSelect);
159
164
  }
160
165
  },
161
- { immediate: true }
166
+ { immediate: true },
162
167
  );
163
168
 
164
169
  // Track user interaction — errors only show after blur
@@ -170,15 +175,13 @@ const onSelect = (val: unknown) => {
170
175
  </script>
171
176
 
172
177
  <template>
173
- <div class="flex flex-column gap-2">
174
- <label v-if="projectedLabel" class="text-color text-left">{{
175
- projectedLabel
176
- }}</label>
177
- <div v-if="control.description" class="text-color-secondary text-left">
178
+ <div class="jf-control">
179
+ <label v-if="projectedLabel" class="jf-label">{{ projectedLabel }}</label>
180
+ <div v-if="control.description" class="jf-description">
178
181
  {{ control.description }}
179
182
  </div>
180
183
  <Dropdown
181
- :class="['w-full', { 'p-invalid': showErrors }]"
184
+ :class="['w-full!', { 'p-invalid': showErrors }]"
182
185
  :options="options"
183
186
  option-label="label"
184
187
  option-value="value"