@svadmin/ui 0.84.1 → 0.86.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 (71) hide show
  1. package/README.md +29 -0
  2. package/dist/app-shell.css +216 -0
  3. package/dist/app.css +496 -171
  4. package/dist/app.theme.css +496 -171
  5. package/dist/component-registry.d.ts +7292 -529
  6. package/dist/component-registry.js +32 -3
  7. package/dist/components/AppShellPage.svelte +172 -0
  8. package/dist/components/AppShellPage.svelte.d.ts +30 -0
  9. package/dist/components/AuthPageShell.svelte +14 -7
  10. package/dist/components/AuthPageShell.svelte.d.ts +1 -0
  11. package/dist/components/AutoForm.svelte +7 -12
  12. package/dist/components/AutoForm.svelte.d.ts +0 -1
  13. package/dist/components/AutoTable.svelte +2 -0
  14. package/dist/components/AutoTable.svelte.d.ts +2 -0
  15. package/dist/components/ConfigurationPage.svelte +0 -3
  16. package/dist/components/ConfigurationPage.svelte.d.ts +0 -1
  17. package/dist/components/CreatePage.svelte +1 -5
  18. package/dist/components/CreatePage.svelte.d.ts +0 -1
  19. package/dist/components/EditPage.svelte +1 -5
  20. package/dist/components/EditPage.svelte.d.ts +0 -1
  21. package/dist/components/FieldRenderer.svelte +2 -10
  22. package/dist/components/FieldRenderer.svelte.d.ts +0 -1
  23. package/dist/components/ListPage.svelte +2 -5
  24. package/dist/components/ListPage.svelte.d.ts +0 -1
  25. package/dist/components/PageHeader.svelte +1 -3
  26. package/dist/components/PageHeader.svelte.d.ts +0 -1
  27. package/dist/components/PagePattern.svelte +36 -13
  28. package/dist/components/PagePattern.svelte.d.ts +7 -0
  29. package/dist/components/QuickEditDrawer.svelte +0 -1
  30. package/dist/components/ShowPage.svelte +5 -9
  31. package/dist/components/ShowPage.svelte.d.ts +0 -1
  32. package/dist/components/SvarAutoTable.svelte +2 -1
  33. package/dist/components/SvarDataGrid.svelte +8 -4
  34. package/dist/components/SvarDataGrid.svelte.d.ts +3 -0
  35. package/dist/components/SvarResourceTable.svelte +0 -1
  36. package/dist/components/SvarResourceTable.svelte.d.ts +0 -1
  37. package/dist/components/SvarResourceTableView.svelte +2 -2
  38. package/dist/components/auto-table-grid.d.ts +1 -0
  39. package/dist/components/content/ContentPageHeader.svelte +2 -1
  40. package/dist/components/content/ContentPageHeader.svelte.d.ts +1 -0
  41. package/dist/components/content/ContentPageShell.svelte +1 -1
  42. package/dist/components/content/ContentPageShell.svelte.d.ts +1 -0
  43. package/dist/components/content/DataPanel.svelte +58 -0
  44. package/dist/components/content/DataPanel.svelte.d.ts +16 -0
  45. package/dist/components/content/DescriptionList.svelte +5 -8
  46. package/dist/components/content/DescriptionList.svelte.d.ts +0 -1
  47. package/dist/components/content/FilterToolbar.svelte +2 -5
  48. package/dist/components/content/FilterToolbar.svelte.d.ts +0 -1
  49. package/dist/components/content/NetworkTable.svelte +3 -3
  50. package/dist/components/content/NetworkTable.svelte.d.ts +0 -1
  51. package/dist/components/content/PageSection.svelte +1 -1
  52. package/dist/components/content/StatusTabs.svelte +2 -7
  53. package/dist/components/content/StatusTabs.svelte.d.ts +0 -1
  54. package/dist/components/content/index.d.ts +1 -0
  55. package/dist/components/content/index.js +1 -0
  56. package/dist/components/ui/table/index.d.ts +0 -1
  57. package/dist/components/ui/table/table.svelte +1 -0
  58. package/dist/components/ui/table/table.svelte.d.ts +1 -0
  59. package/dist/components.css +1 -11
  60. package/dist/data-panel.css +88 -0
  61. package/dist/design-contract.d.ts +11 -0
  62. package/dist/design-contract.js +8 -0
  63. package/dist/design-system.d.ts +3 -2
  64. package/dist/design-system.js +3 -2
  65. package/dist/index.d.ts +4 -2
  66. package/dist/index.js +2 -0
  67. package/dist/page-chrome.css +53 -61
  68. package/dist/recipes.d.ts +67 -154
  69. package/dist/recipes.js +32 -68
  70. package/dist/styles/recipes.css +15 -48
  71. package/package.json +4 -4
@@ -15,7 +15,6 @@
15
15
  onBack?: () => void;
16
16
  backLabel?: string;
17
17
  showBreadcrumbs?: boolean;
18
- density?: 'compact' | 'comfortable';
19
18
  class?: string;
20
19
  }
21
20
 
@@ -29,13 +28,12 @@
29
28
  onBack,
30
29
  backLabel = 'Back',
31
30
  showBreadcrumbs = true,
32
- density = 'comfortable',
33
31
  class: className = '',
34
32
  }: Props = $props();
35
33
 
