@genesislcap/foundation-forms 14.397.2 → 14.398.0

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 (77) hide show
  1. package/dist/custom-elements.json +389 -4
  2. package/dist/dts/form.d.ts +100 -1
  3. package/dist/dts/form.d.ts.map +1 -1
  4. package/dist/dts/form.styles.d.ts.map +1 -1
  5. package/dist/dts/form.template.d.ts.map +1 -1
  6. package/dist/dts/jsonforms/json-forms.d.ts +13 -0
  7. package/dist/dts/jsonforms/json-forms.d.ts.map +1 -1
  8. package/dist/dts/jsonforms/renderers/ArrayListWrapperRenderer.d.ts +5 -0
  9. package/dist/dts/jsonforms/renderers/ArrayListWrapperRenderer.d.ts.map +1 -1
  10. package/dist/dts/jsonforms/renderers/BooleanControlRenderer.d.ts.map +1 -1
  11. package/dist/dts/jsonforms/renderers/ConnectedMultiselectControlRenderer.d.ts.map +1 -1
  12. package/dist/dts/jsonforms/renderers/ControlWrapperRenderer.d.ts.map +1 -1
  13. package/dist/dts/jsonforms/renderers/EnumControlRenderer.d.ts.map +1 -1
  14. package/dist/dts/jsonforms/renderers/LayoutFormGridRenderer.d.ts +3 -0
  15. package/dist/dts/jsonforms/renderers/LayoutFormGridRenderer.d.ts.map +1 -0
  16. package/dist/dts/jsonforms/renderers/RenderersRanks.d.ts +1 -0
  17. package/dist/dts/jsonforms/renderers/RenderersRanks.d.ts.map +1 -1
  18. package/dist/dts/jsonforms/testers/isOneOfOptionMultiselect.d.ts.map +1 -1
  19. package/dist/dts/types.d.ts +89 -2
  20. package/dist/dts/types.d.ts.map +1 -1
  21. package/dist/dts/utils/csv-parser.d.ts +85 -0
  22. package/dist/dts/utils/csv-parser.d.ts.map +1 -0
  23. package/dist/dts/utils/index.d.ts +1 -0
  24. package/dist/dts/utils/index.d.ts.map +1 -1
  25. package/dist/dts/utils/schema-utils.d.ts +46 -0
  26. package/dist/dts/utils/schema-utils.d.ts.map +1 -0
  27. package/dist/dts/utils/validation.d.ts +2 -0
  28. package/dist/dts/utils/validation.d.ts.map +1 -1
  29. package/dist/esm/form.js +423 -5
  30. package/dist/esm/form.styles.js +41 -1
  31. package/dist/esm/form.template.js +33 -1
  32. package/dist/esm/jsonforms/json-forms.js +30 -0
  33. package/dist/esm/jsonforms/renderers/ArrayListWrapperRenderer.js +223 -22
  34. package/dist/esm/jsonforms/renderers/BooleanControlRenderer.js +1 -2
  35. package/dist/esm/jsonforms/renderers/ConnectedMultiselectControlRenderer.js +13 -2
  36. package/dist/esm/jsonforms/renderers/ControlWrapperRenderer.js +25 -4
  37. package/dist/esm/jsonforms/renderers/EnumControlRenderer.js +14 -5
  38. package/dist/esm/jsonforms/renderers/LayoutFormGridRenderer.js +39 -0
  39. package/dist/esm/jsonforms/renderers/RenderersRanks.js +1 -0
  40. package/dist/esm/jsonforms/testers/isOneOfOptionMultiselect.js +1 -1
  41. package/dist/esm/utils/csv-parser.js +486 -0
  42. package/dist/esm/utils/index.js +1 -0
  43. package/dist/esm/utils/schema-utils.js +120 -0
  44. package/dist/esm/utils/validation.js +2 -0
  45. package/dist/foundation-forms.api.json +1028 -34
  46. package/dist/foundation-forms.d.ts +285 -2
  47. package/docs/api/foundation-forms.arrayrendereroptions.md +2 -2
  48. package/docs/api/foundation-forms.bulkrowstatus.md +22 -0
  49. package/docs/api/foundation-forms.bulkrowsubmitstatus.md +13 -0
  50. package/docs/api/foundation-forms.bulksubmitfaileditem.md +20 -0
  51. package/docs/api/foundation-forms.bulksubmitresult.md +18 -0
  52. package/docs/api/foundation-forms.bulksubmitsuccessitem.md +17 -0
  53. package/docs/api/foundation-forms.childuischemaresolver.md +15 -0
  54. package/docs/api/foundation-forms.csvmappingresult.mappedrows.md +13 -0
  55. package/docs/api/foundation-forms.csvmappingresult.md +77 -0
  56. package/docs/api/foundation-forms.csvmappingresult.unmappedcolumns.md +13 -0
  57. package/docs/api/foundation-forms.csvparseresult.errors.md +13 -0
  58. package/docs/api/foundation-forms.csvparseresult.headers.md +13 -0
  59. package/docs/api/foundation-forms.csvparseresult.md +96 -0
  60. package/docs/api/foundation-forms.csvparseresult.rows.md +13 -0
  61. package/docs/api/foundation-forms.downloadcsvtemplate.md +74 -0
  62. package/docs/api/foundation-forms.form.bulkinsert.md +13 -0
  63. package/docs/api/foundation-forms.form.bulkinsertmaxitems.md +13 -0
  64. package/docs/api/foundation-forms.form.bulkinsertminitems.md +13 -0
  65. package/docs/api/foundation-forms.form.clearrowsubmitstatuses.md +17 -0
  66. package/docs/api/foundation-forms.form.downloadcsvtemplate.md +17 -0
  67. package/docs/api/foundation-forms.form.handlecsvfileselected.md +54 -0
  68. package/docs/api/foundation-forms.form.md +132 -0
  69. package/docs/api/foundation-forms.form.rowsubmitstatuses.md +13 -0
  70. package/docs/api/foundation-forms.form.submitsinglerow.md +56 -0
  71. package/docs/api/foundation-forms.generatecsvtemplate.md +104 -0
  72. package/docs/api/foundation-forms.mapcsvtoschema.md +88 -0
  73. package/docs/api/foundation-forms.md +147 -0
  74. package/docs/api/foundation-forms.parsecsv.md +56 -0
  75. package/docs/api/foundation-forms.uischemaelementtype.md +1 -1
  76. package/docs/api-report.md.api.md +87 -4
  77. package/package.json +19 -17
