@svadmin/ui 0.72.0 → 0.74.0

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 (276) hide show
  1. package/README.md +62 -22
  2. package/THIRD_PARTY_NOTICES.md +52 -0
  3. package/dist/app.css +8488 -6297
  4. package/dist/app.theme.css +8514 -6374
  5. package/dist/class-properties.generated.d.ts +1 -0
  6. package/dist/class-properties.generated.js +2 -0
  7. package/dist/classnames.d.ts +8 -0
  8. package/dist/classnames.js +26 -0
  9. package/dist/component-registry.d.ts +14977 -0
  10. package/dist/component-registry.js +216 -0
  11. package/dist/components/AboutSettings.svelte +7 -1
  12. package/dist/components/AboutSettings.svelte.d.ts +4 -1
  13. package/dist/components/ActivityFeed.svelte +9 -3
  14. package/dist/components/ActivityFeed.svelte.d.ts +3 -0
  15. package/dist/components/AdminApp.svelte +19 -10
  16. package/dist/components/AdminApp.svelte.d.ts +6 -0
  17. package/dist/components/ApiSettings.svelte +41 -5
  18. package/dist/components/ApprovalCenter.svelte +283 -0
  19. package/dist/components/ApprovalCenter.svelte.d.ts +10 -0
  20. package/dist/components/AuditLogViewer.svelte +3 -1
  21. package/dist/components/AutoForm.svelte +53 -9
  22. package/dist/components/AutoForm.svelte.d.ts +3 -0
  23. package/dist/components/AutoTable.svelte +846 -43
  24. package/dist/components/AutoTable.svelte.d.ts +22 -1
  25. package/dist/components/BoundRecordDetailDrawer.svelte +17 -2
  26. package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +4 -0
  27. package/dist/components/Breadcrumbs.svelte +11 -1
  28. package/dist/components/CancelTaskButton.svelte +12 -42
  29. package/dist/components/ColorPicker.svelte +73 -0
  30. package/dist/components/ColorPicker.svelte.d.ts +15 -0
  31. package/dist/components/ComboboxField.svelte +143 -34
  32. package/dist/components/ComboboxField.svelte.d.ts +4 -2
  33. package/dist/components/CreatePage.svelte +4 -0
  34. package/dist/components/CreatePage.svelte.d.ts +2 -0
  35. package/dist/components/DashboardView.svelte +99 -0
  36. package/dist/components/DashboardView.svelte.d.ts +14 -0
  37. package/dist/components/DatePicker.svelte +10 -0
  38. package/dist/components/DatePicker.svelte.d.ts +6 -0
  39. package/dist/components/DateRangeInput.svelte +155 -0
  40. package/dist/components/DateRangeInput.svelte.d.ts +35 -0
  41. package/dist/components/DateRangePicker.svelte +10 -0
  42. package/dist/components/DateRangePicker.svelte.d.ts +6 -0
  43. package/dist/components/DateTimeInput.svelte +134 -0
  44. package/dist/components/DateTimeInput.svelte.d.ts +27 -0
  45. package/dist/components/DateTimePicker.svelte +10 -0
  46. package/dist/components/DateTimePicker.svelte.d.ts +6 -0
  47. package/dist/components/DevTools.svelte +36 -28
  48. package/dist/components/DevframePanel.svelte +123 -0
  49. package/dist/components/DevframePanel.svelte.d.ts +3 -0
  50. package/dist/components/EditPage.svelte +4 -0
  51. package/dist/components/EditPage.svelte.d.ts +2 -0
  52. package/dist/components/ErrorSummary.svelte +52 -0
  53. package/dist/components/ErrorSummary.svelte.d.ts +14 -0
  54. package/dist/components/FieldRenderer.svelte +172 -99
  55. package/dist/components/FileUpload.svelte +412 -0
  56. package/dist/components/FileUpload.svelte.d.ts +43 -0
  57. package/dist/components/FilterBuilder.svelte +244 -265
  58. package/dist/components/FilterBuilder.svelte.d.ts +3 -0
  59. package/dist/components/FilterCollectionInput.svelte +80 -0
  60. package/dist/components/FilterCollectionInput.svelte.d.ts +10 -0
  61. package/dist/components/GanttChart.svelte +66 -14
  62. package/dist/components/GanttChart.svelte.d.ts +6 -0
  63. package/dist/components/Header.svelte +18 -2
  64. package/dist/components/ImportWizard.svelte +509 -100
  65. package/dist/components/ImportWizard.svelte.d.ts +11 -0
  66. package/dist/components/JsonSchemaForm.svelte +322 -98
  67. package/dist/components/JsonSchemaForm.svelte.d.ts +18 -1
  68. package/dist/components/KanbanBoard.svelte +195 -40
  69. package/dist/components/KanbanBoard.svelte.d.ts +9 -2
  70. package/dist/components/Layout.svelte +4 -3
  71. package/dist/components/LazyAutoForm.svelte +28 -0
  72. package/dist/components/LazyAutoForm.svelte.d.ts +8 -0
  73. package/dist/components/LazyAutoTable.svelte +28 -0
  74. package/dist/components/LazyAutoTable.svelte.d.ts +8 -0
  75. package/dist/components/LazySettingsPage.svelte +28 -0
  76. package/dist/components/LazySettingsPage.svelte.d.ts +8 -0
  77. package/dist/components/LazyShowPage.svelte +28 -0
  78. package/dist/components/LazyShowPage.svelte.d.ts +8 -0
  79. package/dist/components/LazyTaskQueueDrawer.svelte.d.ts +1 -1
  80. package/dist/components/ListPage.svelte +9 -1
  81. package/dist/components/ListPage.svelte.d.ts +5 -0
  82. package/dist/components/LoginPage.svelte +2 -2
  83. package/dist/components/MoneyInput.svelte +25 -0
  84. package/dist/components/MoneyInput.svelte.d.ts +20 -0
  85. package/dist/components/MultiTabKeepAlive.svelte +11 -6
  86. package/dist/components/NotificationsSettings.svelte +69 -2
  87. package/dist/components/NotificationsSettings.svelte.d.ts +25 -1
  88. package/dist/components/NumberInput.svelte +25 -0
  89. package/dist/components/NumberInput.svelte.d.ts +19 -0
  90. package/dist/components/NumericInput.svelte +110 -0
  91. package/dist/components/NumericInput.svelte.d.ts +23 -0
  92. package/dist/components/PercentInput.svelte +25 -0
  93. package/dist/components/PercentInput.svelte.d.ts +20 -0
  94. package/dist/components/PermissionMatrix.svelte +20 -1
  95. package/dist/components/PivotExportButton.svelte +157 -0
  96. package/dist/components/PivotExportButton.svelte.d.ts +16 -0
  97. package/dist/components/PivotTable.svelte +229 -74
  98. package/dist/components/PivotTable.svelte.d.ts +19 -2
  99. package/dist/components/QuickEditDrawer.svelte +4 -1
  100. package/dist/components/QuickEditDrawer.svelte.d.ts +2 -0
  101. package/dist/components/RadioGroup.svelte +121 -0
  102. package/dist/components/RadioGroup.svelte.d.ts +43 -0
  103. package/dist/components/RangeSlider.svelte +127 -0
  104. package/dist/components/RangeSlider.svelte.d.ts +22 -0
  105. package/dist/components/Rate.svelte +121 -0
  106. package/dist/components/Rate.svelte.d.ts +16 -0
  107. package/dist/components/RecordDetailDrawer.svelte +6 -2
  108. package/dist/components/RecordDetailDrawer.svelte.d.ts +4 -0
  109. package/dist/components/RelationPicker.svelte +341 -0
  110. package/dist/components/RelationPicker.svelte.d.ts +26 -0
  111. package/dist/components/ResourceOperationsPage.svelte +25 -19
  112. package/dist/components/ResourceOperationsPage.svelte.d.ts +5 -1
  113. package/dist/components/RetryTaskButton.svelte +12 -42
  114. package/dist/components/SecuritySettings.svelte +29 -5
  115. package/dist/components/SegmentedControl.svelte +145 -0
  116. package/dist/components/SegmentedControl.svelte.d.ts +38 -0
  117. package/dist/components/SettingsPage.svelte +3 -1
  118. package/dist/components/SettingsPage.svelte.d.ts +1 -0
  119. package/dist/components/ShowInferencer.svelte +4 -2
  120. package/dist/components/ShowInferencer.svelte.d.ts +2 -0
  121. package/dist/components/ShowPage.svelte +25 -6
  122. package/dist/components/ShowPage.svelte.d.ts +5 -0
  123. package/dist/components/Sidebar.svelte +5 -5
  124. package/dist/components/Slider.svelte +100 -0
  125. package/dist/components/Slider.svelte.d.ts +19 -0
  126. package/dist/components/SpreadsheetView.svelte +1037 -124
  127. package/dist/components/SpreadsheetView.svelte.d.ts +19 -0
  128. package/dist/components/StepsForm.svelte +5 -5
  129. package/dist/components/SvarAutoTable.svelte +39 -0
  130. package/dist/components/SvarAutoTable.svelte.d.ts +13 -0
  131. package/dist/components/SvarDataGrid.svelte +362 -0
  132. package/dist/components/SvarDataGrid.svelte.d.ts +57 -0
  133. package/dist/components/SvarGridCell.svelte +10 -0
  134. package/dist/components/SvarGridCell.svelte.d.ts +7 -0
  135. package/dist/components/SvarResourceRead.svelte +50 -0
  136. package/dist/components/SvarResourceRead.svelte.d.ts +23 -0
  137. package/dist/components/SvarResourceTable.svelte +63 -0
  138. package/dist/components/SvarResourceTable.svelte.d.ts +42 -0
  139. package/dist/components/SvarResourceTableView.svelte +364 -0
  140. package/dist/components/SvarResourceTableView.svelte.d.ts +4 -0
  141. package/dist/components/TagsInput.svelte +178 -0
  142. package/dist/components/TagsInput.svelte.d.ts +17 -0
  143. package/dist/components/TaskQueueDrawer.svelte +72 -16
  144. package/dist/components/TimePicker.svelte +10 -0
  145. package/dist/components/TimePicker.svelte.d.ts +6 -0
  146. package/dist/components/TreeSelect.svelte +440 -46
  147. package/dist/components/TreeSelect.svelte.d.ts +6 -1
  148. package/dist/components/TreeTable.svelte +484 -82
  149. package/dist/components/TreeTable.svelte.d.ts +24 -1
  150. package/dist/components/TwoFactorAuthPage.svelte +85 -48
  151. package/dist/components/TwoFactorAuthPage.svelte.d.ts +12 -1
  152. package/dist/components/VirtualTable.svelte +116 -20
  153. package/dist/components/VirtualTable.svelte.d.ts +5 -0
  154. package/dist/components/account/CompanyProfilePage.svelte +74 -38
  155. package/dist/components/account/GetStartedPage.svelte +2 -1
  156. package/dist/components/account/ImportMembersPage.svelte +22 -167
  157. package/dist/components/account/ImportMembersPage.svelte.d.ts +4 -1
  158. package/dist/components/account/MemberDirectory.svelte +156 -0
  159. package/dist/components/account/MemberDirectory.svelte.d.ts +19 -0
  160. package/dist/components/account/MembersStarterPage.svelte +9 -55
  161. package/dist/components/account/MembersStarterPage.svelte.d.ts +5 -1
  162. package/dist/components/account/SecurityLogPage.svelte +4 -1
  163. package/dist/components/account/SettingsPlainPage.svelte +7 -38
  164. package/dist/components/account/SettingsPlainPage.svelte.d.ts +4 -1
  165. package/dist/components/account/SettingsSidebarPage.svelte +7 -20
  166. package/dist/components/account/TeamMembersPage.svelte +4 -20
  167. package/dist/components/account/TeamMembersPage.svelte.d.ts +5 -1
  168. package/dist/components/account/UserProfilePage.svelte +3 -25
  169. package/dist/components/account/UserProfilePage.svelte.d.ts +17 -2
  170. package/dist/components/auto-table-grid.d.ts +26 -0
  171. package/dist/components/auto-table-grid.js +1 -0
  172. package/dist/components/buttons/ExportButton.svelte +56 -12
  173. package/dist/components/buttons/ExportButton.svelte.d.ts +11 -0
  174. package/dist/components/content/ContentPageHeader.svelte +12 -9
  175. package/dist/components/content/ContentPageShell.svelte +6 -9
  176. package/dist/components/content/FileBrowser.svelte +35 -0
  177. package/dist/components/content/FileBrowser.svelte.d.ts +14 -0
  178. package/dist/components/content/MetricBlock.svelte +10 -13
  179. package/dist/components/content/NetworkTable.svelte +3 -3
  180. package/dist/components/content/NetworkTable.svelte.d.ts +1 -0
  181. package/dist/components/content/PageToolbar.svelte +6 -10
  182. package/dist/components/content/ReferenceNotice.svelte +5 -0
  183. package/dist/components/content/ReferenceNotice.svelte.d.ts +18 -0
  184. package/dist/components/content/SectionHeader.svelte +8 -13
  185. package/dist/components/content/SettingsFieldRow.svelte +9 -23
  186. package/dist/components/content/SettingsGroup.svelte +11 -27
  187. package/dist/components/content/StatusBadge.svelte +3 -8
  188. package/dist/components/content/WorkspaceLayout.svelte +8 -12
  189. package/dist/components/enterprise/filter-tree.d.ts +48 -0
  190. package/dist/components/enterprise/filter-tree.js +224 -0
  191. package/dist/components/enterprise/json-schema-form.d.ts +39 -0
  192. package/dist/components/enterprise/json-schema-form.js +195 -0
  193. package/dist/components/enterprise/recursive-schema-form.d.ts +30 -0
  194. package/dist/components/enterprise/recursive-schema-form.js +196 -0
  195. package/dist/components/enterprise/spreadsheet-formula.d.ts +12 -0
  196. package/dist/components/enterprise/spreadsheet-formula.js +245 -0
  197. package/dist/components/export-reference.d.ts +2 -0
  198. package/dist/components/export-reference.js +9 -0
  199. package/dist/components/fieldComponentMap.js +2 -0
  200. package/dist/components/fields/DateField.svelte +12 -12
  201. package/dist/components/fields/date-display.d.ts +6 -0
  202. package/dist/components/fields/date-display.js +24 -0
  203. package/dist/components/fields/date-field-value.d.ts +2 -0
  204. package/dist/components/fields/date-field-value.js +13 -0
  205. package/dist/components/json-schema-form-state.d.ts +37 -0
  206. package/dist/components/json-schema-form-state.js +168 -0
  207. package/dist/components/network/TeamCrewTablePage.svelte +6 -1
  208. package/dist/components/network/UserCardsNFTPage.svelte +2 -0
  209. package/dist/components/profile/PublicProfilePage.svelte +2 -0
  210. package/dist/components/record-detail.svelte.d.ts +3 -0
  211. package/dist/components/record-detail.svelte.js +10 -4
  212. package/dist/components/saved-list-views.d.ts +74 -1
  213. package/dist/components/saved-list-views.js +191 -3
  214. package/dist/components/svar-grid-cells.d.ts +14 -0
  215. package/dist/components/svar-grid-cells.js +2 -0
  216. package/dist/components/svar-grid-contract.d.ts +80 -0
  217. package/dist/components/svar-grid-contract.js +159 -0
  218. package/dist/components/svar-grid-interactions.d.ts +54 -0
  219. package/dist/components/svar-grid-interactions.js +174 -0
  220. package/dist/components/svar-grid-loading.d.ts +40 -0
  221. package/dist/components/svar-grid-loading.js +180 -0
  222. package/dist/components/svar-grid-operations.d.ts +37 -0
  223. package/dist/components/svar-grid-operations.js +186 -0
  224. package/dist/components/svar-grid-panes.d.ts +34 -0
  225. package/dist/components/svar-grid-panes.js +66 -0
  226. package/dist/components/svar-grid-resource-loading.d.ts +18 -0
  227. package/dist/components/svar-grid-resource-loading.js +68 -0
  228. package/dist/components/svar-grid-resource-session.svelte.d.ts +29 -0
  229. package/dist/components/svar-grid-resource-session.svelte.js +61 -0
  230. package/dist/components/table-contract.d.ts +12 -1
  231. package/dist/components/task-action.svelte.d.ts +13 -0
  232. package/dist/components/task-action.svelte.js +73 -0
  233. package/dist/components/ui/DesignSystemShowcase.svelte +164 -0
  234. package/dist/components/ui/DesignSystemShowcase.svelte.d.ts +3 -0
  235. package/dist/components/ui/badge/badge-variants.d.ts +3 -2
  236. package/dist/components/ui/badge/badge-variants.js +2 -1
  237. package/dist/components/ui/badge/badge.svelte +3 -0
  238. package/dist/components/ui/badge/badge.svelte.d.ts +1 -0
  239. package/dist/components/ui/button/button-variants.d.ts +5 -4
  240. package/dist/components/ui/button/button-variants.js +7 -2
  241. package/dist/components/ui/checkbox/checkbox.svelte +5 -1
  242. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +5 -1
  243. package/dist/components/ui/input/input.svelte +8 -6
  244. package/dist/components/ui/input/input.svelte.d.ts +4 -1
  245. package/dist/components/ui/select/select.svelte +4 -1
  246. package/dist/components/ui/select/select.svelte.d.ts +2 -1
  247. package/dist/components/ui/textarea/textarea.svelte +2 -1
  248. package/dist/components.css +3110 -0
  249. package/dist/date-input-policy.d.ts +4 -0
  250. package/dist/date-input-policy.js +35 -0
  251. package/dist/design-contract.d.ts +13 -0
  252. package/dist/design-contract.js +11 -0
  253. package/dist/design-system-components.d.ts +100 -0
  254. package/dist/design-system-components.js +101 -0
  255. package/dist/design-system.d.ts +15 -0
  256. package/dist/design-system.js +7 -0
  257. package/dist/devtools-bridge.d.ts +80 -0
  258. package/dist/devtools-bridge.js +92 -0
  259. package/dist/index.d.ts +50 -1
  260. package/dist/index.js +32 -2
  261. package/dist/page-chrome.css +12 -49
  262. package/dist/recipes.d.ts +960 -0
  263. package/dist/recipes.js +264 -0
  264. package/dist/rendering/index.d.ts +87 -0
  265. package/dist/rendering/index.js +117 -0
  266. package/dist/styles/aliases.css +49 -0
  267. package/dist/styles/compatibility.epilogue.css +384 -0
  268. package/dist/styles/compatibility.prelude.css +5513 -0
  269. package/dist/styles/conditional-states.css +28 -0
  270. package/dist/styles/conditional-utilities.css +22 -0
  271. package/dist/tree-table-model.d.ts +24 -0
  272. package/dist/tree-table-model.js +111 -0
  273. package/dist/utils.d.ts +1 -1
  274. package/dist/utils.js +1 -1
  275. package/package.json +40 -10
  276. package/styles-compatibility.json +12 -0
