@shwfed/nuxt 0.9.2 → 0.10.1

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.
@@ -1,17 +1,20 @@
1
1
  import { Effect } from 'effect';
2
- export { CalendarFieldC, FieldC, FieldsConfigC, NumberFieldC, SelectFieldC, StringFieldC, ValidationRuleC, validationC, } from './schema.js';
3
- export type { Field, FieldsConfig, ValidationRule } from './schema.js';
2
+ import type { CSSProperties } from 'vue';
3
+ export { CalendarFieldC, EmptyFieldC, FieldC, FieldsConfigC, NumberFieldC, SelectFieldC, SlotFieldC, StringFieldC, ValidationRuleC, validationC, } from './schema.js';
4
+ export type { EmptyField, Field, FieldsConfig, SlotField, ValidationRule } from './schema.js';
4
5
  declare const _default: typeof __VLS_export;
5
6
  export default _default;
6
7
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
7
8
  config: Effect.Effect<Readonly<{
8
9
  fields: readonly ({
10
+ id: string;
9
11
  type: "string";
10
12
  path: string;
11
13
  title: readonly {
12
14
  locale: "zh" | "ja" | "en" | "ko";
13
15
  message: string;
14
16
  }[];
17
+ required?: boolean | undefined;
15
18
  icon?: string | undefined;
16
19
  style?: string | undefined;
17
20
  discardEmptyString?: boolean | undefined;
@@ -23,12 +26,33 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
23
26
  message: string;
24
27
  }>[] | undefined;
25
28
  } | {
29
+ id: string;
30
+ type: "textarea";
31
+ path: string;
32
+ title: readonly {
33
+ locale: "zh" | "ja" | "en" | "ko";
34
+ message: string;
35
+ }[];
36
+ required?: boolean | undefined;
37
+ icon?: string | undefined;
38
+ style?: string | undefined;
39
+ discardEmptyString?: boolean | undefined;
40
+ maxLength?: string | undefined;
41
+ hidden?: string | undefined;
42
+ disabled?: string | undefined;
43
+ validation?: readonly Readonly<{
44
+ expression: string;
45
+ message: string;
46
+ }>[] | undefined;
47
+ } | {
48
+ id: string;
26
49
  type: "number";
27
50
  path: string;
28
51
  title: readonly {
29
52
  locale: "zh" | "ja" | "en" | "ko";
30
53
  message: string;
31
54
  }[];
55
+ required?: boolean | undefined;
32
56
  icon?: string | undefined;
33
57
  style?: string | undefined;
34
58
  min?: string | undefined;
@@ -41,6 +65,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
41
65
  message: string;
42
66
  }>[] | undefined;
43
67
  } | {
68
+ id: string;
44
69
  type: "select";
45
70
  path: string;
46
71
  title: readonly {
@@ -51,6 +76,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
51
76
  label: string;
52
77
  value: string;
53
78
  key: string;
79
+ required?: boolean | undefined;
54
80
  icon?: string | undefined;
55
81
  style?: string | undefined;
56
82
  hidden?: string | undefined;
@@ -60,6 +86,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
60
86
  message: string;
61
87
  }>[] | undefined;
62
88
  } | {
89
+ id: string;
63
90
  type: "calendar";
64
91
  path: string;
65
92
  title: readonly {
@@ -68,6 +95,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
68
95
  }[];
69
96
  mode: "date" | "month" | "year";
70
97
  value: string;
98
+ required?: boolean | undefined;
71
99
  icon?: string | undefined;
72
100
  style?: string | undefined;
73
101
  display?: string | undefined;
@@ -78,6 +106,14 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
78
106
  expression: string;
79
107
  message: string;
80
108
  }>[] | undefined;
109
+ } | {
110
+ id: string;
111
+ type: "slot";
112
+ style?: string | undefined;
113
+ } | {
114
+ id: string;
115
+ type: "empty";
116
+ style?: string | undefined;
81
117
  })[];
82
118
  orientation?: "vertical" | "horizontal" | "floating" | undefined;
83
119
  style?: string | undefined;
@@ -88,12 +124,14 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
88
124
  "update:modelValue": (value: Record<string, unknown>) => any;
