@svadmin/ui 0.70.0 → 0.72.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 (158) hide show
  1. package/dist/actions.js +1 -1
  2. package/dist/app.css +102 -63
  3. package/dist/app.theme.css +102 -63
  4. package/dist/component-registry.svelte.d.ts +33 -19
  5. package/dist/component-registry.svelte.js +6 -4
  6. package/dist/components/AdminApp.svelte +55 -53
  7. package/dist/components/AdminApp.svelte.d.ts +2 -2
  8. package/dist/components/ApiSettings.svelte +19 -1
  9. package/dist/components/AuditLogDrawer.svelte +14 -3
  10. package/dist/components/AutoForm.svelte +146 -48
  11. package/dist/components/AutoForm.svelte.d.ts +2 -0
  12. package/dist/components/AutoTable.svelte +358 -258
  13. package/dist/components/AutoTable.svelte.d.ts +1 -0
  14. package/dist/components/BoundRecordDetailDrawer.svelte +166 -0
  15. package/dist/components/BoundRecordDetailDrawer.svelte.d.ts +9 -0
  16. package/dist/components/Breadcrumbs.svelte +7 -4
  17. package/dist/components/CancelTaskButton.svelte +9 -5
  18. package/dist/components/ColumnHeaderFilter.svelte +4 -3
  19. package/dist/components/ColumnSettings.svelte +1 -0
  20. package/dist/components/ComboboxField.svelte +90 -30
  21. package/dist/components/ComboboxField.svelte.d.ts +2 -2
  22. package/dist/components/CreatePage.svelte +3 -1
  23. package/dist/components/DetailDrawer.svelte +4 -0
  24. package/dist/components/DetailDrawer.svelte.d.ts +1 -0
  25. package/dist/components/DevTools.svelte +6 -19
  26. package/dist/components/DraggableGrid.svelte +1 -0
  27. package/dist/components/DraggableHeader.svelte +5 -9
  28. package/dist/components/DraggableHeader.svelte.d.ts +43 -18
  29. package/dist/components/DraggableRowTable.svelte +2 -2
  30. package/dist/components/DynamicFormList.svelte +17 -17
  31. package/dist/components/DynamicFormList.svelte.d.ts +2 -1
  32. package/dist/components/EditPage.svelte +3 -1
  33. package/dist/components/EditableTable.svelte +4 -0
  34. package/dist/components/ErrorPage.svelte +3 -1
  35. package/dist/components/FieldDisplay.svelte +14 -0
  36. package/dist/components/FieldDisplay.svelte.d.ts +7 -0
  37. package/dist/components/FieldRenderer.svelte +9 -5
  38. package/dist/components/FilterBuilder.svelte +19 -8
  39. package/dist/components/FilterDropdown.svelte.d.ts +1 -1
  40. package/dist/components/Header.svelte +5 -6
  41. package/dist/components/ImportWizard.svelte +3 -2
  42. package/dist/components/InfiniteList.svelte +22 -8
  43. package/dist/components/InfiniteList.svelte.d.ts +5 -3
  44. package/dist/components/InlineEdit.svelte +114 -44
  45. package/dist/components/JsonSchemaForm.svelte +19 -14
  46. package/dist/components/Layout.svelte +19 -15
  47. package/dist/components/LazyTaskQueueDrawer.svelte +26 -0
  48. package/dist/components/LazyTaskQueueDrawer.svelte.d.ts +8 -0
  49. package/dist/components/ListPage.svelte +7 -6
  50. package/dist/components/MasterDetailView.svelte +3 -3
  51. package/dist/components/MediaLibraryModal.svelte +5 -2
  52. package/dist/components/MentionsInput.svelte +4 -3
  53. package/dist/components/NavigateToResource.svelte +3 -2
  54. package/dist/components/PermissionMatrix.svelte +4 -3
  55. package/dist/components/ProfilePage.svelte +2 -2
  56. package/dist/components/QuickEditDrawer.svelte +39 -0
  57. package/dist/components/QuickEditDrawer.svelte.d.ts +8 -0
  58. package/dist/components/RecordDetailDrawer.svelte +14 -108
  59. package/dist/components/RecordRowActions.svelte +41 -0
  60. package/dist/components/RecordRowActions.svelte.d.ts +14 -0
  61. package/dist/components/ResourceAccessGuard.svelte +7 -5
  62. package/dist/components/RetryTaskButton.svelte +9 -5
  63. package/dist/components/RowActions.svelte +5 -3
  64. package/dist/components/SensitiveDataMask.svelte +3 -3
  65. package/dist/components/SettingsPage.svelte +1 -1
  66. package/dist/components/ShowPage.svelte +44 -38
  67. package/dist/components/Sidebar.svelte +10 -8
  68. package/dist/components/SplitPaneLayout.svelte +4 -2
  69. package/dist/components/StepsForm.svelte +161 -44
  70. package/dist/components/StepsForm.svelte.d.ts +1 -0
  71. package/dist/components/TaskDetails.svelte +20 -7
  72. package/dist/components/TaskList.svelte +19 -7
  73. package/dist/components/TaskQueueDrawer.svelte +21 -22
  74. package/dist/components/Toast.svelte +4 -2
  75. package/dist/components/TooltipButton.svelte +1 -1
  76. package/dist/components/TreeSelect.svelte +4 -2
  77. package/dist/components/ValidatedField.svelte +27 -0
  78. package/dist/components/ValidatedField.svelte.d.ts +35 -0
  79. package/dist/components/account/ImportMembersPage.svelte +2 -2
  80. package/dist/components/account/SecurityLogPage.svelte +3 -1
  81. package/dist/components/account/SettingsEnterprisePage.svelte +7 -5
  82. package/dist/components/account/TeamMembersPage.svelte +1 -1
  83. package/dist/components/buttons/CloneButton.svelte +6 -4
  84. package/dist/components/buttons/DeleteButton.svelte +95 -29
  85. package/dist/components/buttons/DeleteButton.svelte.d.ts +2 -0
  86. package/dist/components/buttons/EditButton.svelte +6 -4
  87. package/dist/components/buttons/ExportButton.svelte +22 -4
  88. package/dist/components/buttons/ImportButton.svelte +83 -38
  89. package/dist/components/buttons/ImportButton.svelte.d.ts +6 -10
  90. package/dist/components/buttons/RefreshButton.svelte +48 -8
  91. package/dist/components/buttons/ShowButton.svelte +6 -4
  92. package/dist/components/content/ApiKeyList.svelte +3 -1
  93. package/dist/components/content/ContentPageShell.svelte +3 -1
  94. package/dist/components/content/FileList.svelte +3 -1
  95. package/dist/components/content/MemberList.svelte +3 -1
  96. package/dist/components/content/NetworkTable.svelte +3 -1
  97. package/dist/components/content/SecurityEventTable.svelte +3 -1
  98. package/dist/components/content/StatusTabs.svelte +2 -2
  99. package/dist/components/fieldComponentMap.d.ts +18 -13
  100. package/dist/components/fieldComponentMap.js +95 -47
  101. package/dist/components/fields/AvatarField.svelte +1 -1
  102. package/dist/components/fields/ChoiceField.svelte +16 -0
  103. package/dist/components/fields/ChoiceField.svelte.d.ts +10 -0
  104. package/dist/components/fields/CodeField.svelte +11 -12
  105. package/dist/components/fields/CodeField.svelte.d.ts +1 -1
  106. package/dist/components/fields/DateRangeField.svelte +2 -4
  107. package/dist/components/fields/ImageField.svelte +3 -1
  108. package/dist/components/fields/ImagesField.svelte +23 -0
  109. package/dist/components/fields/ImagesField.svelte.d.ts +6 -0
  110. package/dist/components/fields/JsonField.svelte +19 -13
  111. package/dist/components/fields/PasswordField.svelte +5 -0
  112. package/dist/components/fields/PasswordField.svelte.d.ts +6 -0
  113. package/dist/components/fields/json-value.d.ts +11 -0
  114. package/dist/components/fields/json-value.js +28 -0
  115. package/dist/components/profile/ActivityTimeline.svelte +2 -2
  116. package/dist/components/record-detail.svelte.d.ts +16 -0
  117. package/dist/components/record-detail.svelte.js +28 -0
  118. package/dist/components/saved-list-views.js +29 -29
  119. package/dist/components/table-contract.d.ts +13 -0
  120. package/dist/components/table-contract.js +42 -0
  121. package/dist/components/task-utils.js +4 -2
  122. package/dist/components/ui/alert/alert-variants.d.ts +2 -3
  123. package/dist/components/ui/alert/alert-variants.js +1 -2
  124. package/dist/components/ui/alert/alert.svelte +4 -5
  125. package/dist/components/ui/alert/alert.svelte.d.ts +3 -8
  126. package/dist/components/ui/alert/index.js +0 -2
  127. package/dist/components/ui/avatar/avatar-variants.d.ts +2 -3
  128. package/dist/components/ui/avatar/avatar-variants.js +1 -2
  129. package/dist/components/ui/avatar/avatar.svelte +5 -6
  130. package/dist/components/ui/avatar/avatar.svelte.d.ts +3 -8
  131. package/dist/components/ui/badge/badge-variants.d.ts +2 -3
  132. package/dist/components/ui/badge/badge-variants.js +1 -2
  133. package/dist/components/ui/badge/badge.svelte +4 -5
  134. package/dist/components/ui/badge/badge.svelte.d.ts +3 -8
  135. package/dist/components/ui/badge/index.js +0 -2
  136. package/dist/components/ui/button/button-variants.d.ts +2 -3
  137. package/dist/components/ui/button/button-variants.js +1 -2
  138. package/dist/components/ui/button/button.svelte +100 -44
  139. package/dist/components/ui/button/button.svelte.d.ts +8 -12
  140. package/dist/components/ui/button/index.js +0 -2
  141. package/dist/components/ui/command/command-dialog.svelte +3 -1
  142. package/dist/components/ui/command/command-dialog.svelte.d.ts +1 -1
  143. package/dist/components/ui/command/command-group.svelte +4 -2
  144. package/dist/components/ui/command/command-item.svelte +4 -2
  145. package/dist/components/ui/command/command-separator.svelte +3 -1
  146. package/dist/components/ui/command/index.d.ts +5 -5
  147. package/dist/components/ui/input/input.svelte +40 -20
  148. package/dist/components/ui/input/input.svelte.d.ts +5 -4
  149. package/dist/components/ui/sheet/sheet.svelte +9 -3
  150. package/dist/components/ui/sheet/sheet.svelte.d.ts +1 -0
  151. package/dist/components/ui/tooltip/tooltip.svelte +4 -2
  152. package/dist/index.d.ts +1 -1
  153. package/dist/inline-value.d.ts +5 -0
  154. package/dist/inline-value.js +24 -0
  155. package/dist/numeric-input.d.ts +2 -0
  156. package/dist/numeric-input.js +9 -0
  157. package/dist/types.d.ts +3 -3
  158. package/package.json +11 -5
