radiant-docs 0.1.64 → 0.1.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +53 -10
- package/package.json +4 -3
- package/template/package-lock.json +1991 -4096
- package/template/package.json +7 -19
- package/template/src/components/OpenApiPage.astro +107 -18
- package/template/src/components/Sidebar.astro +1 -0
- package/template/src/components/endpoint/PlaygroundBar.astro +1 -1
- package/template/src/components/endpoint/PlaygroundField.astro +433 -71
- package/template/src/components/endpoint/PlaygroundForm.astro +470 -87
- package/template/src/components/endpoint/RequestSnippets.astro +6 -1
- package/template/src/components/endpoint/ResponseDisplay.astro +109 -2
- package/template/src/components/endpoint/ResponseFieldTree.astro +1 -1
- package/template/src/components/endpoint/ResponseFields.astro +97 -28
- package/template/src/components/endpoint/ResponseSnippets.astro +19 -7
- package/template/src/layouts/Layout.astro +94 -0
- package/template/src/lib/openapi/operation-doc.ts +308 -70
- package/template/src/lib/openapi/response-content.ts +133 -0
- package/template/src/lib/openapi/schema-variant-labels.ts +213 -0
- package/template/.vscode/extensions.json +0 -4
- package/template/.vscode/launch.json +0 -11
- package/template/scripts/generate-og-images.mjs +0 -667
- package/template/scripts/generate-og-metadata.mjs +0 -206
- package/template/scripts/generate-proxy-allowed-origins.mjs +0 -48
- package/template/scripts/generate-robots-txt.mjs +0 -47
- package/template/scripts/publish-shiki-platform-assets.mjs +0 -1177
- package/template/scripts/remove-assistant-for-non-pro.mjs +0 -28
- package/template/scripts/stamp-image-versions.mjs +0 -355
- package/template/scripts/stamp-og-image-versions.mjs +0 -199
- package/template/scripts/stamp-pagefind-runtime-version.mjs +0 -140
|
@@ -8,9 +8,16 @@ interface Props {
|
|
|
8
8
|
requestPart: string;
|
|
9
9
|
scopeExpr?: string;
|
|
10
10
|
defaultsEnabledExpr?: string;
|
|
11
|
+
requiredEnabledExpr?: string;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
field,
|
|
16
|
+
requestPart,
|
|
17
|
+
scopeExpr,
|
|
18
|
+
defaultsEnabledExpr,
|
|
19
|
+
requiredEnabledExpr,
|
|
20
|
+
} = Astro.props;
|
|
14
21
|
|
|
15
22
|
function cloneDefaultTemplate<T>(value: T): T {
|
|
16
23
|
if (value === undefined) return value;
|
|
@@ -49,6 +56,16 @@ function mergeObjectDefaults(
|
|
|
49
56
|
});
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
function isObjectLikeOpenApiField(field: FieldType): boolean {
|
|
60
|
+
return (
|
|
61
|
+
field.isAdditionalProperty === true ||
|
|
62
|
+
Boolean(field.nested && field.nested.length > 0) ||
|
|
63
|
+
Boolean(field.variants && field.variants.length > 0) ||
|
|
64
|
+
Boolean(field.valueVariants && field.valueVariants.length > 0) ||
|
|
65
|
+
/\bobject\b/.test(field.type)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
52
69
|
function buildVariantDefaultTemplate(field: FieldType): Record<string, unknown> {
|
|
53
70
|
const variants = field.variants || [];
|
|
54
71
|
if (variants.length === 0) return {};
|
|
@@ -107,17 +124,34 @@ function buildFieldDefaultTemplate(field: FieldType): unknown | undefined {
|
|
|
107
124
|
return Object.keys(objectDefaults).length > 0 ? objectDefaults : undefined;
|
|
108
125
|
}
|
|
109
126
|
|
|
127
|
+
function buildFieldInitialValue(field: FieldType): unknown {
|
|
128
|
+
if (field.hasDefault) {
|
|
129
|
+
return cloneDefaultTemplate(field.defaultValue);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (field.isArray) return [];
|
|
133
|
+
if (isObjectLikeOpenApiField(field)) return {};
|
|
134
|
+
return "";
|
|
135
|
+
}
|
|
136
|
+
|
|
110
137
|
const requestPartKey = JSON.stringify(requestPart);
|
|
111
138
|
const fieldNameKey = JSON.stringify(field.name);
|
|
112
139
|
const defaultScopeExpr = `inputs[${requestPartKey}]`;
|
|
113
140
|
const resolvedScopeExpr = scopeExpr || defaultScopeExpr;
|
|
114
141
|
const resolvedDefaultsEnabledExpr = defaultsEnabledExpr || "true";
|
|
142
|
+
const resolvedRequiredEnabledExpr =
|
|
143
|
+
requiredEnabledExpr || resolvedDefaultsEnabledExpr;
|
|
115
144
|
const fieldModelExpr = `${resolvedScopeExpr}[${fieldNameKey}]`;
|
|
116
145
|
const isNumericType = /\b(number|integer)\b/.test(field.type);
|
|
117
146
|
const isIntegerType = /\binteger\b/.test(field.type);
|
|
118
147
|
const hasStringType = /\bstring\b/.test(field.type);
|
|
119
148
|
const isBooleanType = /\bboolean\b/.test(field.type);
|
|
120
|
-
const
|
|
149
|
+
const isFileInput = field.isFile === true;
|
|
150
|
+
const inputType = isFileInput
|
|
151
|
+
? "file"
|
|
152
|
+
: isNumericType && !hasStringType
|
|
153
|
+
? "number"
|
|
154
|
+
: "text";
|
|
121
155
|
const isRequiredField = field.required === true;
|
|
122
156
|
const stringMinLength =
|
|
123
157
|
typeof field.minLength === "number" &&
|
|
@@ -193,13 +227,35 @@ const stringMaxLengthLiteral =
|
|
|
193
227
|
stringMaxLength !== undefined ? JSON.stringify(stringMaxLength) : "undefined";
|
|
194
228
|
const hasNestedFields = Boolean(field.nested && field.nested.length > 0);
|
|
195
229
|
const hasFieldVariants = Boolean(field.variants && field.variants.length > 0);
|
|
230
|
+
const valueVariants = field.valueVariants || [];
|
|
231
|
+
const hasValueVariants = valueVariants.length > 0;
|
|
196
232
|
const hasOneOfVariants = field.variantType === "oneOf" && hasFieldVariants;
|
|
197
233
|
const oneOfVariantFieldKeys = hasOneOfVariants
|
|
198
234
|
? (field.variants || []).map((variant) =>
|
|
199
235
|
(variant.fields || []).map((variantField) => variantField.name),
|
|
200
236
|
)
|
|
201
237
|
: [];
|
|
238
|
+
const oneOfVariantDefaultTemplates = hasOneOfVariants
|
|
239
|
+
? (field.variants || []).map((variant) =>
|
|
240
|
+
buildObjectDefaultTemplateFromFields(variant.fields),
|
|
241
|
+
)
|
|
242
|
+
: [];
|
|
243
|
+
const oneOfVariantDefaultTemplatesJson = JSON.stringify(
|
|
244
|
+
oneOfVariantDefaultTemplates,
|
|
245
|
+
).replaceAll("`", "\\`");
|
|
246
|
+
const valueVariantMeta = valueVariants.map((variant) => ({
|
|
247
|
+
initialValue: buildFieldInitialValue(variant.field),
|
|
248
|
+
isArray: variant.field.isArray === true,
|
|
249
|
+
isObjectLike:
|
|
250
|
+
!variant.field.isArray && isObjectLikeOpenApiField(variant.field),
|
|
251
|
+
type: variant.field.type,
|
|
252
|
+
}));
|
|
253
|
+
const valueVariantMetaJson = JSON.stringify(valueVariantMeta).replaceAll(
|
|
254
|
+
"`",
|
|
255
|
+
"\\`",
|
|
256
|
+
);
|
|
202
257
|
const isAdditionalPropertyField = field.isAdditionalProperty === true;
|
|
258
|
+
const renderAsJsonInput = field.renderAsJson === true && !field.isArray;
|
|
203
259
|
const mapKnownKeys = JSON.stringify(field.mapKnownKeys || []);
|
|
204
260
|
const oneOfVariantFieldKeysJson = JSON.stringify(oneOfVariantFieldKeys);
|
|
205
261
|
const defaultTemplate = buildFieldDefaultTemplate(field);
|
|
@@ -212,15 +268,28 @@ const hasComplexMapValue =
|
|
|
212
268
|
field.isArray ||
|
|
213
269
|
hasNestedFields ||
|
|
214
270
|
hasFieldVariants ||
|
|
271
|
+
hasValueVariants ||
|
|
272
|
+
renderAsJsonInput ||
|
|
215
273
|
/\bobject\b/.test(field.type);
|
|
216
274
|
const isObjectLikeField =
|
|
217
275
|
isAdditionalPropertyField ||
|
|
218
276
|
hasNestedFields ||
|
|
219
277
|
hasFieldVariants ||
|
|
278
|
+
hasValueVariants ||
|
|
220
279
|
/\bobject\b/.test(field.type);
|
|
221
280
|
const layoutClass = isObjectLikeField
|
|
222
281
|
? "flex justify-between flex-col gap-4"
|
|
223
282
|
: "flex justify-between flex-col sm:flex-row lg:flex-col xl:flex-row gap-4";
|
|
283
|
+
const fieldPlaceholder = field.valuePrefix
|
|
284
|
+
? `Enter ${field.valuePrefix.toLowerCase()} token`
|
|
285
|
+
: `Enter ${field.name}`;
|
|
286
|
+
const fieldRequiredExpr = isRequiredField
|
|
287
|
+
? `Boolean(${resolvedRequiredEnabledExpr})`
|
|
288
|
+
: "false";
|
|
289
|
+
const fieldValueGetterExpr = `readFieldValue(() => ${fieldModelExpr})`;
|
|
290
|
+
const childRequiredEnabledExpr = isRequiredField
|
|
291
|
+
? `Boolean(${resolvedRequiredEnabledExpr})`
|
|
292
|
+
: `Boolean(${resolvedRequiredEnabledExpr}) && isRequiredScopeActive(${fieldValueGetterExpr})`;
|
|
224
293
|
---
|
|
225
294
|
|
|
226
295
|
<div
|
|
@@ -245,6 +314,28 @@ const layoutClass = isObjectLikeField
|
|
|
245
314
|
return value;
|
|
246
315
|
}
|
|
247
316
|
},
|
|
317
|
+
readFieldValue(getter) {
|
|
318
|
+
try {
|
|
319
|
+
return getter();
|
|
320
|
+
} catch (e) {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
isRequiredScopeActive(value) {
|
|
325
|
+
if (value === undefined || value === null || value === '') return false;
|
|
326
|
+
|
|
327
|
+
if (Array.isArray(value)) {
|
|
328
|
+
return value.some((item) => this.isRequiredScopeActive(item));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (typeof value === 'object') {
|
|
332
|
+
return Object.values(value).some((item) =>
|
|
333
|
+
this.isRequiredScopeActive(item),
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return true;
|
|
338
|
+
},
|
|
248
339
|
defaultsAreEnabled() {
|
|
249
340
|
try {
|
|
250
341
|
return Boolean(${resolvedDefaultsEnabledExpr});
|
|
@@ -279,8 +370,36 @@ const layoutClass = isObjectLikeField
|
|
|
279
370
|
this.applyInitialDefault();
|
|
280
371
|
},
|
|
281
372
|
oneOfVariantFieldKeys: ${oneOfVariantFieldKeysJson},
|
|
373
|
+
oneOfVariantDefaultTemplates: ${oneOfVariantDefaultTemplatesJson},
|
|
374
|
+
valueVariantMeta: ${valueVariantMetaJson},
|
|
375
|
+
selectedValueVariant: null,
|
|
282
376
|
selectedOneOfVariant: null,
|
|
283
377
|
selectedArrayItemVariants: {},
|
|
378
|
+
arrayValueKeys: [],
|
|
379
|
+
arrayObjectKeys: [],
|
|
380
|
+
createArrayItemKey() {
|
|
381
|
+
return Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);
|
|
382
|
+
},
|
|
383
|
+
syncArrayKeys(keys, length) {
|
|
384
|
+
while (keys.length < length) {
|
|
385
|
+
keys.push(this.createArrayItemKey());
|
|
386
|
+
}
|
|
387
|
+
if (keys.length > length) {
|
|
388
|
+
keys.splice(length);
|
|
389
|
+
}
|
|
390
|
+
return keys;
|
|
391
|
+
},
|
|
392
|
+
getArrayValueKey(index) {
|
|
393
|
+
const values = ${fieldModelExpr};
|
|
394
|
+
const length = Array.isArray(values) ? values.length : 1;
|
|
395
|
+
const keys = this.syncArrayKeys(this.arrayValueKeys, length);
|
|
396
|
+
return keys[index] || String(index);
|
|
397
|
+
},
|
|
398
|
+
getArrayObjectKey(index) {
|
|
399
|
+
const values = this.getArrayObjectValues();
|
|
400
|
+
const keys = this.syncArrayKeys(this.arrayObjectKeys, values.length);
|
|
401
|
+
return keys[index] || String(index);
|
|
402
|
+
},
|
|
284
403
|
ensureFieldObject() {
|
|
285
404
|
this.ensureScopeObject();
|
|
286
405
|
if (
|
|
@@ -330,6 +449,21 @@ const layoutClass = isObjectLikeField
|
|
|
330
449
|
delete target[key];
|
|
331
450
|
});
|
|
332
451
|
},
|
|
452
|
+
applyObjectDefaults(target, defaults, overwrite = false) {
|
|
453
|
+
if (!target || typeof target !== 'object' || Array.isArray(target)) return;
|
|
454
|
+
if (!defaults || typeof defaults !== 'object' || Array.isArray(defaults)) return;
|
|
455
|
+
|
|
456
|
+
Object.entries(defaults).forEach(([key, value]) => {
|
|
457
|
+
if (!overwrite && Object.prototype.hasOwnProperty.call(target, key)) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
target[key] = this.cloneDefaultValue(value);
|
|
461
|
+
});
|
|
462
|
+
},
|
|
463
|
+
applyOneOfVariantDefaults(target, variantIndex, overwrite = false) {
|
|
464
|
+
const defaults = this.oneOfVariantDefaultTemplates[variantIndex];
|
|
465
|
+
this.applyObjectDefaults(target, defaults, overwrite);
|
|
466
|
+
},
|
|
333
467
|
getSelectedOneOfVariant() {
|
|
334
468
|
if (Number.isInteger(this.selectedOneOfVariant)) {
|
|
335
469
|
return this.selectedOneOfVariant;
|
|
@@ -343,6 +477,68 @@ const layoutClass = isObjectLikeField
|
|
|
343
477
|
this.selectedOneOfVariant = variantIndex;
|
|
344
478
|
const target = this.ensureFieldObject();
|
|
345
479
|
this.pruneObjectForOneOf(target, variantIndex);
|
|
480
|
+
this.applyOneOfVariantDefaults(target, variantIndex, true);
|
|
481
|
+
},
|
|
482
|
+
getValueVariantMeta(variantIndex) {
|
|
483
|
+
const meta = this.valueVariantMeta[variantIndex];
|
|
484
|
+
return meta && typeof meta === 'object' ? meta : {};
|
|
485
|
+
},
|
|
486
|
+
isScalarValueVariant(meta) {
|
|
487
|
+
return !meta.isArray && !meta.isObjectLike;
|
|
488
|
+
},
|
|
489
|
+
findValueVariantIndex(predicate) {
|
|
490
|
+
const index = this.valueVariantMeta.findIndex((meta) => predicate(meta));
|
|
491
|
+
return index >= 0 ? index : undefined;
|
|
492
|
+
},
|
|
493
|
+
detectValueVariant(value) {
|
|
494
|
+
if (!Array.isArray(this.valueVariantMeta) || this.valueVariantMeta.length === 0) {
|
|
495
|
+
return 0;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
let matchedIndex;
|
|
499
|
+
if (Array.isArray(value)) {
|
|
500
|
+
matchedIndex = this.findValueVariantIndex((meta) => meta.isArray);
|
|
501
|
+
} else if (value && typeof value === 'object') {
|
|
502
|
+
matchedIndex = this.findValueVariantIndex((meta) => meta.isObjectLike);
|
|
503
|
+
} else if (typeof value === 'boolean') {
|
|
504
|
+
matchedIndex = this.findValueVariantIndex((meta) =>
|
|
505
|
+
String(meta.type || '').includes('boolean'),
|
|
506
|
+
);
|
|
507
|
+
} else if (typeof value === 'number') {
|
|
508
|
+
matchedIndex = this.findValueVariantIndex((meta) =>
|
|
509
|
+
/\b(number|integer)\b/.test(String(meta.type || '')),
|
|
510
|
+
);
|
|
511
|
+
} else {
|
|
512
|
+
matchedIndex = this.findValueVariantIndex((meta) =>
|
|
513
|
+
/\bstring\b/.test(String(meta.type || '')),
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (matchedIndex !== undefined) return matchedIndex;
|
|
518
|
+
matchedIndex = this.findValueVariantIndex((meta) =>
|
|
519
|
+
this.isScalarValueVariant(meta),
|
|
520
|
+
);
|
|
521
|
+
return matchedIndex !== undefined ? matchedIndex : 0;
|
|
522
|
+
},
|
|
523
|
+
cloneValueVariantInitialValue(variantIndex) {
|
|
524
|
+
const initialValue = this.getValueVariantMeta(variantIndex).initialValue;
|
|
525
|
+
return this.cloneDefaultValue(initialValue);
|
|
526
|
+
},
|
|
527
|
+
getSelectedValueVariant() {
|
|
528
|
+
if (Number.isInteger(this.selectedValueVariant)) {
|
|
529
|
+
return this.selectedValueVariant;
|
|
530
|
+
}
|
|
531
|
+
const detected = this.detectValueVariant(${fieldModelExpr});
|
|
532
|
+
this.selectedValueVariant = detected;
|
|
533
|
+
return detected;
|
|
534
|
+
},
|
|
535
|
+
selectValueVariant(variantIndex) {
|
|
536
|
+
this.selectedValueVariant = variantIndex;
|
|
537
|
+
this.ensureScopeObject();
|
|
538
|
+
${fieldModelExpr} = this.cloneValueVariantInitialValue(variantIndex);
|
|
539
|
+
this.arrayValueKeys = [];
|
|
540
|
+
this.arrayObjectKeys = [];
|
|
541
|
+
this.selectedArrayItemVariants = {};
|
|
346
542
|
},
|
|
347
543
|
getSelectedArrayItemVariant(itemIndex) {
|
|
348
544
|
if (Object.prototype.hasOwnProperty.call(this.selectedArrayItemVariants, itemIndex)) {
|
|
@@ -357,6 +553,7 @@ const layoutClass = isObjectLikeField
|
|
|
357
553
|
this.selectedArrayItemVariants[itemIndex] = variantIndex;
|
|
358
554
|
const target = this.ensureArrayObjectItem(itemIndex);
|
|
359
555
|
this.pruneObjectForOneOf(target, variantIndex);
|
|
556
|
+
this.applyOneOfVariantDefaults(target, variantIndex, true);
|
|
360
557
|
},
|
|
361
558
|
shiftArrayItemVariantSelection(removedIndex) {
|
|
362
559
|
const nextSelections = {};
|
|
@@ -405,9 +602,15 @@ const layoutClass = isObjectLikeField
|
|
|
405
602
|
target[mapKey] = this.coerceScalarValue(value);
|
|
406
603
|
this.setScalarValidity(element, value);
|
|
407
604
|
},
|
|
605
|
+
isFileValue(value) {
|
|
606
|
+
return (
|
|
607
|
+
(typeof File !== 'undefined' && value instanceof File) ||
|
|
608
|
+
(typeof Blob !== 'undefined' && value instanceof Blob)
|
|
609
|
+
);
|
|
610
|
+
},
|
|
408
611
|
coerceScalarValue(rawValue) {
|
|
612
|
+
if (this.isFileValue(rawValue)) return rawValue;
|
|
409
613
|
const value = rawValue === undefined || rawValue === null ? '' : String(rawValue).trim();
|
|
410
|
-
if (value === '__clear__') return '';
|
|
411
614
|
if (value === '') return '';
|
|
412
615
|
if (!${isNumericType}) return value;
|
|
413
616
|
|
|
@@ -422,8 +625,12 @@ const layoutClass = isObjectLikeField
|
|
|
422
625
|
},
|
|
423
626
|
setScalarValidity(element, rawValue) {
|
|
424
627
|
if (!element || typeof element.setCustomValidity !== 'function') return;
|
|
628
|
+
if (this.isFileValue(rawValue)) {
|
|
629
|
+
element.setCustomValidity('');
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
425
632
|
const value = rawValue === undefined || rawValue === null ? '' : String(rawValue).trim();
|
|
426
|
-
if (value === ''
|
|
633
|
+
if (value === '') {
|
|
427
634
|
element.setCustomValidity('');
|
|
428
635
|
return;
|
|
429
636
|
}
|
|
@@ -467,11 +674,6 @@ const layoutClass = isObjectLikeField
|
|
|
467
674
|
|
|
468
675
|
element.setCustomValidity('');
|
|
469
676
|
},
|
|
470
|
-
reportFieldValidity(element) {
|
|
471
|
-
if (!element || typeof element.reportValidity !== 'function') return true;
|
|
472
|
-
this.setScalarValidity(element, element.value);
|
|
473
|
-
return element.reportValidity();
|
|
474
|
-
},
|
|
475
677
|
toBooleanOption(value) {
|
|
476
678
|
if (value === true || value === 'true') return 'true';
|
|
477
679
|
if (value === false || value === 'false') return 'false';
|
|
@@ -549,6 +751,51 @@ const layoutClass = isObjectLikeField
|
|
|
549
751
|
// Keep previous valid value while editing invalid JSON.
|
|
550
752
|
}
|
|
551
753
|
},
|
|
754
|
+
getJsonFieldValue() {
|
|
755
|
+
const value = ${fieldModelExpr};
|
|
756
|
+
if (value === undefined || value === null || value === '') return '';
|
|
757
|
+
try {
|
|
758
|
+
return JSON.stringify(value, null, 2);
|
|
759
|
+
} catch (e) {
|
|
760
|
+
return '';
|
|
761
|
+
}
|
|
762
|
+
},
|
|
763
|
+
setJsonFieldValue(jsonValue, element) {
|
|
764
|
+
const raw = String(jsonValue || '');
|
|
765
|
+
this.ensureScopeObject();
|
|
766
|
+
|
|
767
|
+
if (!raw.trim()) {
|
|
768
|
+
delete ${resolvedScopeExpr}[${fieldNameKey}];
|
|
769
|
+
if (element && typeof element.setCustomValidity === 'function') {
|
|
770
|
+
element.setCustomValidity('');
|
|
771
|
+
}
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
try {
|
|
776
|
+
const parsed = JSON.parse(raw);
|
|
777
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
778
|
+
if (element && typeof element.setCustomValidity === 'function') {
|
|
779
|
+
element.setCustomValidity('Enter a JSON object.');
|
|
780
|
+
}
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
${fieldModelExpr} = parsed;
|
|
785
|
+
if (element && typeof element.setCustomValidity === 'function') {
|
|
786
|
+
element.setCustomValidity('');
|
|
787
|
+
}
|
|
788
|
+
} catch (e) {
|
|
789
|
+
if (element && typeof element.setCustomValidity === 'function') {
|
|
790
|
+
element.setCustomValidity('Enter valid JSON.');
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
formatJsonFieldValue(element) {
|
|
795
|
+
if (!element || typeof element.value !== 'string') return;
|
|
796
|
+
if (element.validationMessage) return;
|
|
797
|
+
element.value = this.getJsonFieldValue();
|
|
798
|
+
},
|
|
552
799
|
getFieldValue() {
|
|
553
800
|
const value = ${fieldModelExpr};
|
|
554
801
|
return value === undefined || value === null ? '' : value;
|
|
@@ -558,6 +805,10 @@ const layoutClass = isObjectLikeField
|
|
|
558
805
|
${fieldModelExpr} = this.coerceScalarValue(value);
|
|
559
806
|
this.setScalarValidity(element, value);
|
|
560
807
|
},
|
|
808
|
+
clearFieldValue() {
|
|
809
|
+
this.ensureScopeObject();
|
|
810
|
+
delete ${resolvedScopeExpr}[${fieldNameKey}];
|
|
811
|
+
},
|
|
561
812
|
ensureArrayField() {
|
|
562
813
|
this.ensureScopeObject();
|
|
563
814
|
if (!Array.isArray(${fieldModelExpr})) {
|
|
@@ -567,7 +818,7 @@ const layoutClass = isObjectLikeField
|
|
|
567
818
|
},
|
|
568
819
|
getArrayValues() {
|
|
569
820
|
const values = ${fieldModelExpr};
|
|
570
|
-
return Array.isArray(values)
|
|
821
|
+
return Array.isArray(values) ? values : [''];
|
|
571
822
|
},
|
|
572
823
|
setArrayValue(index, value, element) {
|
|
573
824
|
const values = this.ensureArrayField();
|
|
@@ -575,20 +826,34 @@ const layoutClass = isObjectLikeField
|
|
|
575
826
|
this.setScalarValidity(element, value);
|
|
576
827
|
},
|
|
577
828
|
addArrayValue() {
|
|
829
|
+
const hadArray = Array.isArray(${fieldModelExpr});
|
|
578
830
|
const values = this.ensureArrayField();
|
|
579
|
-
if (
|
|
831
|
+
if (!hadArray) {
|
|
832
|
+
this.arrayValueKeys = [];
|
|
833
|
+
}
|
|
834
|
+
if (values.length === 0 && !hadArray) {
|
|
580
835
|
values.push('', '');
|
|
836
|
+
this.syncArrayKeys(this.arrayValueKeys, values.length);
|
|
581
837
|
return;
|
|
582
838
|
}
|
|
583
839
|
values.push('');
|
|
840
|
+
this.syncArrayKeys(this.arrayValueKeys, values.length);
|
|
584
841
|
},
|
|
585
842
|
removeArrayValue(index) {
|
|
586
843
|
const values = ${fieldModelExpr};
|
|
587
|
-
if (!Array.isArray(values))
|
|
844
|
+
if (!Array.isArray(values)) {
|
|
845
|
+
this.ensureScopeObject();
|
|
846
|
+
${fieldModelExpr} = [];
|
|
847
|
+
this.arrayValueKeys = [];
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
588
850
|
values.splice(index, 1);
|
|
851
|
+
this.arrayValueKeys.splice(index, 1);
|
|
589
852
|
if (values.length === 0) {
|
|
590
|
-
|
|
853
|
+
this.ensureScopeObject();
|
|
854
|
+
${fieldModelExpr} = [];
|
|
591
855
|
}
|
|
856
|
+
this.syncArrayKeys(this.arrayValueKeys, values.length);
|
|
592
857
|
},
|
|
593
858
|
getArrayObjectValues() {
|
|
594
859
|
const values = ${fieldModelExpr};
|
|
@@ -608,15 +873,19 @@ const layoutClass = isObjectLikeField
|
|
|
608
873
|
addArrayObjectValue() {
|
|
609
874
|
const values = this.ensureArrayField();
|
|
610
875
|
values.push({});
|
|
876
|
+
this.syncArrayKeys(this.arrayObjectKeys, values.length);
|
|
611
877
|
},
|
|
612
878
|
removeArrayObjectValue(index) {
|
|
613
879
|
const values = ${fieldModelExpr};
|
|
614
880
|
if (!Array.isArray(values)) return;
|
|
615
881
|
values.splice(index, 1);
|
|
882
|
+
this.arrayObjectKeys.splice(index, 1);
|
|
616
883
|
this.shiftArrayItemVariantSelection(index);
|
|
617
884
|
if (values.length === 0) {
|
|
618
|
-
|
|
885
|
+
this.ensureScopeObject();
|
|
886
|
+
${fieldModelExpr} = [];
|
|
619
887
|
}
|
|
888
|
+
this.syncArrayKeys(this.arrayObjectKeys, values.length);
|
|
620
889
|
}
|
|
621
890
|
}`}
|
|
622
891
|
x-effect="applyInitialDefault()"
|
|
@@ -638,7 +907,56 @@ const layoutClass = isObjectLikeField
|
|
|
638
907
|
</div>
|
|
639
908
|
<div class="w-full">
|
|
640
909
|
{
|
|
641
|
-
|
|
910
|
+
hasValueVariants ? (
|
|
911
|
+
<div class="rounded-lg border border-neutral-200 bg-neutral-50/50 p-2.5 dark:border-neutral-800 dark:bg-neutral-900/50">
|
|
912
|
+
<div class="space-y-3">
|
|
913
|
+
<div class="space-y-1.5">
|
|
914
|
+
<p class="text-xs text-neutral-500 dark:text-neutral-400">
|
|
915
|
+
Select value type.
|
|
916
|
+
</p>
|
|
917
|
+
<div class="inline-flex max-w-full flex-wrap items-center gap-1 rounded-lg bg-neutral-100 p-1 dark:bg-neutral-900/60">
|
|
918
|
+
{valueVariants.map((variant, variantIndex) => (
|
|
919
|
+
<button
|
|
920
|
+
type="button"
|
|
921
|
+
@click={`selectValueVariant(${variantIndex})`}
|
|
922
|
+
:class={`{
|
|
923
|
+
'bg-white text-neutral-900 shadow-xs ring-1 ring-neutral-200 dark:bg-(--rd-code-surface) dark:text-neutral-100 dark:ring-neutral-700/70': getSelectedValueVariant() === ${variantIndex},
|
|
924
|
+
'text-neutral-600 hover:bg-neutral-50 hover:text-neutral-800 dark:text-neutral-400 dark:hover:bg-neutral-800/70 dark:hover:text-neutral-200': getSelectedValueVariant() !== ${variantIndex}
|
|
925
|
+
}`}
|
|
926
|
+
class="inline-flex h-7 items-center justify-center whitespace-nowrap rounded-md px-2.5 text-[11px] font-medium transition-all duration-200 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-300 dark:focus-visible:ring-neutral-700"
|
|
927
|
+
>
|
|
928
|
+
{variant.label}
|
|
929
|
+
</button>
|
|
930
|
+
))}
|
|
931
|
+
</div>
|
|
932
|
+
</div>
|
|
933
|
+
{valueVariants.map((variant, variantIndex) => (
|
|
934
|
+
<template x-if={`getSelectedValueVariant() === ${variantIndex}`}>
|
|
935
|
+
<div class="rounded-md border border-neutral-200 bg-white p-2.5 dark:border-neutral-800 dark:bg-neutral-900/60">
|
|
936
|
+
<Astro.self
|
|
937
|
+
field={variant.field}
|
|
938
|
+
requestPart={requestPart}
|
|
939
|
+
scopeExpr={resolvedScopeExpr}
|
|
940
|
+
defaultsEnabledExpr={resolvedDefaultsEnabledExpr}
|
|
941
|
+
requiredEnabledExpr={resolvedRequiredEnabledExpr}
|
|
942
|
+
/>
|
|
943
|
+
</div>
|
|
944
|
+
</template>
|
|
945
|
+
))}
|
|
946
|
+
</div>
|
|
947
|
+
</div>
|
|
948
|
+
) : renderAsJsonInput ? (
|
|
949
|
+
<textarea
|
|
950
|
+
name={`${requestPart}_${field.name}`}
|
|
951
|
+
rows="8"
|
|
952
|
+
:value="getJsonFieldValue()"
|
|
953
|
+
@input="setJsonFieldValue($event.target.value, $event.target)"
|
|
954
|
+
@blur="formatJsonFieldValue($event.target)"
|
|
955
|
+
:required={fieldRequiredExpr}
|
|
956
|
+
class="w-full px-3 py-2 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow placeholder:text-neutral-400 transition-all duration-200 bg-white font-mono dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200 dark:placeholder:text-neutral-500 dark:focus:border-neutral-600"
|
|
957
|
+
placeholder={`{\n "type": "object",\n "properties": {}\n}`}
|
|
958
|
+
/>
|
|
959
|
+
) : isAdditionalPropertyField ? (
|
|
642
960
|
<div class="space-y-2">
|
|
643
961
|
<template
|
|
644
962
|
x-for={`(mapKey, mapIndex) in getMapEntryKeys()`}
|
|
@@ -680,7 +998,6 @@ const layoutClass = isObjectLikeField
|
|
|
680
998
|
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow transition-all duration-200 bg-white appearance-none dark:border-neutral-700 dark:bg-neutral-900 dark:focus:border-neutral-600"
|
|
681
999
|
>
|
|
682
1000
|
<option value="" disabled hidden>Select value</option>
|
|
683
|
-
<option value="__clear__">Clear selection</option>
|
|
684
1001
|
{field.enum.map((value) => (
|
|
685
1002
|
<option value={String(value)}>{value}</option>
|
|
686
1003
|
))}
|
|
@@ -699,7 +1016,6 @@ const layoutClass = isObjectLikeField
|
|
|
699
1016
|
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow transition-all duration-200 bg-white appearance-none dark:border-neutral-700 dark:bg-neutral-900 dark:focus:border-neutral-600"
|
|
700
1017
|
>
|
|
701
1018
|
<option value="" disabled hidden>Select value</option>
|
|
702
|
-
<option value="__clear__">Clear selection</option>
|
|
703
1019
|
<option value="true">true</option>
|
|
704
1020
|
<option value="false">false</option>
|
|
705
1021
|
</select>
|
|
@@ -713,7 +1029,7 @@ const layoutClass = isObjectLikeField
|
|
|
713
1029
|
type={inputType}
|
|
714
1030
|
:value="getMapValue(mapKey)"
|
|
715
1031
|
@input="setMapValue(mapKey, $event.target.value, $event.target)"
|
|
716
|
-
@blur="
|
|
1032
|
+
@blur="setScalarValidity($event.target, $event.target.value)"
|
|
717
1033
|
min={numericInputMin}
|
|
718
1034
|
max={numericInputMax}
|
|
719
1035
|
step={numericInputStep}
|
|
@@ -740,10 +1056,10 @@ const layoutClass = isObjectLikeField
|
|
|
740
1056
|
<div class="space-y-2">
|
|
741
1057
|
<template
|
|
742
1058
|
x-for={`(item, index) in getArrayObjectValues()`}
|
|
743
|
-
:key={
|
|
1059
|
+
:key={`getArrayObjectKey(index)`}
|
|
744
1060
|
>
|
|
745
1061
|
<div
|
|
746
|
-
class="rounded-
|
|
1062
|
+
class="overflow-hidden rounded-xl border-[0.5px] border-neutral-900/12 bg-neutral-50/50 p-3 shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] transition-colors duration-200 dark:border-white/6 dark:bg-(--rd-code-surface) dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]"
|
|
747
1063
|
x-init="ensureArrayObjectItem(index)"
|
|
748
1064
|
>
|
|
749
1065
|
<div class="mb-2 flex items-center justify-between">
|
|
@@ -765,8 +1081,9 @@ const layoutClass = isObjectLikeField
|
|
|
765
1081
|
<Astro.self
|
|
766
1082
|
field={nestedField}
|
|
767
1083
|
requestPart={requestPart}
|
|
768
|
-
scopeExpr=
|
|
1084
|
+
scopeExpr="item"
|
|
769
1085
|
defaultsEnabledExpr={resolvedDefaultsEnabledExpr}
|
|
1086
|
+
requiredEnabledExpr={resolvedRequiredEnabledExpr}
|
|
770
1087
|
/>
|
|
771
1088
|
</div>
|
|
772
1089
|
))}
|
|
@@ -807,8 +1124,9 @@ const layoutClass = isObjectLikeField
|
|
|
807
1124
|
<Astro.self
|
|
808
1125
|
field={variantField}
|
|
809
1126
|
requestPart={requestPart}
|
|
810
|
-
scopeExpr=
|
|
1127
|
+
scopeExpr="item"
|
|
811
1128
|
defaultsEnabledExpr={`(${resolvedDefaultsEnabledExpr}) && getSelectedArrayItemVariant(index) === ${variantIndex}`}
|
|
1129
|
+
requiredEnabledExpr={`(${resolvedRequiredEnabledExpr}) && getSelectedArrayItemVariant(index) === ${variantIndex}`}
|
|
812
1130
|
/>
|
|
813
1131
|
</div>
|
|
814
1132
|
))}
|
|
@@ -833,8 +1151,9 @@ const layoutClass = isObjectLikeField
|
|
|
833
1151
|
<Astro.self
|
|
834
1152
|
field={variantField}
|
|
835
1153
|
requestPart={requestPart}
|
|
836
|
-
scopeExpr=
|
|
1154
|
+
scopeExpr="item"
|
|
837
1155
|
defaultsEnabledExpr={resolvedDefaultsEnabledExpr}
|
|
1156
|
+
requiredEnabledExpr={resolvedRequiredEnabledExpr}
|
|
838
1157
|
/>
|
|
839
1158
|
</div>
|
|
840
1159
|
))}
|
|
@@ -859,7 +1178,7 @@ const layoutClass = isObjectLikeField
|
|
|
859
1178
|
</div>
|
|
860
1179
|
) : (
|
|
861
1180
|
<div class="space-y-2">
|
|
862
|
-
<template x-for={`(value, index) in getArrayValues()`} :key={
|
|
1181
|
+
<template x-for={`(value, index) in getArrayValues()`} :key={`getArrayValueKey(index)`}>
|
|
863
1182
|
<div class="flex items-center gap-2">
|
|
864
1183
|
{
|
|
865
1184
|
field.enum && field.enum.length > 0 ? (
|
|
@@ -868,12 +1187,11 @@ const layoutClass = isObjectLikeField
|
|
|
868
1187
|
name={`${requestPart}_${field.name}`}
|
|
869
1188
|
:value="value"
|
|
870
1189
|
@change={`setArrayValue(index, $event.target.value, $event.target)`}
|
|
871
|
-
:required={`index === 0 && ${
|
|
1190
|
+
:required={`index === 0 && (${fieldRequiredExpr})`}
|
|
872
1191
|
:class="value ? 'text-neutral-700 dark:text-neutral-200' : 'text-neutral-400 dark:text-neutral-500'"
|
|
873
1192
|
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow transition-all duration-200 bg-white appearance-none dark:border-neutral-700 dark:bg-neutral-900 dark:focus:border-neutral-600"
|
|
874
1193
|
>
|
|
875
1194
|
<option value="" disabled hidden>Select value</option>
|
|
876
|
-
<option value="__clear__">Clear selection</option>
|
|
877
1195
|
{field.enum.map((value) => (
|
|
878
1196
|
<option value={String(value)}>{value}</option>
|
|
879
1197
|
))}
|
|
@@ -890,12 +1208,11 @@ const layoutClass = isObjectLikeField
|
|
|
890
1208
|
name={`${requestPart}_${field.name}`}
|
|
891
1209
|
:value="getArrayBooleanValue(index)"
|
|
892
1210
|
@change={`setArrayBooleanValue(index, $event.target.value)`}
|
|
893
|
-
:required={`index === 0 && ${
|
|
1211
|
+
:required={`index === 0 && (${fieldRequiredExpr})`}
|
|
894
1212
|
:class="getArrayBooleanValue(index) ? 'text-neutral-700 dark:text-neutral-200' : 'text-neutral-400 dark:text-neutral-500'"
|
|
895
1213
|
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow transition-all duration-200 bg-white appearance-none dark:border-neutral-700 dark:bg-neutral-900 dark:focus:border-neutral-600"
|
|
896
1214
|
>
|
|
897
1215
|
<option value="" disabled hidden>Select value</option>
|
|
898
|
-
<option value="__clear__">Clear selection</option>
|
|
899
1216
|
<option value="true">true</option>
|
|
900
1217
|
<option value="false">false</option>
|
|
901
1218
|
</select>
|
|
@@ -904,15 +1221,23 @@ const layoutClass = isObjectLikeField
|
|
|
904
1221
|
name="lucide:chevrons-up-down"
|
|
905
1222
|
/>
|
|
906
1223
|
</div>
|
|
1224
|
+
) : isFileInput ? (
|
|
1225
|
+
<input
|
|
1226
|
+
name={field.name}
|
|
1227
|
+
type="file"
|
|
1228
|
+
@change={`setArrayValue(index, $event.target.files?.[0] || '', $event.target)`}
|
|
1229
|
+
:required={`index === 0 && (${fieldRequiredExpr})`}
|
|
1230
|
+
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow file:mr-3 file:rounded-md file:border-0 file:bg-neutral-100 file:px-2.5 file:py-1 file:text-xs file:font-medium file:text-neutral-700 transition-all duration-200 bg-white dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200 dark:file:bg-neutral-800 dark:file:text-neutral-200 dark:focus:border-neutral-600"
|
|
1231
|
+
/>
|
|
907
1232
|
) : (
|
|
908
1233
|
<input
|
|
909
1234
|
name={field.name}
|
|
910
|
-
placeholder={
|
|
1235
|
+
placeholder={fieldPlaceholder}
|
|
911
1236
|
type={inputType}
|
|
912
1237
|
:value="value"
|
|
913
1238
|
@input={`setArrayValue(index, $event.target.value, $event.target)`}
|
|
914
|
-
@blur="
|
|
915
|
-
:required={`index === 0 && ${
|
|
1239
|
+
@blur="setScalarValidity($event.target, $event.target.value)"
|
|
1240
|
+
:required={`index === 0 && (${fieldRequiredExpr})`}
|
|
916
1241
|
min={numericInputMin}
|
|
917
1242
|
max={numericInputMax}
|
|
918
1243
|
step={numericInputStep}
|
|
@@ -953,6 +1278,7 @@ const layoutClass = isObjectLikeField
|
|
|
953
1278
|
requestPart={requestPart}
|
|
954
1279
|
scopeExpr={fieldModelExpr}
|
|
955
1280
|
defaultsEnabledExpr={resolvedDefaultsEnabledExpr}
|
|
1281
|
+
requiredEnabledExpr={childRequiredEnabledExpr}
|
|
956
1282
|
/>
|
|
957
1283
|
</div>
|
|
958
1284
|
))}
|
|
@@ -995,6 +1321,7 @@ const layoutClass = isObjectLikeField
|
|
|
995
1321
|
requestPart={requestPart}
|
|
996
1322
|
scopeExpr={fieldModelExpr}
|
|
997
1323
|
defaultsEnabledExpr={`(${resolvedDefaultsEnabledExpr}) && getSelectedOneOfVariant() === ${variantIndex}`}
|
|
1324
|
+
requiredEnabledExpr={`(${childRequiredEnabledExpr}) && getSelectedOneOfVariant() === ${variantIndex}`}
|
|
998
1325
|
/>
|
|
999
1326
|
</div>
|
|
1000
1327
|
))}
|
|
@@ -1021,6 +1348,7 @@ const layoutClass = isObjectLikeField
|
|
|
1021
1348
|
requestPart={requestPart}
|
|
1022
1349
|
scopeExpr={fieldModelExpr}
|
|
1023
1350
|
defaultsEnabledExpr={resolvedDefaultsEnabledExpr}
|
|
1351
|
+
requiredEnabledExpr={childRequiredEnabledExpr}
|
|
1024
1352
|
/>
|
|
1025
1353
|
</div>
|
|
1026
1354
|
))}
|
|
@@ -1036,55 +1364,89 @@ const layoutClass = isObjectLikeField
|
|
|
1036
1364
|
) : (
|
|
1037
1365
|
<>
|
|
1038
1366
|
{field.enum && field.enum.length > 0 ? (
|
|
1039
|
-
<div class="
|
|
1040
|
-
<
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1367
|
+
<div class="flex items-center gap-2">
|
|
1368
|
+
<div class="relative w-full">
|
|
1369
|
+
<select
|
|
1370
|
+
name={`${requestPart}_${field.name}`}
|
|
1371
|
+
:value="getFieldValue()"
|
|
1372
|
+
@change="setFieldValue($event.target.value, $event.target)"
|
|
1373
|
+
:required={fieldRequiredExpr}
|
|
1374
|
+
:class="getFieldValue() ? 'text-neutral-700 dark:text-neutral-200' : 'text-neutral-400 dark:text-neutral-500'"
|
|
1375
|
+
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow transition-all duration-200 bg-white appearance-none dark:border-neutral-700 dark:bg-neutral-900 dark:focus:border-neutral-600"
|
|
1376
|
+
>
|
|
1377
|
+
<option value="" disabled hidden>Select value</option>
|
|
1378
|
+
{field.enum.map((value) => (
|
|
1379
|
+
<option value={String(value)}>{value}</option>
|
|
1380
|
+
))}
|
|
1381
|
+
</select>
|
|
1382
|
+
<Icon
|
|
1383
|
+
class="absolute right-3 top-1/2 -translate-y-1/2 size-4 pointer-events-none text-neutral-400"
|
|
1384
|
+
name="lucide:chevrons-up-down"
|
|
1385
|
+
/>
|
|
1386
|
+
</div>
|
|
1387
|
+
{!isRequiredField && (
|
|
1388
|
+
<button
|
|
1389
|
+
type="button"
|
|
1390
|
+
@click="clearFieldValue()"
|
|
1391
|
+
x-show="getFieldValue()"
|
|
1392
|
+
x-cloak
|
|
1393
|
+
class="h-[31px] px-2 rounded-md border border-neutral-200 text-neutral-500 hover:text-neutral-700 hover:border-neutral-300 hover:bg-neutral-50 transition-colors duration-200 cursor-pointer dark:border-neutral-700 dark:text-neutral-400 dark:hover:border-neutral-600 dark:hover:bg-neutral-800/70 dark:hover:text-neutral-200"
|
|
1394
|
+
aria-label={`Clear ${field.name}`}
|
|
1395
|
+
>
|
|
1396
|
+
<Icon class="size-4" name="lucide:x" />
|
|
1397
|
+
</button>
|
|
1398
|
+
)}
|
|
1058
1399
|
</div>
|
|
1059
1400
|
) : isBooleanType ? (
|
|
1060
|
-
<div class="
|
|
1061
|
-
<
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1401
|
+
<div class="flex items-center gap-2">
|
|
1402
|
+
<div class="relative w-full">
|
|
1403
|
+
<select
|
|
1404
|
+
name={`${requestPart}_${field.name}`}
|
|
1405
|
+
:value="getBooleanFieldValue()"
|
|
1406
|
+
@change="setBooleanFieldValue($event.target.value)"
|
|
1407
|
+
:required={fieldRequiredExpr}
|
|
1408
|
+
:class="getBooleanFieldValue() ? 'text-neutral-700 dark:text-neutral-200' : 'text-neutral-400 dark:text-neutral-500'"
|
|
1409
|
+
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow transition-all duration-200 bg-white appearance-none dark:border-neutral-700 dark:bg-neutral-900 dark:focus:border-neutral-600"
|
|
1410
|
+
>
|
|
1411
|
+
<option value="" disabled hidden>Select value</option>
|
|
1412
|
+
<option value="true">true</option>
|
|
1413
|
+
<option value="false">false</option>
|
|
1414
|
+
</select>
|
|
1415
|
+
<Icon
|
|
1416
|
+
class="absolute right-3 top-1/2 -translate-y-1/2 size-4 pointer-events-none text-neutral-400"
|
|
1417
|
+
name="lucide:chevrons-up-down"
|
|
1418
|
+
/>
|
|
1419
|
+
</div>
|
|
1420
|
+
{!isRequiredField && (
|
|
1421
|
+
<button
|
|
1422
|
+
type="button"
|
|
1423
|
+
@click="clearFieldValue()"
|
|
1424
|
+
x-show="getBooleanFieldValue()"
|
|
1425
|
+
x-cloak
|
|
1426
|
+
class="h-[31px] px-2 rounded-md border border-neutral-200 text-neutral-500 hover:text-neutral-700 hover:border-neutral-300 hover:bg-neutral-50 transition-colors duration-200 cursor-pointer dark:border-neutral-700 dark:text-neutral-400 dark:hover:border-neutral-600 dark:hover:bg-neutral-800/70 dark:hover:text-neutral-200"
|
|
1427
|
+
aria-label={`Clear ${field.name}`}
|
|
1428
|
+
>
|
|
1429
|
+
<Icon class="size-4" name="lucide:x" />
|
|
1430
|
+
</button>
|
|
1431
|
+
)}
|
|
1078
1432
|
</div>
|
|
1433
|
+
) : isFileInput ? (
|
|
1434
|
+
<input
|
|
1435
|
+
name={field.name}
|
|
1436
|
+
type="file"
|
|
1437
|
+
@change="setFieldValue($event.target.files?.[0] || '', $event.target)"
|
|
1438
|
+
:required={fieldRequiredExpr}
|
|
1439
|
+
class="w-full px-3 py-1.5 text-sm border border-neutral-200 focus:border-neutral-300 outline-none rounded-md shadow-xs focus:shadow file:mr-3 file:rounded-md file:border-0 file:bg-neutral-100 file:px-2.5 file:py-1 file:text-xs file:font-medium file:text-neutral-700 transition-all duration-200 bg-white dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200 dark:file:bg-neutral-800 dark:file:text-neutral-200 dark:focus:border-neutral-600"
|
|
1440
|
+
/>
|
|
1079
1441
|
) : (
|
|
1080
1442
|
<input
|
|
1081
1443
|
name={field.name}
|
|
1082
|
-
placeholder={
|
|
1444
|
+
placeholder={fieldPlaceholder}
|
|
1083
1445
|
type={inputType}
|
|
1084
1446
|
:value="getFieldValue()"
|
|
1085
1447
|
@input="setFieldValue($event.target.value, $event.target)"
|
|
1086
|
-
@blur="
|
|
1087
|
-
required={
|
|
1448
|
+
@blur="setScalarValidity($event.target, $event.target.value)"
|
|
1449
|
+
:required={fieldRequiredExpr}
|
|
1088
1450
|
min={numericInputMin}
|
|
1089
1451
|
max={numericInputMax}
|
|
1090
1452
|
step={numericInputStep}
|