@genesislcap/foundation-forms 14.396.4 → 14.397.1-alpha-87a7828.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 (60) hide show
  1. package/dist/custom-elements.json +565 -241
  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/types.d.ts +88 -1
  11. package/dist/dts/types.d.ts.map +1 -1
  12. package/dist/dts/utils/csv-parser.d.ts +82 -0
  13. package/dist/dts/utils/csv-parser.d.ts.map +1 -0
  14. package/dist/dts/utils/index.d.ts +1 -0
  15. package/dist/dts/utils/index.d.ts.map +1 -1
  16. package/dist/dts/utils/schema-utils.d.ts +46 -0
  17. package/dist/dts/utils/schema-utils.d.ts.map +1 -0
  18. package/dist/dts/utils/validation.d.ts +2 -0
  19. package/dist/dts/utils/validation.d.ts.map +1 -1
  20. package/dist/esm/form.js +421 -5
  21. package/dist/esm/form.styles.js +38 -1
  22. package/dist/esm/form.template.js +33 -1
  23. package/dist/esm/jsonforms/json-forms.js +30 -0
  24. package/dist/esm/jsonforms/renderers/ArrayListWrapperRenderer.js +207 -13
  25. package/dist/esm/utils/csv-parser.js +458 -0
  26. package/dist/esm/utils/index.js +1 -0
  27. package/dist/esm/utils/schema-utils.js +120 -0
  28. package/dist/esm/utils/validation.js +2 -0
  29. package/dist/foundation-forms.api.json +1006 -29
  30. package/dist/foundation-forms.d.ts +281 -1
  31. package/docs/api/foundation-forms.arrayrendereroptions.md +2 -2
  32. package/docs/api/foundation-forms.bulkrowstatus.md +22 -0
  33. package/docs/api/foundation-forms.bulkrowsubmitstatus.md +13 -0
  34. package/docs/api/foundation-forms.bulksubmitfaileditem.md +20 -0
  35. package/docs/api/foundation-forms.bulksubmitresult.md +18 -0
  36. package/docs/api/foundation-forms.bulksubmitsuccessitem.md +17 -0
  37. package/docs/api/foundation-forms.childuischemaresolver.md +15 -0
  38. package/docs/api/foundation-forms.csvmappingresult.mappedrows.md +13 -0
  39. package/docs/api/foundation-forms.csvmappingresult.md +77 -0
  40. package/docs/api/foundation-forms.csvmappingresult.unmappedcolumns.md +13 -0
  41. package/docs/api/foundation-forms.csvparseresult.errors.md +13 -0
  42. package/docs/api/foundation-forms.csvparseresult.headers.md +13 -0
  43. package/docs/api/foundation-forms.csvparseresult.md +96 -0
  44. package/docs/api/foundation-forms.csvparseresult.rows.md +13 -0
  45. package/docs/api/foundation-forms.downloadcsvtemplate.md +74 -0
  46. package/docs/api/foundation-forms.form.bulkinsert.md +13 -0
  47. package/docs/api/foundation-forms.form.bulkinsertmaxitems.md +13 -0
  48. package/docs/api/foundation-forms.form.bulkinsertminitems.md +13 -0
  49. package/docs/api/foundation-forms.form.clearrowsubmitstatuses.md +17 -0
  50. package/docs/api/foundation-forms.form.downloadcsvtemplate.md +17 -0
  51. package/docs/api/foundation-forms.form.handlecsvfileselected.md +54 -0
  52. package/docs/api/foundation-forms.form.md +132 -0
  53. package/docs/api/foundation-forms.form.rowsubmitstatuses.md +13 -0
  54. package/docs/api/foundation-forms.form.submitsinglerow.md +56 -0
  55. package/docs/api/foundation-forms.generatecsvtemplate.md +104 -0
  56. package/docs/api/foundation-forms.mapcsvtoschema.md +72 -0
  57. package/docs/api/foundation-forms.md +147 -0
  58. package/docs/api/foundation-forms.parsecsv.md +56 -0
  59. package/docs/api-report.md.api.md +85 -3
  60. package/package.json +19 -17
