@svadmin/ui 0.47.1 → 0.49.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 (28) hide show
  1. package/dist/components/AdminApp.svelte +20 -0
  2. package/dist/components/AdminApp.svelte.d.ts +5 -1
  3. package/dist/components/ApiSettings.svelte +137 -50
  4. package/dist/components/AutoTable.svelte +7 -3
  5. package/dist/components/AutoTable.svelte.d.ts +1 -0
  6. package/dist/components/Layout.svelte +15 -1
  7. package/dist/components/PasswordInput.svelte +4 -0
  8. package/dist/components/PasswordInput.svelte.d.ts +1 -0
  9. package/dist/components/SecuritySettings.svelte +156 -91
  10. package/dist/components/SecuritySettings.svelte.d.ts +1 -2
  11. package/dist/components/account/SettingsEnterprisePage.svelte +227 -23
  12. package/dist/components/account/SettingsSidebarPage.svelte +12 -1
  13. package/dist/components/content/WorkspaceActionBar.svelte +33 -0
  14. package/dist/components/content/WorkspaceActionBar.svelte.d.ts +12 -0
  15. package/dist/components/content/WorkspaceInspector.svelte +57 -0
  16. package/dist/components/content/WorkspaceInspector.svelte.d.ts +15 -0
  17. package/dist/components/content/WorkspaceLayout.svelte +12 -1
  18. package/dist/components/content/WorkspaceLayout.svelte.d.ts +2 -0
  19. package/dist/components/content/WorkspaceSplitPane.svelte +34 -0
  20. package/dist/components/content/WorkspaceSplitPane.svelte.d.ts +11 -0
  21. package/dist/components/content/WorkspaceStageStepper.svelte +71 -0
  22. package/dist/components/content/WorkspaceStageStepper.svelte.d.ts +17 -0
  23. package/dist/components/content/index.d.ts +4 -0
  24. package/dist/components/content/index.js +4 -0
  25. package/dist/components/ui/sheet/sheet.svelte +122 -10
  26. package/dist/index.d.ts +5 -0
  27. package/dist/index.js +4 -0
  28. package/package.json +2 -2
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { cn } from '../../utils.js';
4
+
5
+ interface Props {
6
+ title: string;
7
+ description?: string;
8
+ status?: string;
9
+ primaryAction: Snippet;
10
+ secondaryActions?: Snippet;
11
+ class?: string;
12
+ }
13
+
14
+ let { title, description, status, primaryAction, secondaryActions, class: className = '' }: Props = $props();
15
+ </script>
16
+
17
+ <section
18
+ class={cn('flex flex-col gap-3 border-y border-border bg-card px-4 py-3 sm:flex-row sm:items-center sm:justify-between', className)}
19
+ aria-label={title}
20
+ data-svadmin-workspace-action-bar
21
+ >
22
+ <div class="min-w-0">
23
+ <div class="flex flex-wrap items-center gap-2">
24
+ {#if status}<span class="rounded-sm bg-warning/15 px-2 py-0.5 text-xs font-medium text-warning-foreground">{status}</span>{/if}
25
+ <h2 class="text-sm font-semibold text-foreground">{title}</h2>
26
+ </div>
27
+ {#if description}<p class="mt-1 text-xs leading-5 text-muted-foreground">{description}</p>{/if}
28
+ </div>
29
+ <div class="flex shrink-0 flex-wrap items-center gap-2">
30
+ {#if secondaryActions}{@render secondaryActions()}{/if}
31
+ {@render primaryAction()}
32
+ </div>
33
+ </section>
@@ -0,0 +1,12 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ title: string;
4
+ description?: string;
5
+ status?: string;
6
+ primaryAction: Snippet;
7
+ secondaryActions?: Snippet;
8
+ class?: string;
9
+ }
10
+ declare const WorkspaceActionBar: import("svelte").Component<Props, {}, "">;
11
+ type WorkspaceActionBar = ReturnType<typeof WorkspaceActionBar>;
12
+ export default WorkspaceActionBar;
@@ -0,0 +1,57 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { PanelRightClose, PanelRightOpen } from '@lucide/svelte';
4
+ import { Button } from '../ui/button/index.js';
5
+ import { cn } from '../../utils.js';
6
+
7
+ interface Props {
8
+ title: string;
9
+ description?: string;
10
+ open?: boolean;
11
+ ontoggle?: (open: boolean) => void;
12
+ children: Snippet;
13
+ footer?: Snippet;
14
+ openLabel?: string;
15
+ closeLabel?: string;
16
+ class?: string;
17
+ }
18
+
19
+ let {
20
+ title,
21
+ description,
22
+ open = true,
23
+ ontoggle,
24
+ children,
25
+ footer,
26
+ openLabel = 'Open inspector',
27
+ closeLabel = 'Close inspector',
28
+ class: className = '',
29
+ }: Props = $props();
30
+
31
+ function toggle(): void {
32
+ ontoggle?.(!open);
33
+ }
34
+ </script>
35
+
36
+ <aside class={cn('overflow-hidden rounded-lg border border-border bg-card', className)} data-svadmin-workspace-inspector data-open={open}>
37
+ {#if open}
38
+ <header class="flex items-start justify-between gap-3 border-b border-border px-4 py-3">
39
+ <div class="min-w-0">
40
+ <h2 class="text-sm font-semibold text-foreground">{title}</h2>
41
+ {#if description}<p class="mt-1 text-xs leading-5 text-muted-foreground">{description}</p>{/if}
42
+ </div>
43
+ <Button variant="ghost" size="icon-sm" aria-label={closeLabel} title={closeLabel} onclick={toggle}>
44
+ <PanelRightClose class="size-4" />
45
+ </Button>
46
+ </header>
47
+ <div class="max-h-[calc(100vh-15rem)] overflow-y-auto p-4">{@render children()}</div>
48
+ {#if footer}<footer class="border-t border-border p-3">{@render footer()}</footer>{/if}
49
+ {:else}
50
+ <div class="flex min-h-64 flex-col items-center gap-3 py-3">
51
+ <Button variant="ghost" size="icon-sm" aria-label={openLabel} title={openLabel} onclick={toggle}>
52
+ <PanelRightOpen class="size-4" />
53
+ </Button>
54
+ <span class="[writing-mode:vertical-rl] text-xs font-medium text-muted-foreground">{title}</span>
55
+ </div>
56
+ {/if}
57
+ </aside>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ title: string;
4
+ description?: string;
5
+ open?: boolean;
6
+ ontoggle?: (open: boolean) => void;
7
+ children: Snippet;
8
+ footer?: Snippet;
9
+ openLabel?: string;
10
+ closeLabel?: string;
11
+ class?: string;
12
+ }
13
+ declare const WorkspaceInspector: import("svelte").Component<Props, {}, "">;
14
+ type WorkspaceInspector = ReturnType<typeof WorkspaceInspector>;
15
+ export default WorkspaceInspector;
@@ -7,6 +7,8 @@
7
7
  secondary?: Snippet;
8
8
  summary?: Snippet;
9
9
  secondaryWidth?: string;
10
+ secondaryCollapsed?: boolean;
11
+ secondaryCollapsedWidth?: string;
10
12
  mobileOrder?: 'primary-first' | 'secondary-first';
11
13
  class?: string;
12
14
  }
@@ -16,12 +18,21 @@
16
18
  secondary,
17
19
  summary,
18
20
  secondaryWidth = '22rem',
21
+ secondaryCollapsed = false,
22
+ secondaryCollapsedWidth = '3rem',
19
23
  mobileOrder = 'primary-first',
20
24
  class: className = '',
21
25
  }: Props = $props();
26
+
27
+ const resolvedSecondaryWidth = $derived(secondaryCollapsed ? secondaryCollapsedWidth : secondaryWidth);
22
28
  </script>
23
29
 
24
- <div class={cn('flex flex-col gap-6', className)} data-svadmin-workspace-layout style:--workspace-secondary-width={secondaryWidth}>
30
+ <div
31
+ class={cn('flex flex-col gap-6', className)}
32
+ data-svadmin-workspace-layout
33
+ data-secondary-collapsed={secondaryCollapsed}
34
+ style:--workspace-secondary-width={resolvedSecondaryWidth}
35
+ >
25
36
  {#if summary}<div data-svadmin-workspace-summary>{@render summary()}</div>{/if}
26
37
  <div class={cn('grid min-w-0 items-start gap-6 xl:grid-cols-[minmax(0,1fr)_var(--workspace-secondary-width)]', mobileOrder === 'secondary-first' && 'grid-rows-[auto_auto]')}>
27
38
  {#if mobileOrder === 'secondary-first' && secondary}<aside class="order-1 min-w-0 xl:order-2">{@render secondary()}</aside>{/if}
@@ -4,6 +4,8 @@ interface Props {
4
4
  secondary?: Snippet;
5
5
  summary?: Snippet;
6
6
  secondaryWidth?: string;
7
+ secondaryCollapsed?: boolean;
8
+ secondaryCollapsedWidth?: string;
7
9
  mobileOrder?: 'primary-first' | 'secondary-first';
8
10
  class?: string;
9
11
  }
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { cn } from '../../utils.js';
4
+
5
+ interface Props {
6
+ primary: Snippet;
7
+ secondary: Snippet;
8
+ secondaryWidth?: string;
9
+ reverse?: boolean;
10
+ class?: string;
11
+ }
12
+
13
+ let {
14
+ primary,
15
+ secondary,
16
+ secondaryWidth = '42%',
17
+ reverse = false,
18
+ class: className = '',
19
+ }: Props = $props();
20
+ </script>
21
+
22
+ <div
23
+ class={cn(
24
+ 'grid min-w-0 overflow-hidden rounded-lg border border-border bg-card',
25
+ reverse ? 'lg:grid-cols-[var(--workspace-split-width)_minmax(0,1fr)]' : 'lg:grid-cols-[minmax(0,1fr)_var(--workspace-split-width)]',
26
+ className,
27
+ )}
28
+ style:--workspace-split-width={secondaryWidth}
29
+ data-svadmin-workspace-split-pane
30
+ data-reverse={reverse}
31
+ >
32
+ <section class={cn('min-w-0 p-4', reverse && 'lg:order-2')} data-svadmin-split-primary>{@render primary()}</section>
33
+ <section class={cn('min-w-0 border-t border-border bg-muted/15 p-4 lg:border-l lg:border-t-0', reverse && 'lg:order-1 lg:border-l-0 lg:border-r')} data-svadmin-split-secondary>{@render secondary()}</section>
34
+ </div>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ primary: Snippet;
4
+ secondary: Snippet;
5
+ secondaryWidth?: string;
6
+ reverse?: boolean;
7
+ class?: string;
8
+ }
9
+ declare const WorkspaceSplitPane: import("svelte").Component<Props, {}, "">;
10
+ type WorkspaceSplitPane = ReturnType<typeof WorkspaceSplitPane>;
11
+ export default WorkspaceSplitPane;
@@ -0,0 +1,71 @@
1
+ <script module lang="ts">
2
+ export type WorkspaceStageStatus = 'complete' | 'current' | 'blocked' | 'pending';
3
+
4
+ export interface WorkspaceStage {
5
+ id: string;
6
+ label: string;
7
+ description?: string;
8
+ status: WorkspaceStageStatus;
9
+ }
10
+ </script>
11
+
12
+ <script lang="ts">
13
+ import { AlertTriangle, Check, Circle } from '@lucide/svelte';
14
+ import { cn } from '../../utils.js';
15
+
16
+ interface Props {
17
+ stages: WorkspaceStage[];
18
+ activeId: string;
19
+ onselect?: (stage: WorkspaceStage) => void;
20
+ ariaLabel?: string;
21
+ class?: string;
22
+ }
23
+
24
+ let {
25
+ stages,
26
+ activeId,
27
+ onselect,
28
+ ariaLabel = 'Workflow stages',
29
+ class: className = '',
30
+ }: Props = $props();
31
+
32
+ const markerClass: Record<WorkspaceStageStatus, string> = {
33
+ complete: 'border-success/30 bg-success/10 text-success',
34
+ current: 'border-primary bg-primary text-primary-foreground',
35
+ blocked: 'border-warning/40 bg-warning/15 text-warning-foreground',
36
+ pending: 'border-border bg-background text-muted-foreground',
37
+ };
38
+ </script>
39
+
40
+ <nav aria-label={ariaLabel} class={cn('overflow-x-auto', className)} data-svadmin-workspace-stages>
41
+ <ol class="flex min-w-max items-start gap-0 px-0.5 py-1">
42
+ {#each stages as stage, index (stage.id)}
43
+ <li class="flex items-start">
44
+ <button
45
+ type="button"
46
+ class="group grid min-w-28 grid-cols-[auto_minmax(0,1fr)] gap-x-2 rounded-md px-2 py-1.5 text-left outline-none transition-colors hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-ring sm:min-w-36"
47
+ aria-current={stage.id === activeId ? 'step' : undefined}
48
+ aria-label={`${stage.label}: ${stage.status}`}
49
+ onclick={() => onselect?.(stage)}
50
+ >
51
+ <span class={cn('flex size-7 items-center justify-center rounded-full border', markerClass[stage.status])}>
52
+ {#if stage.status === 'complete'}
53
+ <Check class="size-3.5" />
54
+ {:else if stage.status === 'blocked'}
55
+ <AlertTriangle class="size-3.5" />
56
+ {:else}
57
+ <Circle class={cn('size-2.5', stage.status === 'current' && 'fill-current')} />
58
+ {/if}
59
+ </span>
60
+ <span class="min-w-0 pt-0.5">
61
+ <span class={cn('block text-xs font-medium', stage.id === activeId ? 'text-foreground' : 'text-muted-foreground')}>{stage.label}</span>
62
+ {#if stage.description}<span class="mt-0.5 block max-w-32 truncate text-[0.6875rem] text-muted-foreground">{stage.description}</span>{/if}
63
+ </span>
64
+ </button>
65
+ {#if index < stages.length - 1}
66
+ <span class={cn('mt-5 h-px w-4 bg-border sm:w-7', stage.status === 'complete' && 'bg-success/50')} aria-hidden="true"></span>
67
+ {/if}
68
+ </li>
69
+ {/each}
70
+ </ol>
71
+ </nav>
@@ -0,0 +1,17 @@
1
+ export type WorkspaceStageStatus = 'complete' | 'current' | 'blocked' | 'pending';
2
+ export interface WorkspaceStage {
3
+ id: string;
4
+ label: string;
5
+ description?: string;
6
+ status: WorkspaceStageStatus;
7
+ }
8
+ interface Props {
9
+ stages: WorkspaceStage[];
10
+ activeId: string;
11
+ onselect?: (stage: WorkspaceStage) => void;
12
+ ariaLabel?: string;
13
+ class?: string;
14
+ }
15
+ declare const WorkspaceStageStepper: import("svelte").Component<Props, {}, "">;
16
+ type WorkspaceStageStepper = ReturnType<typeof WorkspaceStageStepper>;
17
+ export default WorkspaceStageStepper;
@@ -3,6 +3,10 @@ export { default as ContentPageHeader } from './ContentPageHeader.svelte';
3
3
  export { default as SectionHeader } from './SectionHeader.svelte';
4
4
  export { default as PageToolbar } from './PageToolbar.svelte';
5
5
  export { default as WorkspaceLayout } from './WorkspaceLayout.svelte';
6
+ export { default as WorkspaceStageStepper } from './WorkspaceStageStepper.svelte';
7
+ export { default as WorkspaceActionBar } from './WorkspaceActionBar.svelte';
8
+ export { default as WorkspaceInspector } from './WorkspaceInspector.svelte';
9
+ export { default as WorkspaceSplitPane } from './WorkspaceSplitPane.svelte';
6
10
  export { default as SettingsGroup } from './SettingsGroup.svelte';
7
11
  export { default as SettingsFieldRow } from './SettingsFieldRow.svelte';
8
12
  export { default as MetricBlock } from './MetricBlock.svelte';
@@ -3,6 +3,10 @@ export { default as ContentPageHeader } from './ContentPageHeader.svelte';
3
3
  export { default as SectionHeader } from './SectionHeader.svelte';
4
4
  export { default as PageToolbar } from './PageToolbar.svelte';
5
5
  export { default as WorkspaceLayout } from './WorkspaceLayout.svelte';
6
+ export { default as WorkspaceStageStepper } from './WorkspaceStageStepper.svelte';
7
+ export { default as WorkspaceActionBar } from './WorkspaceActionBar.svelte';
8
+ export { default as WorkspaceInspector } from './WorkspaceInspector.svelte';
9
+ export { default as WorkspaceSplitPane } from './WorkspaceSplitPane.svelte';
6
10
  export { default as SettingsGroup } from './SettingsGroup.svelte';
7
11
  export { default as SettingsFieldRow } from './SettingsFieldRow.svelte';
8
12
  export { default as MetricBlock } from './MetricBlock.svelte';
@@ -1,8 +1,51 @@
1
+ <script lang="ts" module>
2
+ let bodyScrollLockDepth = 0;
3
+ let bodyOverflowBeforeLock = "";
4
+ const openSheets: HTMLElement[] = [];
5
+
6
+ function lockBodyScroll() {
7
+ if (bodyScrollLockDepth === 0) bodyOverflowBeforeLock = document.body.style.overflow;
8
+ bodyScrollLockDepth += 1;
9
+ document.body.style.overflow = "hidden";
10
+ }
11
+
12
+ function unlockBodyScroll() {
13
+ bodyScrollLockDepth = Math.max(0, bodyScrollLockDepth - 1);
14
+ if (bodyScrollLockDepth > 0) return;
15
+ document.body.style.overflow = bodyOverflowBeforeLock;
16
+ bodyOverflowBeforeLock = "";
17
+ }
18
+
19
+ function registerSheet(panel: HTMLElement) {
20
+ openSheets.push(panel);
21
+ }
22
+
23
+ function unregisterSheet(panel: HTMLElement) {
24
+ const index = openSheets.lastIndexOf(panel);
25
+ if (index >= 0) openSheets.splice(index, 1);
26
+ }
27
+
28
+ function isTopmostSheet(panel: HTMLElement) {
29
+ return openSheets.at(-1) === panel;
30
+ }
31
+ </script>
32
+
1
33
  <script lang="ts">
2
34
  /* eslint-disable svelte/no-unused-svelte-ignore */
35
+ import { tick } from "svelte";
3
36
  import { cn, type WithElementRef } from "../../../utils.js";
4
37
  import type { HTMLAttributes } from "svelte/elements";
5
38
 
39
+ const focusableSelector = [
40
+ 'a[href]',
41
+ 'button',
42
+ 'input',
43
+ 'select',
44
+ 'textarea',
45
+ '[tabindex]:not([tabindex="-1"])',
46
+ '[contenteditable]:not([contenteditable="false"])',
47
+ ].join(",");
48
+
6
49
  type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
7
50
  open?: boolean;
8
51
  side?: "left" | "right";
@@ -15,6 +58,7 @@
15
58
  side = "right",
16
59
  onClose,
17
60
  class: className,
61
+ tabindex = -1,
18
62
  children,
19
63
  ...restProps
20
64
  }: Props = $props();
@@ -24,22 +68,88 @@
24
68
  onClose?.();
25
69
  }
26
70
 
27
- function handleKeydown(e: KeyboardEvent) {
28
- if (e.key === "Escape") close();
71
+ function isContentEditableHost(element: HTMLElement) {
72
+ const contentEditable = element.getAttribute("contenteditable");
73
+ const isEditable = element.isContentEditable || (contentEditable !== null && contentEditable.toLowerCase() !== "false");
74
+ return isEditable && !element.parentElement?.isContentEditable;
29
75
  }
30
76
 
31
- $effect(() => {
32
- if (open) {
33
- document.addEventListener("keydown", handleKeydown);
34
- document.body.style.overflow = "hidden";
35
- return () => {
36
- document.removeEventListener("keydown", handleKeydown);
37
- document.body.style.overflow = "";
38
- };
77
+ function isVisible(element: HTMLElement) {
78
+ for (let current: HTMLElement | null = element; current; current = current.parentElement) {
79
+ const style = getComputedStyle(current);
80
+ if (style.display === "none" || style.visibility === "hidden") return false;
81
+ if (current === ref) break;
39
82
  }
83
+ return true;
84
+ }
85
+
86
+ function isTabbable(element: HTMLElement) {
87
+ if (element.matches(":disabled, [aria-disabled='true']")) return false;
88
+ if (element.closest("[hidden], [inert], [aria-hidden='true']")) return false;
89
+ if (element.hasAttribute("tabindex") && element.tabIndex < 0) return false;
90
+ if (!element.hasAttribute("tabindex") && !isContentEditableHost(element) && element.tabIndex < 0) return false;
91
+ return isVisible(element);
92
+ }
93
+
94
+ function tabbableElements() {
95
+ return ref ? [...ref.querySelectorAll<HTMLElement>(focusableSelector)].filter(isTabbable) : [];
96
+ }
97
+
98
+ function handleKeydown(event: KeyboardEvent) {
99
+ if (event.defaultPrevented || !open || !ref || !isTopmostSheet(ref)) return;
100
+ if (event.key === "Escape") {
101
+ event.preventDefault();
102
+ close();
103
+ return;
104
+ }
105
+ if (event.key !== "Tab") return;
106
+
107
+ const tabbable = tabbableElements();
108
+ if (tabbable.length === 0) {
109
+ event.preventDefault();
110
+ ref.focus();
111
+ return;
112
+ }
113
+
114
+ const first = tabbable[0];
115
+ const last = tabbable.at(-1);
116
+ const activeIndex = tabbable.indexOf(document.activeElement as HTMLElement);
117
+ if (!ref.contains(document.activeElement) || activeIndex === -1) {
118
+ event.preventDefault();
119
+ (event.shiftKey ? last : first)?.focus();
120
+ } else if (event.shiftKey && activeIndex === 0) {
121
+ event.preventDefault();
122
+ last?.focus();
123
+ } else if (!event.shiftKey && activeIndex === tabbable.length - 1) {
124
+ event.preventDefault();
125
+ first.focus();
126
+ }
127
+ }
128
+
129
+ $effect(() => {
130
+ if (!open || !ref) return;
131
+ const panel = ref;
132
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
133
+ registerSheet(panel);
134
+ lockBodyScroll();
135
+ void tick().then(() => {
136
+ if (open && ref === panel && isTopmostSheet(panel)) {
137
+ (tabbableElements()[0] ?? panel).focus();
138
+ }
139
+ });
140
+ return () => {
141
+ unregisterSheet(panel);
142
+ unlockBodyScroll();
143
+ const remainingSheet = openSheets.at(-1);
144
+ if (!remainingSheet || (previousFocus && remainingSheet.contains(previousFocus))) {
145
+ previousFocus?.focus();
146
+ }
147
+ };
40
148
  });
41
149
  </script>
42
150
 
151
+ <svelte:document onkeydown={handleKeydown} />
152
+
43
153
  {#if open}
44
154
  <!-- Overlay -->
45
155
  <!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
@@ -50,9 +160,11 @@
50
160
  ></div>
51
161
 
52
162
  <!-- Sheet panel -->
163
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
53
164
  <div
54
165
  bind:this={ref}
55
166
  data-slot="sheet"
167
+ {tabindex}
56
168
  class={cn(
57
169
  "fixed z-50 flex translate-x-0 flex-col gap-4 bg-background p-6 shadow-lg",
58
170
  side === "right"
package/dist/index.d.ts CHANGED
@@ -159,6 +159,11 @@ export { default as ContentPageHeader } from './components/content/ContentPageHe
159
159
  export { default as SectionHeader } from './components/content/SectionHeader.svelte';
160
160
  export { default as PageToolbar } from './components/content/PageToolbar.svelte';
161
161
  export { default as WorkspaceLayout } from './components/content/WorkspaceLayout.svelte';
162
+ export { default as WorkspaceStageStepper } from './components/content/WorkspaceStageStepper.svelte';
163
+ export type { WorkspaceStage, WorkspaceStageStatus } from './components/content/WorkspaceStageStepper.svelte';
164
+ export { default as WorkspaceActionBar } from './components/content/WorkspaceActionBar.svelte';
165
+ export { default as WorkspaceInspector } from './components/content/WorkspaceInspector.svelte';
166
+ export { default as WorkspaceSplitPane } from './components/content/WorkspaceSplitPane.svelte';
162
167
  export { default as SettingsGroup } from './components/content/SettingsGroup.svelte';
163
168
  export { default as SettingsFieldRow } from './components/content/SettingsFieldRow.svelte';
164
169
  export { default as MetricBlock } from './components/content/MetricBlock.svelte';
package/dist/index.js CHANGED
@@ -174,6 +174,10 @@ export { default as ContentPageHeader } from './components/content/ContentPageHe
174
174
  export { default as SectionHeader } from './components/content/SectionHeader.svelte';
175
175
  export { default as PageToolbar } from './components/content/PageToolbar.svelte';
176
176
  export { default as WorkspaceLayout } from './components/content/WorkspaceLayout.svelte';
177
+ export { default as WorkspaceStageStepper } from './components/content/WorkspaceStageStepper.svelte';
178
+ export { default as WorkspaceActionBar } from './components/content/WorkspaceActionBar.svelte';
179
+ export { default as WorkspaceInspector } from './components/content/WorkspaceInspector.svelte';
180
+ export { default as WorkspaceSplitPane } from './components/content/WorkspaceSplitPane.svelte';
177
181
  export { default as SettingsGroup } from './components/content/SettingsGroup.svelte';
178
182
  export { default as SettingsFieldRow } from './components/content/SettingsFieldRow.svelte';
179
183
  export { default as MetricBlock } from './components/content/MetricBlock.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svadmin/ui",
3
- "version": "0.47.1",
3
+ "version": "0.49.0",
4
4
  "description": "Pre-built admin UI components — AdminApp, AutoTable, AutoForm, Sidebar, Layout",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -39,7 +39,7 @@
39
39
  "./components/*": "./dist/components/*"
40
40
  },
41
41
  "peerDependencies": {
42
- "@svadmin/core": "^0.38.0",
42
+ "@svadmin/core": "^0.39.0",
43
43
  "@tanstack/svelte-query": "^6.1.38",
44
44
  "highlight.js": "^11.11.1",
45
45
  "isomorphic-dompurify": "^3.22.0",