@fudge-me/design-system 0.1.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 (57) hide show
  1. package/README.md +140 -0
  2. package/dist/components/.gitkeep +0 -0
  3. package/dist/components/Button.svelte +118 -0
  4. package/dist/components/Button.svelte.d.ts +12 -0
  5. package/dist/components/CommandPalette.svelte +167 -0
  6. package/dist/components/CommandPalette.svelte.d.ts +16 -0
  7. package/dist/components/Input.svelte +70 -0
  8. package/dist/components/Input.svelte.d.ts +9 -0
  9. package/dist/components/Modal.svelte +83 -0
  10. package/dist/components/Modal.svelte.d.ts +12 -0
  11. package/dist/components/Tooltip.svelte +92 -0
  12. package/dist/components/Tooltip.svelte.d.ts +12 -0
  13. package/dist/components/index.d.ts +8 -0
  14. package/dist/components/index.js +5 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.js +3 -0
  17. package/dist/layout/.gitkeep +0 -0
  18. package/dist/layout/AIPanel.svelte +34 -0
  19. package/dist/layout/AIPanel.svelte.d.ts +11 -0
  20. package/dist/layout/AppShell.svelte +78 -0
  21. package/dist/layout/AppShell.svelte.d.ts +11 -0
  22. package/dist/layout/Canvas.svelte +22 -0
  23. package/dist/layout/Canvas.svelte.d.ts +7 -0
  24. package/dist/layout/CommandBar.svelte +25 -0
  25. package/dist/layout/CommandBar.svelte.d.ts +7 -0
  26. package/dist/layout/Panel.svelte +157 -0
  27. package/dist/layout/Panel.svelte.d.ts +13 -0
  28. package/dist/layout/Sidebar.svelte +34 -0
  29. package/dist/layout/Sidebar.svelte.d.ts +11 -0
  30. package/dist/layout/StatusBar.svelte +26 -0
  31. package/dist/layout/StatusBar.svelte.d.ts +7 -0
  32. package/dist/layout/__tests__/helpers.js +53 -0
  33. package/dist/layout/index.d.ts +8 -0
  34. package/dist/layout/index.js +7 -0
  35. package/dist/themes/ThemeProvider.svelte +44 -0
  36. package/dist/themes/ThemeProvider.svelte.d.ts +10 -0
  37. package/dist/themes/dark.css +49 -0
  38. package/dist/themes/index.d.ts +2 -0
  39. package/dist/themes/index.js +1 -0
  40. package/dist/themes/light.css +79 -0
  41. package/dist/tokens/.gitkeep +0 -0
  42. package/dist/tokens/__tests__/helpers.js +117 -0
  43. package/dist/tokens/color.css +112 -0
  44. package/dist/tokens/components/appshell.css +22 -0
  45. package/dist/tokens/components/button.css +16 -0
  46. package/dist/tokens/components/command-palette.css +15 -0
  47. package/dist/tokens/components/input.css +16 -0
  48. package/dist/tokens/components/modal.css +9 -0
  49. package/dist/tokens/components/panel.css +16 -0
  50. package/dist/tokens/components/tooltip.css +10 -0
  51. package/dist/tokens/index.css +13 -0
  52. package/dist/tokens/radii.css +10 -0
  53. package/dist/tokens/semantic.css +79 -0
  54. package/dist/tokens/shadows.css +11 -0
  55. package/dist/tokens/spacing.css +32 -0
  56. package/dist/tokens/typography.css +39 -0
  57. package/package.json +70 -0