@@ -0,0 +1,458 @@
1
+ import Papa from 'papaparse';
2
+ /**
3
+ * Parses a CSV string into headers and rows using PapaParse.
4
+ * Handles quoted fields, escaped quotes, empty values, and mixed line endings.
5
+ * @param content - The CSV content as a string
6
+ * @returns The parsed result with headers, rows, and any errors
7
+ * @public
8
+ */
9
+ export function parseCsv(content) {
10
+ var _a, _b, _c;
11
+ const errors = [];
12
+ if (!(content === null || content === void 0 ? void 0 : content.trim())) {
13
+ errors.push('CSV file is empty');
14
+ return { headers: [], rows: [], errors };
15
+ }
16
+ const result = Papa.parse(content, {
17
+ header: true,
18
+ skipEmptyLines: true,
19
+ dynamicTyping: false, // Keep all values as strings; mapCsvToSchema handles type conversion
20
+ });
21
+ const headers = (_a = result.meta.fields) !== null && _a !== void 0 ? _a : [];
22
+ if (headers.length === 0) {
23
+ errors.push('CSV file has no headers');
24
+ return { headers: [], rows: [], errors };
25
+ }
26
+ // Add PapaParse errors
27
+ for (const err of result.errors) {
28
+ errors.push((_b = err.message) !== null && _b !== void 0 ? _b : `Parse error at row ${(_c = err.row) !== null && _c !== void 0 ? _c : '?'}`);
29
+ }
30
+ // Ensure all row values are strings (PapaParse may return undefined for missing cells)
31
+ const rows = result.data.map((row) => {
32
+ const stringRow = {};
33
+ for (const header of headers) {
34
+ const val = row[header];
35
+ stringRow[header] = val === undefined || val === null ? '' : String(val);
36
+ }
37
+ return stringRow;
38
+ });
39
+ return { headers, rows, errors };
40
+ }
41
+ /**
42
+ * Maps CSV rows to schema fields with case-insensitive matching.
43
+ * Converts values to appropriate types based on schema definition.
44
+ * @param csvRows - The parsed CSV rows
45
+ * @param schema - The JSON schema defining the fields
46
+ * @returns Mapped rows and list of unmapped columns
47
+ * @public
48
+ */
49
+ export function mapCsvToSchema(csvRows, schema) {
50
+ var _a;
51
+ if (!(schema === null || schema === void 0 ? void 0 : schema.properties) || csvRows.length === 0) {
52
+ return { mappedRows: [], unmappedColumns: [] };
53
+ }
54
+ const schemaFields = Object.keys(schema.properties);
55
+ // Create case-insensitive mapping from CSV headers to schema fields
56
+ const headerMapping = new Map();
57
+ const unmappedColumns = [];
58
+ if (csvRows.length > 0) {
59
+ const csvHeaders = Object.keys((_a = csvRows[0]) !== null && _a !== void 0 ? _a : {});
60
+ for (const csvHeader of csvHeaders) {
61
+ const normalizedCsvHeader = csvHeader.toUpperCase();
62
+ const matchedField = schemaFields.find((field) => field.toUpperCase() === normalizedCsvHeader);
63
+ if (matchedField) {
64
+ headerMapping.set(csvHeader, matchedField);
65
+ }
66
+ else {
67
+ unmappedColumns.push(csvHeader);
68
+ }
69
+ }
70
+ }
71
+ // Map each row
72
+ const mappedRows = csvRows.map((row) => {
73
+ var _a;
74
+ const mappedRow = {};
75
+ for (const [csvHeader, schemaField] of headerMapping) {
76
+ const rawValue = row[csvHeader];
77
+ const fieldSchema = (_a = schema.properties) === null || _a === void 0 ? void 0 : _a[schemaField];
78
+ mappedRow[schemaField] = convertValue(rawValue, fieldSchema);
79
+ }
80
+ return mappedRow;
81
+ });
82
+ return { mappedRows, unmappedColumns };
83
+ }
84
+ /**
85
+ * Converts a string value to the appropriate type based on schema.
86
+ * @param value - The string value from CSV
87
+ * @param fieldSchema - The JSON schema for this field
88
+ * @returns The converted value
89
+ */
90
+ function convertValue(value, fieldSchema) {
91
+ if (value === '') {
92
+ return value;
93
+ }
94
+ if (!fieldSchema) {
95
+ return value;
96
+ }
97
+ const fieldType = getFieldType(fieldSchema);
98
+ switch (fieldType) {
99
+ case 'integer':
100
+ case 'number': {
101
+ const num = parseFloat(value);
102
+ return isNaN(num) ? value : num;
103
+ }
104
+ case 'boolean': {
105
+ const lowerValue = value.toLowerCase();
106
+ if (['true', 'yes', '1'].includes(lowerValue)) {
107
+ return true;
108
+ }
109
+ if (['false', 'no', '0'].includes(lowerValue)) {
110
+ return false;
111
+ }
112
+ return value;
113
+ }
114
+ default:
115
+ return value;
116
+ }
117
+ }
118
+ /**
119
+ * Gets the type from a JSON schema, handling oneOf/anyOf cases.
120
+ * @param schema - The JSON schema
121
+ * @returns The field type
122
+ */
123
+ function getFieldType(schema) {
124
+ if (schema.type) {
125
+ return Array.isArray(schema.type) ? schema.type[0] : schema.type;
126
+ }
127
+ // Handle oneOf/anyOf by finding the first non-null type
128
+ const alternatives = schema.oneOf || schema.anyOf;
129
+ if (alternatives) {
130
+ for (const alt of alternatives) {
131
+ if (typeof alt === 'object' && alt.type && alt.type !== 'null') {
132
+ return Array.isArray(alt.type) ? alt.type[0] : alt.type;
133
+ }
134
+ }
135
+ }
136
+ return undefined;
137
+ }
138
+ /**
139
+ * Generates a CSV template string with headers and sample data based on JSON schema.
140
+ * If a UI schema is provided, it will be used to determine which fields to include
141
+ * and in what order. Hidden fields in the UI schema will be excluded.
142
+ * @param schema - The JSON schema defining the fields
143
+ * @param uiSchema - Optional UI schema to determine field order and visibility
144
+ * @param includeOptionalFields - Whether to include optional fields when no UI schema (default: true)
145
+ * @param includeBom - Whether to prepend UTF-8 BOM for Excel compatibility (default: true)
146
+ * @returns The CSV template string with headers and one sample row
147
+ * @public
148
+ */
149
+ export function generateCsvTemplate(schema, uiSchema, includeOptionalFields = true, includeBom = true) {
150
+ if (!(schema === null || schema === void 0 ? void 0 : schema.properties)) {
151
+ return '';
152
+ }
153
+ const requiredFields = new Set(schema.required || []);
154
+ const headers = [];
155
+ const sampleValues = [];
156
+ // Get field order from UI schema if provided
157
+ const fieldsFromUiSchema = uiSchema ? extractFieldsFromUiSchema(uiSchema) : null;
158
+ if (fieldsFromUiSchema && fieldsFromUiSchema.length > 0) {
159
+ // Use UI schema order, filtering out hidden fields
160
+ for (const { fieldName, isHidden } of fieldsFromUiSchema) {
161
+ // Skip hidden fields
162
+ if (isHidden) {
163
+ continue;
164
+ }
165
+ // Check if field exists in JSON schema
166
+ const fieldSchema = schema.properties[fieldName];
167
+ if (!fieldSchema) {
168
+ continue;
169
+ }
170
+ headers.push(fieldName);
171
+ const isRequired = requiredFields.has(fieldName);
172
+ const sampleValue = generateSampleValue(fieldName, fieldSchema, isRequired);
173
+ sampleValues.push(escapeCsvValue(sampleValue));
174
+ }
175
+ }
176
+ else {
177
+ // Fall back to JSON schema order
178
+ for (const [fieldName, fieldSchema] of Object.entries(schema.properties)) {
179
+ const isRequired = requiredFields.has(fieldName);
180
+ // Skip optional fields if not including them
181
+ if (!includeOptionalFields && !isRequired) {
182
+ continue;
183
+ }
184
+ headers.push(fieldName);
185
+ const fieldDef = fieldSchema;
186
+ const sampleValue = generateSampleValue(fieldName, fieldDef, isRequired);
187
+ sampleValues.push(escapeCsvValue(sampleValue));
188
+ }
189
+ }
190
+ if (headers.length === 0) {
191
+ return '';
192
+ }
193
+ // Build CSV content (escape headers in case they contain commas/quotes)
194
+ const headerRow = headers.map((h) => escapeCsvValue(h)).join(',');
195
+ const sampleRow = sampleValues.join(',');
196
+ const content = `${headerRow}\n${sampleRow}`;
197
+ return includeBom ? '\uFEFF' + content : content;
198
+ }
199
+ /**
200
+ * Extracts field names from a UI schema in the order they appear.
201
+ * @param uiSchema - The UI schema to extract fields from
202
+ * @returns Array of field info with name and hidden status
203
+ * @internal
204
+ */
205
+ export function extractFieldsFromUiSchema(uiSchema) {
206
+ const fields = [];
207
+ function processElement(element) {
208
+ var _a, _b;
209
+ if (element.type === 'Control' && element.scope) {
210
+ const fieldName = extractFieldNameFromScope(element.scope);
211
+ if (fieldName) {
212
+ const isHidden = ((_a = element.options) === null || _a === void 0 ? void 0 : _a.hidden) === true;
213
+ fields.push({ fieldName, isHidden });
214
+ }
215
+ }
216
+ if (element.elements) {
217
+ for (const child of element.elements) {
218
+ processElement(child);
219
+ }
220
+ }
221
+ if ((_b = element.options) === null || _b === void 0 ? void 0 : _b.childElements) {
222
+ for (const child of element.options.childElements) {
223
+ processElement(child);
224
+ }
225
+ }
226
+ }
227
+ if (uiSchema.elements) {
228
+ for (const element of uiSchema.elements) {
229
+ processElement(element);
230
+ }
231
+ }
232
+ const schemaOptions = uiSchema.options;
233
+ const topLevelChildElements = schemaOptions === null || schemaOptions === void 0 ? void 0 : schemaOptions.childElements;
234
+ if (topLevelChildElements) {
235
+ for (const element of topLevelChildElements) {
236
+ processElement(element);
237
+ }
238
+ }
239
+ return fields;
240
+ }
241
+ /**
242
+ * Extracts the field name from a JSON schema scope string.
243
+ * @param scope - The scope string (e.g., "#/properties/FIELD_NAME")
244
+ * @returns The field name or null if not a valid scope
245
+ * @internal
246
+ */
247
+ function extractFieldNameFromScope(scope) {
248
+ const match = scope.match(/^#\/properties\/(.+)$/);
249
+ return match ? match[1] : null;
250
+ }
251
+ /**
252
+ * Generates a sample value for a field based on its schema type.
253
+ * @param fieldName - The name of the field
254
+ * @param fieldSchema - The JSON schema for this field
255
+ * @param isRequired - Whether the field is required
256
+ * @returns A sample value string
257
+ */
258
+ function generateSampleValue(fieldName, fieldSchema, isRequired) {
259
+ const fieldType = getFieldType(fieldSchema);
260
+ // Check for enum values first
261
+ if (fieldSchema.enum && fieldSchema.enum.length > 0) {
262
+ return String(fieldSchema.enum[0]);
263
+ }
264
+ // Check for const value
265
+ if (fieldSchema.const !== undefined) {
266
+ return String(fieldSchema.const);
267
+ }
268
+ // Check for default value
269
+ if (fieldSchema.default !== undefined) {
270
+ return String(fieldSchema.default);
271
+ }
272
+ // Check for examples
273
+ if (fieldSchema.examples &&
274
+ Array.isArray(fieldSchema.examples) &&
275
+ fieldSchema.examples.length > 0) {
276
+ return String(fieldSchema.examples[0]);
277
+ }
278
+ // Generate sample based on type
279
+ switch (fieldType) {
280
+ case 'string':
281
+ return generateStringSample(fieldName, fieldSchema);
282
+ case 'integer':
283
+ return generateIntegerSample(fieldSchema);
284
+ case 'number':
285
+ return generateNumberSample(fieldSchema);
286
+ case 'boolean':
287
+ return 'true';
288
+ case 'array':
289
+ return ''; // Arrays typically need special handling
290
+ case 'object':
291
+ return ''; // Objects typically need special handling
292
+ default:
293
+ // Default to a simple string sample
294
+ return isRequired ? `sample_${fieldName.toLowerCase()}` : '';
295
+ }
296
+ }
297
+ /**
298
+ * Generates a sample string value based on field name and schema.
299
+ * Uses format hints first, then heuristic inference from field name.
300
+ * @param fieldName - The name of the field
301
+ * @param fieldSchema - The JSON schema for this field
302
+ * @returns A sample string value
303
+ */
304
+ function generateStringSample(fieldName, fieldSchema) {
305
+ const lowerName = fieldName.toLowerCase();
306
+ // Check for format hints
307
+ if (fieldSchema.format) {
308
+ switch (fieldSchema.format) {
309
+ case 'date':
310
+ return '2024-01-15';
311
+ case 'date-time':
312
+ return '2024-01-15T10:30:00Z';
313
+ case 'time':
314
+ return '10:30:00';
315
+ case 'email':
316
+ return 'user@example.com';
317
+ case 'uri':
318
+ case 'url':
319
+ return 'https://example.com';
320
+ case 'uuid':
321
+ return '550e8400-e29b-41d4-a716-446655440000';
322
+ case 'hostname':
323
+ return 'example.com';
324
+ case 'ipv4':
325
+ return '192.168.1.1';
326
+ case 'ipv6':
327
+ return '2001:0db8:85a3:0000:0000:8a2e:0370:7334';
328
+ }
329
+ }
330
+ // Infer from field name
331
+ if (lowerName.includes('email')) {
332
+ return 'user@example.com';
333
+ }
334
+ if (lowerName.includes('phone') || lowerName.includes('tel')) {
335
+ return '+1234567890';
336
+ }
337
+ if (lowerName.includes('date') || lowerName.includes('time')) {
338
+ if (lowerName.includes('time') && !lowerName.includes('date')) {
339
+ return '10:30:00';
340
+ }
341
+ return '2024-01-15';
342
+ }
343
+ if (lowerName.includes('url') || lowerName.includes('link') || lowerName.includes('website')) {
344
+ return 'https://example.com';
345
+ }
346
+ if (lowerName.includes('name')) {
347
+ if (lowerName.includes('first')) {
348
+ return 'John';
349
+ }
350
+ if (lowerName.includes('last')) {
351
+ return 'Doe';
352
+ }
353
+ return 'Sample Name';
354
+ }
355
+ if (lowerName.includes('address')) {
356
+ return '123 Main Street';
357
+ }
358
+ if (lowerName.includes('city')) {
359
+ return 'New York';
360
+ }
361
+ if (lowerName.includes('country')) {
362
+ return 'USA';
363
+ }
364
+ if (lowerName.includes('description') ||
365
+ lowerName.includes('comment') ||
366
+ lowerName.includes('notes')) {
367
+ return 'Sample description';
368
+ }
369
+ if (lowerName.includes('id') || lowerName.includes('code')) {
370
+ return 'ABC123';
371
+ }
372
+ // Check for minLength/maxLength constraints
373
+ const minLen = fieldSchema.minLength || 0;
374
+ const DEFAULT_MAX_LENGTH = 50;
375
+ const maxLen = fieldSchema.maxLength || DEFAULT_MAX_LENGTH;
376
+ let sample = `Sample ${fieldName}`;
377
+ if (sample.length < minLen) {
378
+ sample = sample.padEnd(minLen, '_');
379
+ }
380
+ if (sample.length > maxLen) {
381
+ sample = sample.substring(0, maxLen);
382
+ }
383
+ return sample;
384
+ }
385
+ /**
386
+ * Generates a sample integer value based on schema constraints.
387
+ * @param fieldSchema - The JSON schema for this field
388
+ * @returns A sample integer string
389
+ */
390
+ function generateIntegerSample(fieldSchema) {
391
+ var _a, _b;
392
+ const min = (_a = fieldSchema.minimum) !== null && _a !== void 0 ? _a : 0;
393
+ const max = (_b = fieldSchema.maximum) !== null && _b !== void 0 ? _b : 100;
394
+ // Use minimum if specified, otherwise use a value in range
395
+ if (fieldSchema.minimum !== undefined) {
396
+ return String(Math.ceil(min));
397
+ }
398
+ // Return a sensible default within range
399
+ const value = Math.min(Math.max(1, min), max);
400
+ return String(Math.floor(value));
401
+ }
402
+ /**
403
+ * Generates a sample number value based on schema constraints.
404
+ * @param fieldSchema - The JSON schema for this field
405
+ * @returns A sample number string
406
+ */
407
+ function generateNumberSample(fieldSchema) {
408
+ var _a, _b;
409
+ const min = (_a = fieldSchema.minimum) !== null && _a !== void 0 ? _a : 0;
410
+ const max = (_b = fieldSchema.maximum) !== null && _b !== void 0 ? _b : 100;
411
+ // Use minimum if specified, otherwise use a value in range
412
+ if (fieldSchema.minimum !== undefined) {
413
+ return String(min);
414
+ }
415
+ // Return a sensible default within range
416
+ const DEFAULT_NUMERIC_VALUE = 1.5;
417
+ const value = Math.min(Math.max(DEFAULT_NUMERIC_VALUE, min), max);
418
+ return String(value);
419
+ }
420
+ /**
421
+ * Escapes a value for CSV output.
422
+ * Values containing commas, quotes, or newlines are wrapped in quotes.
423
+ * Quotes within values are escaped by doubling them.
424
+ * @param value - The value to escape
425
+ * @returns The escaped value
426
+ */
427
+ function escapeCsvValue(value) {
428
+ if (!value) {
429
+ return '';
430
+ }
431
+ // Check if escaping is needed
432
+ const needsEscaping = value.includes(',') || value.includes('"') || value.includes('\n') || value.includes('\r');
433
+ if (needsEscaping) {
434
+ // Escape quotes by doubling them and wrap in quotes
435
+ const escaped = value.replace(/"/g, '""');
436
+ return `"${escaped}"`;
437
+ }
438
+ return value;
439
+ }
440
+ /**
441
+ * Triggers a download of the CSV template file in the browser.
442
+ * @param csvContent - The CSV content to download
443
+ * @param fileName - The name for the downloaded file (default: 'template.csv')
444
+ * @remarks Browser-only; uses document and URL.createObjectURL. Will throw in Node.js.
445
+ * @public
446
+ */
447
+ export function downloadCsvTemplate(csvContent, fileName = 'template.csv') {
448
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
449
+ const url = URL.createObjectURL(blob);
450
+ const link = document.createElement('a');
451
+ link.href = url;
452
+ link.download = fileName;
453
+ link.style.display = 'none';
454
+ document.body.appendChild(link);
455
+ link.click();
456
+ document.body.removeChild(link);
457
+ URL.revokeObjectURL(url);
458
+ }
@@ -1,3 +1,4 @@
1
+ export * from './csv-parser';
1
2
  export * from './filters';
2
3
  export * from './logger';
3
4
  export * from './translation';
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Extracts the field name from a JSON schema scope string.
3
+ * @param scope - The scope string (e.g. "#/properties/FIELD_NAME" or "#/properties/obj/properties/FIELD")
4
+ * @returns The field name or null if not a valid scope
5
+ * @internal
6
+ */
7
+ function extractFieldNameFromScope(scope) {
8
+ const match = scope.match(/^#\/properties\/(.+)$/);
9
+ return match ? match[1] : null;
10
+ }
11
+ /**
12
+ * Recursively extracts Control elements from a UI schema in display order.
13
+ * Used for grid-style array layouts where labels are shown only in the header row.
14
+ *
15
+ * @param uiSchema - The UI schema to extract controls from
16
+ * @returns Array of control info with uischema, label, and field name
17
+ * @internal
18
+ */
19
+ export function extractControlsFromUiSchema(uiSchema) {
20
+ var _a;
21
+ const controls = [];
22
+ function processElement(element) {
23
+ var _a, _b, _c;
24
+ if (element.type === 'Control' && element.scope) {
25
+ const fieldName = extractFieldNameFromScope(element.scope);
26
+ if (fieldName) {
27
+ const isHidden = ((_a = element.options) === null || _a === void 0 ? void 0 : _a.hidden) === true;
28
+ if (!isHidden) {
29
+ const label = (_b = element.label) !== null && _b !== void 0 ? _b : fieldName;
30
+ controls.push({
31
+ uischema: element,
32
+ label: String(label),
33
+ fieldName,
34
+ });
35
+ }
36
+ }
37
+ }
38
+ if (element.elements) {
39
+ for (const child of element.elements) {
40
+ processElement(child);
41
+ }
42
+ }
43
+ if ((_c = element.options) === null || _c === void 0 ? void 0 : _c.childElements) {
44
+ for (const child of element.options.childElements) {
45
+ processElement(child);
46
+ }
47
+ }
48
+ }
49
+ if (uiSchema.elements) {
50
+ for (const element of uiSchema.elements) {
51
+ processElement(element);
52
+ }
53
+ }
54
+ if ((_a = uiSchema.options) === null || _a === void 0 ? void 0 : _a.childElements) {
55
+ for (const element of uiSchema.options.childElements) {
56
+ processElement(element);
57
+ }
58
+ }
59
+ return controls;
60
+ }
61
+ /**
62
+ * Creates a deep copy of the UI schema with gridView option set to true on all Control elements.
63
+ * Used for grid-style array layouts so child controls can adapt their behavior.
64
+ *
65
+ * @param uiSchema - The UI schema to modify
66
+ * @returns A new UI schema with gridView option on all controls
67
+ * @internal
68
+ */
69
+ export function withGridView(uiSchema) {
70
+ const clone = structuredClone(uiSchema);
71
+ function processElement(element) {
72
+ var _a;
73
+ if ((element === null || element === void 0 ? void 0 : element.type) === 'Control') {
74
+ element.options = Object.assign(Object.assign({}, element.options), { gridView: true });
75
+ }
76
+ if (element === null || element === void 0 ? void 0 : element.elements) {
77
+ element.elements.forEach(processElement);
78
+ }
79
+ if ((_a = element === null || element === void 0 ? void 0 : element.options) === null || _a === void 0 ? void 0 : _a.childElements) {
80
+ element.options.childElements.forEach(processElement);
81
+ }
82
+ }
83
+ processElement(clone);
84
+ return clone;
85
+ }
86
+ /**
87
+ * Checks if the provided UI schema is already configured for bulk insert mode.
88
+ * @param uischema - The UI schema to check
89
+ * @returns true if the schema has a Control element for #/properties/items
90
+ * @internal
91
+ */
92
+ export function isBulkUiSchema(uischema) {
93
+ var _a;
94
+ return (_a = uischema === null || uischema === void 0 ? void 0 : uischema.elements) === null || _a === void 0 ? void 0 : _a.some((element) => element.scope === '#/properties/items' && element.type === 'Control');
95
+ }
96
+ /**
97
+ * Generates a UI schema suitable for bulk insert mode with array control.
98
+ * @param userProvidedUiSchema - Optional user-provided UI schema to use as childUiSchema
99
+ * @returns A UI schema configured for bulk insert
100
+ * @internal
101
+ */
102
+ export function generateBulkUiSchema(userProvidedUiSchema) {
103
+ const options = {
104
+ addLabel: 'Add another',
105
+ deleteLabel: '',
106
+ };
107
+ if (userProvidedUiSchema) {
108
+ options.childUiSchema = userProvidedUiSchema;
109
+ }
110
+ return {
111
+ type: 'VerticalLayout',
112
+ elements: [
113
+ {
114
+ type: 'Control',
115
+ scope: '#/properties/items',
116
+ options,
117
+ },
118
+ ],
119
+ };
120
+ }
@@ -48,6 +48,8 @@ const describeError = (prop, parentProps) => {
48
48
  /**
49
49
  * Computes a human-friendly anyOf error message for a given control path.
50
50
  * Prefers UI schema custom message, then JSON schema errorMessage.anyOf, then a constructed fallback.
51
+ *
52
+ * @public
51
53
  */
52
54
  export const getAnyOfErrorMessage = (errors, schema, controlPath, uiCustomMsg) => {
53
55
  var _a, _b, _c;