@@ -1,4 +1,4 @@
1
- <script lang="ts">
1
+ <script lang="ts" generics="TColumn extends { id: string }">
2
2
  /**
3
3
  * DraggableHeader — Wraps table header cells with HTML5 Drag and Drop
4
4
  * to enable column reorder. The parent owns persistence and restoration.
@@ -12,11 +12,6 @@
12
12
  */
13
13
  import type { Snippet } from 'svelte';
14
14
 
15
- interface Column {
16
- id: string;
17
- [key: string]: unknown;
18
- }
19
-
20
15
  interface DragHeaderProps {
21
16
  draggable: true;
22
17
  ondragstart: (event: DragEvent) => void;
@@ -29,9 +24,9 @@
29
24
  }
30
25
 
31
26
  interface Props {
32
- columns: Column[];
33
- onReorder: (newOrder: Column[]) => void;
34
- header: Snippet<[Column, number, DragHeaderProps]>;
27
+ columns: TColumn[];
28
+ onReorder: (newOrder: TColumn[]) => void;
29
+ header: Snippet<[TColumn, number, DragHeaderProps]>;
35
30
  }
36
31
 
37
32
  let { columns, onReorder, header }: Props = $props();
@@ -65,6 +60,7 @@
65
60
 
66
61
  const newColumns = [...columns];
