@questpie/admin 0.0.1 → 1.0.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.
Files changed (250) hide show
  1. package/README.md +439 -424
  2. package/dist/auth-layout-M8K8_q5R.mjs +181 -0
  3. package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
  4. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs +273 -0
  5. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs.map +1 -0
  6. package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
  7. package/dist/card-BKHjBQfw.mjs.map +1 -0
  8. package/dist/client/styles/index.css +434 -0
  9. package/dist/client-DbpZKSgH.d.mts +13585 -0
  10. package/dist/client-DbpZKSgH.d.mts.map +1 -0
  11. package/dist/client-njX1rZmi.mjs +22612 -0
  12. package/dist/client-njX1rZmi.mjs.map +1 -0
  13. package/dist/client.d.mts +3 -0
  14. package/dist/client.mjs +13 -0
  15. package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
  16. package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
  17. package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
  18. package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
  19. package/dist/dashboard-page-mCY0pgZv.mjs +3 -0
  20. package/dist/dropzone-Do3awXKd.mjs +634 -0
  21. package/dist/dropzone-Do3awXKd.mjs.map +1 -0
  22. package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
  23. package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
  24. package/dist/forgot-password-page-CEwsdLwn.mjs +3 -0
  25. package/dist/index-B9Xwk4hi.d.mts +2753 -0
  26. package/dist/index-B9Xwk4hi.d.mts.map +1 -0
  27. package/dist/index.d.mts +3 -0
  28. package/dist/index.mjs +13 -0
  29. package/dist/login-page-BUnpCbCa.mjs +3 -0
  30. package/dist/login-page-CP4gA-dl.mjs +298 -0
  31. package/dist/login-page-CP4gA-dl.mjs.map +1 -0
  32. package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
  33. package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
  34. package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
  35. package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
  36. package/dist/reset-password-page-CufHz3h3.mjs +3 -0
  37. package/dist/runtime-6VZM878K.mjs +69 -0
  38. package/dist/runtime-6VZM878K.mjs.map +1 -0
  39. package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
  40. package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
  41. package/dist/server.d.mts +250 -0
  42. package/dist/server.d.mts.map +1 -0
  43. package/dist/server.mjs +832 -0
  44. package/dist/server.mjs.map +1 -0
  45. package/dist/setup-page-BNNzt_Z6.mjs +3 -0
  46. package/dist/setup-page-YAP_fzqh.mjs +264 -0
  47. package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
  48. package/dist/shared.d.mts +57 -0
  49. package/dist/shared.d.mts.map +1 -0
  50. package/dist/shared.mjs +3 -0
  51. package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
  52. package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
  53. package/package.json +48 -198
  54. package/.turbo/turbo-build.log +0 -108
  55. package/CHANGELOG.md +0 -10
  56. package/STATUS.md +0 -917
  57. package/VALIDATION.md +0 -602
  58. package/components.json +0 -24
  59. package/dist/__tests__/setup.mjs +0 -38
  60. package/dist/__tests__/test-utils.mjs +0 -45
  61. package/dist/__tests__/vitest.d.mjs +0 -3
  62. package/dist/components/admin-app.mjs +0 -69
  63. package/dist/components/fields/array-field.mjs +0 -190
  64. package/dist/components/fields/checkbox-field.mjs +0 -34
  65. package/dist/components/fields/custom-field.mjs +0 -32
  66. package/dist/components/fields/date-field.mjs +0 -41
  67. package/dist/components/fields/datetime-field.mjs +0 -42
  68. package/dist/components/fields/email-field.mjs +0 -37
  69. package/dist/components/fields/embedded-collection.mjs +0 -253
  70. package/dist/components/fields/field-types.mjs +0 -1
  71. package/dist/components/fields/field-utils.mjs +0 -10
  72. package/dist/components/fields/field-wrapper.mjs +0 -34
  73. package/dist/components/fields/index.mjs +0 -23
  74. package/dist/components/fields/json-field.mjs +0 -243
  75. package/dist/components/fields/locale-badge.mjs +0 -16
  76. package/dist/components/fields/number-field.mjs +0 -39
  77. package/dist/components/fields/password-field.mjs +0 -37
  78. package/dist/components/fields/relation-field.mjs +0 -104
  79. package/dist/components/fields/relation-picker.mjs +0 -229
  80. package/dist/components/fields/relation-select.mjs +0 -188
  81. package/dist/components/fields/rich-text-editor/index.mjs +0 -897
  82. package/dist/components/fields/select-field.mjs +0 -41
  83. package/dist/components/fields/switch-field.mjs +0 -34
  84. package/dist/components/fields/text-field.mjs +0 -38
  85. package/dist/components/fields/textarea-field.mjs +0 -38
  86. package/dist/components/index.mjs +0 -59
  87. package/dist/components/primitives/checkbox-input.mjs +0 -127
  88. package/dist/components/primitives/date-input.mjs +0 -303
  89. package/dist/components/primitives/index.mjs +0 -12
  90. package/dist/components/primitives/number-input.mjs +0 -104
  91. package/dist/components/primitives/select-input.mjs +0 -177
  92. package/dist/components/primitives/tag-input.mjs +0 -135
  93. package/dist/components/primitives/text-input.mjs +0 -39
  94. package/dist/components/primitives/textarea-input.mjs +0 -37
  95. package/dist/components/primitives/toggle-input.mjs +0 -31
  96. package/dist/components/primitives/types.mjs +0 -12
  97. package/dist/components/ui/accordion.mjs +0 -55
  98. package/dist/components/ui/avatar.mjs +0 -54
  99. package/dist/components/ui/badge.mjs +0 -34
  100. package/dist/components/ui/button.mjs +0 -48
  101. package/dist/components/ui/checkbox.mjs +0 -21
  102. package/dist/components/ui/combobox.mjs +0 -163
  103. package/dist/components/ui/dialog.mjs +0 -95
  104. package/dist/components/ui/dropdown-menu.mjs +0 -138
  105. package/dist/components/ui/field.mjs +0 -113
  106. package/dist/components/ui/input-group.mjs +0 -82
  107. package/dist/components/ui/input.mjs +0 -17
  108. package/dist/components/ui/label.mjs +0 -15
  109. package/dist/components/ui/popover.mjs +0 -56
  110. package/dist/components/ui/scroll-area.mjs +0 -38
  111. package/dist/components/ui/select.mjs +0 -100
  112. package/dist/components/ui/separator.mjs +0 -16
  113. package/dist/components/ui/sheet.mjs +0 -90
  114. package/dist/components/ui/sidebar.mjs +0 -387
  115. package/dist/components/ui/skeleton.mjs +0 -14
  116. package/dist/components/ui/spinner.mjs +0 -16
  117. package/dist/components/ui/switch.mjs +0 -22
  118. package/dist/components/ui/table.mjs +0 -68
  119. package/dist/components/ui/tabs.mjs +0 -48
  120. package/dist/components/ui/textarea.mjs +0 -15
  121. package/dist/components/ui/tooltip.mjs +0 -44
  122. package/dist/config/component-registry.mjs +0 -38
  123. package/dist/config/index.mjs +0 -129
  124. package/dist/hooks/admin-provider.mjs +0 -70
  125. package/dist/hooks/index.mjs +0 -7
  126. package/dist/hooks/store.mjs +0 -178
  127. package/dist/hooks/use-collection-db.mjs +0 -146
  128. package/dist/hooks/use-collection.mjs +0 -112
  129. package/dist/hooks/use-global.mjs +0 -46
  130. package/dist/hooks/use-mobile.mjs +0 -20
  131. package/dist/lib/utils.mjs +0 -10
  132. package/dist/styles/index.css +0 -336
  133. package/dist/styles/index.mjs +0 -1
  134. package/dist/utils/index.mjs +0 -9
  135. package/dist/views/auth/auth-layout.mjs +0 -52
  136. package/dist/views/auth/index.mjs +0 -6
  137. package/dist/views/auth/login-form.mjs +0 -156
  138. package/dist/views/collection/auto-form-fields.mjs +0 -525
  139. package/dist/views/collection/collection-form.mjs +0 -91
  140. package/dist/views/collection/collection-list.mjs +0 -76
  141. package/dist/views/collection/form-field.mjs +0 -42
  142. package/dist/views/collection/index.mjs +0 -6
  143. package/dist/views/common/index.mjs +0 -4
  144. package/dist/views/common/locale-switcher.mjs +0 -39
  145. package/dist/views/common/version-history.mjs +0 -272
  146. package/dist/views/index.mjs +0 -9
  147. package/dist/views/layout/admin-layout.mjs +0 -40
  148. package/dist/views/layout/admin-router.mjs +0 -95
  149. package/dist/views/layout/admin-sidebar.mjs +0 -63
  150. package/dist/views/layout/index.mjs +0 -5
  151. package/src/__tests__/setup.ts +0 -44
  152. package/src/__tests__/test-utils.tsx +0 -49
  153. package/src/__tests__/vitest.d.ts +0 -9
  154. package/src/components/admin-app.tsx +0 -221
  155. package/src/components/fields/array-field.tsx +0 -237
  156. package/src/components/fields/checkbox-field.tsx +0 -47
  157. package/src/components/fields/custom-field.tsx +0 -50
  158. package/src/components/fields/date-field.tsx +0 -65
  159. package/src/components/fields/datetime-field.tsx +0 -67
  160. package/src/components/fields/email-field.tsx +0 -51
  161. package/src/components/fields/embedded-collection.tsx +0 -315
  162. package/src/components/fields/field-types.ts +0 -162
  163. package/src/components/fields/field-utils.ts +0 -6
  164. package/src/components/fields/field-wrapper.tsx +0 -52
  165. package/src/components/fields/index.ts +0 -66
  166. package/src/components/fields/json-field.tsx +0 -440
  167. package/src/components/fields/locale-badge.tsx +0 -15
  168. package/src/components/fields/number-field.tsx +0 -57
  169. package/src/components/fields/password-field.tsx +0 -51
  170. package/src/components/fields/relation-field.tsx +0 -243
  171. package/src/components/fields/relation-picker.tsx +0 -402
  172. package/src/components/fields/relation-select.tsx +0 -327
  173. package/src/components/fields/rich-text-editor/index.tsx +0 -1337
  174. package/src/components/fields/select-field.tsx +0 -61
  175. package/src/components/fields/switch-field.tsx +0 -47
  176. package/src/components/fields/text-field.tsx +0 -55
  177. package/src/components/fields/textarea-field.tsx +0 -55
  178. package/src/components/index.ts +0 -40
  179. package/src/components/primitives/checkbox-input.tsx +0 -193
  180. package/src/components/primitives/date-input.tsx +0 -401
  181. package/src/components/primitives/index.ts +0 -24
  182. package/src/components/primitives/number-input.tsx +0 -132
  183. package/src/components/primitives/select-input.tsx +0 -296
  184. package/src/components/primitives/tag-input.tsx +0 -200
  185. package/src/components/primitives/text-input.tsx +0 -49
  186. package/src/components/primitives/textarea-input.tsx +0 -46
  187. package/src/components/primitives/toggle-input.tsx +0 -36
  188. package/src/components/primitives/types.ts +0 -235
  189. package/src/components/ui/accordion.tsx +0 -72
  190. package/src/components/ui/avatar.tsx +0 -106
  191. package/src/components/ui/badge.tsx +0 -48
  192. package/src/components/ui/button.tsx +0 -53
  193. package/src/components/ui/card.tsx +0 -94
  194. package/src/components/ui/checkbox.tsx +0 -27
  195. package/src/components/ui/combobox.tsx +0 -290
  196. package/src/components/ui/dialog.tsx +0 -151
  197. package/src/components/ui/dropdown-menu.tsx +0 -254
  198. package/src/components/ui/field.tsx +0 -227
  199. package/src/components/ui/input-group.tsx +0 -149
  200. package/src/components/ui/input.tsx +0 -20
  201. package/src/components/ui/label.tsx +0 -18
  202. package/src/components/ui/popover.tsx +0 -88
  203. package/src/components/ui/scroll-area.tsx +0 -53
  204. package/src/components/ui/select.tsx +0 -192
  205. package/src/components/ui/separator.tsx +0 -23
  206. package/src/components/ui/sheet.tsx +0 -127
  207. package/src/components/ui/sidebar.tsx +0 -723
  208. package/src/components/ui/skeleton.tsx +0 -13
  209. package/src/components/ui/spinner.tsx +0 -10
  210. package/src/components/ui/switch.tsx +0 -32
  211. package/src/components/ui/table.tsx +0 -99
  212. package/src/components/ui/tabs.tsx +0 -82
  213. package/src/components/ui/textarea.tsx +0 -18
  214. package/src/components/ui/tooltip.tsx +0 -70
  215. package/src/config/component-registry.ts +0 -190
  216. package/src/config/index.ts +0 -1099
  217. package/src/hooks/README.md +0 -269
  218. package/src/hooks/admin-provider.tsx +0 -110
  219. package/src/hooks/index.ts +0 -41
  220. package/src/hooks/store.ts +0 -248
  221. package/src/hooks/use-auth.ts +0 -168
  222. package/src/hooks/use-collection-db.ts +0 -209
  223. package/src/hooks/use-collection.ts +0 -156
  224. package/src/hooks/use-global.ts +0 -69
  225. package/src/hooks/use-mobile.ts +0 -21
  226. package/src/lib/utils.ts +0 -6
  227. package/src/styles/index.css +0 -340
  228. package/src/utils/index.ts +0 -6
  229. package/src/views/auth/auth-layout.tsx +0 -77
  230. package/src/views/auth/forgot-password-form.tsx +0 -192
  231. package/src/views/auth/index.ts +0 -21
  232. package/src/views/auth/login-form.tsx +0 -229
  233. package/src/views/auth/reset-password-form.tsx +0 -232
  234. package/src/views/collection/auto-form-fields.tsx +0 -982
  235. package/src/views/collection/collection-form.tsx +0 -186
  236. package/src/views/collection/collection-list.tsx +0 -223
  237. package/src/views/collection/form-field.tsx +0 -52
  238. package/src/views/collection/index.ts +0 -15
  239. package/src/views/common/index.ts +0 -8
  240. package/src/views/common/locale-switcher.tsx +0 -45
  241. package/src/views/common/version-history.tsx +0 -406
  242. package/src/views/index.ts +0 -25
  243. package/src/views/layout/admin-layout.tsx +0 -117
  244. package/src/views/layout/admin-router.tsx +0 -206
  245. package/src/views/layout/admin-sidebar.tsx +0 -185
  246. package/src/views/layout/index.ts +0 -12
  247. package/tsconfig.json +0 -13
  248. package/tsconfig.tsbuildinfo +0 -1
  249. package/tsdown.config.ts +0 -13
  250. package/vitest.config.ts +0 -29
