@dxos/react-ui-form 0.8.4-main.dedc0f3 → 0.8.4-main.dfabb4ec29

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 (234) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +2772 -2208
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/translations.mjs +82 -0
  6. package/dist/lib/browser/translations.mjs.map +7 -0
  7. package/dist/lib/node-esm/index.mjs +2772 -2208
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/lib/node-esm/translations.mjs +84 -0
  11. package/dist/lib/node-esm/translations.mjs.map +7 -0
  12. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +8 -7
  13. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  14. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +69 -60
  15. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.d.ts +109 -26
  17. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/Form.stories.d.ts +116 -138
  19. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormField.d.ts +43 -0
  21. package/dist/types/src/components/Form/FormField.d.ts.map +1 -0
  22. package/dist/types/src/components/Form/FormFieldComponent.d.ts +79 -0
  23. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -0
  24. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts +9 -0
  25. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Form/FormFieldSet.d.ts +15 -0
  27. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -0
  28. package/dist/types/src/components/Form/fields/ArrayField.d.ts +18 -0
  29. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -0
  30. package/dist/types/src/components/Form/fields/BooleanField.d.ts +4 -0
  31. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -0
  32. package/dist/types/src/components/Form/fields/GeoPointField.d.ts +5 -0
  33. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -0
  34. package/dist/types/src/components/Form/fields/MarkdownField.d.ts +11 -0
  35. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -0
  36. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts +84 -0
  37. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +1 -0
  38. package/dist/types/src/components/Form/fields/NumberField.d.ts +4 -0
  39. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -0
  40. package/dist/types/src/components/Form/fields/RefField.d.ts +22 -0
  41. package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -0
  42. package/dist/types/src/components/Form/fields/SelectField.d.ts +10 -0
  43. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -0
  44. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +5 -0
  45. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -0
  46. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +84 -0
  47. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -0
  48. package/dist/types/src/components/Form/fields/TextAreaField.d.ts +4 -0
  49. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -0
  50. package/dist/types/src/components/Form/fields/TextField.d.ts +4 -0
  51. package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -0
  52. package/dist/types/src/components/Form/fields/TupleField.d.ts +6 -0
  53. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -0
  54. package/dist/types/src/components/Form/fields/index.d.ts +12 -0
  55. package/dist/types/src/components/Form/fields/index.d.ts.map +1 -0
  56. package/dist/types/src/components/Form/index.d.ts +2 -4
  57. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  58. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts +9 -0
  59. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -0
  60. package/dist/types/src/components/ObjectForm/index.d.ts +2 -0
  61. package/dist/types/src/components/ObjectForm/index.d.ts.map +1 -0
  62. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +68 -0
  63. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
  64. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +87 -0
  65. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
  66. package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
  67. package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
  68. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +9 -0
  69. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -0
  70. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts +127 -0
  71. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts.map +1 -0
  72. package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts +2 -0
  73. package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts.map +1 -0
  74. package/dist/types/src/components/ObjectProperties/index.d.ts +2 -0
  75. package/dist/types/src/components/ObjectProperties/index.d.ts.map +1 -0
  76. package/dist/types/src/components/Settings/Settings.d.ts +51 -0
  77. package/dist/types/src/components/Settings/Settings.d.ts.map +1 -0
  78. package/dist/types/src/components/Settings/Settings.stories.d.ts +84 -0
  79. package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -0
  80. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +43 -0
  81. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +1 -0
  82. package/dist/types/src/components/Settings/SettingsItem.d.ts +16 -0
  83. package/dist/types/src/components/Settings/SettingsItem.d.ts.map +1 -0
  84. package/dist/types/src/components/Settings/SettingsSelectField.d.ts +18 -0
  85. package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +1 -0
  86. package/dist/types/src/components/Settings/index.d.ts +4 -0
  87. package/dist/types/src/components/Settings/index.d.ts.map +1 -0
  88. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +22 -11
  89. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  90. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +72 -65
  91. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/index.d.ts +4 -1
  93. package/dist/types/src/components/index.d.ts.map +1 -1
  94. package/dist/types/src/components/testing.d.ts +4 -6
  95. package/dist/types/src/components/testing.d.ts.map +1 -1
  96. package/dist/types/src/hooks/index.d.ts +2 -3
  97. package/dist/types/src/hooks/index.d.ts.map +1 -1
  98. package/dist/types/src/hooks/useFormHandler.d.ts +82 -0
  99. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -0
  100. package/dist/types/src/hooks/useKeyHandler.d.ts +7 -0
  101. package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -0
  102. package/dist/types/src/index.d.ts +0 -2
  103. package/dist/types/src/index.d.ts.map +1 -1
  104. package/dist/types/src/translations.d.ts +65 -59
  105. package/dist/types/src/translations.d.ts.map +1 -1
  106. package/dist/types/src/util/field-type.d.ts +19 -0
  107. package/dist/types/src/util/field-type.d.ts.map +1 -0
  108. package/dist/types/src/util/field.d.ts +3 -3
  109. package/dist/types/src/util/field.d.ts.map +1 -1
  110. package/dist/types/src/util/formatting.d.ts +2 -2
  111. package/dist/types/src/util/formatting.d.ts.map +1 -1
  112. package/dist/types/src/util/index.d.ts +2 -1
  113. package/dist/types/src/util/index.d.ts.map +1 -1
  114. package/dist/types/src/util/properties.d.ts +7 -0
  115. package/dist/types/src/util/properties.d.ts.map +1 -0
  116. package/dist/types/src/util/refs.d.ts +3 -3
  117. package/dist/types/src/util/refs.d.ts.map +1 -1
  118. package/dist/types/tsconfig.tsbuildinfo +1 -1
  119. package/package.json +56 -50
  120. package/src/components/FieldEditor/FieldEditor.stories.tsx +46 -26
  121. package/src/components/FieldEditor/FieldEditor.test.tsx +0 -1
  122. package/src/components/FieldEditor/FieldEditor.tsx +80 -80
  123. package/src/components/Form/AUDIT.md +17 -0
  124. package/src/components/Form/Form.stories.tsx +142 -254
  125. package/src/components/Form/Form.tsx +375 -99
  126. package/src/components/Form/FormField.tsx +306 -0
  127. package/src/components/Form/FormFieldComponent.stories.tsx +65 -0
  128. package/src/components/Form/FormFieldComponent.tsx +174 -0
  129. package/src/components/Form/FormFieldSet.tsx +144 -0
  130. package/src/components/Form/README.md +3 -0
  131. package/src/components/Form/fields/ArrayField.tsx +155 -0
  132. package/src/components/Form/fields/BooleanField.tsx +22 -0
  133. package/src/components/Form/fields/GeoPointField.tsx +121 -0
  134. package/src/components/Form/fields/MarkdownField.stories.tsx +206 -0
  135. package/src/components/Form/fields/MarkdownField.tsx +168 -0
  136. package/src/components/Form/fields/NumberField.tsx +39 -0
  137. package/src/components/Form/fields/RefField.tsx +229 -0
  138. package/src/components/Form/fields/SelectField.tsx +65 -0
  139. package/src/components/Form/fields/SelectOptionField.stories.tsx +66 -0
  140. package/src/components/Form/{custom/SelectOptionsInput.tsx → fields/SelectOptionField.tsx} +31 -25
  141. package/src/components/Form/fields/TextAreaField.tsx +38 -0
  142. package/src/components/Form/fields/TextField.tsx +38 -0
  143. package/src/components/Form/{custom/TupleInput.tsx → fields/TupleField.tsx} +16 -9
  144. package/src/components/Form/fields/index.ts +15 -0
  145. package/src/components/Form/index.ts +3 -4
  146. package/src/components/ObjectForm/ObjectForm.tsx +114 -0
  147. package/src/components/{ControlSection → ObjectForm}/index.ts +1 -1
  148. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +212 -0
  149. package/src/components/ObjectPicker/ObjectPicker.tsx +202 -0
  150. package/src/components/ObjectPicker/index.ts +5 -0
  151. package/src/components/ObjectProperties/ObjectProperties.stories.tsx +362 -0
  152. package/src/components/ObjectProperties/ObjectProperties.test.tsx +101 -0
  153. package/src/components/ObjectProperties/ObjectProperties.tsx +141 -0
  154. package/src/components/ObjectProperties/index.ts +5 -0
  155. package/src/components/Settings/AUDIT.md +52 -0
  156. package/src/components/Settings/Settings.stories.tsx +104 -0
  157. package/src/components/Settings/Settings.tsx +80 -0
  158. package/src/components/Settings/SettingsFieldSet.tsx +257 -0
  159. package/src/components/Settings/SettingsItem.tsx +58 -0
  160. package/src/components/Settings/SettingsSelectField.tsx +59 -0
  161. package/src/components/Settings/index.ts +7 -0
  162. package/src/components/ViewEditor/ViewEditor.stories.tsx +126 -75
  163. package/src/components/ViewEditor/ViewEditor.test.tsx +10 -9
  164. package/src/components/ViewEditor/ViewEditor.tsx +326 -195
  165. package/src/components/index.ts +4 -1
  166. package/src/components/testing.tsx +24 -11
  167. package/src/hooks/index.ts +2 -3
  168. package/src/hooks/useFormHandler.ts +380 -0
  169. package/src/hooks/useKeyHandler.tsx +37 -0
  170. package/src/index.ts +0 -4
  171. package/src/translations.ts +70 -64
  172. package/src/util/field-type.ts +60 -0
  173. package/src/util/field.ts +25 -25
  174. package/src/util/formatting.ts +22 -22
  175. package/src/util/index.ts +2 -1
  176. package/src/util/properties.ts +18 -0
  177. package/src/util/refs.ts +17 -19
  178. package/dist/types/src/components/ControlSection/ControlSection.d.ts +0 -23
  179. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +0 -1
  180. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +0 -83
  181. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +0 -1
  182. package/dist/types/src/components/ControlSection/index.d.ts +0 -2
  183. package/dist/types/src/components/ControlSection/index.d.ts.map +0 -1
  184. package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
  185. package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
  186. package/dist/types/src/components/Form/Defaults.d.ts +0 -14
  187. package/dist/types/src/components/Form/Defaults.d.ts.map +0 -1
  188. package/dist/types/src/components/Form/FormActions.d.ts +0 -9
  189. package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
  190. package/dist/types/src/components/Form/FormContent.d.ts +0 -63
  191. package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
  192. package/dist/types/src/components/Form/FormContext.d.ts +0 -23
  193. package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
  194. package/dist/types/src/components/Form/Input.d.ts +0 -29
  195. package/dist/types/src/components/Form/Input.d.ts.map +0 -1
  196. package/dist/types/src/components/Form/RefField.d.ts +0 -18
  197. package/dist/types/src/components/Form/RefField.d.ts.map +0 -1
  198. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +0 -4
  199. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +0 -1
  200. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +0 -4
  201. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +0 -1
  202. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +0 -78
  203. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +0 -1
  204. package/dist/types/src/components/Form/custom/TupleInput.d.ts +0 -6
  205. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +0 -1
  206. package/dist/types/src/components/Form/custom/index.d.ts +0 -4
  207. package/dist/types/src/components/Form/custom/index.d.ts.map +0 -1
  208. package/dist/types/src/components/Form/factory.d.ts +0 -8
  209. package/dist/types/src/components/Form/factory.d.ts.map +0 -1
  210. package/dist/types/src/hooks/useForm.d.ts +0 -67
  211. package/dist/types/src/hooks/useForm.d.ts.map +0 -1
  212. package/dist/types/src/hooks/useQueryRefOptions.d.ts +0 -23
  213. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +0 -1
  214. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
  215. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
  216. package/dist/types/src/util/schema.d.ts +0 -3
  217. package/dist/types/src/util/schema.d.ts.map +0 -1
  218. package/src/components/ControlSection/ControlSection.stories.tsx +0 -39
  219. package/src/components/ControlSection/ControlSection.tsx +0 -153
  220. package/src/components/Form/ArrayField.tsx +0 -124
  221. package/src/components/Form/Defaults.tsx +0 -205
  222. package/src/components/Form/FormActions.tsx +0 -54
  223. package/src/components/Form/FormContent.tsx +0 -302
  224. package/src/components/Form/FormContext.tsx +0 -110
  225. package/src/components/Form/Input.tsx +0 -54
  226. package/src/components/Form/RefField.tsx +0 -299
  227. package/src/components/Form/custom/GeoPointInput.tsx +0 -80
  228. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -62
  229. package/src/components/Form/custom/index.ts +0 -7
  230. package/src/components/Form/factory.tsx +0 -31
  231. package/src/hooks/useForm.ts +0 -293
  232. package/src/hooks/useQueryRefOptions.ts +0 -53
  233. package/src/hooks/useRefQueryLookupHandler.ts +0 -39
  234. package/src/util/schema.ts +0 -14
