@dxos/react-ui-form 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5

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 (229) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +2753 -2121
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +2753 -2121
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +8 -8
  9. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +83 -5
  11. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/Form.d.ts +86 -25
  13. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Form.stories.d.ts +129 -56
  15. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/FormField.d.ts +43 -0
  17. package/dist/types/src/components/Form/FormField.d.ts.map +1 -0
  18. package/dist/types/src/components/Form/FormFieldComponent.d.ts +77 -0
  19. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -0
  20. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts +9 -0
  21. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -0
  22. package/dist/types/src/components/Form/FormFieldSet.d.ts +18 -0
  23. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -0
  24. package/dist/types/src/components/Form/fields/ArrayField.d.ts +18 -0
  25. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -0
  26. package/dist/types/src/components/Form/fields/BooleanField.d.ts +4 -0
  27. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -0
  28. package/dist/types/src/components/Form/fields/GeoPointField.d.ts +5 -0
  29. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -0
  30. package/dist/types/src/components/Form/fields/MarkdownField.d.ts +4 -0
  31. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -0
  32. package/dist/types/src/components/Form/fields/NumberField.d.ts +4 -0
  33. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -0
  34. package/dist/types/src/components/Form/fields/RefField.d.ts +16 -0
  35. package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -0
  36. package/dist/types/src/components/Form/fields/SelectField.d.ts +10 -0
  37. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -0
  38. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +5 -0
  39. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -0
  40. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +83 -0
  41. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -0
  42. package/dist/types/src/components/Form/fields/TextAreaField.d.ts +4 -0
  43. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -0
  44. package/dist/types/src/components/Form/fields/TextField.d.ts +4 -0
  45. package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -0
  46. package/dist/types/src/components/Form/fields/TupleField.d.ts +6 -0
  47. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -0
  48. package/dist/types/src/components/Form/fields/index.d.ts +12 -0
  49. package/dist/types/src/components/Form/fields/index.d.ts.map +1 -0
  50. package/dist/types/src/components/Form/index.d.ts +2 -4
  51. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  52. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts +9 -0
  53. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -0
  54. package/dist/types/src/components/ObjectForm/index.d.ts +2 -0
  55. package/dist/types/src/components/ObjectForm/index.d.ts.map +1 -0
  56. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +54 -0
  57. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
  58. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +86 -0
  59. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
  60. package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
  61. package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
  62. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +9 -0
  63. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -0
  64. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts +83 -0
  65. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts.map +1 -0
  66. package/dist/types/src/components/ObjectProperties/index.d.ts +2 -0
  67. package/dist/types/src/components/ObjectProperties/index.d.ts.map +1 -0
  68. package/dist/types/src/components/Settings/Settings.d.ts +43 -0
  69. package/dist/types/src/components/Settings/Settings.d.ts.map +1 -0
  70. package/dist/types/src/components/Settings/Settings.stories.d.ts +83 -0
  71. package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -0
  72. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +38 -0
  73. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +1 -0
  74. package/dist/types/src/components/Settings/SettingsItem.d.ts +17 -0
  75. package/dist/types/src/components/Settings/SettingsItem.d.ts.map +1 -0
  76. package/dist/types/src/components/Settings/index.d.ts +3 -0
  77. package/dist/types/src/components/Settings/index.d.ts.map +1 -0
  78. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +22 -10
  79. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  80. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +85 -8
  81. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  82. package/dist/types/src/components/index.d.ts +4 -2
  83. package/dist/types/src/components/index.d.ts.map +1 -1
  84. package/dist/types/src/components/testing.d.ts +4 -4
  85. package/dist/types/src/components/testing.d.ts.map +1 -1
  86. package/dist/types/src/hooks/index.d.ts +2 -3
  87. package/dist/types/src/hooks/index.d.ts.map +1 -1
  88. package/dist/types/src/hooks/useFormHandler.d.ts +82 -0
  89. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -0
  90. package/dist/types/src/hooks/useKeyHandler.d.ts +7 -0
  91. package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -0
  92. package/dist/types/src/translations.d.ts +64 -55
  93. package/dist/types/src/translations.d.ts.map +1 -1
  94. package/dist/types/src/util/field-type.d.ts +19 -0
  95. package/dist/types/src/util/field-type.d.ts.map +1 -0
  96. package/dist/types/src/util/field.d.ts +3 -3
  97. package/dist/types/src/util/field.d.ts.map +1 -1
  98. package/dist/types/src/util/formatting.d.ts +2 -2
  99. package/dist/types/src/util/formatting.d.ts.map +1 -1
  100. package/dist/types/src/util/index.d.ts +2 -1
  101. package/dist/types/src/util/index.d.ts.map +1 -1
  102. package/dist/types/src/util/properties.d.ts +7 -0
  103. package/dist/types/src/util/properties.d.ts.map +1 -0
  104. package/dist/types/src/util/refs.d.ts +3 -3
  105. package/dist/types/src/util/refs.d.ts.map +1 -1
  106. package/dist/types/tsconfig.tsbuildinfo +1 -1
  107. package/package.json +45 -43
  108. package/src/components/FieldEditor/FieldEditor.stories.tsx +48 -31
  109. package/src/components/FieldEditor/FieldEditor.test.tsx +0 -1
  110. package/src/components/FieldEditor/FieldEditor.tsx +84 -90
  111. package/src/components/Form/AUDIT.md +17 -0
  112. package/src/components/Form/Form.stories.tsx +144 -222
  113. package/src/components/Form/Form.tsx +359 -96
  114. package/src/components/Form/FormField.tsx +304 -0
  115. package/src/components/Form/FormFieldComponent.stories.tsx +65 -0
  116. package/src/components/Form/FormFieldComponent.tsx +171 -0
  117. package/src/components/Form/FormFieldSet.tsx +144 -0
  118. package/src/components/Form/README.md +3 -0
  119. package/src/components/Form/fields/ArrayField.tsx +154 -0
  120. package/src/components/Form/fields/BooleanField.tsx +22 -0
  121. package/src/components/Form/fields/GeoPointField.tsx +120 -0
  122. package/src/components/Form/fields/MarkdownField.tsx +78 -0
  123. package/src/components/Form/fields/NumberField.tsx +39 -0
  124. package/src/components/Form/fields/RefField.tsx +198 -0
  125. package/src/components/Form/fields/SelectField.tsx +65 -0
  126. package/src/components/Form/fields/SelectOptionField.stories.tsx +65 -0
  127. package/src/components/Form/{custom/SelectOptionsInput.tsx → fields/SelectOptionField.tsx} +36 -31
  128. package/src/components/Form/fields/TextAreaField.tsx +38 -0
  129. package/src/components/Form/fields/TextField.tsx +38 -0
  130. package/src/components/Form/{custom/TupleInput.tsx → fields/TupleField.tsx} +17 -10
  131. package/src/components/Form/fields/index.ts +15 -0
  132. package/src/components/Form/index.ts +3 -4
  133. package/src/components/ObjectForm/ObjectForm.tsx +113 -0
  134. package/src/components/{ControlSection → ObjectForm}/index.ts +1 -1
  135. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +209 -0
  136. package/src/components/ObjectPicker/ObjectPicker.tsx +186 -0
  137. package/src/components/ObjectPicker/index.ts +5 -0
  138. package/src/components/ObjectProperties/ObjectProperties.stories.tsx +63 -0
  139. package/src/components/ObjectProperties/ObjectProperties.tsx +129 -0
  140. package/src/components/ObjectProperties/index.ts +5 -0
  141. package/src/components/Settings/Settings.stories.tsx +103 -0
  142. package/src/components/Settings/Settings.tsx +81 -0
  143. package/src/components/Settings/SettingsFieldSet.tsx +211 -0
  144. package/src/components/Settings/SettingsItem.tsx +62 -0
  145. package/src/components/Settings/index.ts +6 -0
  146. package/src/components/ViewEditor/ViewEditor.stories.tsx +139 -63
  147. package/src/components/ViewEditor/ViewEditor.test.tsx +12 -15
  148. package/src/components/ViewEditor/ViewEditor.tsx +346 -211
  149. package/src/components/index.ts +4 -3
  150. package/src/components/testing.tsx +28 -12
  151. package/src/hooks/index.ts +2 -3
  152. package/src/hooks/useFormHandler.ts +380 -0
  153. package/src/hooks/useKeyHandler.tsx +37 -0
  154. package/src/translations.ts +67 -59
  155. package/src/util/field-type.ts +57 -0
  156. package/src/util/field.ts +33 -43
  157. package/src/util/formatting.ts +22 -22
  158. package/src/util/index.ts +2 -1
  159. package/src/util/properties.ts +18 -0
  160. package/src/util/refs.ts +17 -19
  161. package/dist/types/src/components/ControlSection/ControlSection.d.ts +0 -23
  162. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +0 -1
  163. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +0 -8
  164. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +0 -1
  165. package/dist/types/src/components/ControlSection/index.d.ts +0 -2
  166. package/dist/types/src/components/ControlSection/index.d.ts.map +0 -1
  167. package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
  168. package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
  169. package/dist/types/src/components/Form/Defaults.d.ts +0 -14
  170. package/dist/types/src/components/Form/Defaults.d.ts.map +0 -1
  171. package/dist/types/src/components/Form/FormActions.d.ts +0 -9
  172. package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
  173. package/dist/types/src/components/Form/FormContent.d.ts +0 -57
  174. package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
  175. package/dist/types/src/components/Form/FormContext.d.ts +0 -23
  176. package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
  177. package/dist/types/src/components/Form/Input.d.ts +0 -26
  178. package/dist/types/src/components/Form/Input.d.ts.map +0 -1
  179. package/dist/types/src/components/Form/RefField.d.ts +0 -12
  180. package/dist/types/src/components/Form/RefField.d.ts.map +0 -1
  181. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +0 -4
  182. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +0 -1
  183. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +0 -4
  184. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +0 -1
  185. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +0 -7
  186. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +0 -1
  187. package/dist/types/src/components/Form/custom/TupleInput.d.ts +0 -6
  188. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +0 -1
  189. package/dist/types/src/components/Form/custom/index.d.ts +0 -4
  190. package/dist/types/src/components/Form/custom/index.d.ts.map +0 -1
  191. package/dist/types/src/components/Form/factory.d.ts +0 -8
  192. package/dist/types/src/components/Form/factory.d.ts.map +0 -1
  193. package/dist/types/src/components/deprecated/Form.d.ts +0 -15
  194. package/dist/types/src/components/deprecated/Form.d.ts.map +0 -1
  195. package/dist/types/src/components/deprecated/Form.stories.d.ts +0 -13
  196. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +0 -1
  197. package/dist/types/src/components/deprecated/FormInput.d.ts +0 -16
  198. package/dist/types/src/components/deprecated/FormInput.d.ts.map +0 -1
  199. package/dist/types/src/components/deprecated/index.d.ts +0 -2
  200. package/dist/types/src/components/deprecated/index.d.ts.map +0 -1
  201. package/dist/types/src/hooks/useForm.d.ts +0 -67
  202. package/dist/types/src/hooks/useForm.d.ts.map +0 -1
  203. package/dist/types/src/hooks/useQueryRefOptions.d.ts +0 -23
  204. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +0 -1
  205. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
  206. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
  207. package/dist/types/src/util/schema.d.ts +0 -3
  208. package/dist/types/src/util/schema.d.ts.map +0 -1
  209. package/src/components/ControlSection/ControlSection.stories.tsx +0 -42
  210. package/src/components/ControlSection/ControlSection.tsx +0 -139
  211. package/src/components/Form/ArrayField.tsx +0 -125
  212. package/src/components/Form/Defaults.tsx +0 -204
  213. package/src/components/Form/FormActions.tsx +0 -54
  214. package/src/components/Form/FormContent.tsx +0 -241
  215. package/src/components/Form/FormContext.tsx +0 -110
  216. package/src/components/Form/Input.tsx +0 -51
  217. package/src/components/Form/RefField.tsx +0 -214
  218. package/src/components/Form/custom/GeoPointInput.tsx +0 -72
  219. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -62
  220. package/src/components/Form/custom/index.ts +0 -7
  221. package/src/components/Form/factory.tsx +0 -31
  222. package/src/components/deprecated/Form.stories.tsx +0 -63
  223. package/src/components/deprecated/Form.tsx +0 -119
  224. package/src/components/deprecated/FormInput.tsx +0 -71
  225. package/src/components/deprecated/index.ts +0 -5
  226. package/src/hooks/useForm.ts +0 -293
  227. package/src/hooks/useQueryRefOptions.ts +0 -53
  228. package/src/hooks/useRefQueryLookupHandler.ts +0 -39
  229. package/src/util/schema.ts +0 -14