@@ -0,0 +1,92 @@
1
+ <script lang="ts" module>
2
+ export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import type { Snippet } from 'svelte';
7
+
8
+ interface Props {
9
+ content: string;
10
+ position?: TooltipPosition;
11
+ children?: Snippet<[{ 'aria-describedby'?: string }]>;
12
+ }
13
+
14
+ let { content, position = 'top', children }: Props = $props();
15
+
16
+ const tooltipId = `fds-tooltip-${Math.random().toString(36).slice(2, 9)}`;
17
+ let visible = $state(false);
18
+
19
+ function show() { visible = true; }
20
+ function hide() { visible = false; }
21
+ </script>
22
+
23
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
24
+ <div
25
+ class="fds-tooltip-wrapper"
26
+ onmouseenter={show}
27
+ onmouseleave={hide}
28
+ onfocusin={show}
29
+ onfocusout={hide}
30
+ >
31
+ {#if children}
32
+ {@render children({ 'aria-describedby': visible ? tooltipId : undefined })}
33
+ {/if}
34
+ {#if visible}
35
+ <div
36
+ class="fds-tooltip fds-tooltip--{position}"
37
+ id={tooltipId}
38
+ role="tooltip"
39
+ >
40
+ {content}
41
+ </div>
42
+ {/if}
43
+ </div>
44
+
45
+ <style>
46
+ .fds-tooltip-wrapper {
47
+ position: relative;
48
+ display: inline-block;
49
+ }
50
+
51
+ .fds-tooltip {
52
+ position: absolute;
53
+ font-family: var(--fds-tooltip-font-family);
54
+ font-size: var(--fds-tooltip-font-size);
55
+ padding: var(--fds-tooltip-padding-y) var(--fds-tooltip-padding-x);
56
+ background: var(--fds-tooltip-bg);
57
+ color: var(--fds-tooltip-text);
58
+ border-radius: var(--fds-tooltip-radius);
59
+ box-shadow: var(--fds-tooltip-shadow);
60
+ white-space: nowrap;
61
+ pointer-events: none;
62
+ z-index: 1000;
63
+ }
64
+
65
+ .fds-tooltip--top {
66
+ bottom: 100%;
67
+ left: 50%;
68
+ transform: translateX(-50%);
69
+ margin-bottom: 4px;
70
+ }
71
+
72
+ .fds-tooltip--bottom {
73
+ top: 100%;
74
+ left: 50%;
75
+ transform: translateX(-50%);
76
+ margin-top: 4px;
77
+ }
78
+
79
+ .fds-tooltip--left {
80
+ right: 100%;
81
+ top: 50%;
82
+ transform: translateY(-50%);
83
+ margin-right: 4px;
84
+ }
85
+
86
+ .fds-tooltip--right {
87
+ left: 100%;
88
+ top: 50%;
89
+ transform: translateY(-50%);
90
+ margin-left: 4px;
91
+ }
92
+ </style>
@@ -0,0 +1,12 @@
1
+ export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
2
+ import type { Snippet } from 'svelte';
3
+ interface Props {
4
+ content: string;
5
+ position?: TooltipPosition;
6
+ children?: Snippet<[{
7
+ 'aria-describedby'?: string;
8
+ }]>;
9
+ }
10
+ declare const Tooltip: import("svelte").Component<Props, {}, "">;
11
+ type Tooltip = ReturnType<typeof Tooltip>;
12
+ export default Tooltip;
@@ -0,0 +1,8 @@
1
+ export { default as Button } from "./Button.svelte";
2
+ export type { ButtonVariant, ButtonSize } from "./Button.svelte";
3
+ export { default as Input } from "./Input.svelte";
4
+ export { default as Tooltip } from "./Tooltip.svelte";
5
+ export type { TooltipPosition } from "./Tooltip.svelte";
6
+ export { default as Modal } from "./Modal.svelte";
7
+ export { default as CommandPalette } from "./CommandPalette.svelte";
8
+ export type { CommandPaletteItem } from "./CommandPalette.svelte";
@@ -0,0 +1,5 @@
1
+ export { default as Button } from "./Button.svelte";
2
+ export { default as Input } from "./Input.svelte";
3
+ export { default as Tooltip } from "./Tooltip.svelte";
4
+ export { default as Modal } from "./Modal.svelte";
5
+ export { default as CommandPalette } from "./CommandPalette.svelte";
@@ -0,0 +1,3 @@
1
+ export * from "./themes/index.js";
2
+ export * from "./layout/index.js";
3
+ export * from "./components/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./themes/index.js";
2
+ export * from "./layout/index.js";
3
+ export * from "./components/index.js";
File without changes
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import Panel from './Panel.svelte';
4
+
5
+ interface Props {
6
+ collapsed?: boolean;
7
+ width?: number;
8
+ minWidth?: number;
9
+ maxWidth?: number;
10
+ children?: Snippet;
11
+ }
12
+
13
+ let {
14
+ collapsed = $bindable(false),
15
+ width = $bindable(280),
16
+ minWidth = 200,
17
+ maxWidth = 480,
18
+ children,
19
+ }: Props = $props();
20
+ </script>
21
+
22
+ <aside class="fds-aipanel" aria-label="AI Panel">
23
+ <Panel side="right" bind:collapsed bind:width {minWidth} {maxWidth}>
24
+ {#if children}
25
+ {@render children()}
26
+ {/if}
27
+ </Panel>
28
+ </aside>
29
+
30
+ <style>
31
+ .fds-aipanel {
32
+ display: contents;
33
+ }
34
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ collapsed?: boolean;
4
+ width?: number;
5
+ minWidth?: number;
6
+ maxWidth?: number;
7
+ children?: Snippet;
8
+ }
9
+ declare const AIPanel: import("svelte").Component<Props, {}, "collapsed" | "width">;
10
+ type AIPanel = ReturnType<typeof AIPanel>;
11
+ export default AIPanel;
@@ -0,0 +1,78 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ commandbar?: Snippet;
6
+ sidebar?: Snippet;
7
+ canvas?: Snippet;
8
+ aipanel?: Snippet;
9
+ statusbar?: Snippet;
10
+ }
11
+
12
+ let { commandbar, sidebar, canvas, aipanel, statusbar }: Props = $props();
13
+ </script>
14
+
15
+ <div class="fds-appshell">
16
+ <div class="fds-appshell__commandbar">
17
+ {#if commandbar}
18
+ {@render commandbar()}
19
+ {/if}
20
+ </div>
21
+ <div class="fds-appshell__sidebar">
22
+ {#if sidebar}
23
+ {@render sidebar()}
24
+ {/if}
25
+ </div>
26
+ <div class="fds-appshell__canvas">
27
+ {#if canvas}
28
+ {@render canvas()}
29
+ {/if}
30
+ </div>
31
+ <div class="fds-appshell__aipanel">
32
+ {#if aipanel}
33
+ {@render aipanel()}
34
+ {/if}
35
+ </div>
36
+ <div class="fds-appshell__statusbar">
37
+ {#if statusbar}
38
+ {@render statusbar()}
39
+ {/if}
40
+ </div>
41
+ </div>
42
+
43
+ <style>
44
+ .fds-appshell {
45
+ display: grid;
46
+ grid-template-areas:
47
+ 'commandbar commandbar commandbar'
48
+ 'sidebar canvas aipanel'
49
+ 'statusbar statusbar statusbar';
50
+ grid-template-rows: var(--fds-appshell-commandbar-height) 1fr var(--fds-appshell-statusbar-height);
51
+ grid-template-columns: auto 1fr auto;
52
+ width: 100%;
53
+ height: 100vh;
54
+ overflow: hidden;
55
+ background: var(--fds-appshell-bg);
56
+ }
57
+
58
+ .fds-appshell__commandbar {
59
+ grid-area: commandbar;
60
+ }
61
+
62
+ .fds-appshell__sidebar {
63
+ grid-area: sidebar;
64
+ }
65
+
66
+ .fds-appshell__canvas {
67
+ grid-area: canvas;
68
+ min-width: 0;
69
+ }
70
+
71
+ .fds-appshell__aipanel {
72
+ grid-area: aipanel;
73
+ }
74
+
75
+ .fds-appshell__statusbar {
76
+ grid-area: statusbar;
77
+ }
78
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ commandbar?: Snippet;
4
+ sidebar?: Snippet;
5
+ canvas?: Snippet;
6
+ aipanel?: Snippet;
7
+ statusbar?: Snippet;
8
+ }
9
+ declare const AppShell: import("svelte").Component<Props, {}, "">;
10
+ type AppShell = ReturnType<typeof AppShell>;
11
+ export default AppShell;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ children?: Snippet;
6
+ }
7
+
8
+ let { children }: Props = $props();
9
+ </script>
10
+
11
+ <main class="fds-canvas">
12
+ {#if children}
13
+ {@render children()}
14
+ {/if}
15
+ </main>
16
+
17
+ <style>
18
+ .fds-canvas {
19
+ overflow: auto;
20
+ background: var(--fds-canvas-bg);
21
+ }
22
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ children?: Snippet;
4
+ }
5
+ declare const Canvas: import("svelte").Component<Props, {}, "">;
6
+ type Canvas = ReturnType<typeof Canvas>;
7
+ export default Canvas;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ children?: Snippet;
6
+ }
7
+
8
+ let { children }: Props = $props();
9
+ </script>
10
+
11
+ <header class="fds-commandbar">
12
+ {#if children}
13
+ {@render children()}
14
+ {/if}
15
+ </header>
16
+
17
+ <style>
18
+ .fds-commandbar {
19
+ display: flex;
20
+ align-items: center;
21
+ padding: var(--fds-commandbar-padding);
22
+ background: var(--fds-commandbar-bg);
23
+ border-bottom: 1px solid var(--fds-commandbar-border-color);
24
+ }
25
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ children?: Snippet;
4
+ }
5
+ declare const CommandBar: import("svelte").Component<Props, {}, "">;
6
+ type CommandBar = ReturnType<typeof CommandBar>;
7
+ export default CommandBar;
@@ -0,0 +1,157 @@
1
+ <script lang="ts" module>
2
+ export type PanelSide = 'left' | 'right';
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import type { Snippet } from 'svelte';
7
+
8
+ interface Props {
9
+ side?: PanelSide;
10
+ collapsed?: boolean;
11
+ width?: number;
12
+ minWidth?: number;
13
+ maxWidth?: number;
14
+ children?: Snippet;
15
+ }
16
+
17
+ let {
18
+ side = 'left',
19
+ collapsed = $bindable(false),
20
+ width = $bindable(280),
21
+ minWidth = 200,
22
+ maxWidth = 480,
23
+ children,
24
+ }: Props = $props();
25
+
26
+ let resizing = $state(false);
27
+ let startX = 0;
28
+ let startWidth = 0;
29
+
30
+ function onPointerDown(e: PointerEvent) {
31
+ const handle = e.currentTarget as HTMLElement;
32
+ handle.setPointerCapture(e.pointerId);
33
+ resizing = true;
34
+ startX = e.clientX;
35
+ startWidth = width;
36
+ document.body.style.userSelect = 'none';
37
+ document.body.style.cursor = 'col-resize';
38
+ }
39
+
40
+ function onPointerMove(e: PointerEvent) {
41
+ if (!resizing) return;
42
+ const delta = side === 'left' ? e.clientX - startX : startX - e.clientX;
43
+ width = Math.min(maxWidth, Math.max(minWidth, startWidth + delta));
44
+ }
45
+
46
+ function onPointerUp(e: PointerEvent) {
47
+ if (!resizing) return;
48
+ const handle = e.currentTarget as HTMLElement;
49
+ handle.releasePointerCapture(e.pointerId);
50
+ resizing = false;
51
+ document.body.style.userSelect = '';
52
+ document.body.style.cursor = '';
53
+ }
54
+
55
+ function onKeyDown(e: KeyboardEvent) {
56
+ const step = 10;
57
+ if (e.key === 'ArrowLeft') {
58
+ e.preventDefault();
59
+ width = Math.max(minWidth, width - step);
60
+ } else if (e.key === 'ArrowRight') {
61
+ e.preventDefault();
62
+ width = Math.min(maxWidth, width + step);
63
+ }
64
+ }
65
+ </script>
66
+
67
+ <div
68
+ class="fds-panel fds-panel--{side}"
69
+ class:fds-panel--collapsed={collapsed}
70
+ style:width="{collapsed ? 0 : width}px"
71
+ >
72
+ <div class="fds-panel__content" aria-hidden={collapsed}>
73
+ {#if children}
74
+ {@render children()}
75
+ {/if}
76
+ </div>
77
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex, a11y_no_noninteractive_element_interactions -->
78
+ <div
79
+ class="fds-panel__handle"
80
+ role="separator"
81
+ aria-orientation="vertical"
82
+ aria-valuenow={width}
83
+ aria-valuemin={minWidth}
84
+ aria-valuemax={maxWidth}
85
+ tabindex="0"
86
+ onpointerdown={onPointerDown}
87
+ onpointermove={onPointerMove}
88
+ onpointerup={onPointerUp}
89
+ onlostpointercapture={onPointerUp}
90
+ onkeydown={onKeyDown}
91
+ ></div>
92
+ </div>
93
+
94
+ <style>
95
+ .fds-panel {
96
+ position: relative;
97
+ display: flex;
98
+ flex-direction: row;
99
+ background: var(--fds-panel-bg);
100
+ overflow: hidden;
101
+ transition: width 0.2s ease; /* TODO(v0.2): migrate to motion tokens */
102
+ flex-shrink: 0;
103
+ }
104
+
105
+ .fds-panel--collapsed {
106
+ width: 0 !important;
107
+ }
108
+
109
+ .fds-panel__content {
110
+ flex: 1;
111
+ min-width: 0;
112
+ overflow: auto;
113
+ }
114
+
115
+ .fds-panel__handle {
116
+ position: absolute;
117
+ top: 0;
118
+ bottom: 0;
119
+ width: var(--fds-panel-handle-width);
120
+ background: var(--fds-panel-handle-color);
121
+ cursor: col-resize;
122
+ z-index: 1;
123
+ flex-shrink: 0;
124
+ touch-action: none;
125
+ }
126
+
127
+ .fds-panel__handle:hover {
128
+ background: var(--fds-panel-handle-color-hover);
129
+ }
130
+
131
+ .fds-panel__handle:active {
132
+ background: var(--fds-panel-handle-color-active);
133
+ }
134
+
135
+ .fds-panel__handle:focus-visible {
136
+ outline: 2px solid var(--fds-color-border-focus, currentColor);
137
+ outline-offset: -2px;
138
+ }
139
+
140
+ /* Left panel: handle on right edge */
141
+ .fds-panel--left .fds-panel__handle {
142
+ right: 0;
143
+ }
144
+
145
+ /* Right panel: handle on left edge */
146
+ .fds-panel--right .fds-panel__handle {
147
+ left: 0;
148
+ }
149
+
150
+ .fds-panel--right {
151
+ border-left: 1px solid var(--fds-panel-border-color);
152
+ }
153
+
154
+ .fds-panel--left {
155
+ border-right: 1px solid var(--fds-panel-border-color);
156
+ }
157
+ </style>
@@ -0,0 +1,13 @@
1
+ export type PanelSide = 'left' | 'right';
2
+ import type { Snippet } from 'svelte';
3
+ interface Props {
4
+ side?: PanelSide;
5
+ collapsed?: boolean;
6
+ width?: number;
7
+ minWidth?: number;
8
+ maxWidth?: number;
9
+ children?: Snippet;
10
+ }
11
+ declare const Panel: import("svelte").Component<Props, {}, "collapsed" | "width">;
12
+ type Panel = ReturnType<typeof Panel>;
13
+ export default Panel;
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import Panel from './Panel.svelte';
4
+
5
+ interface Props {
6
+ collapsed?: boolean;
7
+ width?: number;
8
+ minWidth?: number;
9
+ maxWidth?: number;
10
+ children?: Snippet;
11
+ }
12
+
13
+ let {
14
+ collapsed = $bindable(false),
15
+ width = $bindable(280),
16
+ minWidth = 200,
17
+ maxWidth = 480,
18
+ children,
19
+ }: Props = $props();
20
+ </script>
21
+
22
+ <nav class="fds-sidebar" aria-label="Sidebar">
23
+ <Panel side="left" bind:collapsed bind:width {minWidth} {maxWidth}>
24
+ {#if children}
25
+ {@render children()}
26
+ {/if}
27
+ </Panel>
28
+ </nav>
29
+
30
+ <style>
31
+ .fds-sidebar {
32
+ display: contents;
33
+ }
34
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ collapsed?: boolean;
4
+ width?: number;
5
+ minWidth?: number;
6
+ maxWidth?: number;
7
+ children?: Snippet;
8
+ }
9
+ declare const Sidebar: import("svelte").Component<Props, {}, "collapsed" | "width">;
10
+ type Sidebar = ReturnType<typeof Sidebar>;
11
+ export default Sidebar;
@@ -0,0 +1,26 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ children?: Snippet;
6
+ }
7
+
8
+ let { children }: Props = $props();
9
+ </script>
10
+
11
+ <footer class="fds-statusbar">
12
+ {#if children}
13
+ {@render children()}
14
+ {/if}
15
+ </footer>
16
+
17
+ <style>
18
+ .fds-statusbar {
19
+ display: flex;
20
+ align-items: center;
21
+ padding: var(--fds-statusbar-padding);
22
+ background: var(--fds-statusbar-bg);
23
+ border-top: 1px solid var(--fds-statusbar-border-color);
24
+ font-size: var(--fds-font-label-size, 0.75rem);
25
+ }
26
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ children?: Snippet;
4
+ }
5
+ declare const StatusBar: import("svelte").Component<Props, {}, "">;
6
+ type StatusBar = ReturnType<typeof StatusBar>;
7
+ export default StatusBar;
@@ -0,0 +1,53 @@
1
+ import { createRawSnippet } from "svelte";
2
+ import { tick } from "svelte";
3
+ import { expect } from "vitest";
4
+ /**
5
+ * Creates a Svelte 5 snippet that renders a text node.
6
+ * Use for slot content in component tests.
7
+ */
8
+ export function textSnippet(text) {
9
+ return createRawSnippet(() => ({
10
+ render: () => `<span>${text}</span>`,
11
+ }));
12
+ }
13
+ /**
14
+ * Asserts WAI-ARIA separator attributes on an element.
15
+ */
16
+ export function assertSeparator(el, { now, min, max }) {
17
+ expect(el.getAttribute("role")).toBe("separator");
18
+ expect(el.getAttribute("aria-orientation")).toBe("vertical");
19
+ expect(el.getAttribute("aria-valuenow")).toBe(String(now));
20
+ expect(el.getAttribute("aria-valuemin")).toBe(String(min));
21
+ expect(el.getAttribute("aria-valuemax")).toBe(String(max));
22
+ expect(el.getAttribute("tabindex")).toBe("0");
23
+ }
24
+ /**
25
+ * Fires a keyDown event for an arrow key and flushes Svelte state.
26
+ */
27
+ export async function pressArrow(el, key) {
28
+ el.dispatchEvent(new KeyboardEvent("keydown", { key, bubbles: true }));
29
+ await tick();
30
+ }
31
+ /**
32
+ * Asserts a landmark element exists with the expected aria-label.
33
+ */
34
+ export function assertLandmark(container, tag, label) {
35
+ const el = container.querySelector(tag);
36
+ expect(el, `expected <${tag}> element`).not.toBeNull();
37
+ expect(el.getAttribute("aria-label")).toBe(label);
38
+ }
39
+ /**
40
+ * Asserts a zone element exists with the expected tag and CSS class.
41
+ */
42
+ export function assertZone(container, tag, className) {
43
+ const el = container.querySelector(`${tag}.${className}`);
44
+ expect(el, `expected <${tag}> with class .${className}`).not.toBeNull();
45
+ }
46
+ /**
47
+ * Queries the separator element within a container. Throws if not found.
48
+ */
49
+ export function getSeparator(container) {
50
+ const el = container.querySelector('[role="separator"]');
51
+ expect(el, "expected [role=separator] element").not.toBeNull();
52
+ return el;
53
+ }
@@ -0,0 +1,8 @@
1
+ export { default as Panel } from "./Panel.svelte";
2
+ export type { PanelSide } from "./Panel.svelte";
3
+ export { default as AppShell } from "./AppShell.svelte";
4
+ export { default as CommandBar } from "./CommandBar.svelte";
5
+ export { default as Canvas } from "./Canvas.svelte";
6
+ export { default as StatusBar } from "./StatusBar.svelte";
7
+ export { default as Sidebar } from "./Sidebar.svelte";
8
+ export { default as AIPanel } from "./AIPanel.svelte";
@@ -0,0 +1,7 @@
1
+ export { default as Panel } from "./Panel.svelte";
2
+ export { default as AppShell } from "./AppShell.svelte";
3
+ export { default as CommandBar } from "./CommandBar.svelte";
4
+ export { default as Canvas } from "./Canvas.svelte";
5
+ export { default as StatusBar } from "./StatusBar.svelte";
6
+ export { default as Sidebar } from "./Sidebar.svelte";
7
+ export { default as AIPanel } from "./AIPanel.svelte";