89
125
  "update:config": (args_0: Readonly<{
90
126
  fields: readonly ({
127
+ id: string;
91
128
  type: "string";
92
129
  path: string;
93
130
  title: readonly {
94
131
  locale: "zh" | "ja" | "en" | "ko";
95
132
  message: string;
96
133
  }[];
134
+ required?: boolean | undefined;
97
135
  icon?: string | undefined;
98
136
  style?: string | undefined;
99
137
  discardEmptyString?: boolean | undefined;
@@ -105,12 +143,33 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
105
143
  message: string;
106
144
  }>[] | undefined;
107
145
  } | {
146
+ id: string;
147
+ type: "textarea";
148
+ path: string;
149
+ title: readonly {
150
+ locale: "zh" | "ja" | "en" | "ko";
151
+ message: string;
152
+ }[];
153
+ required?: boolean | undefined;
154
+ icon?: string | undefined;
155
+ style?: string | undefined;
156
+ discardEmptyString?: boolean | undefined;
157
+ maxLength?: string | undefined;
158
+ hidden?: string | undefined;
159
+ disabled?: string | undefined;
160
+ validation?: readonly Readonly<{
161
+ expression: string;
162
+ message: string;
163
+ }>[] | undefined;
164
+ } | {
165
+ id: string;
108
166
  type: "number";
109
167
  path: string;
110
168
  title: readonly {
111
169
  locale: "zh" | "ja" | "en" | "ko";
112
170
  message: string;
113
171
  }[];
172
+ required?: boolean | undefined;
114
173
  icon?: string | undefined;
115
174
  style?: string | undefined;
116
175
  min?: string | undefined;
@@ -123,6 +182,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
123
182
  message: string;
124
183
  }>[] | undefined;
125
184
  } | {
185
+ id: string;
126
186
  type: "select";
127
187
  path: string;
128
188
  title: readonly {
@@ -133,6 +193,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
133
193
  label: string;
134
194
  value: string;
135
195
  key: string;
196
+ required?: boolean | undefined;
136
197
  icon?: string | undefined;
137
198
  style?: string | undefined;
138
199
  hidden?: string | undefined;
@@ -142,6 +203,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
142
203
  message: string;
143
204
  }>[] | undefined;
144
205
  } | {
206
+ id: string;
145
207
  type: "calendar";
146
208
  path: string;
147
209
  title: readonly {
@@ -150,6 +212,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
150
212
  }[];
151
213
  mode: "date" | "month" | "year";
152
214
  value: string;
215
+ required?: boolean | undefined;
153
216
  icon?: string | undefined;
154
217
  style?: string | undefined;
155
218
  display?: string | undefined;
@@ -160,6 +223,14 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
160
223
  expression: string;
161
224
  message: string;
162
225
  }>[] | undefined;
226
+ } | {
227
+ id: string;
228
+ type: "slot";
229
+ style?: string | undefined;
230
+ } | {
231
+ id: string;
232
+ type: "empty";
233
+ style?: string | undefined;
163
234
  })[];
164
235
  orientation?: "vertical" | "horizontal" | "floating" | undefined;
165
236
  style?: string | undefined;
@@ -167,12 +238,14 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
167
238
  }, string, import("vue").PublicProps, Readonly<{
168
239
  config: Effect.Effect<Readonly<{
169
240
  fields: readonly ({
241
+ id: string;
170
242
  type: "string";
171
243
  path: string;
172
244
  title: readonly {
173
245
  locale: "zh" | "ja" | "en" | "ko";
174
246
  message: string;
175
247
  }[];
248
+ required?: boolean | undefined;
176
249
  icon?: string | undefined;
177
250
  style?: string | undefined;
178
251
  discardEmptyString?: boolean | undefined;
@@ -184,12 +257,33 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
184
257
  message: string;
185
258
  }>[] | undefined;
186
259
  } | {
260
+ id: string;
261
+ type: "textarea";
262
+ path: string;
263
+ title: readonly {
264
+ locale: "zh" | "ja" | "en" | "ko";
265
+ message: string;
266
+ }[];
267
+ required?: boolean | undefined;
268
+ icon?: string | undefined;
269
+ style?: string | undefined;
270
+ discardEmptyString?: boolean | undefined;
271
+ maxLength?: string | undefined;
272
+ hidden?: string | undefined;
273
+ disabled?: string | undefined;
274
+ validation?: readonly Readonly<{
275
+ expression: string;
276
+ message: string;
277
+ }>[] | undefined;
278
+ } | {
279
+ id: string;
187
280
  type: "number";
188
281
  path: string;
189
282
  title: readonly {
190
283
  locale: "zh" | "ja" | "en" | "ko";
191
284
  message: string;
192
285
  }[];
286
+ required?: boolean | undefined;
193
287
  icon?: string | undefined;
194
288
  style?: string | undefined;
195
289
  min?: string | undefined;
@@ -202,6 +296,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
202
296
  message: string;
203
297
  }>[] | undefined;
204
298
  } | {
299
+ id: string;
205
300
  type: "select";
206
301
  path: string;
207
302
  title: readonly {
@@ -212,6 +307,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
212
307
  label: string;
213
308
  value: string;
214
309
  key: string;
310
+ required?: boolean | undefined;
215
311
  icon?: string | undefined;
216
312
  style?: string | undefined;
217
313
  hidden?: string | undefined;
@@ -221,6 +317,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
221
317
  message: string;
222
318
  }>[] | undefined;
223
319
  } | {
320
+ id: string;
224
321
  type: "calendar";
225
322
  path: string;
226
323
  title: readonly {
@@ -229,6 +326,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
229
326
  }[];
230
327
  mode: "date" | "month" | "year";
231
328
  value: string;
329
+ required?: boolean | undefined;
232
330
  icon?: string | undefined;
233
331
  style?: string | undefined;
234
332
  display?: string | undefined;
@@ -239,6 +337,14 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
239
337
  expression: string;
240
338
  message: string;
241
339
  }>[] | undefined;
340
+ } | {
341
+ id: string;
342
+ type: "slot";
343
+ style?: string | undefined;
344
+ } | {
345
+ id: string;
346
+ type: "empty";
347
+ style?: string | undefined;
242
348
  })[];