@@ -1,214 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { type SchemaAST } from 'effect';
6
- import React, { type FocusEvent, useCallback, useMemo } from 'react';
7
-
8
- import {
9
- Expando,
10
- Ref,
11
- ReferenceAnnotationId,
12
- type ReferenceAnnotationValue,
13
- getTypeAnnotation,
14
- } from '@dxos/echo-schema';
15
- import { findAnnotation } from '@dxos/effect';
16
- import { DXN } from '@dxos/keys';
17
- import { DxRefTag } from '@dxos/lit-ui/react';
18
- import { Input, useTranslation } from '@dxos/react-ui';
19
- import { TagPicker, type TagPickerItemData, type TagPickerMode } from '@dxos/react-ui-tag-picker';
20
- import { descriptionText, mx } from '@dxos/react-ui-theme';
21
- import { isNonNullable } from '@dxos/util';
22
-
23
- import { type QueryRefOptions, useQueryRefOptions } from '../../hooks';
24
- import { translationKey } from '../../translations';
25
-
26
- import { TextInput } from './Defaults';
27
- import { InputHeader, type InputProps } from './Input';
28
-
29
- type RefFieldProps = InputProps & {
30
- ast?: SchemaAST.AST;
31
- array?: boolean;
32
- onQueryRefOptions?: QueryRefOptions;
33
- };
34
-
35
- export const RefField = ({
36
- type,
37
- label,
38
- disabled,
39
- placeholder,
40
- inputOnly,
41
- array,
42
- ast,
43
- getValue,
44
- onBlur,
45
- onQueryRefOptions,
46
- onValueChange,
47
- ...restInputProps
48
- }: RefFieldProps) => {
49
- const { t } = useTranslation(translationKey);
50
- const refTypeInfo = useMemo(
51
- () => (ast ? findAnnotation<ReferenceAnnotationValue>(ast, ReferenceAnnotationId) : undefined),
52
- [ast],
53
- );
54
- const { options: availableOptions, loading: _loading } = useQueryRefOptions({ refTypeInfo, onQueryRefOptions });
55
-
56
- if ((refTypeInfo && refTypeInfo?.typename === getTypeAnnotation(Expando)?.typename) || !onQueryRefOptions) {
57
- // If ref type is expando, fall back to taking a DXN in string format.
58
- return (
59
- <RefFieldFallback
60
- {...{ type, label, placeholder, disabled, inputOnly, getValue, onBlur, onValueChange, ...restInputProps }}
61
- />
62
- );
63
- }
64
-
65
- const handleGetValue = useCallback((): TagPickerItemData[] => {
66
- const formValue = getValue();
67
-
68
- const unknownToRefOption = (val: unknown) => {
69
- if (Ref.isRef(val)) {
70
- const dxnString = val.dxn.toString();
71
- const matchingOption = availableOptions.find((option) => option.id === dxnString);
72
- if (matchingOption) {
73
- return matchingOption;
74
- }
75
- }
76
- return undefined;
77
- };
78
-
79
- if (array && Array.isArray(formValue)) {
80
- return formValue.map(unknownToRefOption).filter(isNonNullable) ?? [];
81
- }
82
-
83
- const option = unknownToRefOption(formValue);
84
- if (option) {
85
- return [option];
86
- }
87
-
88
- return [];
89
- }, [getValue, availableOptions, array]);
90
-
91
- const handleSearch = useCallback(
92
- (text: string, ids: string[]): TagPickerItemData[] =>
93
- availableOptions
94
- .filter((option) => !ids.includes(option.id))
95
- .filter((option) => option.label.toLowerCase().includes(text.toLowerCase()))
96
- .map((option) => ({ id: option.id, label: option.label, hue: option.hue as any })),
97
- [availableOptions],
98
- );
99
-
100
- const handleUpdate = useCallback(
101
- (ids: string[]) => {
102
- if (ids.length === 0) {
103
- onValueChange('object', undefined);
104
- return;
105
- }
106
-
107
- const refs = ids
108
- .map((id) => {
109
- const item = availableOptions.find((option) => option.id === id);
110
- if (item) {
111
- const dxn = DXN.parse(item.id);
112
- return Ref.fromDXN(dxn);
113
- }
114
- return null;
115
- })
116
- .filter(isNonNullable);
117
-
118
- if (array) {
119
- onValueChange('object', refs);
120
- } else {
121
- onValueChange('object', refs[0]);
122
- }
123
- },
124
- [availableOptions, array, onValueChange],
125
- );
126
-
127
- const tagPickerMode: TagPickerMode = useMemo(() => (array ? 'multi-select' : 'single-select'), [array]);
128
-
129
- if (!refTypeInfo) {
130
- return null;
131
- }
132
-
133
- const { status, error } = restInputProps.getStatus();
134
-
135
- const items = handleGetValue();
136
-
137
- // NOTE(thure): I left both predicates in-place in case we decide to add variants which do render readonly but empty values.
138
- return disabled && items.length < 1 ? null : (
139
- <Input.Root validationValence={status}>
140
- {!inputOnly && <InputHeader error={error} label={label} />}
141
- <div data-no-submit>
142
- {disabled ? (
143
- items.length < 1 ? (
144
- <p className={mx(descriptionText, 'mbe-2')}>{t('empty readonly ref field label')}</p>
145
- ) : (
146
- items.map((item) => (
147
- <DxRefTag key={item.id} refid={item.id} rootclassname='mie-1' style={{ marginInlineEnd: '.25rem' }}>
148
- {item.label}
149
- </DxRefTag>
150
- ))
151
- )
152
- ) : (
153
- <TagPicker
154
- readonly={disabled}
155
- items={items}
156
- mode={tagPickerMode}
157
- onBlur={(event) => onBlur(event as unknown as FocusEvent<HTMLElement>)}
158
- onUpdate={handleUpdate}
159
- onSearch={handleSearch}
160
- classNames='bg-inputSurface p-1.5 rounded-sm'
161
- />
162
- )}
163
- </div>
164
- {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
165
- </Input.Root>
166
- );
167
- };
168
-
169
- const RefFieldFallback = ({
170
- type,
171
- label,
172
- disabled,
173
- placeholder,
174
- inputOnly,
175
- getValue,
176
- onValueChange,
177
- ...restInputProps
178
- }: InputProps) => {
179
- const handleOnValueChange = (_type: any, dxnString: string) => {
180
- const dxn = DXN.tryParse(dxnString);
181
- if (dxn) {
182
- onValueChange?.('object', Ref.fromDXN(dxn));
183
- } else if (dxnString === '') {
184
- onValueChange?.('object', undefined);
185
- } else {
186
- onValueChange?.('string', dxnString);
187
- }
188
- };
189
-
190
- const handleGetValue = () => {
191
- const formValue = getValue();
192
- if (typeof formValue === 'string') {
193
- return formValue;
194
- }
195
- if (Ref.isRef(formValue)) {
196
- return formValue.dxn.toString();
197
- }
198
-
199
- return undefined;
200
- };
201
-
202
- return (
203
- <TextInput
204
- type={type}
205
- label={label}
206
- disabled={disabled}
207
- placeholder={placeholder}
208
- inputOnly={inputOnly}
209
- getValue={handleGetValue as <V>() => V | undefined}
210
- onValueChange={handleOnValueChange}
211
- {...restInputProps}
212
- />
213
- );
214
- };
@@ -1,72 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React, { type ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react';
6
-
7
- import { GeoLocation, type GeoPoint } from '@dxos/echo-schema';
8
- import { Input, useTranslation } from '@dxos/react-ui';
9
- import { safeParseFloat } from '@dxos/util';
10
-
11
- import { translationKey } from '../../../translations';
12
- import { InputHeader, type InputProps } from '../Input';
13
-
14
- export const GeoPointInput = ({ type, label, disabled, getStatus, getValue, onValueChange, onBlur }: InputProps) => {
15
- const { t } = useTranslation(translationKey);
16
- const { status, error } = getStatus();
17
- const geoPoint = useMemo<GeoPoint>(() => getValue<GeoPoint>() ?? [0, 0], [getValue]);
18
- const geoLocation = useMemo(() => GeoLocation.fromGeoPoint(geoPoint), [geoPoint]);
19
-
20
- const [longitudeText, setLongitudeText] = useState(geoLocation.longitude?.toString());
21
- const [latitudeText, setLatitudeText] = useState(geoLocation.latitude?.toString());
22
-
23
- useEffect(() => {
24
- const location = GeoLocation.fromGeoPoint(geoPoint);
25
- setLongitudeText(location.longitude.toString());
26
- setLatitudeText(location.latitude.toString());
27
- }, [geoPoint]);
28
-
29
- const handleCoordinateChange = useCallback(
30
- (coordinateType: keyof Pick<GeoLocation, 'longitude' | 'latitude'>, setText: (text: string) => void) =>
31
- (event: ChangeEvent<HTMLInputElement>) => {
32
- const inputText = event.target.value;
33
- setText(inputText);
34
- if (inputText !== '' && inputText !== '-') {
35
- const coord = safeParseFloat(inputText);
36
- if (coord !== undefined && !isNaN(coord)) {
37
- const currentLocation = GeoLocation.fromGeoPoint(getValue<GeoPoint>() ?? [0, 0]);
38
- const newLocation = { ...currentLocation, [coordinateType]: coord };
39
- const newValue = GeoLocation.toGeoPoint(newLocation);
40
- onValueChange(type, newValue);
41
- }
42
- }
43
- },
44
- [getValue, onValueChange, type],
45
- );
46
-
47
- return (
48
- <Input.Root validationValence={status}>
49
- <InputHeader error={error} label={label} />
50
- <div role='none' className='grid grid-cols-2 gap-2'>
51
- <Input.TextInput
52
- type='text'
53
- pattern='^-?[0-9]*\.?[0-9]*$'
54
- disabled={disabled}
55
- placeholder={t('placeholder latitude')}
56
- value={latitudeText}
57
- onChange={handleCoordinateChange('latitude', setLatitudeText)}
58
- onBlur={onBlur}
59
- />
60
- <Input.TextInput
61
- type='text'
62
- pattern='^-?[0-9]*\.?[0-9]*$'
63
- disabled={disabled}
64
- placeholder={t('placeholder longitude')}
65
- value={longitudeText}
66
- onChange={handleCoordinateChange('longitude', setLongitudeText)}
67
- onBlur={onBlur}
68
- />
69
- </div>
70
- </Input.Root>
71
- );
72
- };
@@ -1,62 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import '@dxos-theme';
6
-
7
- import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import { Schema } from 'effect';
9
- import React, { useState } from 'react';
10
-
11
- import { type SelectOption, SelectOptionSchema } from '@dxos/echo-schema';
12
- import { withLayout, withTheme } from '@dxos/storybook-utils';
13
-
14
- import { translations } from '../../../translations';
15
- import { TestLayout, TestPanel } from '../../testing';
16
- import { Form } from '../Form';
17
-
18
- import { SelectOptionInput } from './SelectOptionsInput';
19
-
20
- const schema = Schema.Struct({
21
- options: Schema.Array(SelectOptionSchema).pipe(Schema.mutable),
22
- }).pipe(Schema.mutable);
23
-
24
- const DefaultStory = () => {
25
- const [values, setValues] = useState<{ options: SelectOption[] }>({
26
- // TODO(Zaymon): Pick colors from our limited set.
27
- options: [
28
- { id: 'opt_1', title: 'First option', color: 'amber' },
29
- { id: 'opt_2', title: 'Second option', color: 'emerald' },
30
- { id: 'opt_3', title: 'Third option', color: 'rose' },
31
- ],
32
- });
33
-
34
- return (
35
- <TestLayout>
36
- <TestPanel>
37
- <Form
38
- schema={schema}
39
- values={values}
40
- onSave={(vals) => setValues(vals)}
41
- Custom={{ options: SelectOptionInput }}
42
- />
43
- </TestPanel>
44
- </TestLayout>
45
- );
46
- };
47
-
48
- const meta: Meta = {
49
- title: 'ui/react-ui-form/SelectOptionsInput',
50
- component: SelectOptionInput,
51
- render: DefaultStory,
52
- decorators: [withTheme, withLayout({ fullscreen: true })],
53
- parameters: {
54
- translations,
55
- },
56
- };
57
-
58
- export default meta;
59
-
60
- type Story = StoryObj;
61
-
62
- export const Default: Story = {};
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './GeoPointInput';
6
- export * from './SelectOptionsInput';
7
- export * from './TupleInput';
@@ -1,31 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { FormatEnum } from '@dxos/echo-schema';
6
- import { type SimpleType } from '@dxos/effect';
7
-
8
- import { GeoPointInput } from './custom';
9
- import { BooleanInput, MarkdownInput, NumberInput, TextInput } from './Defaults';
10
- import { type InputComponent } from './Input';
11
-
12
- /**
13
- * Get property input component.
14
- */
15
- export const getInputComponent = (type: SimpleType, format?: FormatEnum | string): InputComponent | undefined => {
16
- switch (format) {
17
- case FormatEnum.GeoPoint:
18
- return GeoPointInput;
19
- case FormatEnum.Markdown:
20
- return MarkdownInput;
21
- }
22
-
23
- switch (type) {
24
- case 'string':
25
- return TextInput;
26
- case 'number':
27
- return NumberInput;
28
- case 'boolean':
29
- return BooleanInput;
30
- }
31
- };
@@ -1,63 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import '@dxos-theme';
6
-
7
- import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import React from 'react';
9
-
10
- import { live } from '@dxos/live-object';
11
- import { TestSchema, type TestType, testData, testView } from '@dxos/schema/testing';
12
- import { withLayout, withTheme } from '@dxos/storybook-utils';
13
-
14
- import { translations } from '../../translations';
15
- import { TestLayout, TestPanel } from '../testing';
16
-
17
- import { DeprecatedForm, type DeprecatedFormProps } from './Form';
18
-
19
- const DefaultStory = (props: DeprecatedFormProps) => (
20
- <TestLayout json={{ props }}>
21
- <TestPanel>
22
- <DeprecatedForm {...props} />
23
- </TestPanel>
24
- </TestLayout>
25
- );
26
-
27
- const meta: Meta<typeof DefaultStory> = {
28
- title: 'ui/react-ui-form/DeprecatedForm',
29
- component: DeprecatedForm,
30
- render: DefaultStory,
31
- decorators: [withLayout({ fullscreen: true }), withTheme],
32
- parameters: {
33
- translations,
34
- },
35
- };
36
-
37
- export default meta;
38
-
39
- type Story = StoryObj<DeprecatedFormProps<TestType>>;
40
-
41
- export const Default: Story = {
42
- args: {
43
- object: live(testData),
44
- projection: live(testView).projection,
45
- schema: TestSchema,
46
- },
47
- };
48
-
49
- export const Empty: Story = {
50
- args: {
51
- projection: live(testView).projection,
52
- schema: TestSchema,
53
- },
54
- };
55
-
56
- export const Readonly: Story = {
57
- args: {
58
- object: live(testData),
59
- projection: live(testView).projection,
60
- schema: TestSchema,
61
- readonly: true,
62
- },
63
- };
@@ -1,119 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { Option, type Schema, SchemaAST, pipe } from 'effect';
6
- import React, { useState } from 'react';
7
-
8
- import { findProperty } from '@dxos/effect';
9
- import { Input, type TextInputProps as NativeTextInputProps, type ThemedClassName } from '@dxos/react-ui';
10
- import { mx } from '@dxos/react-ui-theme';
11
- import { type Projection, getFieldValue, setFieldValue } from '@dxos/schema';
12
-
13
- export type DeprecatedFormProps<T extends {} = {}> = ThemedClassName<{
14
- projection: Projection;
15
- object: T;
16
- schema?: Schema.Schema<T>;
17
- readonly?: boolean;
18
- }>;
19
-
20
- /**
21
- * Schema-based object form.
22
- */
23
- export const DeprecatedForm = <T extends {} = {}>({
24
- classNames,
25
- projection,
26
- object,
27
- schema,
28
- readonly,
29
- }: DeprecatedFormProps<T>) => {
30
- return (
31
- <div role='none' className={mx('flex flex-col w-full gap-2 p-2', classNames)}>
32
- {projection.fields.map((field) => {
33
- const prop = schema && findProperty(schema, field.path);
34
- const title = (prop && pipe(SchemaAST.getTitleAnnotation(prop), Option.getOrUndefined)) ?? '';
35
- const description = (prop && pipe(SchemaAST.getDescriptionAnnotation(prop), Option.getOrUndefined)) ?? title;
36
- // const format =
37
- // (prop && (getPatternAnnotation(prop) ?? (SchemaAST.isNumberKeyword(prop) && RealNumberFormat))) || undefined;
38
-
39
- //
40
- // Boolean
41
- //
42
-
43
- if (prop && SchemaAST.isBooleanKeyword(prop)) {
44
- const value = object && getFieldValue(object, field);
45
- const onChange = (checked: boolean) => {
46
- setFieldValue(object, field, checked);
47
- };
48
-
49
- return (
50
- <div key={field.path} className='flex flex-col w-full gap-1'>
51
- <Input.Root>
52
- <Input.Label classNames='px-1'>{title}</Input.Label>
53
- <Input.Switch disabled={readonly} checked={!!value} onCheckedChange={(checked) => onChange(checked)} />
54
- </Input.Root>
55
- </div>
56
- );
57
- }
58
-
59
- //
60
- // Strings
61
- // TODO(burdon): Other types:
62
- // - RichText editor
63
- // - Numbers (with formatting: commas, currency, etc.)
64
- // - Date (https://ark-ui.com/react/docs/components/date-picker)
65
- // - Enum (single/multi-select)
66
- //
67
-
68
- const value = object ? getFieldValue(object, field) : undefined;
69
-
70
- return (
71
- <div key={field.path} className='flex flex-col w-full gap-1'>
72
- <Input.Root>
73
- <Input.Label classNames='px-1'>{title}</Input.Label>
74
- <TextInput
75
- disabled={readonly}
76
- placeholder={description}
77
- // format={format}
78
- value={value ? String(value) : ''}
79
- onChange={(event) => setFieldValue(object, field, event.target.value)}
80
- />
81
- </Input.Root>
82
- </div>
83
- );
84
- })}
85
- </div>
86
- );
87
- };
88
-
89
- type TextInputProps = {
90
- // format?: PatternAnnotation;
91
- } & Omit<NativeTextInputProps, 'style'>;
92
-
93
- /**
94
- * @deprecated
95
- */
96
- // TODO(burdon): Remove.
97
- // TODO(burdon): Use schema validation directly.
98
- const TextInput = ({ onChange, ...props }: TextInputProps) => {
99
- const [valid, _setValid] = useState(true);
100
-
101
- const handleChange: NativeTextInputProps['onChange'] = (ev) => {
102
- // const text = ev.target.value;
103
- // if (!format?.filter || text.match(format.filter)) {
104
- onChange?.(ev);
105
- // if (format?.valid) {
106
- // setValid(format.valid.test(text));
107
- // }
108
- // }
109
- };
110
-
111
- return (
112
- <Input.TextInput
113
- {...props}
114
- // TODO(burdon): validationValence on Input.
115
- style={valid ? {} : ({ '--tw-ring-color': 'red' } as any)}
116
- onChange={handleChange}
117
- />
118
- );
119
- };
@@ -1,71 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import React, { type JSX, type PropsWithChildren } from 'react';
6
-
7
- import { Input, type ThemedClassName } from '@dxos/react-ui';
8
- import { mx, textBlockWidth } from '@dxos/react-ui-theme';
9
-
10
- /**
11
- * @deprecated
12
- */
13
- export const DeprecatedFormContainer = ({ children, classNames }: ThemedClassName<PropsWithChildren>) => {
14
- return (
15
- <div role='none' className='container-max-width p-4 justify-center overflow-x-hidden overflow-y-auto'>
16
- <div role='form' className={mx('flex flex-col', textBlockWidth, classNames)}>
17
- {children}
18
- </div>
19
- </div>
20
- );
21
- };
22
-
23
- export type DeprecatedFormInputProps = {
24
- label: string;
25
- description?: JSX.Element;
26
- secondary?: JSX.Element;
27
- };
28
-
29
- /**
30
- * @deprecated
31
- */
32
- export const DeprecatedFormInput = ({
33
- label,
34
- description,
35
- secondary,
36
- children,
37
- }: PropsWithChildren<DeprecatedFormInputProps>) => {
38
- const primary = (
39
- <div role='none' className='flex w-full gap-4 py-1'>
40
- <Input.Root>
41
- <div role='none' className='flex flex-col w-full'>
42
- <Input.Label classNames='flex min-bs-[--rail-action] items-center' style={{ fontSize: 'unset' }}>
43
- {label}
44
- </Input.Label>
45
- {description && (
46
- <Input.DescriptionAndValidation classNames='mbs-0.5'>
47
- <Input.Description>{description}</Input.Description>
48
- </Input.DescriptionAndValidation>
49
- )}
50
- </div>
51
-
52
- <div role='none'>
53
- <div role='none' className='flex min-bs-[--rail-action] items-center'>
54
- {children}
55
- </div>
56
- </div>
57
- </Input.Root>
58
- </div>
59
- );
60
-
61
- if (secondary) {
62
- return (
63
- <div role='none'>
64
- {primary}
65
- {secondary}
66
- </div>
67
- );
68
- }
69
-
70
- return primary;
71
- };
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './FormInput';