@svadmin/ui 0.72.0 → 0.73.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 (252) hide show
  1. package/README.md +40 -25
  2. package/THIRD_PARTY_NOTICES.md +52 -0
  3. package/dist/app.css +7694 -5117
  4. package/dist/app.theme.css +7645 -5119
  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/components/AutoForm.svelte +20 -6
  10. package/dist/components/AutoForm.svelte.d.ts +2 -0
  11. package/dist/components/AutoTable.svelte +249 -9
  12. package/dist/components/AutoTable.svelte.d.ts +5 -0
  13. package/dist/components/BoundRecordDetailDrawer.svelte +8 -2
  14. package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +2 -0
  15. package/dist/components/ComboboxField.svelte +31 -9
  16. package/dist/components/ComboboxField.svelte.d.ts +3 -2
  17. package/dist/components/CreatePage.svelte +4 -0
  18. package/dist/components/CreatePage.svelte.d.ts +2 -0
  19. package/dist/components/DateRangeInput.svelte +75 -0
  20. package/dist/components/DateRangeInput.svelte.d.ts +25 -0
  21. package/dist/components/DateTimeInput.svelte +65 -0
  22. package/dist/components/DateTimeInput.svelte.d.ts +19 -0
  23. package/dist/components/DevTools.svelte +2 -2
  24. package/dist/components/EditPage.svelte +4 -0
  25. package/dist/components/EditPage.svelte.d.ts +2 -0
  26. package/dist/components/FieldRenderer.svelte +90 -18
  27. package/dist/components/FileUpload.svelte +250 -0
  28. package/dist/components/FileUpload.svelte.d.ts +32 -0
  29. package/dist/components/FilterBuilder.svelte +236 -279
  30. package/dist/components/FilterBuilder.svelte.d.ts +3 -0
  31. package/dist/components/ImportWizard.svelte +181 -94
  32. package/dist/components/JsonSchemaForm.svelte +255 -99
  33. package/dist/components/JsonSchemaForm.svelte.d.ts +12 -1
  34. package/dist/components/Layout.svelte +1 -2
  35. package/dist/components/LazyTaskQueueDrawer.svelte.d.ts +1 -1
  36. package/dist/components/ListPage.svelte +4 -0
  37. package/dist/components/ListPage.svelte.d.ts +2 -0
  38. package/dist/components/LoginPage.svelte +1 -1
  39. package/dist/components/MoneyInput.svelte +25 -0
  40. package/dist/components/MoneyInput.svelte.d.ts +20 -0
  41. package/dist/components/NumberInput.svelte +25 -0
  42. package/dist/components/NumberInput.svelte.d.ts +19 -0
  43. package/dist/components/NumericInput.svelte +110 -0
  44. package/dist/components/NumericInput.svelte.d.ts +23 -0
  45. package/dist/components/PercentInput.svelte +25 -0
  46. package/dist/components/PercentInput.svelte.d.ts +20 -0
  47. package/dist/components/QuickEditDrawer.svelte +4 -1
  48. package/dist/components/QuickEditDrawer.svelte.d.ts +2 -0
  49. package/dist/components/RecordDetailDrawer.svelte +4 -2
  50. package/dist/components/RecordDetailDrawer.svelte.d.ts +2 -0
  51. package/dist/components/ResourceOperationsPage.svelte +25 -19
  52. package/dist/components/ResourceOperationsPage.svelte.d.ts +5 -1
  53. package/dist/components/ShowInferencer.svelte +4 -2
  54. package/dist/components/ShowInferencer.svelte.d.ts +2 -0
  55. package/dist/components/ShowPage.svelte +7 -3
  56. package/dist/components/ShowPage.svelte.d.ts +2 -0
  57. package/dist/components/Sidebar.svelte +5 -5
  58. package/dist/components/SpreadsheetView.svelte +81 -286
  59. package/dist/components/StepsForm.svelte +5 -5
  60. package/dist/components/SvarAutoTable.svelte +39 -0
  61. package/dist/components/SvarAutoTable.svelte.d.ts +13 -0
  62. package/dist/components/SvarDataGrid.svelte +362 -0
  63. package/dist/components/SvarDataGrid.svelte.d.ts +57 -0
  64. package/dist/components/SvarGridCell.svelte +10 -0
  65. package/dist/components/SvarGridCell.svelte.d.ts +7 -0
  66. package/dist/components/SvarResourceRead.svelte +50 -0
  67. package/dist/components/SvarResourceRead.svelte.d.ts +23 -0
  68. package/dist/components/SvarResourceTable.svelte +63 -0
  69. package/dist/components/SvarResourceTable.svelte.d.ts +42 -0
  70. package/dist/components/SvarResourceTableView.svelte +364 -0
  71. package/dist/components/SvarResourceTableView.svelte.d.ts +4 -0
  72. package/dist/components/TaskQueueDrawer.svelte +72 -16
  73. package/dist/components/TreeSelect.svelte +208 -28
  74. package/dist/components/TreeSelect.svelte.d.ts +3 -1
  75. package/dist/components/auto-table-grid.d.ts +26 -0
  76. package/dist/components/auto-table-grid.js +1 -0
  77. package/dist/components/content/ContentPageHeader.svelte +12 -9
  78. package/dist/components/content/ContentPageShell.svelte +6 -9
  79. package/dist/components/content/FileBrowser.svelte +35 -0
  80. package/dist/components/content/FileBrowser.svelte.d.ts +14 -0
  81. package/dist/components/content/MetricBlock.svelte +10 -13
  82. package/dist/components/content/NetworkTable.svelte +3 -3
  83. package/dist/components/content/NetworkTable.svelte.d.ts +1 -0
  84. package/dist/components/content/PageToolbar.svelte +6 -10
  85. package/dist/components/content/SectionHeader.svelte +8 -13
  86. package/dist/components/content/SettingsFieldRow.svelte +9 -23
  87. package/dist/components/content/SettingsGroup.svelte +11 -27
  88. package/dist/components/content/StatusBadge.svelte +3 -8
  89. package/dist/components/content/WorkspaceLayout.svelte +8 -12
  90. package/dist/components/enterprise/filter-tree.d.ts +48 -0
  91. package/dist/components/enterprise/filter-tree.js +224 -0
  92. package/dist/components/enterprise/json-schema-form.d.ts +39 -0
  93. package/dist/components/enterprise/json-schema-form.js +195 -0
  94. package/dist/components/enterprise/recursive-schema-form.d.ts +30 -0
  95. package/dist/components/enterprise/recursive-schema-form.js +196 -0
  96. package/dist/components/enterprise/spreadsheet-formula.d.ts +12 -0
  97. package/dist/components/enterprise/spreadsheet-formula.js +245 -0
  98. package/dist/components/fieldComponentMap.js +5 -0
  99. package/dist/components/fields/DateField.svelte +4 -3
  100. package/dist/components/fields/date-field-value.d.ts +2 -0
  101. package/dist/components/fields/date-field-value.js +13 -0
  102. package/dist/components/json-schema-form-state.d.ts +37 -0
  103. package/dist/components/json-schema-form-state.js +168 -0
  104. package/dist/components/record-detail.svelte.d.ts +3 -0
  105. package/dist/components/record-detail.svelte.js +10 -4
  106. package/dist/components/svar-grid-cells.d.ts +14 -0
  107. package/dist/components/svar-grid-cells.js +2 -0
  108. package/dist/components/svar-grid-contract.d.ts +80 -0
  109. package/dist/components/svar-grid-contract.js +159 -0
  110. package/dist/components/svar-grid-interactions.d.ts +54 -0
  111. package/dist/components/svar-grid-interactions.js +174 -0
  112. package/dist/components/svar-grid-loading.d.ts +40 -0
  113. package/dist/components/svar-grid-loading.js +180 -0
  114. package/dist/components/svar-grid-operations.d.ts +37 -0
  115. package/dist/components/svar-grid-operations.js +186 -0
  116. package/dist/components/svar-grid-panes.d.ts +34 -0
  117. package/dist/components/svar-grid-panes.js +66 -0
  118. package/dist/components/svar-grid-resource-loading.d.ts +18 -0
  119. package/dist/components/svar-grid-resource-loading.js +68 -0
  120. package/dist/components/svar-grid-resource-session.svelte.d.ts +29 -0
  121. package/dist/components/svar-grid-resource-session.svelte.js +61 -0
  122. package/dist/components/ui/badge/badge-variants.js +3 -1
  123. package/dist/components/ui/button/button-variants.js +5 -2
  124. package/dist/components/ui/input/input.svelte +1 -4
  125. package/dist/components/ui/textarea/textarea.svelte +2 -1
  126. package/dist/components.css +3079 -0
  127. package/dist/design-contract.d.ts +13 -0
  128. package/dist/design-contract.js +11 -0
  129. package/dist/design-system.d.ts +15 -0
  130. package/dist/design-system.js +7 -0
  131. package/dist/index.d.ts +14 -0
  132. package/dist/index.js +9 -0
  133. package/dist/page-chrome.css +12 -49
  134. package/dist/recipes.d.ts +4 -0
  135. package/dist/recipes.js +4 -0
  136. package/dist/rendering/index.d.ts +87 -0
  137. package/dist/rendering/index.js +117 -0
  138. package/dist/styled-system/css/conditions.js +36 -0
  139. package/dist/styled-system/css/css.d.ts +22 -0
  140. package/dist/styled-system/css/css.js +45 -0
  141. package/dist/styled-system/css/cva.d.ts +6 -0
  142. package/dist/styled-system/css/cva.js +87 -0
  143. package/dist/styled-system/css/cx.d.ts +5 -0
  144. package/dist/styled-system/css/cx.js +15 -0
  145. package/dist/styled-system/css/index.d.ts +5 -0
  146. package/dist/styled-system/css/index.js +4 -0
  147. package/dist/styled-system/css/sva.d.ts +4 -0
  148. package/dist/styled-system/css/sva.js +46 -0
  149. package/dist/styled-system/helpers.js +316 -0
  150. package/dist/styled-system/patterns/aspect-ratio.d.ts +20 -0
  151. package/dist/styled-system/patterns/aspect-ratio.js +38 -0
  152. package/dist/styled-system/patterns/bleed.d.ts +21 -0
  153. package/dist/styled-system/patterns/bleed.js +24 -0
  154. package/dist/styled-system/patterns/box.d.ts +20 -0
  155. package/dist/styled-system/patterns/box.js +15 -0
  156. package/dist/styled-system/patterns/center.d.ts +20 -0
  157. package/dist/styled-system/patterns/center.js +21 -0
  158. package/dist/styled-system/patterns/circle.d.ts +20 -0
  159. package/dist/styled-system/patterns/circle.js +25 -0
  160. package/dist/styled-system/patterns/container.d.ts +20 -0
  161. package/dist/styled-system/patterns/container.js +21 -0
  162. package/dist/styled-system/patterns/cq.d.ts +21 -0
  163. package/dist/styled-system/patterns/cq.js +21 -0
  164. package/dist/styled-system/patterns/divider.d.ts +22 -0
  165. package/dist/styled-system/patterns/divider.js +25 -0
  166. package/dist/styled-system/patterns/flex.d.ts +26 -0
  167. package/dist/styled-system/patterns/flex.js +26 -0
  168. package/dist/styled-system/patterns/float.d.ts +23 -0
  169. package/dist/styled-system/patterns/float.js +52 -0
  170. package/dist/styled-system/patterns/grid-item.d.ts +25 -0
  171. package/dist/styled-system/patterns/grid-item.js +25 -0
  172. package/dist/styled-system/patterns/grid.d.ts +24 -0
  173. package/dist/styled-system/patterns/grid.js +27 -0
  174. package/dist/styled-system/patterns/hstack.d.ts +21 -0
  175. package/dist/styled-system/patterns/hstack.js +24 -0
  176. package/dist/styled-system/patterns/index.d.ts +21 -0
  177. package/dist/styled-system/patterns/index.js +20 -0
  178. package/dist/styled-system/patterns/link-overlay.d.ts +20 -0
  179. package/dist/styled-system/patterns/link-overlay.js +24 -0
  180. package/dist/styled-system/patterns/spacer.d.ts +20 -0
  181. package/dist/styled-system/patterns/spacer.js +25 -0
  182. package/dist/styled-system/patterns/square.d.ts +20 -0
  183. package/dist/styled-system/patterns/square.js +24 -0
  184. package/dist/styled-system/patterns/stack.d.ts +23 -0
  185. package/dist/styled-system/patterns/stack.js +24 -0
  186. package/dist/styled-system/patterns/visually-hidden.d.ts +20 -0
  187. package/dist/styled-system/patterns/visually-hidden.js +18 -0
  188. package/dist/styled-system/patterns/vstack.d.ts +21 -0
  189. package/dist/styled-system/patterns/vstack.js +24 -0
  190. package/dist/styled-system/patterns/wrap.d.ts +24 -0
  191. package/dist/styled-system/patterns/wrap.js +25 -0
  192. package/dist/styled-system/recipes/content-header.d.ts +31 -0
  193. package/dist/styled-system/recipes/content-header.js +65 -0
  194. package/dist/styled-system/recipes/content-page.d.ts +34 -0
  195. package/dist/styled-system/recipes/content-page.js +43 -0
  196. package/dist/styled-system/recipes/create-recipe.js +82 -0
  197. package/dist/styled-system/recipes/index.d.ts +17 -0
  198. package/dist/styled-system/recipes/index.js +16 -0
  199. package/dist/styled-system/recipes/metric-block.d.ts +34 -0
  200. package/dist/styled-system/recipes/metric-block.js +76 -0
  201. package/dist/styled-system/recipes/product-list.d.ts +31 -0
  202. package/dist/styled-system/recipes/product-list.js +73 -0
  203. package/dist/styled-system/recipes/product-section.d.ts +31 -0
  204. package/dist/styled-system/recipes/product-section.js +49 -0
  205. package/dist/styled-system/recipes/product-settings-row.d.ts +34 -0
  206. package/dist/styled-system/recipes/product-settings-row.js +58 -0
  207. package/dist/styled-system/recipes/product-settings.d.ts +31 -0
  208. package/dist/styled-system/recipes/product-settings.js +57 -0
  209. package/dist/styled-system/recipes/product-status.d.ts +34 -0
  210. package/dist/styled-system/recipes/product-status.js +45 -0
  211. package/dist/styled-system/recipes/product-toolbar.d.ts +31 -0
  212. package/dist/styled-system/recipes/product-toolbar.js +41 -0
  213. package/dist/styled-system/recipes/product-workspace.d.ts +34 -0
  214. package/dist/styled-system/recipes/product-workspace.js +58 -0
  215. package/dist/styled-system/recipes/surface-metric.d.ts +38 -0
  216. package/dist/styled-system/recipes/surface-metric.js +63 -0
  217. package/dist/styled-system/recipes/surface-table.d.ts +34 -0
  218. package/dist/styled-system/recipes/surface-table.js +62 -0
  219. package/dist/styled-system/recipes/ui-badge.d.ts +31 -0
  220. package/dist/styled-system/recipes/ui-badge.js +38 -0
  221. package/dist/styled-system/recipes/ui-button.d.ts +32 -0
  222. package/dist/styled-system/recipes/ui-button.js +43 -0
  223. package/dist/styled-system/recipes/ui-input.d.ts +31 -0
  224. package/dist/styled-system/recipes/ui-input.js +49 -0
  225. package/dist/styled-system/recipes/ui-textarea.d.ts +31 -0
  226. package/dist/styled-system/recipes/ui-textarea.js +24 -0
  227. package/dist/styled-system/styles.css +1257 -0
  228. package/dist/styled-system/tokens/index.d.ts +9 -0
  229. package/dist/styled-system/tokens/index.js +268 -0
  230. package/dist/styled-system/tokens/tokens.d.ts +36 -0
  231. package/dist/styled-system/types/composition.d.ts +227 -0
  232. package/dist/styled-system/types/conditions.d.ts +236 -0
  233. package/dist/styled-system/types/csstype.d.ts +22570 -0
  234. package/dist/styled-system/types/index.d.ts +6 -0
  235. package/dist/styled-system/types/parts.d.ts +8 -0
  236. package/dist/styled-system/types/pattern.d.ts +78 -0
  237. package/dist/styled-system/types/prop-type.d.ts +223 -0
  238. package/dist/styled-system/types/recipe.d.ts +181 -0
  239. package/dist/styled-system/types/selectors.d.ts +59 -0
  240. package/dist/styled-system/types/static-css.d.ts +56 -0
  241. package/dist/styled-system/types/style-props.d.ts +8088 -0
  242. package/dist/styled-system/types/system-types.d.ts +151 -0
  243. package/dist/styles/aliases.css +49 -0
  244. package/dist/styles/compatibility.epilogue.css +384 -0
  245. package/dist/styles/compatibility.prelude.css +5513 -0
  246. package/dist/styles/conditional-states.css +28 -0
  247. package/dist/styles/conditional-utilities.css +22 -0
  248. package/dist/styles/recipes.css +1262 -0
  249. package/dist/utils.d.ts +1 -1
  250. package/dist/utils.js +1 -1
  251. package/package.json +31 -13
  252. package/styles-compatibility.json +12 -0
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { ResourceRendering } from '../rendering/index.js';
2
3
  import { definedOptions } from '@svadmin/core/options';