67
62
  const [moved] = newColumns.splice(dragIndex, 1);
63
+ if (moved === undefined) return;
68
64
  newColumns.splice(index, 0, moved);
69
65
 
70
66
  onReorder(newColumns);
@@ -10,25 +10,50 @@
10
10
  * </DraggableHeader>
11
11
  */
12
12
  import type { Snippet } from 'svelte';
13
- interface Column {
13
+ declare function $$render<TColumn extends {
14
14
  id: string;
15
- [key: string]: unknown;
16
- }
17
- interface DragHeaderProps {
18
- draggable: true;
19
- ondragstart: (event: DragEvent) => void;
20
- ondragover: (event: DragEvent) => void;
21
- ondrop: (event: DragEvent) => void;
22
- ondragend: () => void;
23
- 'data-dragging': boolean;
24
- 'data-drop-target': boolean;
25
- class: string;
15
+ }>(): {
16
+ props: {
17
+ columns: TColumn[];
18
+ onReorder: (newOrder: TColumn[]) => void;
19
+ header: Snippet<[TColumn, number, {
20
+ draggable: true;
21
+ ondragstart: (event: DragEvent) => void;
22
+ ondragover: (event: DragEvent) => void;
23
+ ondrop: (event: DragEvent) => void;
24
+ ondragend: () => void;
25
+ 'data-dragging': boolean;
26
+ 'data-drop-target': boolean;
27
+ class: string;
28
+ }]>;
29
+ };
30
+ exports: {};
31
+ bindings: "";
32
+ slots: {};
33
+ events: {};
34
+ };
35
+ declare class __sveltets_Render<TColumn extends {
36
+ id: string;
37
+ }> {
38
+ props(): ReturnType<typeof $$render<TColumn>>['props'];
39
+ events(): ReturnType<typeof $$render<TColumn>>['events'];
40
+ slots(): ReturnType<typeof $$render<TColumn>>['slots'];
41
+ bindings(): "";
42
+ exports(): {};
26
43
  }
27
- interface Props {
28
- columns: Column[];
29
- onReorder: (newOrder: Column[]) => void;
30
- header: Snippet<[Column, number, DragHeaderProps]>;
44
+ interface $$IsomorphicComponent {
45
+ new <TColumn extends {
46
+ id: string;
47
+ }>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TColumn>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TColumn>['props']>, ReturnType<__sveltets_Render<TColumn>['events']>, ReturnType<__sveltets_Render<TColumn>['slots']>> & {
48
+ $$bindings?: ReturnType<__sveltets_Render<TColumn>['bindings']>;
49
+ } & ReturnType<__sveltets_Render<TColumn>['exports']>;
50
+ <TColumn extends {
51
+ id: string;
52
+ }>(internal: unknown, props: ReturnType<__sveltets_Render<TColumn>['props']> & {}): ReturnType<__sveltets_Render<TColumn>['exports']>;
53
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
31
54
  }
32
- declare const DraggableHeader: import("svelte").Component<Props, {}, "">;
33
- type DraggableHeader = ReturnType<typeof DraggableHeader>;
55
+ declare const DraggableHeader: $$IsomorphicComponent;
56
+ type DraggableHeader<TColumn extends {
57
+ id: string;
58
+ }> = InstanceType<typeof DraggableHeader<TColumn>>;
34
59
  export default DraggableHeader;
@@ -50,8 +50,8 @@
50
50
  }
51
51
 
52
52
  const nextItems = [...items];
53
- const [movedItem] = nextItems.splice(draggedIndex, 1);
54
- nextItems.splice(index, 0, movedItem);
53
+ const movedItems = nextItems.splice(draggedIndex, 1);
54
+ nextItems.splice(index, 0, ...movedItems);
55
55
 
56
56
  items = nextItems;
57
57
  onreorder?.(items);
@@ -14,7 +14,8 @@
14
14
  addButtonLabel?: string;
15
15
  minItems?: number;
16
16
  maxItems?: number;
17
- defaultItem?: T | (() => T);
17
+ defaultItem?: T;
18
+ createItem?: () => T;
18
19
  disabled?: boolean;
19
20
  emptyText?: string;
20
21
  onchange?: (items: T[]) => void;
@@ -39,6 +40,7 @@
39
40
  minItems = 0,
40
41
  maxItems = Infinity,
41
42
  defaultItem,
43
+ createItem,
42
44
  disabled = false,
43
45
  emptyText,
44
46
  onchange,
@@ -47,13 +49,13 @@
47
49
  }: Props = $props();