@@ -1,7 +1,18 @@
1
+ import type { ImportArtifactProvider, TaskProvider } from '@svadmin/core';
1
2
  interface Props {
2
3
  resourceName: string;
3
4
  open?: boolean;
4
5
  batchSize?: number;
6
+ maxRows?: number;
7
+ maxBytes?: number;
8
+ taskName?: string;
9
+ retryTaskName?: string;
10
+ taskProvider?: TaskProvider;
11
+ /** 上传原文件并以 artifact 引用提交任务,避免任务请求重复携带 records。 */
12
+ taskArtifactProvider?: ImportArtifactProvider;
13
+ taskIdempotencyKey?: string;
14
+ initialTaskId?: string;
15
+ onTaskSubmitted?: (taskId: string) => void;
5
16
  onSuccess?: (result: {
6
17
  succeeded: number;
7
18
  failed: number;
@@ -1,16 +1,38 @@
1
1
  <script lang="ts">
2
- import { definedOptions } from '@svadmin/core/options';
2
+ import { assertSchemaFormSchema, isSchemaFormNodeVisible, prepareSchemaFormValue, type SchemaFormSchema } from '@svadmin/core/schema-form';
3
+ import { tick } from 'svelte';
3
4
  import { useTranslation } from '@svadmin/core/i18n';
4
-
5
5
  import { Button } from './ui/button/index.js';
6
- import { Loader2 } from '@lucide/svelte';
6
+ import { Loader2, Plus, Trash2 } from '@lucide/svelte';
7
7
  import { cn } from '../utils.js';
8
+ import { onDestroy, untrack } from 'svelte';
9
+ import {
10
+ initializeSchemaForm, schemaFormArrayItem,
11
+ schemaFormSnapshot, writeSchemaFormPath,
12
+ type JsonSchemaFormSchema,
13
+ } from './json-schema-form-state.js';
14
+ import { readRecursiveSchemaForm, validateRecursiveSchemaForm, schemaFormPointer } from './enterprise/recursive-schema-form.js';
15
+ import { parseSchemaNumber, type SchemaFormIssue } from './enterprise/json-schema-form.js';
16
+ interface JsonSchema extends JsonSchemaFormSchema {
17
+ properties?: Record<string, JsonSchema>;
18
+ items?: JsonSchema;
19
+ visibleWhen?: SchemaFormSchema['visibleWhen'];
20
+ pattern?: string;
21
+ }
8
22
 
9
23
  interface Props {
10
- schema: Record<string, unknown>;
24
+ schema: JsonSchema;
11
25
  value?: Record<string, unknown>;
12
26
  onsubmit?: (data: Record<string, unknown>) => void | Promise<void>;
13
27
  submitText?: string;
28
+ disabled?: boolean;
29
+ readonly?: boolean;
30
+ /** 只决定此实例文案;不修改全局语言。 */
31
+ locale?: string;
32
+ onerror?: (error: unknown) => void;
33
+ onvalidationerror?: (issues: SchemaFormIssue[]) => void;
34
+ /** Use a unique stable prefix when several schema forms share a page. */
35
+ idPrefix?: string;
14
36
  class?: string;
15
37
  }
16
38
 
@@ -19,136 +41,338 @@
19
41
  value = $bindable({}),
20
42
  onsubmit,
21
43
  submitText = 'Submit Form',
44
+ disabled = false,
45
+ readonly = false,
46
+ locale,
47
+ onerror,
48
+ onvalidationerror,
49
+ idPrefix,
22
50
  class: className = '',
23
51
  }: Props = $props();
24
52
 
25
53
  const i18n = useTranslation();
26
-
54
+ const instanceId = $props.id();
55
+ const prefix = $derived(idPrefix ?? `json-form-${instanceId}`);
56
+ const isZh = $derived((locale ?? i18n.locale).startsWith('zh'));
57
+ const labels = $derived(isZh ? { add: '添加项目', remove: '删除', empty: '暂无项目', failed: '提交未完成,请检查状态后重试。', invalid: '请检查表单输入。' }
58
+ : { add: 'Add item', remove: 'Remove item', empty: 'No items', failed: 'Submission did not complete. Check its status before retrying.', invalid: 'Check the form input.' });
27
59
  let isSubmitting = $state(false);
60
+ const model = $derived(readRecursiveSchemaForm(schema));
61
+ // 两个已发布的 schema 子集分别验证;任何一个都不接受时关闭表单。
62
+ const coreSchema = $derived.by(() => {
63
+ try { assertSchemaFormSchema(schema as SchemaFormSchema); return schema as SchemaFormSchema; }
64
+ catch { return undefined; }
65
+ });
66
+ let validationIssues = $state<SchemaFormIssue[]>([]);
67
+ let parseIssues = $state<SchemaFormIssue[]>([]);
68
+ let failure = $state<'invalid' | 'failed' | null>(null);
69
+ let formElement: HTMLFormElement | undefined;
70
+ let destroyed = false;
71
+ let authorityRevision = 0;
72
+ let identity: readonly unknown[] = [];
73
+ let internalValue: Record<string, unknown> | undefined;
74
+
75
+ function cloneDefault(node: JsonSchema): unknown {
76
+ if (node.default !== undefined) return structuredClone($state.snapshot(node.default));
77
+ if (node.type === 'null') return null;
78
+ if (node.type === 'object' || node.properties) {
79
+ return Object.fromEntries(
80
+ Object.entries(node.properties ?? {})
81
+ .map(([key, child]) => [key, cloneDefault(child)])
82
+ .filter(([, child]) => child !== undefined),
83
+ );
84
+ }
85
+ if (node.type === 'array') return [];
86
+ return undefined;
87
+ }
28
88
 
29
- interface FieldMeta {
30
- key: string;
31
- title: string;
32
- description?: string;
33
- type: string;
34
- enum?: Array<string | number>;
35
- required?: boolean;
36
- default?: unknown;
37
- }
38
-
39
- const properties = $derived.by<FieldMeta[]>(() => {
40
- const propsObj = (schema['properties'] ?? {}) as Record<string, Record<string, unknown>>;
41
- const requiredKeys = Array.isArray(schema['required']) ? (schema['required'] as string[]) : [];
42
-
43
- return Object.entries(propsObj).map(([key, propDef]) => (definedOptions({
44
- key,
45
- title: String(propDef['title'] ?? key),
46
- description: propDef['description'] ? String(propDef['description']) : undefined,
47
- type: String(propDef['type'] ?? 'string'),
48
- enum: Array.isArray(propDef['enum']) ? (propDef['enum'] as Array<string | number>) : undefined,
49
- required: requiredKeys.includes(key),
50
- default: propDef['default'],
51
- })));
89
+ function mergeDefaults(node: JsonSchema, current: unknown, present: boolean, budget = { nodes: 0 }): unknown {
90
+ if (++budget.nodes > 1000) throw new Error('Schema form data limit exceeded.');
91
+ const candidate = present ? current : cloneDefault(node);
92
+ if (candidate === null || (present && candidate === undefined)) return candidate;
93
+ if (node.type === 'array') {
94
+ if (Array.isArray(candidate) && candidate.length > 1000 - budget.nodes) throw new Error('Schema form data limit exceeded.');
95
+ return Array.isArray(candidate)
96
+ ? candidate.map(item => mergeDefaults(node.items ?? { type: 'string' }, item, true, budget))
97
+ : candidate;
98
+ }
99
+ if (node.type !== 'object' && !node.properties) return candidate;
100
+ if (candidate !== undefined && (typeof candidate !== 'object' || Array.isArray(candidate))) return candidate;
101
+ const source = (candidate ?? {}) as Record<string, unknown>;
102
+ const result: Record<string, unknown> = { ...source };
103
+ for (const [key, child] of Object.entries(node.properties ?? {})) {
104
+ const own = Object.hasOwn(source, key);
105
+ const next = mergeDefaults(child, own ? source[key] : undefined, own, budget);
106
+ if (next !== undefined || own) Object.defineProperty(result, key, { value: next, enumerable: true, configurable: true, writable: true });
107
+ }
108
+ return result;
109
+ }
110
+
111
+ const prepared = $derived.by(() => {
112
+ try {
113
+ if (model.issues.length && !coreSchema) return { ok: false as const };
114
+ const seeded = mergeDefaults(schema, value, true);
115
+ return { ok: true as const, value: initializeSchemaForm(schema, seeded as Record<string, unknown>) };
116
+ } catch {
117
+ return { ok: false as const };
118
+ }
52
119
  });
120
+ const locked = $derived(disabled || readonly || isSubmitting || !prepared.ok);
121
+ $effect.pre(() => {
122
+ const next = [schema, value, disabled, readonly, onsubmit];
123
+ untrack(() => {
124
+ if (next.some((part, index) => part !== identity[index])) {
125
+ authorityRevision += 1;
126
+ failure = null;
127
+ validationIssues = [];
128
+ if (schema !== identity[0] || value !== internalValue) parseIssues = [];
129
+ internalValue = undefined;
130
+ }
131
+ identity = next;
132
+ });
133
+ });
134
+ onDestroy(() => { destroyed = true; });
53
135
 
54
- async function handleSubmit(e: SubmitEvent) {
55
- e.preventDefault();
136
+ function editable(): boolean {
137
+ return !destroyed && !disabled && !readonly && !isSubmitting && prepared.ok
138
+ && !formElement?.closest('fieldset[disabled]');
139
+ }
140
+ function nodeType(node: JsonSchema): string | undefined {
141
+ return Array.isArray(node.type) ? node.type.find(type => type !== 'null') : node.type;
142
+ }
143
+ function choices(node: JsonSchema): JsonSchema['enum'] {
144
+ return node.enum ?? (Object.hasOwn(node, 'const') ? [node.const ?? null] : undefined);
145
+ }
146
+ function pathReadonly(path: readonly string[]): boolean {
147
+ let node: JsonSchema | undefined = schema;
148
+ if (node.readOnly) return true;
149
+ for (const key of path) {
150
+ node = node && (nodeType(node) === 'array' ? node.items : node.properties?.[key]);
151
+ if (node?.readOnly) return true;
152
+ }
153
+ return false;
154
+ }
155
+ function invalid(issues: SchemaFormIssue[]): void {
156
+ failure = 'invalid';
157
+ validationIssues = issues;
158
+ try { onvalidationerror?.(issues); } catch { /* Observers do not authorize submission. */ }
159
+ }
160
+ function fieldInvalid(path: readonly string[]): boolean {
161
+ return [...validationIssues, ...parseIssues].some(issue => issue.path === schemaFormPointer(path));
162
+ }
163
+ function writeNumber(path: string[], input: HTMLInputElement): void {
164
+ if (!editable() || pathReadonly(path)) return;
165
+ const pointer = schemaFormPointer(path);
166
+ parseIssues = parseIssues.filter(issue => issue.path !== pointer);
167
+ try {
168
+ if (input.validity.badInput) throw new Error('Invalid numeric input');
169
+ writePath(path, parseSchemaNumber(input.value));
170
+ } catch {
171
+ parseIssues = [...parseIssues, { path: pointer, code: 'invalid-value' }];
172
+ invalid(parseIssues);
173
+ }
174
+ }
175
+ function readPath(path: string[]): unknown {
176
+ return path.reduce<unknown>((current, key) => (
177
+ current && typeof current === 'object' && Object.hasOwn(current, key) ? (current as Record<string, unknown>)[key] : undefined
178
+ ), prepared.ok ? prepared.value : {});
179
+ }
180
+
181
+ function writePath(path: string[], nextValue: unknown): boolean {
182
+ if (!editable() || !prepared.ok || pathReadonly(path)) return false;
183
+ try {
184
+ value = writeSchemaFormPath(prepared.value, path, nextValue);
185
+ internalValue = value;
186
+ failure = null;
187
+ validationIssues = [];
188
+ return true;
189
+ } catch { failure = 'invalid'; return false; }
190
+ }
191
+
192
+ function enumToken(index: number): string {
193
+ return coreSchema && model.issues.length ? `__json_enum_${index}` : String(index);
194
+ }
195
+
196
+ function enumIndex(current: unknown, options: JsonSchema['enum']): number {
197
+ return options?.findIndex((option) => Object.is(option, current)) ?? -1;
198
+ }
199
+
200
+ function enumValue(raw: string, options: JsonSchema['enum']): unknown {
201
+ if (!/^(?:__json_enum_)?(0|[1-9]\d*)$/.test(raw)) return undefined;
202
+ const index = Number(raw.replace(/^__json_enum_/, ''));
203
+ return Number.isSafeInteger(index) ? options?.[index] : undefined;
204
+ }
205
+ function addArrayItem(path: string[], itemSchema: JsonSchema): void {
206
+ if (!editable()) return;
207
+ const current = readPath(path);
208
+ const items = Array.isArray(current) ? current : [];
209
+ try { writePath(path, [...items, schemaFormArrayItem(itemSchema)]); }
210
+ catch { failure = 'invalid'; }
211
+ }
212
+ function removeArrayItem(path: string[], index: number): void {
213
+ if (!editable()) return;
214
+ const current = readPath(path);
215
+ if (!Array.isArray(current) || !Number.isSafeInteger(index) || index < 0 || index >= current.length) return;
216
+ const prefix = schemaFormPointer(path) + '/';
217
+ const nextIssues = parseIssues.flatMap(issue => {
218
+ if (!issue.path.startsWith(prefix)) return [issue];
219
+ const tail = issue.path.slice(prefix.length);
220
+ const separator = tail.indexOf('/');
221
+ const segment = separator < 0 ? tail : tail.slice(0, separator);
222
+ if (!/^(0|[1-9][0-9]*)$/u.test(segment)) return [issue];
223
+ const itemIndex = Number(segment);
224
+ if (itemIndex === index) return [];
225
+ if (itemIndex < index) return [issue];
226
+ return [{ ...issue, path: prefix + String(itemIndex - 1) + (separator < 0 ? '' : tail.slice(separator)) }];
227
+ });
228
+ // Retire only the removed item's error and shift surviving descendants with their
229
+ // array item. A rejected readonly/disabled write must not clear any error.
230
+ if (writePath(path, current.filter((_, itemIndex) => itemIndex !== index))) parseIssues = nextIssues;
231
+ }
232
+ async function handleSubmit(event: SubmitEvent): Promise<void> {
233
+ event.preventDefault();
234
+ if (!editable() || !prepared.ok || !onsubmit) return;
235
+ let payload: Record<string, unknown>;
236
+ try {
237
+ const result = coreSchema ? prepareSchemaFormValue(coreSchema, prepared.value) : undefined;
238
+ const detailedIssues = model.issues.length ? [] : validateRecursiveSchemaForm(model, prepared.value);
239
+ const problems = [...parseIssues, ...(result
240
+ ? result.errors.map(issue => {
241
+ const path = schemaFormPointer(JSON.parse(issue.path) as string[]);
242
+ // 共用子集保留公开错误码;核心校验仍决定哪些字段不可提交。
243
+ return detailedIssues.find(detail => detail.path === path) ?? { path, code: 'invalid-value' as const };
244
+ })
245
+ : detailedIssues)];
246
+ if (problems.length) {
247
+ invalid(problems);
248
+ await tick();
249
+ formElement?.querySelector<HTMLElement>('[aria-invalid="true"]')?.focus();
250
+ return;
251
+ }
252
+ payload = schemaFormSnapshot(result?.data ?? prepared.value);
253
+ } catch { invalid([{ path: '', code: 'invalid-value' }]); return; }
254
+ const currentValue = value, currentSchema = schema, handler = onsubmit, revision = authorityRevision;
255
+ const fingerprint = JSON.stringify(schemaFormSnapshot(prepared.value));
256
+ failure = null;
56
257
  isSubmitting = true;
57
258
  try {
58
- await onsubmit?.(value);
259
+ await handler(payload);
260
+ } catch (error) {
261
+ if (!destroyed && revision === authorityRevision && !disabled && !readonly && currentValue === value && currentSchema === schema && handler === onsubmit) {
262
+ try {
263
+ if (JSON.stringify(schemaFormSnapshot(prepared.ok ? prepared.value : value)) === fingerprint) {
264
+ failure = 'failed';
265
+ try { onerror?.(error); } catch { /* 错误观察者不改变提交状态。 */ }
266
+ }
267
+ } catch { /* 新草稿不接收旧请求的错误。 */ }
268
+ }
59
269
  } finally {
60
- isSubmitting = false;
270
+ if (!destroyed) isSubmitting = false;
61
271
  }
62
272
  }
63
273
 
64
- function updateValue(key: string, val: unknown) {
65
- value = {
66
- ...value,
67
- [key]: val,
68
- };
69
- }
70
274
  </script>
71
275
 
72
276
  <form
277
+ novalidate
278
+ data-testid="json-schema-form"
279
+ bind:this={formElement}
280
+ aria-busy={isSubmitting}
73
281
  onsubmit={handleSubmit}
74
282
  class={cn('svadmin-u-3e7ce58d64fa svadmin-u-a217b4eaa918 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-cd0ad9a56558 svadmin-u-0478c89a150f svadmin-u-cef5b893cf23 svadmin-u-359090c2d529', className)}
75
283
  >
76
- {#if schema['title']}
284
+ {#if schema.title}
77
285
  <div class="svadmin-u-f4cc511ff0c1 svadmin-u-65fdbade2025 svadmin-u-05faf5c801ff">
78
- <h3 class="svadmin-u-fc7473ca09eb svadmin-u-e83a7042bc91 svadmin-u-d4108abe6359">{schema['title']}</h3>
79
- {#if schema['description']}
80
- <p class="svadmin-u-359090c2d529 svadmin-u-bfa603190748 svadmin-u-15e1b1f444fe">{schema['description']}</p>
81
- {/if}
286
+ <h3 class="svadmin-u-fc7473ca09eb svadmin-u-e83a7042bc91 svadmin-u-d4108abe6359">{schema.title}</h3>
287
+ {#if schema.description}<p class="svadmin-u-359090c2d529 svadmin-u-bfa603190748 svadmin-u-15e1b1f444fe">{schema.description}</p>{/if}
82
288
  </div>
83
289
  {/if}
84
290
 
85
- <div class="svadmin-u-9c6cdfa2ba3d">
86
- {#each properties as field (field.key)}
291
+ {#if !prepared.ok || failure}
292
+ <p role="alert" data-testid="schema-form-errors">{labels[!prepared.ok ? 'invalid' : failure ?? 'invalid']}</p>
293
+ {/if}
294
+
295
+ {#snippet renderField(node: JsonSchema, path: string[], title: string, required = false)}
296
+ {@const current = readPath(path)}
297
+ {@const id = `${prefix}_${path.map(encodeURIComponent).join('/')}`}
298
+ {@const type = nodeType(node)}
299
+ {@const fieldLocked = locked || pathReadonly(path)}
300
+ {@const error = fieldInvalid(path)}
301
+ {@const options = choices(node)}
302
+ {#if coreSchema && !isSchemaFormNodeVisible(node as SchemaFormSchema, prepared.ok ? prepared.value : {})}
303
+ <!-- 隐藏字段保留草稿,但不进入提交数据。 -->
304
+ {:else if type === 'object' || node.properties}
305
+ <fieldset disabled={fieldLocked} class="svadmin-u-da7c36cd8867 svadmin-u-421ac2be5045">
306
+ <legend class="svadmin-u-0214b4b355d1 svadmin-u-2689f3958069">{title}</legend>
307
+ {#if error}<p id={`${id}-error`}>{i18n.t('validation.invalidFormat')}</p>{/if}
308
+ {#if node.description}<p class="svadmin-u-d058ca6de60f svadmin-u-bfa603190748">{node.description}</p>{/if}
309
+ <div class="svadmin-u-9c6cdfa2ba3d">
310
+ {#each Object.entries(node.properties ?? {}) as [key, child] (key)}
311
+ {@render renderField(child, [...path, key], child.title ?? key, node.required?.includes(key) ?? false)}
312
+ {/each}
313
+ </div>
314
+ </fieldset>
315
+ {:else if type === 'array'}
316
+ {@const items = Array.isArray(current) ? current : []}
317
+ <fieldset disabled={fieldLocked} class="svadmin-u-da7c36cd8867 svadmin-u-421ac2be5045">
318
+ <legend class="svadmin-u-0214b4b355d1 svadmin-u-2689f3958069">{title}</legend>
319
+ {#if error}<p id={`${id}-error`}>{i18n.t('validation.invalidFormat')}</p>{/if}
320
+ {#if node.description}<p class="svadmin-u-d058ca6de60f svadmin-u-bfa603190748">{node.description}</p>{/if}
321
+ {#each items as _, index (index)}
322
+ {@render renderField(node.items ?? { type: 'string' }, [...path, String(index)], `${title} ${index + 1}`)}
323
+ <Button type="button" variant="ghost" size="sm" disabled={fieldLocked || (node.minItems !== undefined && items.length <= node.minItems)} onclick={() => removeArrayItem(path, index)}>
324
+ <Trash2 class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" /> {labels.remove}
325
+ </Button>
326
+ {:else}
327
+ <span class="svadmin-u-bfa603190748">{labels.empty}</span>
328
+ {/each}
329
+ <Button type="button" variant="outline" size="sm" disabled={fieldLocked || (node.maxItems !== undefined && items.length >= node.maxItems)} onclick={() => addArrayItem(path, node.items ?? { type: 'string' })}>
330
+ <Plus class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" /> {labels.add}
331
+ </Button>
332
+ </fieldset>
333
+ {:else}
87
334
  <div class="svadmin-u-da7c36cd8867">
88
- <label for="json_field_{field.key}" class="svadmin-u-0214b4b355d1 svadmin-u-2689f3958069 svadmin-u-d4108abe6359">
89
- {field.title}
90
- {#if field.required}
91
- <span class="svadmin-u-811148b13d1e">*</span>
92
- {/if}
335
+ <label for={id} class="svadmin-u-0214b4b355d1 svadmin-u-2689f3958069 svadmin-u-d4108abe6359">
336
+ {title}{#if required}<span class="svadmin-u-811148b13d1e">*</span>{/if}
93
337
  </label>
94
-
95
- {#if field.description}
96
- <p class="svadmin-u-d058ca6de60f svadmin-u-bfa603190748">{field.description}</p>
97
- {/if}
98
-
99
- {#if field.enum}
100
- <select
101
- id="json_field_{field.key}"
102
- required={field.required}
103
- value={String(value[field.key] ?? field.default ?? '')}
104
- onchange={(e) => updateValue(field.key, e.currentTarget.value)}
105
- class="svadmin-u-ed8a5df7b2fb svadmin-u-6da6a3c3f741 svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-d5eab218aa34 svadmin-u-359090c2d529 svadmin-u-f10f771f87e9 svadmin-u-3e94a98e1466 svadmin-u-9c1295a6914a"
106
- >
338
+ {#if node.description}<p class="svadmin-u-d058ca6de60f svadmin-u-bfa603190748">{node.description}</p>{/if}
339
+ {#if options}
340
+ <select id={id} name={path.join('.')} disabled={fieldLocked} aria-invalid={error ? 'true' : undefined} aria-describedby={error ? `${id}-error` : undefined} required={required} value={enumIndex(current, options) < 0 ? '' : enumToken(enumIndex(current, options))} onchange={(event) => writePath(path, enumValue(event.currentTarget.value, options))} class="svadmin-u-ed8a5df7b2fb svadmin-u-6da6a3c3f741 svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-d5eab218aa34 svadmin-u-359090c2d529">
107
341
  <option value="">{i18n.t('common.selectOption')}</option>
108
- {#each field.enum as option (option)}
109
- <option value={String(option)}>{option}</option>
110
- {/each}
342
+ {#each options as option, index (index)}<option value={enumToken(index)}>{String(option)}</option>{/each}
111
343
  </select>
112
- {:else if field.type === 'boolean'}
113
- <div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4 svadmin-u-6b7d6e21ccbd">
114
- <input
115
- id="json_field_{field.key}"
116
- type="checkbox"
117
- checked={Boolean(value[field.key] ?? field.default)}
118
- onchange={(e) => updateValue(field.key, e.currentTarget.checked)}
119
- class="svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-07389a777c1f svadmin-u-18049387f0af svadmin-u-20aaf08a7ed1 svadmin-u-4df2b13689a4 svadmin-u-34516836730d"
120
- />
121
- <span class="svadmin-u-359090c2d529 svadmin-u-bfa603190748">{field.title}</span>
122
- </div>
123
- {:else if field.type === 'number' || field.type === 'integer'}
124
- <input
125
- id="json_field_{field.key}"
126
- type="number"
127
- required={field.required}
128
- value={Number(value[field.key] ?? field.default ?? 0)}
129
- oninput={(e) => updateValue(field.key, Number(e.currentTarget.value))}
130
- class="svadmin-u-ed8a5df7b2fb svadmin-u-6da6a3c3f741 svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-d5eab218aa34 svadmin-u-359090c2d529 svadmin-u-f10f771f87e9 svadmin-u-3e94a98e1466 svadmin-u-9c1295a6914a"
131
- />
344
+ {:else if node.type === 'null'}
345
+ <input id={id} disabled={fieldLocked} type="text" value="null" readonly />
346
+ {:else if type === 'boolean'}
347
+ <input id={id} name={path.join('.')} disabled={fieldLocked} aria-invalid={error ? 'true' : undefined} aria-describedby={error ? `${id}-error` : undefined} type="checkbox" checked={Boolean(current)} onchange={(event) => writePath(path, event.currentTarget.checked)} />
348
+ {:else if type === 'number' || type === 'integer'}
349
+ <input id={id} name={path.join('.')} disabled={fieldLocked} aria-invalid={error ? 'true' : undefined} aria-describedby={error ? `${id}-error` : undefined} type="number" step={type === 'integer' ? 1 : 'any'} min={node.minimum} max={node.maximum} required={required} value={current == null ? '' : String(current)} oninput={(event) => writeNumber(path, event.currentTarget)} class="svadmin-u-ed8a5df7b2fb svadmin-u-6da6a3c3f741 svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-d5eab218aa34 svadmin-u-359090c2d529" />
132
350
  {:else}
133
- <input
134
- id="json_field_{field.key}"
135
- type="text"
136
- required={field.required}
137
- value={String(value[field.key] ?? field.default ?? '')}
138
- oninput={(e) => updateValue(field.key, e.currentTarget.value)}
139
- class="svadmin-u-ed8a5df7b2fb svadmin-u-6da6a3c3f741 svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-d5eab218aa34 svadmin-u-359090c2d529 svadmin-u-f10f771f87e9 svadmin-u-3e94a98e1466 svadmin-u-9c1295a6914a"
140
- />
351
+ <input id={id} name={path.join('.')} disabled={fieldLocked} aria-invalid={error ? 'true' : undefined} aria-describedby={error ? `${id}-error` : undefined} type="text" minlength={node.minLength} maxlength={node.maxLength} required={required} value={String(current ?? '')} oninput={(event) => writePath(path, event.currentTarget.value)} class="svadmin-u-ed8a5df7b2fb svadmin-u-6da6a3c3f741 svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f svadmin-u-e5795dad4d22 svadmin-u-e6f9e383a762 svadmin-u-d5eab218aa34 svadmin-u-359090c2d529" />
141
352
  {/if}
353
+ {#if error}<p id={`${id}-error`}>{i18n.t('validation.invalidFormat')}</p>{/if}
142
354
  </div>
355
+ {/if}
356
+ {/snippet}
357
+
358
+ <fieldset class="schema-form-fields svadmin-u-3e7ce58d64fa" disabled={locked}>
359
+ {#if prepared.ok}
360
+ <div class="svadmin-u-9c6cdfa2ba3d">
361
+ {#each Object.entries(schema.properties ?? {}) as [key, node] (key)}
362
+ {@render renderField(node, [key], node.title ?? key, schema.required?.includes(key) ?? false)}
143
363
  {/each}
144
364
  </div>
145
365
 
366
+ {/if}
146
367
  <div class="svadmin-u-173fa8f06789 svadmin-u-b950dda299d3 svadmin-u-05faf5c801ff svadmin-u-60fbb7713999 svadmin-u-77c08e015d14">
147
- <Button type="submit" size="sm" disabled={isSubmitting} class="svadmin-u-44ee8ba0a421 svadmin-u-25effcb585ab">
148
- {#if isSubmitting}
149
- <Loader2 class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-afbdd13a380e" />
150
- {/if}
368
+ <Button type="submit" size="sm" disabled={locked} class="svadmin-u-44ee8ba0a421 svadmin-u-25effcb585ab">
369
+ {#if isSubmitting}<Loader2 class="svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-afbdd13a380e" />{/if}
151
370
  {submitText}
152
371
  </Button>
153
372
  </div>
373
+ </fieldset>
154
374
  </form>
375
+
376
+ <style>
377
+ .schema-form-fields { min-width: 0; margin: 0; padding: 0; border: 0; }
378
+ </style>
@@ -1,8 +1,25 @@
1
+ import { type SchemaFormSchema } from '@svadmin/core/schema-form';
2
+ import { type JsonSchemaFormSchema } from './json-schema-form-state.js';
3
+ import { type SchemaFormIssue } from './enterprise/json-schema-form.js';
4
+ interface JsonSchema extends JsonSchemaFormSchema {
5
+ properties?: Record<string, JsonSchema>;
6
+ items?: JsonSchema;
7
+ visibleWhen?: SchemaFormSchema['visibleWhen'];
8
+ pattern?: string;
9
+ }
1
10
  interface Props {
2
- schema: Record<string, unknown>;
11
+ schema: JsonSchema;
3
12
  value?: Record<string, unknown>;
4
13
  onsubmit?: (data: Record<string, unknown>) => void | Promise<void>;
5
14
  submitText?: string;
15
+ disabled?: boolean;
16
+ readonly?: boolean;
17
+ /** 只决定此实例文案;不修改全局语言。 */
18
+ locale?: string;
19
+ onerror?: (error: unknown) => void;
20
+ onvalidationerror?: (issues: SchemaFormIssue[]) => void;
21
+ /** Use a unique stable prefix when several schema forms share a page. */
22
+ idPrefix?: string;
6
23
  class?: string;
7
24
  }
8
25
  declare const JsonSchemaForm: import("svelte").Component<Props, {}, "value">;