@@ -30,6 +30,16 @@ let JSONForms = class JSONForms extends FASTElement {
30
30
  constructor() {
31
31
  super(...arguments);
32
32
  this.ajv = createAjv({ useDefaults: true, $data: true });
33
+ /**
34
+ * Row submit statuses for bulk insert mode.
35
+ * Passed from the parent foundation-form.
36
+ */
37
+ this.rowSubmitStatuses = new Map();
38
+ /**
39
+ * Whether the form is in bulk insert mode.
40
+ * Passed from the parent foundation-form.
41
+ */
42
+ this.bulkInsert = false;
33
43
  this.dispatch = (action) => {
34
44
  this.jsonforms = Object.assign(Object.assign({}, this.jsonforms), { core: coreReducer(this.jsonforms.core, action) });
35
45
  this.$emit('data-change', {
@@ -113,6 +123,8 @@ let JSONForms = class JSONForms extends FASTElement {
113
123
  i18n: i18nReducer(this.i18n, Actions.updateI18n((_b = this.i18n) === null || _b === void 0 ? void 0 : _b.locale, (_c = this.i18n) === null || _c === void 0 ? void 0 : _c.translate, ((_d = this.i18n) === null || _d === void 0 ? void 0 : _d.translateError) || errorTranslator)),
114
124
  renderers: this.renderers,
115
125
  readonly: this.readonly,
126
+ rowSubmitStatuses: this.rowSubmitStatuses,
127
+ bulkInsert: this.bulkInsert,
116
128
  };
117
129
  const additionalErrors = this.validate(this.uichemaToUse);
118
130
  this.$emit('data-change', {
@@ -142,6 +154,18 @@ let JSONForms = class JSONForms extends FASTElement {
142
154
  configChanged() {
143
155
  this.schemaChanged();
144
156
  }
157
+ rowSubmitStatusesChanged() {
158
+ // Update the jsonforms object to trigger re-render in child renderers
159
+ if (this.jsonforms) {
160
+ this.jsonforms = Object.assign(Object.assign({}, this.jsonforms), { rowSubmitStatuses: this.rowSubmitStatuses });
161
+ }
162
+ }
163
+ bulkInsertChanged() {
164
+ // Update the jsonforms object to trigger re-render in child renderers
165
+ if (this.jsonforms) {
166
+ this.jsonforms = Object.assign(Object.assign({}, this.jsonforms), { bulkInsert: this.bulkInsert });
167
+ }
168
+ }
145
169
  get props() {
146
170
  var _a;
147
171
  if (!this.schema && !this.uischema) {
@@ -213,6 +237,12 @@ __decorate([
213
237
  __decorate([
214
238
  observable
215
239
  ], JSONForms.prototype, "config", void 0);
240
+ __decorate([
241
+ observable
242
+ ], JSONForms.prototype, "rowSubmitStatuses", void 0);
243
+ __decorate([
244
+ observable
245
+ ], JSONForms.prototype, "bulkInsert", void 0);
216
246
  JSONForms = __decorate([
217
247
  customElement({
218
248
  name: 'json-forms',
@@ -3,6 +3,13 @@ import { Generate, composePaths, createDefaultValue } from '@jsonforms/core';
3
3
  import { designUnit } from '@microsoft/fast-components';
4
4
  import { html, css, observable, customElement, FASTElement, repeat, } from '@microsoft/fast-element';
5
5
  import { logger } from '../../utils';
6
+ const resolveRowUiSchema = (childUiSchema, index, rowData, formData, fallback) => {
7
+ if (typeof childUiSchema === 'function') {
8
+ const result = childUiSchema(index, rowData, formData);
9
+ return result !== null && result !== void 0 ? result : fallback;
10
+ }
11
+ return fallback;
12
+ };
6
13
  const isDeleteButtonHidden = (ctx) => {
7
14
  var _a, _b, _c;
8
15
  const canDeleteFn = (_a = ctx.parent.control.uischema.options) === null || _a === void 0 ? void 0 : _a.canDelete;
@@ -13,33 +20,81 @@ const isDeleteButtonHidden = (ctx) => {
13
20
  const controlData = formData[ctx.parent.control.path] && formData[ctx.parent.control.path][ctx.index];
14
21
  return !canDeleteFn(controlData);
15
22
  };
23
+ const getRowStatus = (ctx) => {
24
+ var _a;
25
+ const statuses = (_a = ctx.parent.form.jsonforms) === null || _a === void 0 ? void 0 : _a.rowSubmitStatuses;
26
+ return statuses === null || statuses === void 0 ? void 0 : statuses.get(ctx.index);
27
+ };
28
+ const isRowInStatus = (ctx, targetStatus) => {
29
+ const rowStatus = getRowStatus(ctx);
30
+ return (rowStatus === null || rowStatus === void 0 ? void 0 : rowStatus.status) === targetStatus;
31
+ };
32
+ const isRowDisabled = (ctx) => isRowInStatus(ctx, 'success');
33
+ const isRowSubmitting = (ctx) => isRowInStatus(ctx, 'submitting');
16
34
  export const ArrayListWrapperRendererTemplate = (prefix = 'zero') => html `
17
35
  <template>
18
36
  ${repeat((x) => Array(x.control.data), html `
19
- <div class="array-list">
37
+ <div class="array-list ${(x, ctx) => {
38
+ const rowStatus = getRowStatus(ctx);
39
+ return rowStatus ? `row-status-${rowStatus.status}` : '';
40
+ }}"
41
+ data-row-index="${(x, ctx) => ctx.index}"
42
+ >
43
+ <div class="row-status-indicator">
44
+ <${prefix}-progress-ring class="status-spinner"></${prefix}-progress-ring>
45
+ <${prefix}-icon name="check-circle" class="status-icon status-success"></${prefix}-icon>
46
+ <${prefix}-icon
47
+ name="times-circle"
48
+ class="status-icon status-failed"
49
+ title="${(x, ctx) => {
50
+ var _a;
51
+ const rowStatus = getRowStatus(ctx);
52
+ return ((_a = rowStatus === null || rowStatus === void 0 ? void 0 : rowStatus.errors) === null || _a === void 0 ? void 0 : _a.map((e) => e.TEXT).join(', ')) || 'Failed';
53
+ }}"
54
+ ></${prefix}-icon>
55
+ </div>
20
56
  <dispatch-renderer
21
57
  ?submitted=${(x, ctx) => ctx.parent.form.submitted}
22
58
  :dispatch=${(x, ctx) => ctx.parent.form.dispatch}
23
59
  :jsonforms=${(x, ctx) => ctx.parent.form.jsonforms}
24
60
  :prefix=${(x, ctx) => ctx.parent.form.prefix}
25
- :props=${(x, ctx) => ({
26
- uischema: ctx.parent.uiSchema,
27
- schema: ctx.parent.schema,
28
- renderers: ctx.parent.control.renderers,
29
- path: composePaths(ctx.parent.control.path, `${ctx.index}`),
30
- enabled: ctx.parent.control.enabled,
31
- })}
61
+ :props=${(x, ctx) => {
62
+ var _a, _b, _c, _d;
63
+ const childSchema = (_a = ctx.parent.control.uischema.options) === null || _a === void 0 ? void 0 : _a.childUiSchema;
64
+ const formData = (_c = (_b = ctx.parent.form.jsonforms) === null || _b === void 0 ? void 0 : _b.core) === null || _c === void 0 ? void 0 : _c.data;
65
+ const rowData = (_d = ctx.parent.control.data) === null || _d === void 0 ? void 0 : _d[ctx.index];
66
+ const uischema = resolveRowUiSchema(childSchema, ctx.index, rowData, formData, ctx.parent.uiSchema);
67
+ return {
68
+ uischema,
69
+ schema: ctx.parent.schema,
70
+ renderers: ctx.parent.control.renderers,
71
+ path: composePaths(ctx.parent.control.path, `${ctx.index}`),
72
+ enabled: ctx.parent.control.enabled && !isRowDisabled(ctx),
73
+ };
74
+ }}
32
75
  ></dispatch-renderer>
33
- <${prefix}-button
34
- ?hidden=${(x, ctx) => isDeleteButtonHidden(ctx)}
35
- appearance="lightweight"
36
- class="item-control-btn"
37
- data-test-id=${(x, ctx) => `${ctx.parent.control.path}-${ctx.index}-delete-item`}
38
- @click=${(x, ctx) => ctx.parent.deleteItem(ctx.index)}
39
- >
40
- <${prefix}-icon name="trash"></${prefix}-icon>
41
- ${(x, ctx) => { var _a; return ((_a = ctx.parent.control.uischema.options) === null || _a === void 0 ? void 0 : _a.deleteLabel) || ''; }}
42
- </${prefix}-button>
76
+ <div class="button-group">
77
+ <${prefix}-button
78
+ ?hidden=${(x, ctx) => { var _a; return !((_a = ctx.parent.form.jsonforms) === null || _a === void 0 ? void 0 : _a.bulkInsert) || isRowDisabled(ctx); }}
79
+ ?disabled=${(x, ctx) => isRowSubmitting(ctx)}
80
+ appearance="accent"
81
+ class="item-control-btn row-submit-btn"
82
+ data-test-id=${(x, ctx) => `${ctx.parent.control.path}-${ctx.index}-submit-item`}
83
+ @click=${(x, ctx) => ctx.parent.submitRow(ctx.index)}
84
+ >
85
+ <${prefix}-icon name="paper-plane"></${prefix}-icon>
86
+ </${prefix}-button>
87
+ <${prefix}-button
88
+ ?hidden=${(x, ctx) => isDeleteButtonHidden(ctx) || isRowDisabled(ctx)}
89
+ appearance="stealth"
90
+ class="item-control-btn"
91
+ data-test-id=${(x, ctx) => `${ctx.parent.control.path}-${ctx.index}-delete-item`}
92
+ @click=${(x, ctx) => ctx.parent.deleteItem(ctx.index)}
93
+ >
94
+ <${prefix}-icon name="trash"></${prefix}-icon>
95
+ ${(x, ctx) => { var _a; return ((_a = ctx.parent.control.uischema.options) === null || _a === void 0 ? void 0 : _a.deleteLabel) || ''; }}
96
+ </${prefix}-button>
97
+ </div>
43
98
  </div>
44
99
  `, { positioning: true })}
45
100
  <${prefix}-button
@@ -56,27 +111,166 @@ export const ArrayListWrapperRendererTemplate = (prefix = 'zero') => html `
56
111
  const styles = css `
57
112
  :host {
58
113
  padding-left: calc(${designUnit} * 1px);
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: calc(${designUnit} * 3px);
117
+
118
+ /* Row status color tokens - can be overridden via CSS custom properties */
119
+ --row-status-success-color: var(--success-color, #28a745);
120
+ --row-status-failed-color: var(--error-color, #dc3545);
121
+ --row-status-submitting-color: var(--accent-fill-rest, #0078d4);
122
+
123
+ /* Array item card styling - industrial/utilitarian aesthetic */
124
+ --array-item-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 4px 8px rgba(0, 0, 0, 0.06);
125
+ --array-item-shadow-hover: 0 2px 4px rgba(0, 0, 0, 0.06), 0 6px 12px rgba(0, 0, 0, 0.08);
126
+ --array-item-border: 1px solid var(--neutral-stroke-rest, rgba(0, 0, 0, 0.12));
127
+ --array-item-radius: calc(${designUnit} * 2px);
59
128
  }
60
129
 
61
130
  .array-list {
131
+ display: flex;
132
+ align-items: flex-start;
133
+ position: relative;
134
+ padding: calc(${designUnit} * 3px);
135
+ padding-left: calc(${designUnit} * 2px + 3px); /* Extra space for left accent bar */
136
+ margin: 0;
137
+ background-color: var(--neutral-layer-1, #fff);
138
+ border: var(--array-item-border);
139
+ border-radius: var(--array-item-radius);
140
+ box-shadow: var(--array-item-shadow);
141
+ transition:
142
+ background-color 0.15s ease-in-out,
143
+ box-shadow 0.2s ease,
144
+ border-color 0.15s ease;
145
+ }
146
+
147
+ .array-list:hover {
148
+ box-shadow: var(--array-item-shadow-hover);
149
+ }
150
+
151
+ /* Content area grows to fill space; min-width prevents flex overflow */
152
+ .array-list > dispatch-renderer {
153
+ flex: 1;
154
+ min-width: 0;
155
+ }
156
+
157
+ /* Left accent bar for visual hierarchy - industrial form-slot feel */
158
+ .array-list::before {
159
+ content: '';
160
+ position: absolute;
161
+ left: 0;
162
+ top: 0;
163
+ bottom: 0;
164
+ width: 3px;
165
+ border-radius: var(--array-item-radius) 0 0 var(--array-item-radius);
166
+ background: var(--neutral-stroke-subtle, rgba(0, 0, 0, 0.06));
167
+ pointer-events: none;
168
+ }
169
+
170
+ .array-list.row-status-success::before {
171
+ background: var(--row-status-success-color);
172
+ }
173
+
174
+ .array-list.row-status-failed::before {
175
+ background: var(--row-status-failed-color);
176
+ }
177
+
178
+ .array-list.row-status-submitting::before {
179
+ background: var(--row-status-submitting-color);
180
+ }
181
+
182
+ .array-list.row-status-success {
183
+ background-color: color-mix(in srgb, var(--row-status-success-color), transparent 90%);
184
+ }
185
+
186
+ .array-list.row-status-failed {
187
+ background-color: color-mix(in srgb, var(--row-status-failed-color), transparent 90%);
188
+ }
189
+
190
+ .array-list.row-status-submitting {
191
+ background-color: color-mix(in srgb, var(--row-status-submitting-color), transparent 95%);
192
+ }
193
+
194
+ .row-status-indicator {
62
195
  display: flex;
63
196
  align-items: center;
197
+ justify-content: center;
198
+ min-width: calc(${designUnit} * 6px);
199
+ margin-right: calc(${designUnit} * 2px);
200
+ }
201
+
202
+ /* Hide all status indicators by default */
203
+ .row-status-indicator .status-spinner,
204
+ .row-status-indicator .status-success,
205
+ .row-status-indicator .status-failed {
206
+ display: none;
207
+ }
208
+
209
+ /* Show spinner when submitting */
210
+ .array-list.row-status-submitting .row-status-indicator .status-spinner {
211
+ display: flex;
212
+ }
213
+
214
+ /* Show success icon when successful */
215
+ .array-list.row-status-success .row-status-indicator .status-success {
216
+ display: flex;
217
+ }
218
+
219
+ /* Show failed icon when failed */
220
+ .array-list.row-status-failed .row-status-indicator .status-failed {
221
+ display: flex;
222
+ }
223
+
224
+ .status-icon {
225
+ width: calc(${designUnit} * 4px);
226
+ height: calc(${designUnit} * 4px);
227
+ }
228
+
229
+ .status-success {
230
+ color: var(--row-status-success-color);
231
+ }
232
+
233
+ .status-failed {
234
+ color: var(--row-status-failed-color);
235
+ cursor: help;
236
+ }
237
+
238
+ .status-spinner {
239
+ width: calc(${designUnit} * 4px);
240
+ height: calc(${designUnit} * 4px);
64
241
  }
65
242
 
66
243
  .item-control-btn {
67
- color: rgb(135, 155, 166);
68
- margin-left: 10px;
244
+ color: var(--neutral-foreground-hint, rgb(135, 155, 166));
245
+ margin-left: calc(${designUnit} * 3px);
69
246
  }
70
247
 
71
248
  .item-control-btn:hover {
72
249
  color: var(--accent-foreground-hover);
73
250
  }
251
+
252
+ .row-submit-btn {
253
+ min-width: calc(${designUnit} * 8px);
254
+ }
255
+
256
+ .row-submit-btn[disabled] {
257
+ opacity: 0.5;
258
+ cursor: not-allowed;
259
+ }
260
+ .button-group {
261
+ display: flex;
262
+ flex-direction: column;
263
+ gap: 8px;
264
+ }
74
265
  `;
75
266
  let ArrayListWrapper = class ArrayListWrapper extends FASTElement {
76
267
  controlChanged() {
268
+ var _a;
77
269
  this.schema = this.control.schema;
78
- if (this.control.uischema.options) {
79
- this.uiSchema = this.control.uischema.options.childUiSchema;
270
+ const childUiSchema = (_a = this.control.uischema.options) === null || _a === void 0 ? void 0 : _a.childUiSchema;
271
+ // Only use static childUiSchema; when it's a function, resolve per-row in template
272
+ if (childUiSchema && typeof childUiSchema !== 'function') {
273
+ this.uiSchema = childUiSchema;
80
274
  return;
81
275
  }
82
276
  const arrayUiSchema = Generate.uiSchema(this.schema);
@@ -89,6 +283,13 @@ let ArrayListWrapper = class ArrayListWrapper extends FASTElement {
89
283
  deleteItem(index) {
90
284
  this.control.removeItems(this.control.path, [index])();
91
285
  }
286
+ /**
287
+ * Submits a single row by emitting an event that bubbles up to the foundation-form.
288
+ * @param index - The row index to submit
289
+ */
290
+ submitRow(index) {
291
+ this.$emit('submit-single-row', { index }, { bubbles: true, composed: true });
292
+ }
92
293
  };
93
294
  __decorate([
94
295
  observable
@@ -9,7 +9,6 @@ export const BooleanControlRendererTemplate = (prefix = 'zero') => html `
9
9
  :jsonForms=${(x) => x.jsonforms}
10
10
  :touched=${(x) => x.touched}
11
11
  ?submitted=${(x) => x.submitted}
12
- hide-label
13
12
  >
14
13
  <${prefix}-checkbox
15
14
  ?checked=${(x) => x.control.data}
@@ -23,7 +22,7 @@ export const BooleanControlRendererTemplate = (prefix = 'zero') => html `
23
22
  }}
24
23
  id=${(x) => x.control.path}
25
24
  data-test-id=${(x) => x.control.path}
26
- >${(x) => x.control.label}</${prefix}-checkbox>
25
+ ></${prefix}-checkbox>
27
26
  </control-wrapper>
28
27
  </template>
29
28
  `;
@@ -16,10 +16,21 @@ export const ConnectedMultiselectControlRendererTemplate = (prefix = 'zero') =>
16
16
  <${prefix}-multiselect
17
17
  style="width: 100%"
18
18
  async=${(x) => { var _a; return (_a = x.control.uischema.options) === null || _a === void 0 ? void 0 : _a.async; }}
19
- :selectedOptions=${(x) => x.control.data || []}
19
+ ?disabled=${(x) => !x.control.enabled}
20
+ :selectedOptions=${(x) => {
21
+ var _a, _b, _c;
22
+ const selectedOptions = ((_a = x.control.uischema.options) === null || _a === void 0 ? void 0 : _a.delimiter)
23
+ ? (_b = x.control.data) === null || _b === void 0 ? void 0 : _b.split((_c = x.control.uischema.options) === null || _c === void 0 ? void 0 : _c.delimiter)
24
+ : x.control.data;
25
+ return selectedOptions || [];
26
+ }}
20
27
  tabindex="${(x) => { var _a, _b; return (_b = (_a = x.control.uischema) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.tabIndex; }}"
21
28
  @selectionChange=${(x, c) => {
22
- x.control.handleChange(x.control.path, c.event.detail);
29
+ var _a, _b, _c;
30
+ const value = !((_a = x.control.uischema.options) === null || _a === void 0 ? void 0 : _a.delimiter)
31
+ ? c.event.detail
32
+ : (_b = c.event.detail) === null || _b === void 0 ? void 0 : _b.join((_c = x.control.uischema.options) === null || _c === void 0 ? void 0 : _c.delimiter);
33
+ x.control.handleChange(x.control.path, value);
23
34
  x.$emit('change');
24
35
  x.onBlur();
25
36
  }}
@@ -13,13 +13,19 @@ export const ControlWrapperRendererTemplate = html `
13
13
  }}
14
14
  id=${(x) => x.control.path + '-wrapper'}
15
15
  data-test-id=${(x) => x.control.path + '-wrapper'}
16
+ role="group"
17
+ aria-labelledby=${(x) => (x.computedLabel ? x.control.path + '-label' : null)}
16
18
  >
17
- ${when((x) => !x.hideLabel, html `
18
- <div for="${(x) => x.control.path + '-wrapper'}" class="label">
19
+ ${when((x) => x.computedLabel, html `
20
+ <label
21
+ id="${(x) => x.control.path + '-label'}"
22
+ for="${(x) => x.control.path}"
23
+ class="${(x) => classNames('label', ['visually-hidden', x.hideLabel])}"
24
+ >
19
25
  <span>
20
26
  ${(x) => x.computedLabel}${when((x) => { var _a, _b; return (_b = (_a = x.control.uischema) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.tooltip; }, (x) => x.getPrefixedTooltip)}
21
27
  </span>
22
- </div>
28
+ </label>
23
29
  `)}
24
30
 
25
31
  <div class="wrapper">
@@ -39,6 +45,19 @@ export const ControlWrapperRendererTemplate = html `
39
45
  </template>
40
46
  `;
41
47
  const styles = css `
48
+ .visually-hidden {
49
+ position: absolute;
50
+ width: 1px;
51
+ height: 1px;
52
+ padding: 0;
53
+ margin: -1px;
54
+ overflow: hidden;
55
+ clip: rect(0, 0, 0, 0);
56
+ clip-path: inset(50%);
57
+ white-space: nowrap;
58
+ border: 0;
59
+ }
60
+
42
61
  .wrapperRoot {
43
62
  margin-bottom: calc(var(--design-unit) * 4px);
44
63
  }
@@ -50,10 +69,12 @@ const styles = css `
50
69
 
51
70
  .label {
52
71
  color: var(--neutral-foreground-hint);
53
- margin-bottom: calc(var(--design-unit) * 2px);
72
+ margin-bottom: var(--control-label-margin, calc(var(--design-unit) * 2px));
54
73
  display: flex;
55
74
  justify-content: space-between;
56
75
  font-weight: 700;
76
+ /* Reset label defaults to match former div appearance */
77
+ cursor: default;
57
78
  }
58
79
 
59
80
  .labelLeft .wrapper {
@@ -4,6 +4,7 @@ import { capitalCase } from 'change-case';
4
4
  import { comboboxRendererStyles } from '../../form.styles';
5
5
  import { isOneOfEnum } from '../testers/isOneOfEnum';
6
6
  import { ENUM_CONTROL_RANK } from './RenderersRanks';
7
+ const getOptionLabel = (option, labelRowFormatter) => labelRowFormatter ? labelRowFormatter(option.label) : capitalCase(option.label);
7
8
  // overrides https://github.com/eclipsesource/jsonforms/blob/69441cdfc48f359850d87fa4b842856f1f139eb2/packages/core/src/util/renderer.ts#L515
8
9
  // to allow mapping of enums that come as oneOf
9
10
  export const mapStateToEnumControlProps = (state, ownProps) => {
@@ -16,12 +17,13 @@ export const mapStateToEnumControlProps = (state, ownProps) => {
16
17
  return Object.assign(Object.assign({}, props), { options });
17
18
  };
18
19
  const updateEnumData = (dispatchRenderer, data) => {
19
- var _a;
20
- dispatchRenderer.control.handleChange(dispatchRenderer.control.path, (_a = dispatchRenderer.control.options.find((option) => capitalCase(option.label) === data)) === null || _a === void 0 ? void 0 : _a.value);
20
+ var _a, _b, _c;
21
+ const formatter = (_b = (_a = dispatchRenderer.control.uischema) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.labelRowFormatter;
22
+ dispatchRenderer.control.handleChange(dispatchRenderer.control.path, (_c = dispatchRenderer.control.options.find((option) => getOptionLabel(option, formatter) === data)) === null || _c === void 0 ? void 0 : _c.value);
21
23
  dispatchRenderer.onBlur();
22
24
  };
23
25
  const displaySetOrDefaultData = (dispatchRenderer) => {
24
- var _a, _b, _c, _d;
26
+ var _a, _b, _c, _d, _e;
25
27
  let data = dispatchRenderer.control.data;
26
28
  if (!data) {
27
29
  const enumDefault = (_c = (_b = (_a = dispatchRenderer.control.schema) === null || _a === void 0 ? void 0 : _a.oneOf) === null || _b === void 0 ? void 0 : _b.find((x) => x.hasOwnProperty('default'))) === null || _c === void 0 ? void 0 : _c.default;
@@ -30,7 +32,11 @@ const displaySetOrDefaultData = (dispatchRenderer) => {
30
32
  updateEnumData(dispatchRenderer, data);
31
33
  }
32
34
  }
33
- return ((_d = dispatchRenderer.control.options.find((option) => option.value === data)) === null || _d === void 0 ? void 0 : _d.label) || '';
35
+ const option = dispatchRenderer.control.options.find((opt) => opt.value === data);
36
+ if (!option)
37
+ return '';
38
+ const formatter = (_e = (_d = dispatchRenderer.control.uischema) === null || _d === void 0 ? void 0 : _d.options) === null || _e === void 0 ? void 0 : _e.labelRowFormatter;
39
+ return getOptionLabel(option, formatter);
34
40
  };
35
41
  export const EnumControlRendererTemplate = (prefix = 'zero') => html `
36
42
  <template>
@@ -54,7 +60,10 @@ export const EnumControlRendererTemplate = (prefix = 'zero') => html `
54
60
  data-test-id=${(x) => x.control.path}
55
61
  >
56
62
  ${repeat((x) => x.control.options, html `
57
- <${prefix}-option>${(x) => capitalCase(x.label)}</${prefix}-option>
63
+ <${prefix}-option>${(x, ctx) => {
64
+ var _a, _b, _c, _d;
65
+ return getOptionLabel(x, (_d = (_c = (_b = (_a = ctx.parent) === null || _a === void 0 ? void 0 : _a.control) === null || _b === void 0 ? void 0 : _b.uischema) === null || _c === void 0 ? void 0 : _c.options) === null || _d === void 0 ? void 0 : _d.labelRowFormatter);
66
+ }}</${prefix}-option>
58
67
  `)}
59
68
  </${prefix}-combobox>
60
69
  </control-wrapper>
@@ -0,0 +1,39 @@
1
+ import { mapStateToLayoutProps, rankWith } from '@jsonforms/core';
2
+ import { html, repeat } from '@microsoft/fast-element';
3
+ import { LayoutWrapper } from './LayoutRenderer';
4
+ import { LAYOUT_FORM_GRID_RANK } from './RenderersRanks';
5
+ LayoutWrapper;
6
+ export const LayoutFormGridRendererTemplate = html `
7
+ <template>
8
+ <layout-wrapper :control=${(x) => x.control}>
9
+ <div
10
+ style="
11
+ display: grid;
12
+ grid-template-columns: repeat(4, 1fr);
13
+ gap: 8px;
14
+ "
15
+ >
16
+ ${repeat((x) => x.control.uischema.elements, html `
17
+ <dispatch-renderer
18
+ ?submitted=${(x, ctx) => ctx.parent.submitted}
19
+ :dispatch=${(x, ctx) => ctx.parent.dispatch}
20
+ :jsonforms=${(x, ctx) => ctx.parent.jsonforms}
21
+ :prefix=${(x, ctx) => ctx.parent.prefix}
22
+ :props=${(x, ctx) => ({
23
+ uischema: x,
24
+ schema: ctx.parent.control.schema,
25
+ renderers: ctx.parent.control.renderers,
26
+ path: ctx.parent.control.path,
27
+ enabled: ctx.parent.control.enabled,
28
+ })}
29
+ ></dispatch-renderer>
30
+ `)}
31
+ </div>
32
+ </layout-wrapper>
33
+ </template>
34
+ `;
35
+ export const LayoutFormGridEntry = {
36
+ renderer: LayoutFormGridRendererTemplate,
37
+ tester: rankWith(LAYOUT_FORM_GRID_RANK, (uiSchema) => uiSchema.type === 'FormGridLayout'),
38
+ mapper: mapStateToLayoutProps,
39
+ };
@@ -13,5 +13,6 @@ export const LAYOUT_GROUP_RANK = 2;
13
13
  export const LAYOUT_HORIZONTAL_RANK = 2;
14
14
  export const LAYOUT_STEPPER_RANK = 3;
15
15
  export const LAYOUT2COLUMNS_RANK = 2;
16
+ export const LAYOUT_FORM_GRID_RANK = 2;
16
17
  export const INVISIBLE_CONTROL_RANK = 5;
17
18
  export const DIVIDER_CONTROL_RANK = 5;
@@ -1,3 +1,3 @@
1
1
  import { and, hasType, or, schemaMatches } from '@jsonforms/core';
2
2
  import { optionIs } from './optionIs';
3
- export const isOneOfOptionMultiselect = and(or(optionIs('allOptionsResourceName'), optionIs('data')), or(schemaMatches((schema) => hasType(schema, 'array')), schemaMatches((schema) => schema.hasOwnProperty('oneOf') && schema.oneOf.some((s) => hasType(s, 'array')))));
3
+ export const isOneOfOptionMultiselect = and(or(optionIs('allOptionsResourceName'), optionIs('data')), or(optionIs('delimiter'), schemaMatches((schema) => hasType(schema, 'array')), schemaMatches((schema) => schema.hasOwnProperty('oneOf') && schema.oneOf.some((s) => hasType(s, 'array')))));