243
349
  orientation?: "vertical" | "horizontal" | "floating" | undefined;
244
350
  style?: string | undefined;
@@ -249,12 +355,33 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
249
355
  "onUpdate:modelValue"?: ((value: Record<string, unknown>) => any) | undefined;
250
356
  "onUpdate:config"?: ((args_0: Readonly<{
251
357
  fields: readonly ({
358
+ id: string;
252
359
  type: "string";
253
360
  path: string;
254
361
  title: readonly {
255
362
  locale: "zh" | "ja" | "en" | "ko";
256
363
  message: string;
257
364
  }[];
365
+ required?: boolean | undefined;
366
+ icon?: string | undefined;
367
+ style?: string | undefined;
368
+ discardEmptyString?: boolean | undefined;
369
+ maxLength?: string | undefined;
370
+ hidden?: string | undefined;
371
+ disabled?: string | undefined;
372
+ validation?: readonly Readonly<{
373
+ expression: string;
374
+ message: string;
375
+ }>[] | undefined;
376
+ } | {
377
+ id: string;
378
+ type: "textarea";
379
+ path: string;
380
+ title: readonly {
381
+ locale: "zh" | "ja" | "en" | "ko";
382
+ message: string;
383
+ }[];
384
+ required?: boolean | undefined;
258
385
  icon?: string | undefined;
259
386
  style?: string | undefined;
260
387
  discardEmptyString?: boolean | undefined;
@@ -266,12 +393,14 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
266
393
  message: string;
267
394
  }>[] | undefined;
268
395
  } | {
396
+ id: string;
269
397
  type: "number";
270
398
  path: string;
271
399
  title: readonly {
272
400
  locale: "zh" | "ja" | "en" | "ko";
273
401
  message: string;
274
402
  }[];
403
+ required?: boolean | undefined;
275
404
  icon?: string | undefined;
276
405
  style?: string | undefined;
277
406
  min?: string | undefined;
@@ -284,6 +413,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
284
413
  message: string;
285
414
  }>[] | undefined;
286
415
  } | {
416
+ id: string;
287
417
  type: "select";
288
418
  path: string;
289
419
  title: readonly {
@@ -294,6 +424,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
294
424
  label: string;
295
425
  value: string;
296
426
  key: string;
427
+ required?: boolean | undefined;
297
428
  icon?: string | undefined;
298
429
  style?: string | undefined;
299
430
  hidden?: string | undefined;
@@ -303,6 +434,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
303
434
  message: string;
304
435
  }>[] | undefined;
305
436
  } | {
437
+ id: string;
306
438
  type: "calendar";
307
439
  path: string;
308
440
  title: readonly {
@@ -311,6 +443,7 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
311
443
  }[];
312
444
  mode: "date" | "month" | "year";
313
445
  value: string;
446
+ required?: boolean | undefined;
314
447
  icon?: string | undefined;
315
448
  style?: string | undefined;
316
449
  display?: string | undefined;
@@ -321,11 +454,23 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
321
454
  expression: string;
322
455
  message: string;
323
456
  }>[] | undefined;
457
+ } | {
458
+ id: string;
459
+ type: "slot";
460
+ style?: string | undefined;
461
+ } | {
462
+ id: string;
463
+ type: "empty";
464
+ style?: string | undefined;
324
465
  })[];
325
466
  orientation?: "vertical" | "horizontal" | "floating" | undefined;
326
467
  style?: string | undefined;