3
4
 
4
5
  import { useCan, useNavigation, type FieldDefinition } from '@svadmin/core';
@@ -12,11 +13,13 @@
12
13
 
13
14
  let {
14
15
  resourceName,
16
+ rendering,
15
17
  open = $bindable(false),
16
18
  recordId,
17
19
  onClose,
18
20
  }: {
19
21
  resourceName: string;
22
+ rendering?: ResourceRendering | undefined;
20
23
  open?: boolean;
21
24
  recordId: string | number;
22
25
  onClose?: () => void;
@@ -24,7 +27,7 @@
24
27
 
25
28
  const i18n = useTranslation();
26
29
  const navigation = useNavigation();
27
- const detail = useRecordDetail(() => ({ resourceName, id: recordId }));
30
+ const detail = useRecordDetail(() => ({ resourceName, id: recordId, rendering }));
28
31
  const resource = $derived(detail.resource);
29
32
  const showFields = $derived(detail.fields);
30
33
  const fieldGroups = $derived.by(() => {
@@ -68,12 +71,13 @@
68
71
 
69
72
  {#snippet fieldsList(fields: FieldDefinition[])}
70
73
  {#if query.isSuccess}
74
+ {@const record = detail.rendering ? detail.rendering.record(query.data.data) : query.data.data}
71
75
  <dl class="svadmin-u-fa6acbf81d74 svadmin-u-d2c3932343f5">
72
76
  {#each fields as field (field.key)}
73
77
  <div class="svadmin-u-f3c543ad5fe9 svadmin-u-58284b4ea568 svadmin-u-cb11fec3bb46 svadmin-u-d9bdd3d643a2 svadmin-u-022e8076dfea">
74
78
  <dt class="svadmin-u-359090c2d529 svadmin-u-2689f3958069 svadmin-u-bfa603190748 svadmin-u-e2327d142859">{field.label}</dt>
75
79
  <dd class="svadmin-u-7e0b7cdf1a94 svadmin-u-170cee3ff4e4 svadmin-u-fc7473ca09eb svadmin-u-d4108abe6359">
76
- <FieldDisplay type={field.type} value={query.data.data[field.key]} options={field.options} resourceName={field.resource} />
80
+ <FieldDisplay type={field.type} value={record[field.key]} options={field.options} resourceName={field.resource} />
77
81
  </dd>
78
82
  </div>
79
83
  {/each}
@@ -83,6 +87,8 @@
83
87
 
84
88
  <DetailDrawer
85
89
  bind:open
90
+ data-svadmin-rendering-resource={detail.rendering?.resource.name}
91
+ data-svadmin-rendering-kind={detail.rendering ? 'detail-drawer' : undefined}
86
92
  title="{resource.label} {i18n.t('common.detail')}"
87
93
  description={`#${recordId}`}
88
94
  closeLabel={i18n.t('common.close')}
@@ -1,5 +1,7 @@
1
+ import type { ResourceRendering } from '../rendering/index.js';
1
2
  type $$ComponentProps = {
2
3
  resourceName: string;
4
+ rendering?: ResourceRendering | undefined;
3
5
  open?: boolean;
4
6
  recordId: string | number;
5
7
  onClose?: () => void;
@@ -23,12 +23,13 @@
23
23
 
24
24
  interface Props extends Omit<HTMLButtonAttributes, 'value' | 'onchange' | 'children' | 'onclick' | 'type'> {
25
25
  resource: string;
26
- value?: string | number | null;
27
- onchange?: (value: string | number | null) => void;
26
+ value?: string | number | null | (string | number)[];
27
+ onchange?: (value: string | number | null | (string | number)[]) => void;
28
28
  optionLabel?: string;
29
29
  optionValue?: string;
30
30
  placeholder?: string;
31
31
  searchable?: boolean;
32
+ multiple?: boolean;
32
33
  onSearch?: (value: string) => Filter[];
33
34
  id?: string;
34
35
  class?: string;
@@ -42,6 +43,7 @@
42
43
  optionValue = 'id',
43
44
  placeholder = 'Select...',
44
45
  searchable = true,
46
+ multiple = false,
45
47
  onSearch,
46
48
  disabled = false,
47
49
  ...restProps
@@ -67,7 +69,10 @@
67
69
  };
68
70
  },
69
71
  get projectionKey() { return `combobox:${optionLabel}:${optionValue}`; },
70
- get defaultValue() { return value === null ? [] : [value]; },
72
+ get defaultValue() {
73
+ if (Array.isArray(value)) return value;
74
+ return value === null || value === undefined ? [] : [value];
75
+ },
71
76
  get onSearch() { return onSearch ?? (searchable ? defaultSearch : undefined); },
72
77
  }));
73
78
 
@@ -81,11 +86,23 @@
81
86
  open = false;
82
87
  });
83
88
 
84
- const selectedLabel = $derived(
85
- select.options.find(o => o.value === value)?.label ?? ''
89
+ const selectedValues = $derived(
90
+ Array.isArray(value) ? value : value === null || value === undefined ? [] : [value],
86
91
  );
92
+ const selectedLabels = $derived(selectedValues.flatMap(selectedValue => {
93
+ const option = select.options.find(candidate => candidate.value === selectedValue);
94
+ return option ? [option.label] : [];
95
+ }));
96
+ const selectedLabel = $derived(selectedLabels.join(', '));
87
97
 
88
98
  function handleSelect(optValue: string | number) {
99
+ if (multiple) {
100
+ const next = selectedValues.includes(optValue)
101
+ ? selectedValues.filter(selectedValue => selectedValue !== optValue)
102
+ : [...selectedValues, optValue];
103
+ onchange?.(next);
104
+ return;
105
+ }
89
106
  onchange?.(optValue === value ? null : optValue);
90
107
  open = false;
91
108
  searchInputValue = '';
@@ -94,7 +111,7 @@
94
111
 
95
112
  function handleClear(e: Event) {
96
113
  e.stopPropagation();
97
- onchange?.(null);
114
+ onchange?.(multiple ? [] : null);
98
115
  open = false;
99
116
  searchInputValue = '';
100
117
  select.onSearchChange('');
@@ -119,6 +136,7 @@
119
136
  {disabled}
120
137
  aria-haspopup="listbox"
121
138
  aria-expanded={open}
139
+ aria-multiselectable={multiple || undefined}
122
140
  aria-busy={select.isFetching}
123
141
  aria-invalid={select.isError}
124
142
  >
@@ -129,7 +147,7 @@
129
147
  {/if}
130
148
  <ChevronsUpDown class="svadmin-u-fb56d9cff341 svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-012fbd121f37 svadmin-u-0b8c506a0596" />
131
149
  </Button>
132
- {#if value !== null}
150
+ {#if selectedValues.length}
133
151
  <Button type="button" variant="ghost" size="icon-sm" {disabled}
134
152
  title={i18n.t('common.clear')} aria-label={i18n.t('common.clear')} onclick={handleClear}>
135
153
  <X class="svadmin-u-6a60c09e6aaa svadmin-u-9cea05671a29" />
@@ -160,7 +178,11 @@
160
178
  />
161
179
  </div>
162
180
  {/if}
163
- <Command.List class="svadmin-u-558f64349245 svadmin-u-92bf82f493b1 svadmin-u-eb6a3cef9686">
181
+ <Command.List
182
+ role="listbox"
183
+ aria-multiselectable={multiple || undefined}
184
+ class="svadmin-u-558f64349245 svadmin-u-92bf82f493b1 svadmin-u-eb6a3cef9686"
185
+ >
164
186
  {#if select.isLoading}
165
187
  {#each Array(3) as _, _i (_i)}
166
188
  <div class="svadmin-u-d5eab218aa34 svadmin-u-ec0091ee009b"><Skeleton class="svadmin-u-cd0d9c512cdc svadmin-u-6da6a3c3f741" /></div>
@@ -177,7 +199,7 @@
177
199
  onSelect={() => handleSelect(opt.value)}
178
200
  class="svadmin-u-d89972fe17d6 svadmin-u-60fbb7713999 svadmin-u-50ca6ba56aa3 svadmin-u-7f6912283f11 svadmin-u-3960ffc248d9 svadmin-u-36d4469299aa svadmin-u-d5eab218aa34 svadmin-u-ec0091ee009b svadmin-u-fc7473ca09eb svadmin-u-df37b1fd9495 svadmin-u-99afb1cc3b47 svadmin-u-529780e25268"
179
201
  >
180
- <Check class="svadmin-u-d2347e8497a9 svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c {value === opt.value ? 'svadmin-u-3972e98dc84f' : 'svadmin-u-7065497e1ca0'}" />
202
+ <Check class="svadmin-u-d2347e8497a9 svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c {selectedValues.includes(opt.value) ? 'svadmin-u-3972e98dc84f' : 'svadmin-u-7065497e1ca0'}" />
181
203
  {opt.label}
182
204
  </Command.Item>
183
205
  {/each}
@@ -2,12 +2,13 @@ import type { Filter } from '@svadmin/core';
2
2
  import type { HTMLButtonAttributes } from 'svelte/elements';
3
3
  interface Props extends Omit<HTMLButtonAttributes, 'value' | 'onchange' | 'children' | 'onclick' | 'type'> {
4
4
  resource: string;
5
- value?: string | number | null;
6
- onchange?: (value: string | number | null) => void;
5
+ value?: string | number | null | (string | number)[];
6
+ onchange?: (value: string | number | null | (string | number)[]) => void;
7
7
  optionLabel?: string;
8
8
  optionValue?: string;
9
9
  placeholder?: string;
10
10
  searchable?: boolean;
11
+ multiple?: boolean;
11
12
  onSearch?: (value: string) => Filter[];
12
13
  id?: string;
13
14
  class?: string;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { ResourceRendering } from '../rendering/index.js';
2
3
  import { definedOptions } from '@svadmin/core/options';
3
4
 
4
5
  import { getResource, captureAdminContext } from '@svadmin/core';
@@ -12,6 +13,7 @@
12
13
 
13
14
  interface Props {
14
15
  resourceName: string;
16
+ rendering?: ResourceRendering | undefined;
15
17
  title?: string;
16
18
  density?: 'compact' | 'comfortable';
17
19
  columns?: 1 | 2 | 3 | 4;
@@ -22,6 +24,7 @@
22
24
 
23
25
  let {
24
26
  resourceName,
27
+ rendering,
25
28
  title,
26
29
  density = 'comfortable',
27
30
  columns = 1,
@@ -51,6 +54,7 @@
51
54
  </PageHeader>
52
55
 
53
56
  <AutoForm
57
+ {rendering}
54
58
  {resourceName}
55
59
  mode="create"
56
60
  {density}
@@ -1,6 +1,8 @@
1
+ import type { ResourceRendering } from '../rendering/index.js';
1
2
  import type { Snippet } from 'svelte';
2
3
  interface Props {
3
4
  resourceName: string;
5
+ rendering?: ResourceRendering | undefined;
4
6
  title?: string;
5
7
  density?: 'compact' | 'comfortable';
6
8
  columns?: 1 | 2 | 3 | 4;
@@ -0,0 +1,75 @@
1
+ <script lang="ts">
2
+ import DateTimeInput, { type DateTimeInputMode } from './DateTimeInput.svelte';
3
+ import { cn } from '../utils.js';
4
+ import { definedOptions } from '@svadmin/core/options';
5
+
6
+ export interface DateRangeInputValue {
7
+ start: string | null;
8
+ end: string | null;
9
+ }
10
+
11
+ interface Props {
12
+ value?: DateRangeInputValue | null;
13
+ mode?: DateTimeInputMode;
14
+ min?: string;
15
+ max?: string;
16
+ step?: number;
17
+ startId?: string;
18
+ endId?: string;
19
+ startName?: string;
20
+ endName?: string;
21
+ disabled?: boolean;
22
+ required?: boolean;
23
+ invalid?: boolean;
24
+ describedby?: string;
25
+ class?: string;
26
+ onchange?: (value: DateRangeInputValue) => void;
27
+ }
28
+
29
+ let {
30
+ value = $bindable({ start: null, end: null }),
31
+ mode = 'date',
32
+ min,
33
+ max,
34
+ step,
35
+ startId,
36
+ endId,
37
+ startName,
38
+ endName,
39
+ disabled = false,
40
+ required = false,
41
+ invalid = false,
42
+ describedby,
43
+ class: className = '',
44
+ onchange,
45
+ }: Props = $props();
46
+
47
+ function update(part: 'start' | 'end', next: string | null): void {
48
+ // null 范围首次编辑也必须返回两个明确的端点。
49
+ const result: DateRangeInputValue = { start: value?.start ?? null, end: value?.end ?? null, [part]: next };
50
+ value = result;
51
+ onchange?.(result);
52
+ }
53
+ </script>
54
+
55
+ <div class={cn('svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-421ac2be5045', className)} data-date-range-input>
56
+ <DateTimeInput
57
+ value={value?.start ?? null}
58
+ {mode}
59
+ {...definedOptions({ min, max, step, id: startId, name: startName, describedby })}
60
+ {disabled}
61
+ {required}
62
+ {invalid}
63
+ onchange={(next) => update('start', next)}
64
+ />
65
+ <span aria-hidden="true">至</span>
66
+ <DateTimeInput
67
+ value={value?.end ?? null}
68
+ {mode}
69
+ {...definedOptions({ min, max, step, id: endId, name: endName, describedby })}
70
+ {disabled}
71
+ {required}
72
+ {invalid}
73
+ onchange={(next) => update('end', next)}
74
+ />
75
+ </div>
@@ -0,0 +1,25 @@
1
+ import { type DateTimeInputMode } from './DateTimeInput.svelte';
2
+ export interface DateRangeInputValue {
3
+ start: string | null;
4
+ end: string | null;
5
+ }
6
+ interface Props {
7
+ value?: DateRangeInputValue | null;
8
+ mode?: DateTimeInputMode;
9
+ min?: string;
10
+ max?: string;
11
+ step?: number;
12
+ startId?: string;
13
+ endId?: string;
14
+ startName?: string;
15
+ endName?: string;
16
+ disabled?: boolean;
17
+ required?: boolean;
18
+ invalid?: boolean;
19
+ describedby?: string;
20
+ class?: string;
21
+ onchange?: (value: DateRangeInputValue) => void;
22
+ }
23
+ declare const DateRangeInput: import("svelte").Component<Props, {}, "value">;
24
+ type DateRangeInput = ReturnType<typeof DateRangeInput>;
25
+ export default DateRangeInput;
@@ -0,0 +1,65 @@
1
+ <script lang="ts">
2
+ import { Input } from './ui/input/index.js';
3
+ import { cn } from '../utils.js';
4
+
5
+ export type DateTimeInputMode = 'date' | 'time' | 'datetime';
6
+
7
+ interface Props {
8
+ value?: string | null;
9
+ mode?: DateTimeInputMode;
10
+ min?: string;
11
+ max?: string;
12
+ step?: number;
13
+ id?: string;
14
+ name?: string;
15
+ disabled?: boolean;
16
+ required?: boolean;
17
+ invalid?: boolean;
18
+ describedby?: string;
19
+ class?: string;
20
+ onchange?: (value: string | null) => void;
21
+ }
22
+
23
+ let {
24
+ value = $bindable(null),
25
+ mode = 'date',
26
+ min,
27
+ max,
28
+ step,
29
+ id,
30
+ name,
31
+ disabled = false,
32
+ required = false,
33
+ invalid = false,
34
+ describedby,
35
+ class: className = '',
36
+ onchange,
37
+ }: Props = $props();
38
+
39
+ const inputType = $derived(mode === 'datetime' ? 'datetime-local' : mode);
40
+
41
+ function handleInput(event: Event): void {
42
+ const input = event.currentTarget;
43
+ if (!(input instanceof HTMLInputElement)) return;
44
+ const next = input.value === '' ? null : input.value;
45
+ value = next;
46
+ onchange?.(next);
47
+ }
48
+ </script>
49
+
50
+ <div class={cn('svadmin-u-6da6a3c3f741', className)} data-date-time-input={mode}>
51
+ <Input
52
+ {id}
53
+ {name}
54
+ type={inputType}
55
+ value={value ?? ''}
56
+ {min}
57
+ {max}
58
+ {step}
59
+ {disabled}
60
+ {required}
61
+ aria-invalid={invalid || undefined}
62
+ aria-describedby={describedby}
63
+ oninput={handleInput}
64
+ />
65
+ </div>
@@ -0,0 +1,19 @@
1
+ export type DateTimeInputMode = 'date' | 'time' | 'datetime';
2
+ interface Props {
3
+ value?: string | null;
4
+ mode?: DateTimeInputMode;
5
+ min?: string;
6
+ max?: string;
7
+ step?: number;
8
+ id?: string;
9
+ name?: string;
10
+ disabled?: boolean;
11
+ required?: boolean;
12
+ invalid?: boolean;
13
+ describedby?: string;
14
+ class?: string;
15
+ onchange?: (value: string | null) => void;
16
+ }
17
+ declare const DateTimeInput: import("svelte").Component<Props, {}, "value">;
18
+ type DateTimeInput = ReturnType<typeof DateTimeInput>;
19
+ export default DateTimeInput;
@@ -241,8 +241,8 @@
241
241
  {#if visible}
242
242
  <div
243
243
  class="svadmin-u-7bc555991dba svadmin-u-189f036c335c svadmin-u-5a438c30beec svadmin-u-f50571addf44 svadmin-u-11863ecc32e7 svadmin-u-c69e21ff5804 svadmin-u-1301e5c1ce71 svadmin-u-ca6bcd4b6f3f svadmin-u-d5e98261a758 svadmin-u-cd0ad9a56558 svadmin-u-14e46609fd68 svadmin-u-1d5904e7e755 svadmin-u-2cd02d11d1af"
244
- class:w-auto={collapsed}
245
- class:min-w-[200px]={collapsed}
244
+ class:svadmin-devtools--collapsed-width={collapsed}
245
+ class:svadmin-devtools--collapsed-min-width={collapsed}
246
246
  transition:fly={{ y: 400, duration: 300 }}
247
247
  >
248
248
  <div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-0e17f2bd9074 svadmin-u-03b4dd7f172b svadmin-u-2ef11f1cb219 svadmin-u-65fdbade2025">
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import type { ResourceRendering } from '../rendering/index.js';
2
3
  import { definedOptions } from '@svadmin/core/options';
3
4
 
4
5
  import { getResource, useNavigation } from '@svadmin/core';
@@ -16,6 +17,7 @@
16
17
 
17
18
  interface Props {
18
19
  resourceName: string;
20
+ rendering?: ResourceRendering | undefined;
19
21
  id: string | number;
20
22
  title?: string;
21
23
  density?: 'compact' | 'comfortable';
@@ -28,6 +30,7 @@
28
30
 
29
31
  let {
30
32
  resourceName,
33
+ rendering,
31
34
  id,
32
35
  title,
33
36
  density = 'comfortable',
@@ -65,6 +68,7 @@
65
68
  </PageHeader>
66
69
 
67
70
  <AutoForm
71
+ {rendering}
68
72
  {resourceName}
69
73
  mode="edit"
70
74
  {id}
@@ -1,6 +1,8 @@
1
+ import type { ResourceRendering } from '../rendering/index.js';
1
2
  import type { Snippet } from 'svelte';
2
3
  interface Props {
3
4
  resourceName: string;
5
+ rendering?: ResourceRendering | undefined;
4
6
  id: string | number;
5
7
  title?: string;
6
8
  density?: 'compact' | 'comfortable';
@@ -18,6 +18,12 @@
18
18
  import { Button } from './ui/button/index.js';
19
19
  import TooltipButton from './TooltipButton.svelte';
20
20
  import ComboboxField from './ComboboxField.svelte';
21
+ import NumberInput from './NumberInput.svelte';
22
+ import MoneyInput from './MoneyInput.svelte';
23
+ import PercentInput from './PercentInput.svelte';
24
+ import DateTimeInput from './DateTimeInput.svelte';
25
+ import DateRangeInput, { type DateRangeInputValue } from './DateRangeInput.svelte';
26
+ import FileUpload from './FileUpload.svelte';
21
27
  import TreeSelect, { type TreeSelectOption } from './TreeSelect.svelte';
22
28
  import Cascader, { type CascaderOption } from './Cascader.svelte';
23
29
  import Transfer, { type TransferItem } from './Transfer.svelte';
@@ -209,19 +215,52 @@
209
215
  </div>
210
216
 
211
217
  {:else if field.type === 'number'}
212
- <Input
218
+ <NumberInput
213
219
  id={field.key}
214
220
  name={field.key}
215
- type="number"
216
221
  value={numVal}
217
- oninput={(e) => {
218
- const input = e.currentTarget;
219
- if (!(input instanceof HTMLInputElement)) return;
220
- onchange(input.value === '' ? null : numericInputValue(input.valueAsNumber));
221
- }}
222
+ min={field.min}
223
+ max={field.max}
224
+ step={field.step}
225
+ precision={field.precision}
226
+ onchange={onchange}
222
227
  required={field.required}
223
- aria-invalid={invalid || undefined}
224
- aria-describedby={errorId}
228
+ invalid={invalid}
229
+ describedby={errorId}
230
+ {disabled}
231
+ />
232
+
233
+ {:else if field.type === 'currency'}
234
+ <MoneyInput
235
+ id={field.key}
236
+ name={field.key}
237
+ value={numVal}
238
+ currency={field.currency ?? 'USD'}
239
+ min={field.min}
240
+ max={field.max}
241
+ step={field.step}
242
+ precision={field.precision ?? 2}
243
+ onchange={onchange}
244
+ required={field.required}
245
+ invalid={invalid}
246
+ describedby={errorId}
247
+ {disabled}
248
+ />
249
+
250
+ {:else if field.type === 'percent'}
251
+ <PercentInput
252
+ id={field.key}
253
+ name={field.key}
254
+ value={numVal}
255
+ scale={field.scale ?? '100'}
256
+ min={field.min}
257
+ max={field.max}
258
+ step={field.step}
259
+ precision={field.precision ?? 1}
260
+ onchange={onchange}
261
+ required={field.required}
262
+ invalid={invalid}
263
+ describedby={errorId}
225
264
  {disabled}
226
265
  />
227
266
 
@@ -300,14 +339,21 @@
300
339
  />
301
340
 
302
341
  {:else if field.type === 'relation' && field.resource}
303
- <input type="hidden" name={field.key} value={value == null ? '' : String(value)} />
342
+ {#if field.multiple}
343
+ {#each multiVal as selectedValue, _i (selectedValue)}
344
+ <input type="hidden" name={field.key} value={String(selectedValue)} />
345
+ {/each}
346
+ {:else}
347
+ <input type="hidden" name={field.key} value={value == null ? '' : String(value)} />
348
+ {/if}
304
349
  <ComboboxField
305
350
  id={field.key}
306
351
  resource={field.resource}
307
- value={value as string | number | null}
352
+ value={field.multiple ? multiVal : value as string | number | null}
308
353
  onchange={(v) => onchange(v)}
309
354
  optionLabel={field.optionLabel ?? 'title'}
310
355
  optionValue={field.optionValue ?? 'id'}
356
+ multiple={field.multiple}
311
357
  placeholder={i18n.t('field.selectPlaceholder')}
312
358
  aria-invalid={invalid || undefined}
313
359
  aria-describedby={errorId}
@@ -434,19 +480,45 @@
434
480
  />
435
481
  </div>
436
482
 
437
- {:else if field.type === 'date'}
438
- <Input
483
+ {:else if field.type === 'date' || field.type === 'time' || field.type === 'datetime'}
484
+ <DateTimeInput
439
485
  id={field.key}
440
486
  name={field.key}
441
- type="date"
442
- value={strVal}
443
- oninput={(e) => onchange((e.target as HTMLInputElement).value)}
487
+ mode={field.type}
488
+ value={strVal || null}
489
+ onchange={(next) => onchange(next)}
444
490
  required={field.required}
445
- aria-invalid={invalid || undefined}
446
- aria-describedby={errorId}
491
+ invalid={invalid}
492
+ describedby={errorId}
493
+ {disabled}
494
+ />
495
+
496
+ {:else if field.type === 'daterange'}
497
+ <DateRangeInput
498
+ startId={`${field.key}-start`}
499
+ endId={`${field.key}-end`}
500
+ startName={`${field.key}.start`}
501
+ endName={`${field.key}.end`}
502
+ value={value as DateRangeInputValue | null}
503
+ onchange={(next) => onchange(next)}
504
+ required={field.required}
505
+ invalid={invalid}
506
+ describedby={errorId}
447
507
  {disabled}
448
508
  />
449
509
 
510
+ {:else if field.type === 'file'}
511
+ <FileUpload
512
+ id={field.key}
513
+ name={field.key}
514
+ multiple={field.multiple}
515
+ required={field.required && !value}
516
+ disabled={disabled}
517
+ accept={field.accept}
518
+ maxSize={field.maxSize}
519
+ onChange={(items) => onchange(field.multiple ? items.map(item => item.file) : items[0]?.file ?? null)}
520
+ />
521
+
450
522
  {:else if field.type === 'images'}
451
523
  {#each imagesVal as url, imageIndex (imageIndex)}
452
524
  <input type="hidden" name={`${field.key}[]`} value={url} />