@dxos/react-ui-form 0.8.1 → 0.8.2-main.10c050d

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 (112) hide show
  1. package/dist/lib/browser/index.mjs +1818 -1309
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +1774 -1273
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +1818 -1309
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/{ControlSection.d.ts → ControlSection/ControlSection.d.ts} +9 -6
  11. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -0
  12. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +8 -0
  13. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -0
  14. package/dist/types/src/components/ControlSection/index.d.ts +2 -0
  15. package/dist/types/src/components/ControlSection/index.d.ts.map +1 -0
  16. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  17. package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts +2 -0
  18. package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts.map +1 -0
  19. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/Defaults.d.ts +4 -4
  21. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/Form.d.ts +6 -4
  23. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/Form.stories.d.ts +38 -36
  25. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/FormActions.d.ts +1 -1
  27. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/FormContent.d.ts +16 -12
  29. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  30. package/dist/types/src/components/Form/FormContext.d.ts +2 -2
  31. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  32. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  33. package/dist/types/src/components/Form/RefField.d.ts +12 -0
  34. package/dist/types/src/components/Form/RefField.d.ts.map +1 -0
  35. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  36. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  37. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  39. package/dist/types/src/components/Form/factory.d.ts +1 -1
  40. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  41. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  42. package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
  43. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +2 -2
  44. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  45. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +5 -3
  46. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/deprecated/Form.d.ts +2 -2
  48. package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
  49. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
  50. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  51. package/dist/types/src/components/index.d.ts.map +1 -1
  52. package/dist/types/src/components/testing.d.ts.map +1 -1
  53. package/dist/types/src/hooks/index.d.ts +2 -0
  54. package/dist/types/src/hooks/index.d.ts.map +1 -1
  55. package/dist/types/src/hooks/useForm.d.ts +2 -2
  56. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  57. package/dist/types/src/hooks/useQueryRefOptions.d.ts +23 -0
  58. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -0
  59. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +8 -0
  60. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -0
  61. package/dist/types/src/translations.d.ts +5 -0
  62. package/dist/types/src/translations.d.ts.map +1 -1
  63. package/dist/types/src/util/field.d.ts.map +1 -1
  64. package/dist/types/src/util/formatting.d.ts.map +1 -1
  65. package/dist/types/src/util/index.d.ts +2 -0
  66. package/dist/types/src/util/index.d.ts.map +1 -1
  67. package/dist/types/src/util/refs.d.ts +9 -0
  68. package/dist/types/src/util/refs.d.ts.map +1 -0
  69. package/dist/types/src/util/schema.d.ts +3 -0
  70. package/dist/types/src/util/schema.d.ts.map +1 -0
  71. package/dist/types/src/vitest-setup.d.ts +2 -0
  72. package/dist/types/src/vitest-setup.d.ts.map +1 -0
  73. package/dist/types/tsconfig.tsbuildinfo +1 -1
  74. package/package.json +28 -25
  75. package/src/components/ControlSection/ControlSection.stories.tsx +29 -0
  76. package/src/components/{ControlSection.tsx → ControlSection/ControlSection.tsx} +40 -16
  77. package/src/components/ControlSection/index.ts +5 -0
  78. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  79. package/src/components/FieldEditor/FieldEditor.test.tsx +49 -0
  80. package/src/components/FieldEditor/FieldEditor.tsx +3 -2
  81. package/src/components/Form/ArrayField.tsx +63 -50
  82. package/src/components/Form/Defaults.tsx +77 -48
  83. package/src/components/Form/Form.stories.tsx +134 -109
  84. package/src/components/Form/Form.tsx +8 -5
  85. package/src/components/Form/FormActions.tsx +15 -18
  86. package/src/components/Form/FormContent.tsx +116 -46
  87. package/src/components/Form/FormContext.tsx +24 -10
  88. package/src/components/Form/Input.tsx +4 -10
  89. package/src/components/Form/RefField.tsx +217 -0
  90. package/src/components/Form/custom/GeoPointInput.tsx +2 -2
  91. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +6 -5
  92. package/src/components/Form/custom/SelectOptionsInput.tsx +2 -2
  93. package/src/components/Form/factory.tsx +1 -1
  94. package/src/components/Form/index.ts +0 -1
  95. package/src/components/ViewEditor/ViewEditor.stories.tsx +19 -9
  96. package/src/components/ViewEditor/ViewEditor.tsx +65 -35
  97. package/src/components/deprecated/Form.stories.tsx +6 -6
  98. package/src/components/deprecated/Form.tsx +6 -6
  99. package/src/components/deprecated/FormInput.tsx +1 -1
  100. package/src/components/index.ts +1 -0
  101. package/src/components/testing.tsx +5 -9
  102. package/src/hooks/index.ts +3 -1
  103. package/src/hooks/useForm.ts +4 -3
  104. package/src/hooks/useQueryRefOptions.ts +53 -0
  105. package/src/hooks/useRefQueryLookupHandler.ts +39 -0
  106. package/src/translations.ts +9 -2
  107. package/src/util/formatting.ts +15 -3
  108. package/src/util/index.ts +3 -1
  109. package/src/util/refs.ts +38 -0
  110. package/src/util/schema.ts +14 -0
  111. package/src/vitest-setup.ts +11 -0
  112. package/dist/types/src/components/ControlSection.d.ts.map +0 -1