48
50
 
49
51
  function createNewItem(): T {
50
- if (typeof defaultItem === 'function') {
51
- return (defaultItem as () => T)();
52
+ if (createItem) {
53
+ return createItem();
52
54
  }
53
55
  if (defaultItem !== undefined) {
54
56
  return structuredClone(defaultItem);
55
57
  }
56
- return {} as T;
58
+ throw new Error('DynamicFormList requires defaultItem or createItem when adding without a value');
57
59
  }
58
60
 
59
61
  export function add(customItem?: T): void {
@@ -64,7 +66,7 @@
64
66
  }
65
67
 
66
68
  export function remove(index: number): void {
67
- if (disabled || items.length <= minItems || index < 0 || index >= items.length) return;
69
+ if (disabled || items.length <= minItems || !Number.isInteger(index) || index < 0 || index >= items.length) return;
68
70
  const next = [...items];
69
71
  next.splice(index, 1);
70
72
  items = next;
@@ -72,30 +74,28 @@
72
74
  }
73
75
 
74
76
  export function moveUp(index: number): void {
75
- if (disabled || index <= 0 || index >= items.length) return;
77
+ if (disabled || !Number.isInteger(index) || index <= 0 || index >= items.length) return;
76
78
  const next = [...items];
77
- const temp = next[index - 1];
78
- next[index - 1] = next[index];
79
- next[index] = temp;
79
+ const moved = next.splice(index, 1);
80
+ next.splice(index - 1, 0, ...moved);
80
81
  items = next;
81
82
  onchange?.(items);
82
83
  }
83
84
 
84
85
  export function moveDown(index: number): void {
85
- if (disabled || index < 0 || index >= items.length - 1) return;
86
+ if (disabled || !Number.isInteger(index) || index < 0 || index >= items.length - 1) return;
86
87
  const next = [...items];
87
- const temp = next[index + 1];
88
- next[index + 1] = next[index];
89
- next[index] = temp;
88
+ const moved = next.splice(index, 1);
89
+ next.splice(index + 1, 0, ...moved);
90
90
  items = next;
91
91
  onchange?.(items);
92
92
  }
93
93
 
94
94
  export function duplicate(index: number): void {
95
- if (disabled || items.length >= maxItems || index < 0 || index >= items.length) return;
95
+ if (disabled || items.length >= maxItems || !Number.isInteger(index) || index < 0 || index >= items.length) return;
96
96
  const next = [...items];
97
- const cloned = structuredClone(next[index]);
98
- next.splice(index + 1, 0, cloned);
97
+ const cloned = structuredClone(next.slice(index, index + 1));
98
+ next.splice(index + 1, 0, ...cloned);
99
99
  items = next;
100
100
  onchange?.(items);
101
101
  }
@@ -204,7 +204,7 @@
204
204
  variant="outline"
205
205
  size="sm"
206
206
  class="svadmin-u-6da6a3c3f741 svadmin-u-58284b4ea568 svadmin-u-a29b7a649c77"
207
- {disabled}
207
+ disabled={disabled || (defaultItem === undefined && createItem === undefined)}
208
208
  onclick={() => add()}
209
209
  >
210
210
  <Plus class="svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3" />
@@ -7,7 +7,8 @@ declare function $$render<T = Record<string, unknown>>(): {
7
7
  addButtonLabel?: string;
8
8
  minItems?: number;
9
9
  maxItems?: number;
10
- defaultItem?: T | (() => T);
10
+ defaultItem?: T;
11
+ createItem?: () => T;
11
12
  disabled?: boolean;
12
13
  emptyText?: string;
13
14
  onchange?: (items: T[]) => void;
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import { definedOptions } from '@svadmin/core/options';
3
+
2
4
  import { getResource, useNavigation } from '@svadmin/core';
3
5
  import { useTranslation } from '@svadmin/core/i18n';
4
6
 
@@ -70,6 +72,6 @@
70
72
  {columns}
71
73
  showHeader={false}
72
74
  onNavigationGuardReady={(guard) => navigateGuard = guard}
73
- {onSuccess}
75
+ {...definedOptions({ "onSuccess": onSuccess })}
74
76
  />
75
77
  </div>
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { useTranslation } from '@svadmin/core/i18n';
2
3
  import { Button } from './ui/button/index.js';
3
4
  import { Plus, Trash2, Save, Loader2 } from '@lucide/svelte';
4
5
  import { cn } from '../utils.js';
@@ -35,6 +36,8 @@
35
36
  class: className = '',
36
37
  }: Props = $props();
37
38
 
39
+ const i18n = useTranslation();
40
+
38
41
  let isSaving = $state(false);
39
42
 
40
43
  function updateCell(rowIndex: number, columnKey: string, value: unknown) {
@@ -152,6 +155,7 @@
152
155
  {:else if col.type === 'date'}
153
156
  <input
154
157
  type="date"
158
+ lang={i18n.locale}
155
159
  class="svadmin-u-d1c57777d8b6 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"
156
160
  value={String(row[col.key] ?? '')}
157
161
  oninput={(e) => updateCell(rowIndex, col.key, e.currentTarget.value)}
@@ -1,8 +1,10 @@
1
1
  <script lang="ts">
2
+ import { definedOptions } from '@svadmin/core/options';
3
+
2
4
  import SystemErrorState from './content/SystemErrorState.svelte';
3
5
  import ContentPageShell from './content/ContentPageShell.svelte';
4
6
  interface Props { status?: '404' | '500'; title?: string; description?: string; }
5
7
  let { status = '404', title, description }: Props = $props();
6
8
  </script>
7
9
 
8
- <ContentPageShell pageId="system-error" width="narrow"><SystemErrorState {status} {title} {description} /></ContentPageShell>
10
+ <ContentPageShell pageId="system-error" width="narrow"><SystemErrorState {status} {...definedOptions({ "title": title })} {...definedOptions({ "description": description })} /></ContentPageShell>
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import { useTranslation } from '@svadmin/core/i18n';
3
+ import { getDisplayComponent, type FieldDisplayProps } from './fieldComponentMap';
4
+
5
+ let { type, value, options, resourceName }: FieldDisplayProps & { type: string } = $props();
6
+ const Display = $derived(getDisplayComponent(type));
7
+ const i18n = useTranslation();
8
+ </script>
9
+
10
+ {#if Display}
11
+ <Display {value} {options} {resourceName} />
12
+ {:else}
13
+ <span role="status" data-svadmin-invalid-field>{i18n.t('validation.invalidFormat')}</span>
14
+ {/if}
@@ -0,0 +1,7 @@
1
+ import { type FieldDisplayProps } from './fieldComponentMap';
2
+ type $$ComponentProps = FieldDisplayProps & {
3
+ type: string;
4
+ };
5
+ declare const FieldDisplay: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type FieldDisplay = ReturnType<typeof FieldDisplay>;
7
+ export default FieldDisplay;
@@ -4,6 +4,8 @@
4
4
  </script>
5
5
 
6
6
  <script lang="ts">
7
+ import { definedOptions } from '@svadmin/core/options';
8
+
7
9
  import type { FieldDefinition } from '@svadmin/core';
8
10
  import { useTranslation } from '@svadmin/core/i18n';
9
11
  import { Input } from './ui/input/index.js';
@@ -25,6 +27,7 @@
25
27
  import type { Snippet } from 'svelte';
26
28
  import { getRichTextEditor } from '../editor-config.svelte.js';
27
29
  import { cn } from '../utils.js';
30
+ import { numericInputValue } from '../numeric-input.js';
28
31
 
29
32
  const i18n = useTranslation();
30
33
 
@@ -43,7 +46,7 @@
43
46
 
44
47
  // Typed accessors
45
48
  const strVal = $derived((value as string) ?? '');
46
- const numVal = $derived(value as number | null | undefined);
49
+ const numVal = $derived(numericInputValue(value));
47
50
  const boolVal = $derived((value as boolean) ?? false);
48
51
  const tagsVal = $derived((value as string[]) ?? []);
49
52
  const multiVal = $derived((value as (string | number)[]) ?? []);
@@ -210,10 +213,11 @@
210
213
  id={field.key}
211
214
  name={field.key}
212
215
  type="number"
213
- value={numVal == null ? '' : String(numVal)}
216
+ value={numVal}
214
217
  oninput={(e) => {
215
- const v = (e.target as HTMLInputElement).value;
216
- onchange(v === '' ? null : Number(v));
218
+ const input = e.currentTarget;
219
+ if (!(input instanceof HTMLInputElement)) return;
220
+ onchange(input.value === '' ? null : numericInputValue(input.valueAsNumber));
217
221
  }}
218
222
  required={field.required}
219
223
  aria-invalid={invalid || undefined}
@@ -269,7 +273,7 @@
269
273
  {:else if field.type === 'tree-select' || field.type === 'treeselect'}
270
274
  <TreeSelect
271
275
  options={(field.treeOptions ?? field.options ?? []) as TreeSelectOption[]}
272
- value={value as string | number | (string | number)[] | undefined}
276
+ {...definedOptions({ "value": value as string | number | (string | number)[] | undefined })}
273
277
  multiple={field.multiple}
274
278
  disabled={disabled}
275
279
  placeholder={i18n.t('field.selectPlaceholder')}
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { Plus, Trash2, RotateCcw, Filter as FilterIcon, Check } from '@lucide/svelte';
3
3
  import { cn } from '../utils.js';
4
+ import { numericInputValue } from '../numeric-input.js';
4
5
  import { Button } from './ui/button/index.js';
5
6
  import { Input } from './ui/input/index.js';
6
7
  import { Select } from './ui/select/index.js';
@@ -55,8 +56,7 @@
55
56
  const parsedRules: FilterRuleItem[] = [];
56
57
  let nextLogical: 'and' | 'or' = 'and';
57
58
 
58
- for (let i = 0; i < filters.length; i++) {
59
- const item = filters[i];
59
+ for (const [i, item] of filters.entries()) {
60
60
  if ('field' in item) {
61
61
  parsedRules.push({
62
62
  id: `rule-${i}-${Date.now()}`,
@@ -66,8 +66,7 @@
66
66
  });
67
67
  } else if (item.operator === 'and' || item.operator === 'or') {
68
68
  nextLogical = item.operator;
69
- for (let j = 0; j < item.value.length; j++) {
70
- const sub = item.value[j];
69
+ for (const [j, sub] of item.value.entries()) {
71
70
  if ('field' in sub) {
72
71
  parsedRules.push({
73
72
  id: `rule-${i}-${j}-${Date.now()}`,
@@ -264,15 +263,27 @@
264
263
  <option value="true">{i18n.t('common.yes', undefined) ?? '是 (true)'}</option>
265
264
  <option value="false">{i18n.t('common.no', undefined) ?? '否 (false)'}</option>
266
265
  </Select>
266
+ {:else if fieldDef?.type === 'number'}
267
+ <Input
268
+ type="number"
269
+ class="svadmin-u-ed8a5df7b2fb svadmin-u-359090c2d529"
270
+ placeholder="输入筛选值..."
271
+ value={numericInputValue(rule.value)}
272
+ oninput={(e) => {
273
+ const input = e.currentTarget;
274
+ if (!(input instanceof HTMLInputElement)) return;
275
+ rule.value = input.value === '' ? null : numericInputValue(input.valueAsNumber);
276
+ }}
277
+ />
267
278
  {:else}
268
279
  <Input
269
- type={fieldDef?.type === 'number' ? 'number' : 'text'}
280
+ type="text"
270
281
  class="svadmin-u-ed8a5df7b2fb svadmin-u-359090c2d529"
271
282
  placeholder="输入筛选值..."
272
283
  value={String(rule.value ?? '')}
273
- oninput={(e: Event) => {
274
- const val = (e.currentTarget as HTMLInputElement).value;
275
- rule.value = fieldDef?.type === 'number' && val !== '' ? Number(val) : val;
284
+ oninput={(e) => {
285
+ const input = e.currentTarget;
286
+ if (input instanceof HTMLInputElement) rule.value = input.value;
276
287
  }}
277
288
  />
278
289
  {/if}
@@ -19,6 +19,6 @@ interface Props {
19
19
  trigger?: Snippet;
20
20
  class?: string;
21
21
  }
22
- declare const FilterDropdown: import("svelte").Component<Props, {}, "value" | "open">;
22
+ declare const FilterDropdown: import("svelte").Component<Props, {}, "open" | "value">;
23
23
  type FilterDropdown = ReturnType<typeof FilterDropdown>;
24
24
  export default FilterDropdown;
@@ -1,5 +1,4 @@
1
1
  <script lang="ts">
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
2
  import { Moon, Sun, Search, MonitorUp } from '@lucide/svelte';
4
3
  import { Button } from './ui/button';
5
4
  import TooltipButton from './TooltipButton.svelte';
@@ -33,11 +32,11 @@
33
32
  }>();
34
33
 
35
34
  // Retrieve optional component overrides from registry
36
- const registry = getComponentRegistry() || {} as any;
37
- const CustomBreadcrumbs = registry.Breadcrumbs;
38
- const CustomThemeToggle = registry.ThemeToggle;
39
- const CustomUserMenu = registry.UserMenu;
40
- const CustomNotificationPanel = registry.NotificationPanel;
35
+ const registry = getComponentRegistry();
36
+ const CustomBreadcrumbs = registry?.Breadcrumbs;
37
+ const CustomThemeToggle = registry?.ThemeToggle;
38
+ const CustomUserMenu = registry?.UserMenu;
39
+ const CustomNotificationPanel = registry?.NotificationPanel;
41
40
  </script>
42
41
 
43
42
  <header class="svadmin-u-3e0fd166d494 svadmin-u-2167406b24d7 svadmin-u-0f2fff0ae96e svadmin-u-60fbb7713999 svadmin-u-07017cde3e97 svadmin-u-6da6a3c3f741 svadmin-u-012fbd121f37 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-65fdbade2025 svadmin-u-6ee2d41e2d2d svadmin-u-16d6f96aa157 svadmin-u-1ca6dd1e47c4 svadmin-u-f0faeb26d656 svadmin-u-8a3831239aa5">
@@ -62,8 +62,9 @@
62
62
  }
63
63
  } else {
64
64
  const rows = parseCSV(cleanText);
65
- if (rows.length > 0) {
66
- rawHeaders = rows[0];
65
+ const firstRow = rows[0];
66
+ if (firstRow) {
67
+ rawHeaders = firstRow;
67
68
  rawRows = rows.slice(1).filter((r: string[]) => r.some((cell: string) => cell.trim().length > 0));
68
69
  }
69
70
  }
@@ -1,23 +1,26 @@
1
1
  <script lang="ts">
2
+ import { definedReactiveOptions } from '@svadmin/core/options';
3
+
2
4
  import { fade } from 'svelte/transition';
3
- import { useInfiniteList } from '@svadmin/core';
5
+ import { useInfiniteList, useResourceContract } from '@svadmin/core';
4
6
  import type { BaseRecord, Sort, Filter } from '@svadmin/core';
5
7
  import type { Snippet } from 'svelte';
6
8
  import { useTranslation } from '@svadmin/core/i18n';
7
9
 
8
10
  import { Skeleton } from './ui/skeleton/index.js';
9
- import { Loader2 } from '@lucide/svelte';
11
+ import { Loader2, RotateCw } from '@lucide/svelte';
12
+ import { Button } from './ui/button/index.js';
10
13
  import { intersect } from '../actions.js';
11
14
 
12
15
  const i18n = useTranslation();
13
16
 
14
- interface Props<T extends BaseRecord = BaseRecord> {
17
+ interface Props {
15
18
  resource: string;
16
19
  pageSize?: number;
17
20
  sorters?: Sort[];
18
21
  filters?: Filter[];
19
22
  /** Render each item */
20
- children: Snippet<[{ item: T; index: number }]>;
23
+ children: Snippet<[{ item: BaseRecord & { id: string | number }; index: number }]>;
21
24
  /** Custom empty state */
22
25
  empty?: Snippet;
23
26
  /** Custom loading skeleton */
@@ -34,15 +37,18 @@
34
37
  loadingSkeleton,
35
38
  }: Props = $props();
36
39
 
37
- const { query } = useInfiniteList({
38
- get resource() { return resource; },
40
+ const binding = useResourceContract(() => resource);
41
+ const { query } = useInfiniteList(definedReactiveOptions({
42
+ get resource() { return binding.resource; },
43
+ get dataProviderName() { return binding.dataProviderName; },
44
+ get meta() { return binding.meta; },
39
45
  get pagination() { return { pageSize }; },
40
46
  get sorters() { return sorters; },
41
47
  get filters() { return filters; },
42
- });
48
+ }));
43
49
 
44
50
  const allItems = $derived(
45
- (query.data as { pages?: { data: BaseRecord[] }[] })?.pages?.flatMap(p => p.data) ?? []
51
+ query.data?.pages.flatMap(p => p.data) ?? []
46
52
  );
47
53
 
48
54
  const hasNextPage = $derived(query.hasNextPage ?? false);
@@ -66,6 +72,14 @@
66
72
  {/each}
67
73
  </div>
68
74
  {/if}
75
+ {:else if query.isError}
76
+ <div role="alert">
77
+ <p>{i18n.t('common.error')}</p>
78
+ <Button variant="outline" disabled={query.isFetching} onclick={() => query.refetch()}>
79
+ <RotateCw />
80
+ {i18n.t('common.retry')}
81
+ </Button>
82
+ </div>
69
83
  {:else if allItems.length === 0}
70
84
  {#if empty}
71
85
  {@render empty()}
@@ -1,13 +1,15 @@
1
1
  import type { BaseRecord, Sort, Filter } from '@svadmin/core';
2
2
  import type { Snippet } from 'svelte';
3
- interface Props<T extends BaseRecord = BaseRecord> {
3
+ interface Props {
4
4
  resource: string;
5
5
  pageSize?: number;
6
6
  sorters?: Sort[];
7
7
  filters?: Filter[];
8
8
  /** Render each item */
9
9
  children: Snippet<[{
10
- item: T;
10
+ item: BaseRecord & {
11
+ id: string | number;
12
+ };
11
13
  index: number;
12
14
  }]>;
13
15
  /** Custom empty state */
@@ -15,6 +17,6 @@ interface Props<T extends BaseRecord = BaseRecord> {
15
17
  /** Custom loading skeleton */
16
18
  loadingSkeleton?: Snippet;
17
19
  }
18
- declare const InfiniteList: import("svelte").Component<Props<BaseRecord>, {}, "">;
20
+ declare const InfiniteList: import("svelte").Component<Props, {}, "">;
19
21
  type InfiniteList = ReturnType<typeof InfiniteList>;
20
22
  export default InfiniteList;