@@ -1,54 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React, { type FC } from 'react';
6
-
7
- import { type FormatEnum } from '@dxos/echo-schema';
8
- import { type SimpleType } from '@dxos/effect';
9
- import { Icon, Input, Tooltip } from '@dxos/react-ui';
10
- import { labelSpacing } from '@dxos/react-ui-stack';
11
- import { errorText, mx } from '@dxos/react-ui-theme';
12
-
13
- import { type FormInputStateProps } from './FormContext';
14
-
15
- /**
16
- * Props passed to input components.
17
- */
18
- export type InputProps = {
19
- type: SimpleType;
20
- format?: FormatEnum;
21
- label: string;
22
- placeholder?: string;
23
- inputOnly?: boolean;
24
- /**
25
- * Specifies the readonly variant: either disabled inputs, elements indicating they are usually editable but currently are not; or `static`, a field’s representation as regular content without signifiers that it is ever editable.
26
- */
27
- readonly?: 'disabled-input' | 'static' | false;
28
- } & FormInputStateProps;
29
-
30
- /**
31
- * Form input component.
32
- */
33
- export type InputComponent = FC<InputProps>;
34
-
35
- export type InputHeaderProps = {
36
- error?: string;
37
- label: string;
38
- readonly?: boolean;
39
- };
40
-
41
- export const InputHeader = ({ error, label, readonly }: InputHeaderProps) => {
42
- const Label = readonly ? 'span' : Input.Label;
43
- const labelProps = readonly ? {} : { classNames: '!mlb-0' };
44
- return (
45
- <div role='none' className={mx('flex justify-between items-center', labelSpacing)}>
46
- <Label {...labelProps}>{label}</Label>
47
- {error && (
48
- <Tooltip.Trigger asChild content={error} side='bottom'>
49
- <Icon icon='ph--warning--regular' size={4} classNames={errorText} />
50
- </Tooltip.Trigger>
51
- )}
52
- </div>
53
- );
54
- };
@@ -1,299 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { type SchemaAST } from 'effect';
6
- import React, { useCallback, useMemo, useState } from 'react';
7
-
8
- import {
9
- Expando,
10
- Ref,
11
- ReferenceAnnotationId,
12
- type ReferenceAnnotationValue,
13
- type TypeAnnotation,
14
- getTypeAnnotation,
15
- } from '@dxos/echo-schema';
16
- import { findAnnotation } from '@dxos/effect';
17
- import { DXN } from '@dxos/keys';
18
- import { type DxTagPickerItemClick } from '@dxos/lit-ui';
19
- import { DxAnchor } from '@dxos/lit-ui/react';
20
- import { Button, Icon, Input, useTranslation } from '@dxos/react-ui';
21
- import { PopoverCombobox } from '@dxos/react-ui-searchlist';
22
- import { TagPickerItem } from '@dxos/react-ui-tag-picker';
23
- import { descriptionText, mx } from '@dxos/react-ui-theme';
24
- import { type MaybePromise, isNonNullable } from '@dxos/util';
25
-
26
- import { type QueryRefOptions, useQueryRefOptions } from '../../hooks';
27
- import { translationKey } from '../../translations';
28
-
29
- import { TextInput } from './Defaults';
30
- import { InputHeader, type InputProps } from './Input';
31
-
32
- export type RefFieldProps = InputProps & {
33
- ast?: SchemaAST.AST;
34
- array?: boolean;
35
- onQueryRefOptions?: QueryRefOptions;
36
- createOptionLabel?: [string, { ns: string }];
37
- createOptionIcon?: string;
38
- onCreateFromQuery?: (type: TypeAnnotation, query: string) => MaybePromise<void>;
39
- };
40
-
41
- // TODO(thure): Is this a standard that should be better canonized?
42
- const isRefSnapShot = (val: any): val is { '/': string } => {
43
- return typeof val === 'object' && typeof (val as any)?.['/'] === 'string';
44
- };
45
-
46
- export const RefField = ({
47
- type,
48
- label,
49
- readonly,
50
- placeholder,
51
- inputOnly,
52
- array,
53
- ast,
54
- getValue,
55
- onBlur,
56
- onQueryRefOptions,
57
- createOptionLabel,
58
- createOptionIcon,
59
- onCreateFromQuery,
60
- onValueChange,
61
- ...restInputProps
62
- }: RefFieldProps) => {
63
- const { t } = useTranslation(translationKey);
64
- const refTypeInfo = useMemo(
65
- () => (ast ? findAnnotation<ReferenceAnnotationValue>(ast, ReferenceAnnotationId) : undefined),
66
- [ast],
67
- );
68
- const { options: availableOptions, loading: _loading } = useQueryRefOptions({ refTypeInfo, onQueryRefOptions });
69
-
70
- if ((refTypeInfo && refTypeInfo?.typename === getTypeAnnotation(Expando)?.typename) || !onQueryRefOptions) {
71
- // If ref type is expando, fall back to taking a DXN in string format.
72
- return (
73
- <RefFieldFallback
74
- {...{ type, label, placeholder, readonly, inputOnly, getValue, onBlur, onValueChange, ...restInputProps }}
75
- />
76
- );
77
- }
78
-
79
- const handleGetValue = useCallback(() => {
80
- const formValue = getValue();
81
-
82
- const unknownToRefOption = (val: unknown) => {
83
- const isRef = Ref.isRef(val);
84
- if (isRef || isRefSnapShot(val)) {
85
- const dxnString = isRef ? val.dxn.toString() : val['/'];
86
- const matchingOption = availableOptions.find((option) => option.id === dxnString);
87
- if (matchingOption) {
88
- return matchingOption;
89
- }
90
- }
91
- return undefined;
92
- };
93
-
94
- if (array && Array.isArray(formValue)) {
95
- return formValue.map(unknownToRefOption).filter(isNonNullable) ?? [];
96
- }
97
-
98
- const option = unknownToRefOption(formValue);
99
- if (option) {
100
- return [option];
101
- }
102
-
103
- return [];
104
- }, [getValue, availableOptions, array]);
105
-
106
- const handleUpdate = useCallback(
107
- (ids: string[]) => {
108
- if (ids.length === 0) {
109
- onValueChange('object', undefined);
110
- return;
111
- }
112
-
113
- const refs = ids
114
- .map((id) => {
115
- const item = availableOptions.find((option) => option.id === id);
116
- if (item) {
117
- const dxn = DXN.parse(item.id);
118
- return Ref.fromDXN(dxn);
119
- }
120
- return null;
121
- })
122
- .filter(isNonNullable);
123
-
124
- if (array) {
125
- onValueChange('object', refs);
126
- } else {
127
- onValueChange('object', refs[0]);
128
- }
129
- },
130
- [availableOptions, array, onValueChange],
131
- );
132
-
133
- if (!refTypeInfo) {
134
- return null;
135
- }
136
-
137
- const { status, error } = restInputProps.getStatus();
138
-
139
- const items = handleGetValue();
140
- const selectedIds = useMemo(() => items.map((i: any) => i.id), [items]);
141
- const labelById = useMemo(
142
- () =>
143
- availableOptions.reduce((acc: Record<string, string>, option) => {
144
- acc[option.id.toLowerCase()] = option.label.toLowerCase();
145
- return acc;
146
- }, {}),
147
- [availableOptions],
148
- );
149
- const [query, setQuery] = useState('');
150
- const toggleSelect = useCallback(
151
- (id: string) => {
152
- if (array) {
153
- const nextIds = selectedIds.includes(id) ? selectedIds.filter((x) => x !== id) : [...selectedIds, id];
154
- handleUpdate(nextIds);
155
- } else {
156
- if (selectedIds[0] === id) {
157
- handleUpdate([]);
158
- } else {
159
- handleUpdate([id]);
160
- }
161
- }
162
- },
163
- [array, selectedIds, handleUpdate],
164
- );
165
-
166
- // NOTE(thure): I left both predicates in-place in case we decide to add variants which do render readonly but empty values.
167
- return readonly && items.length < 1 ? null : (
168
- <Input.Root validationValence={status}>
169
- {!inputOnly && <InputHeader error={error} label={label} />}
170
- <div data-no-submit>
171
- {readonly ? (
172
- items.length < 1 ? (
173
- <p className={mx(descriptionText, 'mbe-2')}>{t('empty readonly ref field label')}</p>
174
- ) : (
175
- items.map((item) => (
176
- <DxAnchor key={item.id} refid={item.id} rootclassname='mie-1'>
177
- {item.label}
178
- </DxAnchor>
179
- ))
180
- )
181
- ) : (
182
- <PopoverCombobox.Root>
183
- <PopoverCombobox.Trigger asChild>
184
- <Button variant='ghost' classNames='is-full text-start gap-2'>
185
- <div role='none' className='grow'>
186
- {items?.length ? (
187
- items?.map((item) => (
188
- <TagPickerItem
189
- key={item.id}
190
- itemId={item.id}
191
- label={item.label}
192
- {...(item.hue ? { hue: item.hue } : {})}
193
- removeLabel={t('remove item label')}
194
- onItemClick={(event: DxTagPickerItemClick) => {
195
- if (event.action === 'remove') {
196
- toggleSelect(item.id);
197
- }
198
- }}
199
- />
200
- ))
201
- ) : (
202
- <span className='text-description'>
203
- {placeholder ?? t('ref field placeholder', { count: array ? 99 : 1 })}
204
- </span>
205
- )}
206
- </div>
207
- <Icon size={3} icon='ph--caret-down--bold' />
208
- </Button>
209
- </PopoverCombobox.Trigger>
210
- <PopoverCombobox.Content
211
- filter={(value, search) =>
212
- value === '__create__' || labelById[value]?.includes(search.toLowerCase()) ? 1 : 0
213
- }
214
- >
215
- <PopoverCombobox.Input
216
- placeholder={'Search...'}
217
- value={query}
218
- onValueChange={(v) => setQuery(v)}
219
- autoFocus
220
- />
221
- <PopoverCombobox.List>
222
- {availableOptions.map((option) => (
223
- <PopoverCombobox.Item
224
- key={option.id}
225
- value={option.id}
226
- onSelect={() => toggleSelect(option.id)}
227
- classNames='flex items-center gap-2'
228
- >
229
- <span className='grow'>{option.label}</span>
230
- {selectedIds.includes(option.id) && <Icon icon='ph--check--regular' />}
231
- </PopoverCombobox.Item>
232
- ))}
233
- {query.length > 0 && createOptionLabel && createOptionIcon && onCreateFromQuery && (
234
- <PopoverCombobox.Item
235
- value='__create__'
236
- onSelect={() => onCreateFromQuery?.(refTypeInfo, query)}
237
- classNames='flex items-center gap-2'
238
- >
239
- <Icon icon={createOptionIcon} />
240
- {t(createOptionLabel[0], { ns: createOptionLabel[1].ns, text: query })}
241
- </PopoverCombobox.Item>
242
- )}
243
- </PopoverCombobox.List>
244
- <PopoverCombobox.Arrow />
245
- </PopoverCombobox.Content>
246
- </PopoverCombobox.Root>
247
- )}
248
- </div>
249
- {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
250
- </Input.Root>
251
- );
252
- };
253
-
254
- const RefFieldFallback = ({
255
- type,
256
- label,
257
- readonly,
258
- placeholder,
259
- inputOnly,
260
- getValue,
261
- onValueChange,
262
- ...restInputProps
263
- }: InputProps) => {
264
- const handleOnValueChange = (_type: any, dxnString: string) => {
265
- const dxn = DXN.tryParse(dxnString);
266
- if (dxn) {
267
- onValueChange?.('object', Ref.fromDXN(dxn));
268
- } else if (dxnString === '') {
269
- onValueChange?.('object', undefined);
270
- } else {
271
- onValueChange?.('string', dxnString);
272
- }
273
- };
274
-
275
- const handleGetValue = () => {
276
- const formValue = getValue();
277
- if (typeof formValue === 'string') {
278
- return formValue;
279
- }
280
- if (Ref.isRef(formValue)) {
281
- return formValue.dxn.toString();
282
- }
283
-
284
- return undefined;
285
- };
286
-
287
- return (
288
- <TextInput
289
- type={type}
290
- label={label}
291
- readonly={readonly}
292
- placeholder={placeholder}
293
- inputOnly={inputOnly}
294
- getValue={handleGetValue as <V>() => V | undefined}
295
- onValueChange={handleOnValueChange}
296
- {...restInputProps}
297
- />
298
- );
299
- };
@@ -1,80 +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, readonly, 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
- <div role='none'>
52
- <Input.Label>{t('latitude label')}</Input.Label>
53
- <Input.TextInput
54
- type='number'
55
- step='0.00001'
56
- min='-90'
57
- max='90'
58
- disabled={!!readonly}
59
- value={latitudeText}
60
- onChange={handleCoordinateChange('latitude', setLatitudeText)}
61
- onBlur={onBlur}
62
- />
63
- </div>
64
- <div role='none'>
65
- <Input.Label>{t('longitude label')}</Input.Label>
66
- <Input.TextInput
67
- type='number'
68
- step='0.00001'
69
- min='-180'
70
- max='180'
71
- disabled={!!readonly}
72
- value={longitudeText}
73
- onChange={handleCoordinateChange('longitude', setLongitudeText)}
74
- onBlur={onBlur}
75
- />
76
- </div>
77
- </div>
78
- </Input.Root>
79
- );
80
- };
@@ -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 = {
49
- title: 'ui/react-ui-form/SelectOptionsInput',
50
- component: SelectOptionInput as any,
51
- render: DefaultStory,
52
- decorators: [withTheme, withLayout({ fullscreen: true })],
53
- parameters: {
54
- translations,
55
- },
56
- } satisfies Meta<typeof DefaultStory>;
57
-
58
- export default meta;
59
-
60
- type Story = StoryObj<typeof meta>;
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
- };