@@ -79,6 +79,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
79
79
  }
80
80
  return { fieldSchema };
81
81
  });
82
+
82
83
  setReferenceSchema((prev) => {
83
84
  if (_props.referenceSchema !== prev?.typename) {
84
85
  const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
@@ -129,7 +130,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
129
130
  onSave();
130
131
  }, [onSave]);
131
132
 
132
- const Custom: Partial<Record<string, InputComponent>> = useMemo(
133
+ const custom: Partial<Record<string, InputComponent>> = useMemo(
133
134
  () => ({
134
135
  ['format' satisfies keyof PropertyType]: (props) => (
135
136
  <SelectInput
@@ -187,7 +188,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
187
188
  onValidate={handleValidate}
188
189
  onSave={handleSave}
189
190
  onCancel={handleCancel}
190
- Custom={Custom}
191
+ Custom={custom}
191
192
  />
192
193
  );
193
194
  };
@@ -2,15 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { pipe } from 'effect';
5
+ import { SchemaAST, pipe } from 'effect';
6
6
  import { capitalize } from 'effect/String';
7
- import React, { useCallback, useMemo } from 'react';
7
+ import React, { Fragment, useCallback } from 'react';
8
8
 
9
- import { AST } from '@dxos/echo-schema';
10
9
  import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from '@dxos/effect';
11
10
  import { invariant } from '@dxos/invariant';
12
11
  import { IconButton, useTranslation } from '@dxos/react-ui';
13
- import { mx } from '@dxos/react-ui-theme';
14
12
  import { getSchemaProperties, type SchemaProperty } from '@dxos/schema';
15
13
 
16
14
  import { type ComponentLookup } from './Form';
@@ -18,8 +16,7 @@ import { FormField } from './FormContent';
18
16
  import { useFormValues, type FormInputStateProps } from './FormContext';
19
17
  import { InputHeader, type InputComponent } from './Input';
20
18
  import { translationKey } from '../../translations';
21
-
22
- const padding = 'px-2';
19
+ import { findArrayElementType } from '../../util';
23
20
 
24
21
  type ArrayFieldProps = {
25
22
  property: SchemaProperty<any>;
@@ -33,16 +30,17 @@ type ArrayFieldProps = {
33
30
  export const ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }: ArrayFieldProps) => {
34
31
  const { t } = useTranslation(translationKey);
35
32
  const { ast, name, type, title } = property;
36
- const values = useFormValues(path ?? []) as any[];
33
+ // TODO(wittjosiah): The fallback to an empty array stops the form from crashing but isn't immediately live.
34
+ // It doesn't become live until another field is touched, but that's better than the whole form crashing.
35
+ const values = (useFormValues(path ?? []) ?? []) as any[];
37
36
  invariant(Array.isArray(values), `Values at path ${path?.join('.')} must be an array.`);
38
37
  const label = title ?? pipe(name, capitalize);
39
38
 
40
- const tupleType = findNode(ast, AST.isTupleType);
41
- const elementType = (tupleType as AST.TupleType | undefined)?.rest[0]?.type;
39
+ const elementType = findArrayElementType(ast);
42
40
 
43
- const getDefaultObjectValue = (typeNode: AST.AST): any => {
41
+ const getDefaultObjectValue = (typeNode: SchemaAST.AST): any => {
44
42
  const baseNode = findNode(typeNode, isDiscriminatedUnion);
45
- const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST.isTypeLiteral);
43
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, SchemaAST.isTypeLiteral);
46
44
  if (!typeLiteral) {
47
45
  return {};
48
46
  }
@@ -50,17 +48,12 @@ export const ArrayField = ({ property, readonly, path, inputProps, Custom, looku
50
48
  return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [prop.name, prop.defaultValue]));
51
49
  };
52
50
 
53
- const newValue = useMemo(() => {
54
- if (type === 'object' && elementType) {
55
- return getDefaultObjectValue(elementType);
56
- } else {
57
- return SimpleType.getDefaultValue(type);
58
- }
59
- }, [type, elementType]);
51
+ const getDefaultValue = () =>
52
+ type === 'object' && elementType ? getDefaultObjectValue(elementType) : SimpleType.getDefaultValue(type);
60
53
 
61
54
  const handleAdd = useCallback(() => {
62
- inputProps.onValueChange(type, [...values, newValue]);
63
- }, [type, elementType, inputProps, newValue, values]);
55
+ inputProps.onValueChange(type, [...values, getDefaultValue()]);
56
+ }, [type, elementType, inputProps, values]);
64
57
 
65
58
  const handleRemove = useCallback(
66
59
  (index: number) => {
@@ -74,38 +67,58 @@ export const ArrayField = ({ property, readonly, path, inputProps, Custom, looku
74
67
  return null;
75
68
  }
76
69
 
77
- return (
78
- <div role='none' className={mx(padding)}>
70
+ return readonly && values.length < 1 ? null : (
71
+ <>
79
72
  <InputHeader>{label}</InputHeader>
80
- <div role='none' className='flex flex-col gap-1'>
81
- {values.map((_value, index) => (
82
- <div key={index} role='none' className='flex items-center gap-1'>
83
- <div role='none' className='flex-1'>
84
- <FormField
85
- property={{
86
- ...property,
87
- array: false, // NOTE(ZaymonFC): This breaks arrays of arrays but ¯\_(ツ)_/¯. Ping me if you need that.
88
- ast: elementType,
89
- }}
90
- path={[...(path ?? []), index]}
91
- readonly={readonly}
92
- inline
93
- Custom={Custom}
94
- lookupComponent={lookupComponent}
95
- />
96
- </div>
97
- <IconButton
98
- icon='ph--trash--regular'
99
- iconOnly
100
- label={t('button remove')}
101
- onClick={() => handleRemove(index)}
73
+ <div
74
+ role='none'
75
+ className={
76
+ readonly
77
+ ? 'flex flex-wrap gap-1 mlb-1'
78
+ : values.length > 0
79
+ ? 'grid gap-1 grid-cols-[1fr_min-content] mlb-1'
80
+ : 'hidden'
81
+ }
82
+ >
83
+ {values.map((_value, index) => {
84
+ const field = (
85
+ <FormField
86
+ property={{
87
+ ...property,
88
+ array: false, // NOTE(ZaymonFC): This breaks arrays of arrays but ¯\_(ツ)_/¯. Ping me if you need that.
89
+ ast: elementType,
90
+ }}
91
+ path={[...(path ?? []), index]}
92
+ readonly={readonly}
93
+ inline
94
+ Custom={Custom}
95
+ lookupComponent={lookupComponent}
102
96
  />
103
- </div>
104
- ))}
105
- </div>
106
- <div role='none' className='flex justify-between items-center plb-1'>
107
- <IconButton icon='ph--plus--regular' iconOnly label={t('button add')} onClick={handleAdd} />
97
+ );
98
+ return readonly ? (
99
+ field
100
+ ) : (
101
+ <Fragment key={index}>
102
+ <div role='none'>{field}</div>
103
+ <IconButton
104
+ icon='ph--trash--regular'
105
+ iconOnly
106
+ label={t('button remove')}
107
+ onClick={() => handleRemove(index)}
108
+ classNames='self-center'
109
+ />
110
+ </Fragment>
111
+ );
112
+ })}
108
113
  </div>
109
- </div>
114
+ {!readonly && (
115
+ <IconButton
116
+ classNames='is-full mlb-1 flex'
117
+ icon='ph--plus--regular'
118
+ label={t('add field')}
119
+ onClick={handleAdd}
120
+ />
121
+ )}
122
+ </>
110
123
  );
111
124
  };
@@ -4,9 +4,10 @@
4
4
 
5
5
  import React, { useCallback, useEffect, useRef } from 'react';
6
6
 
7
- import { Input, Select } from '@dxos/react-ui';
7
+ import { Input, Select, useTranslation } from '@dxos/react-ui';
8
8
 
9
9
  import { type InputProps, InputHeader } from './Input';
10
+ import { translationKey } from '../../translations';
10
11
 
11
12
  export const TextInput = ({
12
13
  type,
@@ -21,20 +22,26 @@ export const TextInput = ({
21
22
  }: InputProps) => {
22
23
  const { status, error } = getStatus();
23
24
 
24
- return (
25
+ return disabled && !getValue() ? null : disabled && inputOnly ? (
26
+ <p>{getValue() ?? ''}</p>
27
+ ) : (
25
28
  <Input.Root validationValence={status}>
26
29
  {!inputOnly && (
27
30
  <InputHeader error={error}>
28
31
  <Input.Label>{label}</Input.Label>
29
32
  </InputHeader>
30
33
  )}
31
- <Input.TextInput
32
- disabled={disabled}
33
- placeholder={placeholder}
34
- value={getValue() ?? ''}
35
- onChange={(event) => onValueChange(type, event.target.value)}
36
- onBlur={onBlur}
37
- />
34
+ {disabled ? (
35
+ <p>{getValue() ?? ''}</p>
36
+ ) : (
37
+ <Input.TextInput
38
+ disabled={disabled}
39
+ placeholder={placeholder}
40
+ value={getValue() ?? ''}
41
+ onChange={(event) => onValueChange(type, event.target.value)}
42
+ onBlur={onBlur}
43
+ />
44
+ )}
38
45
  {inputOnly && <Input.Validation>{error}</Input.Validation>}
39
46
  </Input.Root>
40
47
  );
@@ -53,29 +60,36 @@ export const NumberInput = ({
53
60
  }: InputProps) => {
54
61
  const { status, error } = getStatus();
55
62
 
56
- return (
63
+ return disabled && !getValue() ? null : disabled && inputOnly ? (
64
+ <p>{getValue() ?? ''}</p>
65
+ ) : (
57
66
  <Input.Root validationValence={status}>
58
67
  {!inputOnly && (
59
68
  <InputHeader error={error}>
60
69
  <Input.Label>{label}</Input.Label>
61
70
  </InputHeader>
62
71
  )}
63
- <Input.TextInput
64
- type='number'
65
- disabled={disabled}
66
- placeholder={placeholder}
67
- value={getValue() ?? 0}
68
- onChange={(event) => onValueChange(type, event.target.value)}
69
- onBlur={onBlur}
70
- />
72
+ {disabled ? (
73
+ <p>{getValue() ?? ''}</p>
74
+ ) : (
75
+ <Input.TextInput
76
+ type='number'
77
+ disabled={disabled}
78
+ placeholder={placeholder}
79
+ value={getValue() ?? 0}
80
+ onChange={(event) => onValueChange(type, event.target.value)}
81
+ onBlur={onBlur}
82
+ />
83
+ )}
71
84
  {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
72
85
  </Input.Root>
73
86
  );
74
87
  };
75
88
 
76
- export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onValueChange }: InputProps) => {
89
+ export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onValueChange, disabled }: InputProps) => {
77
90
  const { status, error } = getStatus();
78
91
  const checked = Boolean(getValue());
92
+ const { t } = useTranslation(translationKey);
79
93
 
80
94
  return (
81
95
  <Input.Root validationValence={status}>
@@ -84,7 +98,11 @@ export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onVa
84
98
  <Input.Label>{label}</Input.Label>
85
99
  </InputHeader>
86
100
  )}
87
- <Input.Switch checked={checked} onCheckedChange={(value) => onValueChange(type, value)} />
101
+ {disabled ? (
102
+ <p>{t(checked ? 'boolean input true value' : 'boolean input false value')}</p>
103
+ ) : (
104
+ <Input.Switch checked={checked} onCheckedChange={(value) => onValueChange(type, value)} />
105
+ )}
88
106
  {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
89
107
  </Input.Root>
90
108
  );
@@ -107,29 +125,36 @@ export const SelectInput = ({
107
125
  }: SelectInputOptions) => {
108
126
  const { status, error } = getStatus();
109
127
 
110
- return (
128
+ const value = getValue() as string | undefined;
129
+ const handleValueChange = useCallback((value: string | number) => onValueChange(type, value), [type, onValueChange]);
130
+
131
+ return disabled && !value ? null : (
111
132
  <Input.Root validationValence={status}>
112
133
  {!inputOnly && (
113
134
  <InputHeader error={error}>
114
135
  <Input.Label>{label}</Input.Label>
115
136
  </InputHeader>
116
137
  )}
117
- <Select.Root value={getValue()} onValueChange={(value) => onValueChange(type, value)}>
118
- {/* TODO(burdon): Placeholder not working? */}
119
- <Select.TriggerButton classNames='is-full' disabled={disabled} placeholder={placeholder} />
120
- <Select.Portal>
121
- <Select.Content>
122
- <Select.Viewport>
123
- {options?.map(({ value, label }) => (
124
- // NOTE: Numeric values are converted to and from strings.
125
- <Select.Option key={String(value)} value={String(value)}>
126
- {label ?? String(value)}
127
- </Select.Option>
128
- ))}
129
- </Select.Viewport>
130
- </Select.Content>
131
- </Select.Portal>
132
- </Select.Root>
138
+ {disabled ? (
139
+ <p>{options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)}</p>
140
+ ) : (
141
+ <Select.Root value={value} onValueChange={handleValueChange}>
142
+ {/* TODO(burdon): Placeholder not working? */}
143
+ <Select.TriggerButton classNames='is-full' disabled={disabled} placeholder={placeholder} />
144
+ <Select.Portal>
145
+ <Select.Content>
146
+ <Select.Viewport>
147
+ {options?.map(({ value, label }) => (
148
+ // NOTE: Numeric values are converted to and from strings.
149
+ <Select.Option key={String(value)} value={String(value)}>
150
+ {label ?? String(value)}
151
+ </Select.Option>
152
+ ))}
153
+ </Select.Viewport>
154
+ </Select.Content>
155
+ </Select.Portal>
156
+ </Select.Root>
157
+ )}
133
158
  {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
134
159
  </Input.Root>
135
160
  );
@@ -177,17 +202,21 @@ export const MarkdownInput = ({
177
202
  <Input.Label>{label}</Input.Label>
178
203
  </InputHeader>
179
204
  )}
180
- <Input.TextArea
181
- ref={textareaRef}
182
- disabled={disabled}
183
- placeholder={placeholder}
184
- value={getValue() ?? ''}
185
- classNames={'min-bs-auto max-h-40 overflow-auto'}
186
- onChange={(event) => onValueChange(type, event.target.value)}
187
- onBlur={onBlur}
188
- style={{ resize: 'none' }}
189
- spellCheck={false}
190
- />
205
+ {disabled ? (
206
+ <p>{getValue() ?? ''}</p>
207
+ ) : (
208
+ <Input.TextArea
209
+ ref={textareaRef}
210
+ disabled={disabled}
211
+ placeholder={placeholder}
212
+ value={getValue() ?? ''}
213
+ classNames={'min-bs-auto max-h-40 overflow-auto'}
214
+ onChange={(event) => onValueChange(type, event.target.value)}
215
+ onBlur={onBlur}
216
+ style={{ resize: 'none' }}
217
+ spellCheck={false}
218
+ />
219
+ )}
191
220
  {inputOnly && <Input.Validation>{error}</Input.Validation>}
192
221
  </Input.Root>
193
222
  );