@@ -1,440 +0,0 @@
1
- /**
2
- * JsonField Component
3
- *
4
- * JSON field with two editing modes:
5
- * - "code" - Raw JSON editing with syntax highlighting
6
- * - "form" - Structured form editing (if schema provided)
7
- *
8
- * Integrates with react-hook-form via Controller.
9
- */
10
-
11
- import * as React from "react";
12
- import { Controller, useFormContext, type Control } from "react-hook-form";
13
- import { Code, ListBullets, WarningCircle } from "@phosphor-icons/react";
14
- import { Button } from "../ui/button";
15
- import { Textarea } from "../ui/textarea";
16
- import {
17
- Field,
18
- FieldContent,
19
- FieldDescription,
20
- FieldError,
21
- FieldLabel,
22
- } from "../ui/field";
23
- import { cn } from "../../lib/utils";
24
-
25
- export type JsonFieldMode = "code" | "form";
26
-
27
- export type JsonFieldProps = {
28
- /**
29
- * Field name (for react-hook-form)
30
- */
31
- name: string;
32
-
33
- /**
34
- * Label for the field
35
- */
36
- label?: string;
37
-
38
- /**
39
- * Description/help text
40
- */
41
- description?: string;
42
-
43
- /**
44
- * Is the field required
45
- */
46
- required?: boolean;
47
-
48
- /**
49
- * Is the field disabled
50
- */
51
- disabled?: boolean;
52
-
53
- /**
54
- * Is the field readonly
55
- */
56
- readOnly?: boolean;
57
-
58
- /**
59
- * Placeholder text for code mode
60
- */
61
- placeholder?: string;
62
-
63
- /**
64
- * Initial editing mode
65
- * @default "code"
66
- */
67
- defaultMode?: JsonFieldMode;
68
-
69
- /**
70
- * Allow switching between modes
71
- * @default true
72
- */
73
- allowModeSwitch?: boolean;
74
-
75
- /**
76
- * Minimum height for the editor
77
- * @default 200
78
- */
79
- minHeight?: number;
80
-
81
- /**
82
- * Maximum height for the editor (0 = no limit)
83
- * @default 400
84
- */
85
- maxHeight?: number;
86
-
87
- /**
88
- * Custom render function for form mode
89
- * Receives current value and onChange handler
90
- */
91
- renderForm?: (props: {
92
- value: any;
93
- onChange: (value: any) => void;
94
- disabled?: boolean;
95
- readOnly?: boolean;
96
- }) => React.ReactNode;
97
-
98
- /**
99
- * Form control (optional, will use useFormContext if not provided)
100
- */
101
- control?: Control<any>;
102
-
103
- /**
104
- * Additional class name
105
- */
106
- className?: string;
107
- };
108
-
109
- /**
110
- * JSON field with code editor and optional form mode.
111
- *
112
- * @example
113
- * ```tsx
114
- * // Basic JSON editor
115
- * <JsonField
116
- * name="metadata"
117
- * label="Metadata"
118
- * description="Additional metadata as JSON"
119
- * />
120
- *
121
- * // With custom form mode
122
- * <JsonField
123
- * name="settings"
124
- * label="Settings"
125
- * renderForm={({ value, onChange }) => (
126
- * <SettingsForm value={value} onChange={onChange} />
127
- * )}
128
- * />
129
- * ```
130
- */
131
- export function JsonField({
132
- name,
133
- label,
134
- description,
135
- required,
136
- disabled,
137
- readOnly,
138
- placeholder = '{\n "key": "value"\n}',
139
- defaultMode = "code",
140
- allowModeSwitch = true,
141
- minHeight = 200,
142
- maxHeight = 400,
143
- renderForm,
144
- control: controlProp,
145
- className,
146
- }: JsonFieldProps) {
147
- const formContext = useFormContext();
148
- const control = controlProp ?? formContext?.control;
149
- const [mode, setMode] = React.useState<JsonFieldMode>(defaultMode);
150
-
151
- if (!control) {
152
- console.warn(
153
- "JsonField: No form control found. Make sure to use within FormProvider or pass control prop.",
154
- );
155
- return null;
156
- }
157
-
158
- // Only show mode switch if form rendering is available
159
- const showModeSwitch = allowModeSwitch && renderForm;
160
-
161
- return (
162
- <Controller
163
- name={name}
164
- control={control}
165
- rules={{
166
- required: required ? `${label || name} is required` : undefined,
167
- validate: (value) => {
168
- if (!value) return true;
169
- // In code mode, validate JSON
170
- if (mode === "code" && typeof value === "string") {
171
- try {
172
- JSON.parse(value);
173
- return true;
174
- } catch {
175
- return "Invalid JSON format";
176
- }
177
- }
178
- return true;
179
- },
180
- }}
181
- render={({ field, fieldState }) => {
182
- const error = fieldState.error?.message;
183
-
184
- return (
185
- <Field data-invalid={!!error} className={className}>
186
- {/* Header with label and mode switch */}
187
- <div className="flex items-center justify-between">
188
- {label && (
189
- <FieldLabel htmlFor={name}>
190
- {label}
191
- {required && <span className="text-destructive ml-1">*</span>}
192
- </FieldLabel>
193
- )}
194
-
195
- {showModeSwitch && (
196
- <div className="flex gap-1">
197
- <Button
198
- type="button"
199
- variant={mode === "code" ? "secondary" : "ghost"}
200
- size="icon-xs"
201
- onClick={() => setMode("code")}
202
- disabled={disabled}
203
- title="Code editor"
204
- >
205
- <Code weight="bold" />
206
- </Button>
207
- <Button
208
- type="button"
209
- variant={mode === "form" ? "secondary" : "ghost"}
210
- size="icon-xs"
211
- onClick={() => setMode("form")}
212
- disabled={disabled}
213
- title="Form editor"
214
- >
215
- <ListBullets weight="bold" />
216
- </Button>
217
- </div>
218
- )}
219
- </div>
220
-
221
- <FieldContent>
222
- {mode === "code" ? (
223
- <JsonCodeEditor
224
- value={field.value}
225
- onChange={field.onChange}
226
- disabled={disabled}
227
- readOnly={readOnly}
228
- placeholder={placeholder}
229
- minHeight={minHeight}
230
- maxHeight={maxHeight}
231
- error={!!error}
232
- />
233
- ) : renderForm ? (
234
- <JsonFormEditor
235
- value={field.value}
236
- onChange={field.onChange}
237
- disabled={disabled}
238
- readOnly={readOnly}
239
- renderForm={renderForm}
240
- />
241
- ) : (
242
- <JsonCodeEditor
243
- value={field.value}
244
- onChange={field.onChange}
245
- disabled={disabled}
246
- readOnly={readOnly}
247
- placeholder={placeholder}
248
- minHeight={minHeight}
249
- maxHeight={maxHeight}
250
- error={!!error}
251
- />
252
- )}
253
-
254
- {description && !error && (
255
- <FieldDescription>{description}</FieldDescription>
256
- )}
257
- <FieldError>{error}</FieldError>
258
- </FieldContent>
259
- </Field>
260
- );
261
- }}
262
- />
263
- );
264
- }
265
-
266
- /**
267
- * Code editor for JSON (using Textarea for simplicity)
268
- * Can be replaced with Monaco/CodeMirror in the future
269
- */
270
- function JsonCodeEditor({
271
- value,
272
- onChange,
273
- disabled,
274
- readOnly,
275
- placeholder,
276
- minHeight,
277
- maxHeight,
278
- error,
279
- }: {
280
- value: any;
281
- onChange: (value: any) => void;
282
- disabled?: boolean;
283
- readOnly?: boolean;
284
- placeholder?: string;
285
- minHeight?: number;
286
- maxHeight?: number;
287
- error?: boolean;
288
- }) {
289
- const [localValue, setLocalValue] = React.useState<string>(() => {
290
- if (typeof value === "string") return value;
291
- if (value === null || value === undefined) return "";
292
- try {
293
- return JSON.stringify(value, null, 2);
294
- } catch {
295
- return "";
296
- }
297
- });
298
- const [parseError, setParseError] = React.useState<string | null>(null);
299
-
300
- // Sync local value when external value changes
301
- React.useEffect(() => {
302
- if (typeof value === "string") {
303
- setLocalValue(value);
304
- } else if (value !== null && value !== undefined) {
305
- try {
306
- setLocalValue(JSON.stringify(value, null, 2));
307
- } catch {
308
- // Keep current local value if stringification fails
309
- }
310
- } else {
311
- setLocalValue("");
312
- }
313
- }, [value]);
314
-
315
- const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
316
- const newValue = e.target.value;
317
- setLocalValue(newValue);
318
-
319
- // Try to parse and update form value
320
- if (!newValue.trim()) {
321
- setParseError(null);
322
- onChange(null);
323
- return;
324
- }
325
-
326
- try {
327
- const parsed = JSON.parse(newValue);
328
- setParseError(null);
329
- onChange(parsed);
330
- } catch (err) {
331
- setParseError("Invalid JSON");
332
- // Still update with raw string so validation can catch it
333
- onChange(newValue);
334
- }
335
- };
336
-
337
- const handleFormat = () => {
338
- try {
339
- const parsed = JSON.parse(localValue);
340
- const formatted = JSON.stringify(parsed, null, 2);
341
- setLocalValue(formatted);
342
- setParseError(null);
343
- onChange(parsed);
344
- } catch {
345
- // Can't format invalid JSON
346
- }
347
- };
348
-
349
- return (
350
- <div className="space-y-2">
351
- <div className="relative">
352
- <Textarea
353
- value={localValue}
354
- onChange={handleChange}
355
- disabled={disabled}
356
- readOnly={readOnly}
357
- placeholder={placeholder}
358
- className={cn(
359
- "font-mono text-xs",
360
- error || parseError ? "border-destructive" : "",
361
- )}
362
- style={{
363
- minHeight: `${minHeight}px`,
364
- maxHeight: maxHeight ? `${maxHeight}px` : undefined,
365
- resize: maxHeight ? "none" : "vertical",
366
- }}
367
- aria-invalid={!!error || !!parseError}
368
- />
369
-
370
- {/* Parse error indicator */}
371
- {parseError && (
372
- <div className="text-destructive absolute right-2 top-2 flex items-center gap-1 text-xs">
373
- <WarningCircle weight="fill" className="size-3" />
374
- {parseError}
375
- </div>
376
- )}
377
- </div>
378
-
379
- {/* Format button */}
380
- {!readOnly && !disabled && localValue && (
381
- <div className="flex justify-end">
382
- <Button
383
- type="button"
384
- variant="ghost"
385
- size="xs"
386
- onClick={handleFormat}
387
- disabled={!!parseError}
388
- >
389
- Format JSON
390
- </Button>
391
- </div>
392
- )}
393
- </div>
394
- );
395
- }
396
-
397
- /**
398
- * Form-based editor wrapper
399
- */
400
- function JsonFormEditor({
401
- value,
402
- onChange,
403
- disabled,
404
- readOnly,
405
- renderForm,
406
- }: {
407
- value: any;
408
- onChange: (value: any) => void;
409
- disabled?: boolean;
410
- readOnly?: boolean;
411
- renderForm: JsonFieldProps["renderForm"];
412
- }) {
413
- // Ensure value is an object for form mode
414
- const safeValue = React.useMemo(() => {
415
- if (typeof value === "object" && value !== null) {
416
- return value;
417
- }
418
- if (typeof value === "string") {
419
- try {
420
- return JSON.parse(value);
421
- } catch {
422
- return {};
423
- }
424
- }
425
- return {};
426
- }, [value]);
427
-
428
- if (!renderForm) return null;
429
-
430
- return (
431
- <div className="rounded-lg border p-4">
432
- {renderForm({
433
- value: safeValue,
434
- onChange,
435
- disabled,
436
- readOnly,
437
- })}
438
- </div>
439
- );
440
- }
@@ -1,15 +0,0 @@
1
- import * as React from "react";
2
- import { Badge } from "../ui/badge";
3
-
4
- type LocaleBadgeProps = {
5
- locale?: string;
6
- };
7
-
8
- export function LocaleBadge({ locale }: LocaleBadgeProps) {
9
- if (!locale) return null;
10
- return (
11
- <Badge variant="secondary" className="uppercase text-[10px] tracking-wide">
12
- {locale}
13
- </Badge>
14
- );
15
- }
@@ -1,57 +0,0 @@
1
- import { Controller } from "react-hook-form";
2
- import { NumberInput } from "../primitives/number-input";
3
- import { FieldWrapper } from "./field-wrapper";
4
- import { useResolvedControl } from "./field-utils";
5
- import type { NumberFieldProps } from "./field-types";
6
-
7
- export function NumberField({
8
- name,
9
- label,
10
- description,
11
- placeholder,
12
- required,
13
- disabled,
14
- localized,
15
- locale,
16
- control,
17
- className,
18
- min,
19
- max,
20
- step,
21
- showButtons,
22
- }: NumberFieldProps) {
23
- const resolvedControl = useResolvedControl(control);
24
-
25
- return (
26
- <Controller
27
- name={name}
28
- control={resolvedControl}
29
- render={({ field, fieldState }) => (
30
- <FieldWrapper
31
- name={name}
32
- label={label}
33
- description={description}
34
- required={required}
35
- disabled={disabled}
36
- localized={localized}
37
- locale={locale}
38
- error={fieldState.error?.message}
39
- >
40
- <NumberInput
41
- id={name}
42
- value={field.value ?? null}
43
- onChange={field.onChange}
44
- placeholder={placeholder}
45
- disabled={disabled}
46
- min={min}
47
- max={max}
48
- step={step}
49
- showButtons={showButtons}
50
- aria-invalid={!!fieldState.error}
51
- className={className}
52
- />
53
- </FieldWrapper>
54
- )}
55
- />
56
- );
57
- }
@@ -1,51 +0,0 @@
1
- import { Controller } from "react-hook-form";
2
- import { TextInput } from "../primitives/text-input";
3
- import { FieldWrapper } from "./field-wrapper";
4
- import { useResolvedControl } from "./field-utils";
5
- import type { BaseFieldProps } from "./field-types";
6
-
7
- export function PasswordField({
8
- name,
9
- label,
10
- description,
11
- placeholder,
12
- required,
13
- disabled,
14
- localized,
15
- locale,
16
- control,
17
- className,
18
- }: BaseFieldProps) {
19
- const resolvedControl = useResolvedControl(control);
20
-
21
- return (
22
- <Controller
23
- name={name}
24
- control={resolvedControl}
25
- render={({ field, fieldState }) => (
26
- <FieldWrapper
27
- name={name}
28
- label={label}
29
- description={description}
30
- required={required}
31
- disabled={disabled}
32
- localized={localized}
33
- locale={locale}
34
- error={fieldState.error?.message}
35
- >
36
- <TextInput
37
- id={name}
38
- value={field.value ?? ""}
39
- onChange={field.onChange}
40
- type="password"
41
- placeholder={placeholder}
42
- disabled={disabled}
43
- autoComplete="current-password"
44
- aria-invalid={!!fieldState.error}
45
- className={className}
46
- />
47
- </FieldWrapper>
48
- )}
49
- />
50
- );
51
- }