327
468
  }>) => any) | undefined;
328
469
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
470
+ [x: string]: ((props: {
471
+ style: CSSProperties;
472
+ }) => any) | undefined;
473
+ } & {
329
474
  default?: (props: {}) => any;
330
475
  }>;
331
476
  type __VLS_WithSlots<T, S> = T & {
@@ -15,7 +15,7 @@ import { Button } from "../button";
15
15
  import { CommandGroup, CommandItem } from "../command";
16
16
  import { Field, FieldContent, FieldError, FieldLabel } from "../field";
17
17
  import FieldsConfiguratorDialog from "../fields-configurator/FieldsConfiguratorDialog.vue";
18
- import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupCombobox, InputGroupInput, InputGroupNumberField } from "../input-group";
18
+ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupCombobox, InputGroupInput, InputGroupNumberField, InputGroupTextarea } from "../input-group";
19
19
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../popover";
20
20
  import { Skeleton } from "../skeleton";
21
21
  import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip";
@@ -68,6 +68,25 @@ function getConfigStyle(config2) {
68
68
  }
69
69
  return style;
70
70
  }
71
+ function getFieldStyle(field) {
72
+ if (!field.style) {
73
+ return {};
74
+ }
75
+ const style = $dsl.evaluate`${field.style}`();
76
+ const normalizedStyle = {};
77
+ if (!style || typeof style !== "object" || Array.isArray(style)) {
78
+ return normalizedStyle;
79
+ }
80
+ for (const [key, value] of Object.entries(style)) {
81
+ if (typeof value === "string" || typeof value === "number") {
82
+ Reflect.set(normalizedStyle, key, value);
83
+ }
84
+ }
85
+ return normalizedStyle;
86
+ }
87
+ function isPassiveField(field) {
88
+ return field.type === "slot" || field.type === "empty";
89
+ }
71
90
  function toCalendarDateValue(value, valueFormat) {
72
91
  if (typeof value !== "string") return void 0;
73
92
  const date = parse(value, valueFormat, /* @__PURE__ */ new Date());
@@ -126,6 +145,9 @@ function isFieldInvalid(field) {
126
145
  function getFieldLabel(field) {
127
146
  return getLocalizedText(field.title, locale.value) ?? field.path;
128
147
  }
148
+ function isFieldRequired(field) {
149
+ return field.required === true;
150
+ }
129
151
  function renderValidationMessage(field) {
130
152
  const error = validationErrors.value[field.path];
131
153
  if (!error) return "";
@@ -159,7 +181,7 @@ watch(config, (value) => {
159
181
  watchEffect(() => {
160
182
  const activePaths = /* @__PURE__ */ new Set();
161
183
  for (const field of displayConfig.value.fields) {
162
- if (!isFieldHidden(field) && !isFieldDisabled(field)) {
184
+ if (!isPassiveField(field) && !isFieldHidden(field) && !isFieldDisabled(field)) {
163
185
  activePaths.add(field.path);
164
186
  }
165
187
  }
@@ -179,10 +201,12 @@ watchEffect(() => {
179
201
  <script>
180
202
  export {
181
203
  CalendarFieldC,
204
+ EmptyFieldC,
182
205
  FieldC,
183
206
  FieldsConfigC,
184
207
  NumberFieldC,
185
208
  SelectFieldC,
209
+ SlotFieldC,
186
210
  StringFieldC,
187
211
  ValidationRuleC,
188
212
  validationC
@@ -223,17 +247,32 @@ export {
223
247
 
224
248
  <template
225
249
  v-for="field in displayConfig.fields"
226
- :key="field.path"
250
+ :key="field.id"
227
251
  >
252
+ <slot
253
+ v-if="field.type === 'slot'"
254
+ :name="field.id"
255
+ :style="getFieldStyle(field)"
256
+ />
257
+ <div
258
+ v-else-if="field.type === 'empty'"
259
+ :style="getFieldStyle(field)"
260
+ />
228
261
  <Field
229
- v-if="!isFieldHidden(field)"
262
+ v-else-if="!isFieldHidden(field)"
230
263
  :data-disabled="isFieldDisabled(field) ? 'true' : void 0"
231
264
  :data-invalid="isFieldInvalid(field) ? 'true' : void 0"
232
265
  :orientation="getConfigOrientation(displayConfig)"
233
- :style="field.style ? $dsl.evaluate`${field.style}`() : {}"
266
+ :style="getFieldStyle(field)"
234
267
  >
235
- <FieldLabel :for="['string', 'number'].includes(field.type) ? `${id}:${field.path}` : void 0">
236
- {{ getFieldLabel(field) }}
268
+ <FieldLabel :for="['string', 'textarea', 'number'].includes(field.type) ? `${id}:${field.path}` : void 0">
269
+ <span class="inline-flex items-start gap-0.5">
270
+ <span>{{ getFieldLabel(field) }}</span>
271
+ <sup
272
+ v-if="isFieldRequired(field)"
273
+ class="text-red-500 leading-none"
274
+ >*</sup>
275
+ </span>
237
276
  <span v-if="isCheating">
238
277
  <span class="font-mono">{{ field.path }}</span>
239
278
  </span>
@@ -307,7 +346,33 @@ export {
307
346
  <InputGroup
308
347
  v-else
309
348
  :data-disabled="isFieldDisabled(field) ? 'true' : void 0"
349
+ :class="field.type === 'textarea' ? 'h-auto flex-col items-stretch' : void 0"
310
350
  >
351
+ <div
352
+ v-if="field.type === 'textarea'"
353
+ class="flex min-w-0 w-full items-center"
354
+ >
355
+ <InputGroupTextarea
356
+ :id="`${id}:${field.path}`"
357
+ :model-value="getProperty(modelValue, field.path)"
358
+ :maxlength="field.maxLength ? $dsl.evaluate`${field.maxLength}`() : void 0"
359
+ :disabled="isFieldDisabled(field)"
360
+ :aria-invalid="isFieldInvalid(field) ? 'true' : void 0"
361
+ @update:model-value="(value) => {
362
+ if (!value && !field.discardEmptyString) {
363
+ deleteProperty(modelValue, field.path);
364
+ } else {
365
+ setProperty(modelValue, field.path, value);
366
+ }
367
+ }"
368
+ @blur="validateField(field)"
369
+ />
370
+ <InputGroupAddon v-if="field.icon">
371
+ <Icon
372
+ :icon="field.icon"
373
+ />
374
+ </InputGroupAddon>
375
+ </div>
311
376
  <InputGroupInput
312
377
  v-if="field.type === 'string'"
313
378
  :id="`${id}:${field.path}`"
@@ -360,13 +425,13 @@ export {
360
425
  </CommandItem>
361
426
  </CommandGroup>
362
427
  </InputGroupCombobox>
363
- <InputGroupAddon v-if="field.icon">
428
+ <InputGroupAddon v-if="field.type !== 'textarea' && field.icon">
364
429
  <Icon
365
430
  :icon="field.icon"
366
431
  />
367
432
  </InputGroupAddon>
368
433
  <InputGroupAddon
369
- v-if="hasProperty(modelValue, field.path)"
434
+ v-if="field.type !== 'textarea' && hasProperty(modelValue, field.path)"
370
435
  align="inline-end"
371
436
  :class="getConfigOrientation(displayConfig) === 'floating' ? 'group-data-[disabled=true]/input-group:hidden' : void 0"
372
437
  >
@@ -398,6 +463,39 @@ export {
398
463
  <span class="inline-block text-right">{{ String(getProperty(modelValue, field.path) ?? "").length }}</span>/{{ field.maxLength }}
399
464
  </span>
400
465
  </InputGroupAddon>
466
+ <InputGroupAddon
467
+ v-if="field.type === 'textarea' && (hasProperty(modelValue, field.path) || field.maxLength && getProperty(modelValue, field.path))"
468
+ align="block-end"
469
+ >
470
+ <Tooltip
471
+ v-if="hasProperty(modelValue, field.path)"
472
+ :delay-duration="800"
473
+ >
474
+ <TooltipTrigger>
475
+ <InputGroupButton as-child>
476
+ <button
477
+ type="button"
478
+ class="text-zinc-300 hover:text-zinc-500 transition-colors"
479
+ :disabled="isFieldDisabled(field)"
480
+ @click="deleteProperty(modelValue, field.path)"
481
+ >
482
+ <Icon
483
+ icon="fluent:dismiss-20-regular"
484
+ />
485
+ </button>
486
+ </InputGroupButton>
487
+ </TooltipTrigger>
488
+ <TooltipContent>
489
+ {{ t("clear") }}
490
+ </TooltipContent>
491
+ </Tooltip>
492
+ <span
493
+ v-if="field.maxLength && getProperty(modelValue, field.path)"
494
+ class="text-xs text-zinc-400 font-mono"
495
+ >
496
+ <span class="inline-block text-right">{{ String(getProperty(modelValue, field.path) ?? "").length }}</span>/{{ field.maxLength }}
497
+ </span>
498
+ </InputGroupAddon>
401
499
  </InputGroup>
402
500
 
403
501
  <FieldError v-if="isFieldInvalid(field)">