36
34
  </script>
37
35
 
38
- <div class={cn('svadmin-page-header', className)} data-density={density}>
36
+ <div class={cn('svadmin-page-header', className)}>
39
37
  {#if showBreadcrumbs}
40
38
  <Breadcrumbs class="svadmin-page-header__breadcrumbs" />
41
39
  {/if}
@@ -9,7 +9,6 @@ interface Props {
9
9
  onBack?: () => void;
10
10
  backLabel?: string;
11
11
  showBreadcrumbs?: boolean;
12
- density?: 'compact' | 'comfortable';
13
12
  class?: string;
14
13
  }
15
14
  declare const PageHeader: import("svelte").Component<Props, {}, "">;
@@ -3,8 +3,10 @@
3
3
  import { definedOptions } from '@svadmin/core/options';
4
4
  import ContentPageShell from './content/ContentPageShell.svelte';
5
5
  import WorkspaceLayout from './content/WorkspaceLayout.svelte';
6
+ import DataState from './content/DataState.svelte';
6
7
 
7
8
  export type PagePatternKind = 'list' | 'form' | 'detail' | 'workspace' | 'dashboard';
9
+ export type PagePatternState = 'ready' | 'loading' | 'empty' | 'error' | 'forbidden';
8
10
 
9
11
  interface Props {
10
12
  kind: PagePatternKind;
@@ -18,8 +20,14 @@
18
20
  children: Snippet;
19
21
  footer?: Snippet;
20
22
  width?: 'narrow' | 'default' | 'wide';
23
+ /** @deprecated Accepted for compatibility; the product baseline is shared. */
21
24
  density?: 'compact' | 'comfortable';
22
25
  pageId?: string;
26
+ state?: PagePatternState;
27
+ stateTitle?: string;
28
+ stateDescription?: string;
29
+ retry?: () => void;
30
+ stateAction?: Snippet;
23
31
  class?: string;
24
32
  }
25
33
 
@@ -35,24 +43,41 @@
35
43
  children,
36
44
  footer,
37
45
  width,
38
- density,
46
+ density = 'comfortable',
39
47
  pageId,
48
+ state = 'ready',
49
+ stateTitle,
50
+ stateDescription,
51
+ retry,
52
+ stateAction,
40
53
  class: className = '',
41
54
  }: Props = $props();
42
55
 
43
56
  const resolvedPageId = $derived(pageId ?? `pattern-${kind}`);
44
57
  const resolvedWidth = $derived(width ?? (kind === 'form' ? 'narrow' : kind === 'detail' ? 'default' : 'wide'));
45
- const resolvedDensity = $derived(density ?? 'comfortable');
58
+ const showState = $derived(state !== 'ready');
46
59
  </script>
47
60
 
48
61
  <ContentPageShell
49
62
  {title}
50
63
  {...definedOptions({ description, eyebrow, actions })}
51
- density={resolvedDensity}
52
64
  width={resolvedWidth}
65
+ {density}
53
66
  pageId={resolvedPageId}
54
67
  class={className}
55
68
  >
69
+ <div data-page-pattern-kind={kind} data-page-pattern-state={state}>
70
+ {#if showState}
71
+ {#if state === 'loading' || state === 'empty' || state === 'error' || state === 'forbidden'}
72
+ <DataState
73
+ {state}
74
+ {...definedOptions({ title: stateTitle })}
75
+ {...definedOptions({ description: stateDescription })}
76
+ {...definedOptions({ retry: state === 'error' ? retry : undefined })}
77
+ {...definedOptions({ action: stateAction })}
78
+ />
79
+ {/if}
80
+ {:else}
56
81
  {#if metrics}
57
82
  <div class="page-pattern__metrics" data-page-pattern-metrics>
58
83
  {@render metrics()}
@@ -68,7 +93,7 @@
68
93
  {#if secondary}
69
94
  <WorkspaceLayout primary={children} {...definedOptions({ secondary })} />
70
95
  {:else}
71
- <div class="page-pattern__content" data-page-pattern-content={kind} data-density={resolvedDensity}>
96
+ <div class="page-pattern__content" data-page-pattern-content={kind}>
72
97
  {@render children()}
73
98
  </div>
74
99
  {/if}
@@ -78,13 +103,15 @@
78
103
  {@render footer()}
79
104
  </footer>
80
105
  {/if}
106
+ {/if}
107
+ </div>
81
108
  </ContentPageShell>
82
109
 
83
110
  <style>
84
111
  .page-pattern__metrics {
85
112
  display: grid;
86
113
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
87
- gap: 16px;
114
+ gap: var(--svadmin-space-4);
88
115
  }
89
116
 
90
117
  .page-pattern__toolbar,
@@ -94,11 +121,7 @@
94
121
 
95
122
  .page-pattern__content {
96
123
  display: grid;
97
- gap: 24px;
98
- }
99
-
100
- .page-pattern__content[data-density='compact'] {
101
- gap: 16px;
124
+ gap: var(--svadmin-space-5);
102
125
  }
103
126
 
104
127
  .page-pattern__footer {
@@ -106,9 +129,9 @@
106
129
  flex-wrap: wrap;
107
130
  align-items: center;
108
131
  justify-content: flex-end;
109
- gap: 8px;
110
- margin-top: 24px;
111
- padding-top: 12px;
132
+ gap: var(--svadmin-space-2);
133
+ margin-top: var(--svadmin-space-5);
134
+ padding-top: var(--svadmin-space-3);
112
135
  border-top: 1px solid var(--border);
113
136
  }
114
137
  </style>
@@ -1,5 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  export type PagePatternKind = 'list' | 'form' | 'detail' | 'workspace' | 'dashboard';
3
+ export type PagePatternState = 'ready' | 'loading' | 'empty' | 'error' | 'forbidden';
3
4
  interface Props {
4
5
  kind: PagePatternKind;
5
6
  title: string;
@@ -12,8 +13,14 @@ interface Props {
12
13
  children: Snippet;
13
14
  footer?: Snippet;
14
15
  width?: 'narrow' | 'default' | 'wide';
16
+ /** @deprecated Accepted for compatibility; the product baseline is shared. */
15
17
  density?: 'compact' | 'comfortable';
16
18
  pageId?: string;
19
+ state?: PagePatternState;
20
+ stateTitle?: string;
21
+ stateDescription?: string;
22
+ retry?: () => void;
23
+ stateAction?: Snippet;
17
24
  class?: string;
18
25
  }
19
26
  declare const PagePattern: import("svelte").Component<Props, {}, "">;
@@ -32,7 +32,6 @@
32
32
  {resourceName}
33
33
  id={recordId}
34
34
  mode="edit"
35
- density="compact"
36
35
  showHeader={false}
37
36
  redirect={false}
38
37
  onSuccess={onClose}
@@ -20,7 +20,6 @@
20
20
  resourceName: string;
21
21
  rendering?: ResourceRendering | undefined;
22
22
  id: string | number;
23
- density?: 'compact' | 'comfortable';
24
23
  layout?: 'list' | 'grid';
25
24
  columns?: 1 | 2 | 3 | 4;
26
25
  bordered?: boolean;
@@ -36,7 +35,6 @@
36
35
  resourceName,
37
36
  rendering,
38
37
  id,
39
- density = 'comfortable',
40
38
  layout = 'list',
41
39
  columns = 2,
42
40
  bordered = false,
@@ -58,7 +56,6 @@
58
56
  }
59
57
  navigation.list(resourceName);
60
58
  }
61
- const isCompact = $derived(density === 'compact');
62
59
 
63
60
  const detail = useRecordDetail(() => ({ resourceName, id, rendering }));
64
61
  const activeRendering = $derived(detail.rendering);
@@ -76,10 +73,9 @@
76
73
  });
77
74
  </script>
78
75
 
79
- <div data-svadmin-rendering-resource={activeRendering?.resource.name} data-svadmin-rendering-kind={activeRendering ? 'show' : undefined} class="{isCompact ? 'svadmin-u-6ed543e2fbbb' : 'svadmin-u-3e7ce58d64fa'} {className}">
76
+ <div data-svadmin-rendering-resource={activeRendering?.resource.name} data-svadmin-rendering-kind={activeRendering ? 'show' : undefined} class="svadmin-u-3e7ce58d64fa {className}">
80
77
  <PageHeader
81
78
  title="{resource.label} {i18n.t('common.detail')} #{id}"
82
- {density}
83
79
  onBack={goBack}
84
80
  backLabel={i18n.t('common.back')}
85
81
  >
@@ -108,7 +104,7 @@
108
104
  <Card.Root class="svadmin-u-2cd02d11d1af svadmin-u-6ee2d41e2d2d svadmin-u-438b2237b8d6">
109
105
  <Card.Content class="svadmin-u-8a539c7fe216">
110
106
  {#each showFields.slice(0, 6) as _, i (i)}
111
- <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-020ba687fa12 {isCompact ? 'svadmin-u-f0faeb26d656 svadmin-u-03b4dd7f172b' : 'svadmin-u-f0faeb26d656 svadmin-u-7a9aabfcd059 svadmin-u-1b2d54a3fd12 svadmin-u-b7daff9b9ddd'} {i % 2 === 1 ? 'svadmin-u-967d113a1451' : ''}">
107
+ <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-020ba687fa12 svadmin-u-f0faeb26d656 svadmin-u-7a9aabfcd059 svadmin-u-1b2d54a3fd12 svadmin-u-b7daff9b9ddd {i % 2 === 1 ? 'svadmin-u-967d113a1451' : ''}">
112
108
  <Skeleton class="svadmin-u-11e59c6d5f6b svadmin-u-b7ce0d2f6c04 svadmin-u-5a14cc9f9ed4" />
113
109
  <Skeleton class="svadmin-u-11e59c6d5f6b svadmin-u-1d9f2d98d149 svadmin-u-d2ffb24f3e1d svadmin-u-b6b02c0ebef6 svadmin-u-dfe9bd9e7001 svadmin-u-77533d414653" />
114
110
  </div>
@@ -153,9 +149,9 @@
153
149
  <Card.Content class="svadmin-u-8a539c7fe216 svadmin-u-fa6acbf81d74 svadmin-u-3533cbce9e93">
154
150
  {#each showFields as field, i (i)}
155
151
  {@const value = record[field.key]}
156
- <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-020ba687fa12 {isCompact ? 'svadmin-u-f0faeb26d656 svadmin-u-03b4dd7f172b svadmin-u-cc06a6575385 svadmin-u-7209fd2a90e7' : 'svadmin-u-f0faeb26d656 svadmin-u-7a9aabfcd059 svadmin-u-1b2d54a3fd12 svadmin-u-4701b613ff95'} {i % 2 === 1 ? 'svadmin-u-8a25a995eb8e' : ''}">
157
- <div class="svadmin-u-b03f3c253900 {isCompact ? 'svadmin-u-359090c2d529' : 'svadmin-u-359090c2d529 svadmin-u-e2327d142859'} svadmin-u-2689f3958069 svadmin-u-bfa603190748 svadmin-u-65281709dacf svadmin-u-84bdd56b0e81">{field.label}</div>
158
- <div class="svadmin-u-6b3526212209 {isCompact ? 'svadmin-u-359090c2d529 svadmin-u-e2327d142859' : 'svadmin-u-fc7473ca09eb'} svadmin-u-d4108abe6359">
152
+ <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-020ba687fa12 svadmin-u-f0faeb26d656 svadmin-u-7a9aabfcd059 svadmin-u-1b2d54a3fd12 svadmin-u-4701b613ff95 {i % 2 === 1 ? 'svadmin-u-8a25a995eb8e' : ''}">
153
+ <div class="svadmin-u-b03f3c253900 svadmin-u-359090c2d529 svadmin-u-e2327d142859 svadmin-u-2689f3958069 svadmin-u-bfa603190748 svadmin-u-65281709dacf svadmin-u-84bdd56b0e81">{field.label}</div>
154
+ <div class="svadmin-u-6b3526212209 svadmin-u-fc7473ca09eb svadmin-u-d4108abe6359">
159
155
  <FieldDisplay
160
156
  type={field.type}
161
157
  {value}
@@ -4,7 +4,6 @@ interface Props {
4
4
  resourceName: string;
5
5
  rendering?: ResourceRendering | undefined;
6
6
  id: string | number;
7
- density?: 'compact' | 'comfortable';
8
7
  layout?: 'list' | 'grid';
9
8
  columns?: 1 | 2 | 3 | 4;
10
9
  bordered?: boolean;
@@ -26,8 +26,9 @@
26
26
  {#snippet gridBody(state)}
27
27
  <details><summary>{state.locale.startsWith('zh') ? '表格选择与列顺序' : 'Selection and column order'}</summary>{@render state.controls()}</details>
28
28
  <SvarDataGrid {Grid} {Theme} items={state.records} columns={state.columns} primaryKey={state.primaryKey}
29
+ density={state.density}
29
30
  {height} freezeLeft={Math.min(freezeLeft, state.columns.length - Math.min(freezeRight, state.columns.length - 1))}
30
- freezeRight={Math.min(freezeRight, state.columns.length - 1)} density={state.density}
31
+ freezeRight={Math.min(freezeRight, state.columns.length - 1)}
31
32
  queryMode="server" sorters={state.sorters} onSortChange={state.onSortChange}
32
33
  disabled={state.disabled} scopeKey={state.scopeKey} locale={state.locale} label={state.label}>
33
34
  {#snippet cellContent({ id, field })}{@render state.cell({ id, field })}{/snippet}
@@ -18,7 +18,10 @@
18
18
  primaryKey?: string;
19
19
  childrenKey?: string;
20
20
  height?: number;
21
+ /** @deprecated Retained for compatibility; comfortable is the shared default. */
21
22
  density?: 'compact' | 'comfortable';
23
+ rowHeight?: number;
24
+ headerHeight?: number;
22
25
  freezeLeft?: number;
23
26
  /** 独立右侧面板,不使用上游 split.right。 */
24
27
  freezeRight?: number;
@@ -52,14 +55,15 @@
52
55
  disabledLabel?: string;
53
56
  fallbackLabel?: string;
54
57
  }
55
- let { Grid, Theme, items = [], columns, primaryKey = 'id', childrenKey, height = 420, density = 'comfortable', freezeLeft = 0, freezeRight = 0, queryMode = 'local',
58
+ let { Grid, Theme, items = [], columns, primaryKey = 'id', childrenKey, height = 420, density = 'comfortable', rowHeight: rowHeightProp, headerHeight: headerHeightProp, freezeLeft = 0, freezeRight = 0, queryMode = 'local',
56
59
  sorters = [], filters = [], onSortChange, onFilterChange, onCellEdit, selectable = false, selectedIds = [], onSelectionChange, onRecordsChange, cellContent,
57
60
  windowSource, loadChildren, hasChildrenKey = 'hasChildren', onLoadMore, hasMore = false, scopeKey = 0,
58
61
  loading = false, error, disabled = false, locale = 'en-US', label = 'Data grid', emptyLabel = 'No records', loadingLabel = 'Loading',
59
62
  disabledLabel = 'Grid is disabled', fallbackLabel = 'Static preview (up to 20 rows)',
60
63
  }: SvarDataGridProps = $props();
61
64
  const treeKey = $derived(loadChildren ? childrenKey ?? 'children' : childrenKey);
62
- const rowHeight = $derived(density === 'compact' ? 32 : 44);
65
+ const rowHeight = $derived(rowHeightProp ?? (density === 'compact' ? 32 : 44));
66
+ const headerHeight = $derived(headerHeightProp ?? (density === 'compact' ? 32 : 36));
63
67
  // 普通追加不重建引擎,否则无限加载会把滚动位置重置。懒树根替换必须清理分支缓存。
64
68
  const dataOwner = $derived({ scopeKey, items: loadChildren ? items : undefined, source: windowSource,
65
69
  loadChildren, onLoadMore, primaryKey, treeKey, hasChildrenKey, freezeRight, Grid });
@@ -304,12 +308,12 @@
304
308
  {#key dataOwner}<div class="grid-panes" inert={disabled}>
305
309
  <div class="grid-viewport center-pane" data-svar-pane="center" style:height="{height}px" role="region" aria-label="Scrollable columns" onkeydowncapture={event => navigatePane(event, 0)}>
306
310
  <Grid columns={model.center} data={activeError || isLoading ? [] : records.rows} tree={treeKey !== undefined}
307
- split={{ left: freezeLeft }} sizes={{ rowHeight, headerHeight: 36, columnWidth: 160 }} select={selectable} multiselect={selectable} {selectedRows}
311
+ split={{ left: freezeLeft }} sizes={{ rowHeight, headerHeight, columnWidth: 160 }} select={selectable} multiselect={selectable} {selectedRows}
308
312
  reorder={false} draggableRows={false} undo={false} {...queryProps} {...dynamicProps} init={api => init(api, 0)} />
309
313
  </div>
310
314
  {#if freezeRight > 0}<div class="grid-viewport right-pane" data-svar-pane="right" style:height="{height}px" style:width="{model.rightWidth}px" role="region" aria-label="Frozen right columns" onkeydowncapture={event => navigatePane(event, 1)}>
311
315
  <Grid columns={model.right} data={activeError || isLoading ? [] : rightRows} tree={treeKey !== undefined}
312
- split={{ left: 0 }} sizes={{ rowHeight, headerHeight: 36, columnWidth: 160 }} select={selectable} multiselect={selectable} {selectedRows}
316
+ split={{ left: 0 }} sizes={{ rowHeight, headerHeight, columnWidth: 160 }} select={selectable} multiselect={selectable} {selectedRows}
313
317
  reorder={false} draggableRows={false} undo={false} {...queryProps} {...dynamicProps} init={api => init(api, 1)} />
314
318
  </div>{/if}
315
319
  </div>{/key}
@@ -16,7 +16,10 @@ export interface SvarDataGridProps {
16
16
  primaryKey?: string;
17
17
  childrenKey?: string;
18
18
  height?: number;
19
+ /** @deprecated Retained for compatibility; comfortable is the shared default. */
19
20
  density?: 'compact' | 'comfortable';
21
+ rowHeight?: number;
22
+ headerHeight?: number;
20
23
  freezeLeft?: number;
21
24
  /** 独立右侧面板,不使用上游 split.right。 */
22
25
  freezeRight?: number;
@@ -20,7 +20,6 @@
20
20
  /** 高级读取仍使用资源契约、Provider 和核心查询缓存。 */
21
21
  loadingMode?: 'page' | 'window' | 'infinite';
22
22
  lazyTree?: SvarLazyTree;
23
- density?: 'compact' | 'comfortable';
24
23
  childrenKey?: string;
25
24
  dataScopeKey?: string | number;
26
25
  disabled?: boolean;
@@ -16,7 +16,6 @@ export interface SvarResourceTableProps {
16
16
  /** 高级读取仍使用资源契约、Provider 和核心查询缓存。 */
17
17
  loadingMode?: 'page' | 'window' | 'infinite';
18
18
  lazyTree?: SvarLazyTree;
19
- density?: 'compact' | 'comfortable';
20
19
  childrenKey?: string;
21
20
  dataScopeKey?: string | number;
22
21
  disabled?: boolean;
@@ -15,7 +15,7 @@
15
15
  import type { SvarResourceTableProps } from './SvarResourceTable.svelte';
16
16
 
17
17
  let { Grid, Theme, resourceName, pageSize = 25, filters = [], initialSorters = [], height = 420,
18
- freezeLeft = 0, freezeRight = 0, loadingMode = 'page', lazyTree, density = 'comfortable', childrenKey: providedChildrenKey, dataScopeKey = 0, disabled = false,
18
+ freezeLeft = 0, freezeRight = 0, loadingMode = 'page', lazyTree, childrenKey: providedChildrenKey, dataScopeKey = 0, disabled = false,
19
19
  editable = false, selectable = false, batchUpdate = false, batchDelete = false, exportable = false,
20
20
  savedViews = false, preferenceScopeKey, migrateAutoTableViews = false, deleteVariables, formats = {},
21
21
  }: SvarResourceTableProps = $props();
@@ -333,7 +333,7 @@
333
333
  </div>{/if}
334
334
  {#if feedback}<p role="alert">{feedback}</p>{/if}
335
335
  {#if result}<p role="status">{zh ? '成功 / 失败 / 未执行' : 'Succeeded / failed / skipped'}: {result.succeeded.length} / {result.failed.length} / {result.skipped.length}</p>{/if}
336
- <SvarDataGrid {Grid} {Theme} items={gridItems} {columns} {primaryKey} {height} freezeRight={Math.min(freezeRight, Math.max(0, columns.length - 1))} freezeLeft={Math.min(freezeLeft, columns.length - Math.min(freezeRight, Math.max(0, columns.length - 1)))} {density}
336
+ <SvarDataGrid {Grid} {Theme} items={gridItems} {columns} {primaryKey} {height} freezeRight={Math.min(freezeRight, Math.max(0, columns.length - 1))} freezeLeft={Math.min(freezeLeft, columns.length - Math.min(freezeRight, Math.max(0, columns.length - 1)))}
337
337
  queryMode="server" {sorters} filters={textFilters} onSortChange={changeSort} onFilterChange={changeFilter}
338
338
  selectable={selectable || batchUpdate || batchDelete} {selectedIds} onSelectionChange={selection} {...advanced ? { onRecordsChange: loaded } : {}} scopeKey={gridScope}
339
339
  {...windowSource ? { windowSource } : {}}
@@ -11,6 +11,7 @@ export interface AutoTableGridState {
11
11
  }[];
12
12
  readonly primaryKey: string;
13
13
  readonly sorters: readonly Sort[];
14
+ /** @deprecated Retained for custom grid renderers during the baseline transition. */
14
15
  readonly density: 'compact' | 'comfortable';
15
16
  readonly locale: string;
16
17
  readonly label: string;
@@ -8,6 +8,7 @@
8
8
  description?: string;
9
9
  breadcrumbs?: string[];
10
10
  actions?: Snippet;
11
+ /** @deprecated Accepted for compatibility; the product baseline is shared. */
11
12
  density?: 'compact' | 'comfortable';
12
13
  headingLevel?: 'h1' | 'h2';
13
14
  class?: string;
@@ -22,7 +23,7 @@
22
23
  headingLevel = 'h1',
23
24
  class: className = '',
24
25
  }: Props = $props();
25
- const styles = $derived(contentHeader({ density }));
26
+ const styles = $derived(contentHeader());
26
27
  </script>
27
28
 
28
29
  <header
@@ -5,6 +5,7 @@ interface Props {
5
5
  description?: string;
6
6
  breadcrumbs?: string[];
7
7
  actions?: Snippet;
8
+ /** @deprecated Accepted for compatibility; the product baseline is shared. */
8
9
  density?: 'compact' | 'comfortable';
9
10
  headingLevel?: 'h1' | 'h2';
10
11
  class?: string;
@@ -12,6 +12,7 @@
12
12
  children: Snippet;
13
13
  pageId?: string;
14
14
  width?: 'narrow' | 'default' | 'wide';
15
+ /** @deprecated Accepted for compatibility; the product baseline is shared. */
15
16
  density?: 'compact' | 'comfortable';
16
17
  class?: string;
17
18
  }
@@ -32,7 +33,6 @@
32
33
  const resolvedWidth = $derived(width === 'narrow' || width === 'wide' ? width : 'default');
33
34
  const styles = $derived(contentPage({
34
35
  width: resolvedWidth,
35
- density,
36
36
  }));
37
37
  </script>
38
38
 
@@ -7,6 +7,7 @@ interface Props {
7
7
  children: Snippet;
8
8
  pageId?: string;
9
9
  width?: 'narrow' | 'default' | 'wide';
10
+ /** @deprecated Accepted for compatibility; the product baseline is shared. */
10
11
  density?: 'compact' | 'comfortable';
11
12
  class?: string;
12
13
  }
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { cn } from '../../utils.js';
4
+
5
+ interface Props {
6
+ /** Panel heading. Omit it for an untitled surface. */
7
+ title?: string;
8
+ description?: string;
9
+ actions?: Snippet;
10
+ children: Snippet;
11
+ footer?: Snippet;
12
+ /** `none` removes body padding so a table or list can meet the panel edge. */
13
+ padding?: 'default' | 'compact' | 'none';
14
+ headingLevel?: 'h2' | 'h3';
15
+ class?: string;
16
+ }
17
+
18
+ let {
19
+ title,
20
+ description,
21
+ actions,
22
+ children,
23
+ footer,
24
+ padding = 'default',
25
+ headingLevel = 'h2',
26
+ class: className = '',
27
+ }: Props = $props();
28
+
29
+ const uid = $props.id();
30
+ const headingId = `svadmin-data-panel-${uid}`;
31
+ </script>
32
+
33
+ <section
34
+ class={cn('svadmin-data-panel', className)}
35
+ data-svadmin-data-panel
36
+ data-padding={padding}
37
+ aria-labelledby={title ? headingId : undefined}
38
+ >
39
+ {#if title}
40
+ <header class="svadmin-data-panel__header" data-slot="data-panel-header">
41
+ <div class="svadmin-data-panel__heading">
42
+ <svelte:element this={headingLevel} id={headingId} class="svadmin-data-panel__title">
43
+ {title}
44
+ </svelte:element>
45
+ {#if description}
46
+ <p class="svadmin-data-panel__description">{description}</p>
47
+ {/if}
48
+ </div>
49
+ {#if actions}
50
+ <div class="svadmin-data-panel__actions">{@render actions()}</div>
51
+ {/if}
52
+ </header>
53
+ {/if}
54
+ <div class="svadmin-data-panel__body" data-slot="data-panel-body">{@render children()}</div>
55
+ {#if footer}
56
+ <footer class="svadmin-data-panel__footer" data-slot="data-panel-footer">{@render footer()}</footer>
57
+ {/if}
58
+ </section>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ /** Panel heading. Omit it for an untitled surface. */
4
+ title?: string;
5
+ description?: string;
6
+ actions?: Snippet;
7
+ children: Snippet;
8
+ footer?: Snippet;
9
+ /** `none` removes body padding so a table or list can meet the panel edge. */
10
+ padding?: 'default' | 'compact' | 'none';
11
+ headingLevel?: 'h2' | 'h3';
12
+ class?: string;
13
+ }
14
+ declare const DataPanel: import("svelte").Component<Props, {}, "">;
15
+ type DataPanel = ReturnType<typeof DataPanel>;
16
+ export default DataPanel;
@@ -14,7 +14,6 @@
14
14
  columns?: 1 | 2 | 3 | 4;
15
15
  layout?: 'vertical' | 'horizontal';
16
16
  bordered?: boolean;
17
- density?: 'compact' | 'comfortable';
18
17
  class?: string;
19
18
  }
20
19
 
@@ -23,11 +22,9 @@
23
22
  columns = 1,
24
23
  layout = 'vertical',
25
24
  bordered = false,
26
- density = 'comfortable',
27
25
  class: className = '',
28
26
  }: Props = $props();
29
27
 
30
- const isCompact = $derived(density === 'compact');
31
28
  const isHorizontal = $derived(layout === 'horizontal');
32
29
 
33
30
  function spanClass(span: number | undefined): string {
@@ -65,7 +62,7 @@
65
62
  <dt
66
63
  class={cn(
67
64
  'svadmin-u-2859c861d7de svadmin-u-2689f3958069 svadmin-u-bfa603190748 svadmin-u-012fbd121f37 svadmin-u-65fdbade2025 svadmin-u-a968a4123359 svadmin-u-27165ed73e86 svadmin-u-cdf6e054e5e0',
68
- isCompact ? 'svadmin-u-0e17f2bd9074 svadmin-u-ec0091ee009b svadmin-u-359090c2d529' : 'svadmin-u-f0faeb26d656 svadmin-u-e7ee55ac7ffe svadmin-u-359090c2d529 svadmin-u-e2327d142859',
65
+ 'svadmin-u-f0faeb26d656 svadmin-u-e7ee55ac7ffe svadmin-u-359090c2d529 svadmin-u-e2327d142859',
69
66
  isHorizontal ? 'svadmin-u-b03f3c253900' : '',
70
67
  )}
71
68
  >
@@ -74,7 +71,7 @@
74
71
  <dd
75
72
  class={cn(
76
73
  'svadmin-u-170cee3ff4e4 svadmin-u-2689f3958069 svadmin-u-d4108abe6359 svadmin-u-cd0ad9a56558 svadmin-u-36e579c0b41c svadmin-u-7e0b7cdf1a94',
77
- isCompact ? 'svadmin-u-0e17f2bd9074 svadmin-u-ec0091ee009b svadmin-u-359090c2d529' : 'svadmin-u-f0faeb26d656 svadmin-u-e7ee55ac7ffe svadmin-u-359090c2d529 svadmin-u-e2327d142859',
74
+ 'svadmin-u-f0faeb26d656 svadmin-u-e7ee55ac7ffe svadmin-u-359090c2d529 svadmin-u-e2327d142859',
78
75
  )}
79
76
  >
80
77
  {#if item.href}
@@ -95,7 +92,7 @@
95
92
  class={cn(
96
93
  'svadmin-u-f3c543ad5fe9',
97
94
  columnClass,
98
- isCompact ? 'svadmin-u-513d5c30bf66 svadmin-u-bcf14a5a5472' : 'svadmin-u-706c16d853e6 svadmin-u-375f36f67650',
95
+ 'svadmin-u-706c16d853e6 svadmin-u-375f36f67650',
99
96
  className,
100
97
  )}
101
98
  >
@@ -110,7 +107,7 @@
110
107
  <dt
111
108
  class={cn(
112
109
  'svadmin-u-2689f3958069 svadmin-u-bfa603190748',
113
- isCompact ? 'svadmin-u-359090c2d529' : 'svadmin-u-359090c2d529',
110
+ 'svadmin-u-359090c2d529',
114
111
  isHorizontal ? 'svadmin-u-012fbd121f37 svadmin-u-2e7a6d18a20d' : '',
115
112
  )}
116
113
  >
@@ -119,7 +116,7 @@
119
116
  <dd
120
117
  class={cn(
121
118
  'svadmin-u-170cee3ff4e4 svadmin-u-2689f3958069 svadmin-u-d4108abe6359 svadmin-u-7e0b7cdf1a94 svadmin-u-36e579c0b41c',
122
- isHorizontal ? 'svadmin-u-359090c2d529 svadmin-u-e2327d142859' : isCompact ? 'svadmin-u-15e1b1f444fe svadmin-u-359090c2d529 svadmin-u-e2327d142859' : 'svadmin-u-b6b02c0ebef6 svadmin-u-fc7473ca09eb',
119
+ isHorizontal ? 'svadmin-u-359090c2d529 svadmin-u-e2327d142859' : 'svadmin-u-b6b02c0ebef6 svadmin-u-fc7473ca09eb',
123
120
  )}
124
121
  >
125
122
  {#if item.href}
@@ -10,7 +10,6 @@ interface Props {
10
10
  columns?: 1 | 2 | 3 | 4;
11
11
  layout?: 'vertical' | 'horizontal';
12
12
  bordered?: boolean;
13
- density?: 'compact' | 'comfortable';
14
13
  class?: string;
15
14
  }
16
15
  declare const DescriptionList: import("svelte").Component<Props, {}, "">;
@@ -16,7 +16,6 @@
16
16
  clearLabel?: string;
17
17
  advancedLabel?: string;
18
18
  showSearch?: boolean;
19
- density?: 'compact' | 'comfortable';
20
19
  activeFilterCount?: number;
21
20
  advancedOpen?: boolean;
22
21
  filters?: Snippet;
@@ -31,7 +30,6 @@
31
30
  clearLabel = 'Clear search',
32
31
  advancedLabel = 'Filters',
33
32
  showSearch = true,
34
- density = 'compact',
35
33
  activeFilterCount = 0,
36
34
  advancedOpen = $bindable(false),
37
35
  filters,
@@ -40,7 +38,6 @@
40
38
  class: className = '',
41
39
  }: Props = $props();
42
40
 
43
- const isCompact = $derived(density === 'compact');
44
41
  const advancedPanelId = `svadmin-filter-toolbar-advanced-${uid}`;
45
42
  const i18n = useTranslation();
46
43
  let mobile = $state(false);
@@ -53,7 +50,7 @@
53
50
  });
54
51
  </script>
55
52
 
56
- <div class={cn('svadmin-filter-toolbar', className)} data-density={density} data-svadmin-filter-toolbar data-advanced-open={advanced && advancedOpen ? 'true' : 'false'}>
53
+ <div class={cn('svadmin-filter-toolbar', className)} data-svadmin-filter-toolbar data-advanced-open={advanced && advancedOpen ? 'true' : 'false'}>
57
54
  <div class="svadmin-filter-toolbar__row">
58
55
  {#if showSearch}
59
56
  <div class="svadmin-filter-toolbar__search">
@@ -86,7 +83,7 @@
86
83
  {#if advanced || (mobile && filters)}
87
84
  <Button
88
85
  variant={advancedOpen ? 'secondary' : 'outline'}
89
- size={isCompact ? 'sm' : 'default'}
86
+ size="default"
90
87
  class="svadmin-filter-toolbar__toggle"
91
88
  onclick={() => advancedOpen = !advancedOpen}
92
89
  aria-expanded={advancedOpen}
@@ -5,7 +5,6 @@ interface Props {
5
5
  clearLabel?: string;
6
6
  advancedLabel?: string;
7
7
  showSearch?: boolean;
8
- density?: 'compact' | 'comfortable';
9
8
  activeFilterCount?: number;
10
9
  advancedOpen?: boolean;
11
10
  filters?: Snippet;
@@ -6,15 +6,15 @@
6
6
  import DataState from './DataState.svelte';
7
7
  import type { DataStateKind } from './DataState.svelte';
8
8
  import type { NetworkColumn } from './NetworkTable.types.js';
9
- interface Props { rows?: T[]; columns: NetworkColumn<T>[]; row?: Snippet<[T]>; state?: DataStateKind; stateTitle?: string; stateDescription?: string; emptyTitle?: string; emptyDescription?: string; retry?: () => void; retryLabel?: string; loadingLabel?: string; class?: string; density?: 'comfortable' | 'compact'; }
10
- let { rows = [], columns, row, state, stateTitle, stateDescription, emptyTitle, emptyDescription, retry, retryLabel, loadingLabel, class: className = '', density = 'comfortable' }: Props = $props();
9
+ interface Props { rows?: T[]; columns: NetworkColumn<T>[]; row?: Snippet<[T]>; state?: DataStateKind; stateTitle?: string; stateDescription?: string; emptyTitle?: string; emptyDescription?: string; retry?: () => void; retryLabel?: string; loadingLabel?: string; class?: string; }
10
+ let { rows = [], columns, row, state, stateTitle, stateDescription, emptyTitle, emptyDescription, retry, retryLabel, loadingLabel, class: className = '' }: Props = $props();
11
11
  const resolvedState = $derived(state ?? (rows.length === 0 ? 'empty' : undefined));
12
12
  </script>
13
13
  {#if resolvedState}
14
14
  <DataState state={resolvedState} {...definedOptions({ title: stateTitle ?? emptyTitle, description: stateDescription ?? emptyDescription, retry, retryLabel, loadingLabel })} class={className} />
15
15
  {:else}
16
16
  <div class={'svadmin-u-1384f66f41d0 svadmin-u-5f22e64f2282 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-cd0ad9a56558 ' + className}>
17
- <Table.Root {density} data-svadmin-datatable>
17
+ <Table.Root data-svadmin-datatable>
18
18
  <Table.Header data-svadmin-table-head><Table.Row>{#each columns as column (String(column.key))}<Table.Head>{column.label}</Table.Head>{/each}</Table.Row></Table.Header>
19
19
  <Table.Body>
20
20
  {#each rows as item, index (String('id' in item ? item.id : index))}
@@ -15,7 +15,6 @@ declare function $$render<T extends object>(): {
15
15
  retryLabel?: string;
16
16
  loadingLabel?: string;
17
17
  class?: string;
18
- density?: "comfortable" | "compact";
19
18
  };
20
19
  exports: {};
21
20
  bindings: "";