sh3-core 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 (134) hide show
  1. package/dist/Shell.svelte +185 -0
  2. package/dist/Shell.svelte.d.ts +4 -0
  3. package/dist/api.d.ts +22 -0
  4. package/dist/api.js +45 -0
  5. package/dist/apps/lifecycle.d.ts +37 -0
  6. package/dist/apps/lifecycle.js +153 -0
  7. package/dist/apps/registry.svelte.d.ts +37 -0
  8. package/dist/apps/registry.svelte.js +60 -0
  9. package/dist/apps/types.d.ts +61 -0
  10. package/dist/apps/types.js +10 -0
  11. package/dist/assets/icons.svg +1119 -0
  12. package/dist/auth/auth.svelte.d.ts +44 -0
  13. package/dist/auth/auth.svelte.js +119 -0
  14. package/dist/auth/index.d.ts +1 -0
  15. package/dist/auth/index.js +1 -0
  16. package/dist/build.d.ts +29 -0
  17. package/dist/build.js +85 -0
  18. package/dist/contract.d.ts +20 -0
  19. package/dist/contract.js +28 -0
  20. package/dist/documents/backends.d.ts +17 -0
  21. package/dist/documents/backends.js +156 -0
  22. package/dist/documents/config.d.ts +7 -0
  23. package/dist/documents/config.js +27 -0
  24. package/dist/documents/handle.d.ts +6 -0
  25. package/dist/documents/handle.js +154 -0
  26. package/dist/documents/http-backend.d.ts +22 -0
  27. package/dist/documents/http-backend.js +78 -0
  28. package/dist/documents/index.d.ts +6 -0
  29. package/dist/documents/index.js +8 -0
  30. package/dist/documents/notifications.d.ts +9 -0
  31. package/dist/documents/notifications.js +39 -0
  32. package/dist/documents/types.d.ts +97 -0
  33. package/dist/documents/types.js +12 -0
  34. package/dist/host-entry.d.ts +9 -0
  35. package/dist/host-entry.js +15 -0
  36. package/dist/host.d.ts +13 -0
  37. package/dist/host.js +73 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +13 -0
  40. package/dist/layout/DragPreview.svelte +63 -0
  41. package/dist/layout/DragPreview.svelte.d.ts +3 -0
  42. package/dist/layout/LayoutRenderer.svelte +260 -0
  43. package/dist/layout/LayoutRenderer.svelte.d.ts +6 -0
  44. package/dist/layout/SlotContainer.svelte +140 -0
  45. package/dist/layout/SlotContainer.svelte.d.ts +8 -0
  46. package/dist/layout/SlotDropZone.svelte +122 -0
  47. package/dist/layout/SlotDropZone.svelte.d.ts +8 -0
  48. package/dist/layout/drag.svelte.d.ts +45 -0
  49. package/dist/layout/drag.svelte.js +191 -0
  50. package/dist/layout/inspection.d.ts +52 -0
  51. package/dist/layout/inspection.js +157 -0
  52. package/dist/layout/ops.d.ts +78 -0
  53. package/dist/layout/ops.js +281 -0
  54. package/dist/layout/slotHostPool.svelte.d.ts +36 -0
  55. package/dist/layout/slotHostPool.svelte.js +229 -0
  56. package/dist/layout/store.svelte.d.ts +39 -0
  57. package/dist/layout/store.svelte.js +150 -0
  58. package/dist/layout/tree-walk.d.ts +15 -0
  59. package/dist/layout/tree-walk.js +33 -0
  60. package/dist/layout/types.d.ts +108 -0
  61. package/dist/layout/types.js +25 -0
  62. package/dist/overlays/ModalFrame.svelte +87 -0
  63. package/dist/overlays/ModalFrame.svelte.d.ts +10 -0
  64. package/dist/overlays/PopupFrame.svelte +85 -0
  65. package/dist/overlays/PopupFrame.svelte.d.ts +10 -0
  66. package/dist/overlays/ToastItem.svelte +77 -0
  67. package/dist/overlays/ToastItem.svelte.d.ts +9 -0
  68. package/dist/overlays/focusTrap.d.ts +1 -0
  69. package/dist/overlays/focusTrap.js +64 -0
  70. package/dist/overlays/modal.d.ts +9 -0
  71. package/dist/overlays/modal.js +141 -0
  72. package/dist/overlays/popup.d.ts +9 -0
  73. package/dist/overlays/popup.js +108 -0
  74. package/dist/overlays/roots.d.ts +4 -0
  75. package/dist/overlays/roots.js +31 -0
  76. package/dist/overlays/toast.d.ts +6 -0
  77. package/dist/overlays/toast.js +93 -0
  78. package/dist/overlays/types.d.ts +31 -0
  79. package/dist/overlays/types.js +15 -0
  80. package/dist/primitives/.gitkeep +0 -0
  81. package/dist/primitives/ResizableSplitter.svelte +333 -0
  82. package/dist/primitives/ResizableSplitter.svelte.d.ts +35 -0
  83. package/dist/primitives/TabbedPanel.svelte +305 -0
  84. package/dist/primitives/TabbedPanel.svelte.d.ts +50 -0
  85. package/dist/registry/client.d.ts +74 -0
  86. package/dist/registry/client.js +118 -0
  87. package/dist/registry/index.d.ts +13 -0
  88. package/dist/registry/index.js +14 -0
  89. package/dist/registry/installer.d.ts +53 -0
  90. package/dist/registry/installer.js +170 -0
  91. package/dist/registry/integrity.d.ts +32 -0
  92. package/dist/registry/integrity.js +92 -0
  93. package/dist/registry/loader.d.ts +50 -0
  94. package/dist/registry/loader.js +145 -0
  95. package/dist/registry/schema.d.ts +47 -0
  96. package/dist/registry/schema.js +180 -0
  97. package/dist/registry/storage.d.ts +37 -0
  98. package/dist/registry/storage.js +101 -0
  99. package/dist/registry/types.d.ts +245 -0
  100. package/dist/registry/types.js +14 -0
  101. package/dist/registry-shard/RegistryView.svelte +561 -0
  102. package/dist/registry-shard/RegistryView.svelte.d.ts +3 -0
  103. package/dist/registry-shard/registryApp.d.ts +10 -0
  104. package/dist/registry-shard/registryApp.js +24 -0
  105. package/dist/registry-shard/registryShard.svelte.d.ts +45 -0
  106. package/dist/registry-shard/registryShard.svelte.js +125 -0
  107. package/dist/shards/activate.svelte.d.ts +45 -0
  108. package/dist/shards/activate.svelte.js +124 -0
  109. package/dist/shards/registry.d.ts +4 -0
  110. package/dist/shards/registry.js +28 -0
  111. package/dist/shards/types.d.ts +155 -0
  112. package/dist/shards/types.js +20 -0
  113. package/dist/shell-shard/ShellHome.svelte +285 -0
  114. package/dist/shell-shard/ShellHome.svelte.d.ts +3 -0
  115. package/dist/shell-shard/shellShard.svelte.d.ts +2 -0
  116. package/dist/shell-shard/shellShard.svelte.js +47 -0
  117. package/dist/shellRuntime.svelte.d.ts +27 -0
  118. package/dist/shellRuntime.svelte.js +27 -0
  119. package/dist/state/backends.d.ts +26 -0
  120. package/dist/state/backends.js +99 -0
  121. package/dist/state/types.d.ts +38 -0
  122. package/dist/state/types.js +15 -0
  123. package/dist/state/zones.svelte.d.ts +52 -0
  124. package/dist/state/zones.svelte.js +141 -0
  125. package/dist/store/InstalledView.svelte +201 -0
  126. package/dist/store/InstalledView.svelte.d.ts +3 -0
  127. package/dist/store/StoreView.svelte +470 -0
  128. package/dist/store/StoreView.svelte.d.ts +3 -0
  129. package/dist/store/storeApp.d.ts +11 -0
  130. package/dist/store/storeApp.js +26 -0
  131. package/dist/store/storeShard.svelte.d.ts +29 -0
  132. package/dist/store/storeShard.svelte.js +99 -0
  133. package/dist/tokens.css +79 -0
  134. package/package.json +50 -0
@@ -0,0 +1,9 @@
1
+ import { type Component } from 'svelte';
2
+ import type { ModalHandle, ModalOptions } from './types';
3
+ export interface ModalManager {
4
+ open<P extends Record<string, unknown>>(Content: Component<P & {
5
+ close: () => void;
6
+ }>, props?: P, options?: ModalOptions): ModalHandle;
7
+ closeAll(): void;
8
+ }
9
+ export declare const modalManager: ModalManager;
@@ -0,0 +1,141 @@
1
+ /*
2
+ * Modal manager — stackable, Escape-dismissed, focus-trapped dialogs.
3
+ *
4
+ * Public API:
5
+ * modalManager.open(Content, props?) → ModalHandle
6
+ * modalManager.closeAll()
7
+ *
8
+ * Semantics (from docs/design/layout.md):
9
+ * - Modals stack. Opening a second modal pushes it on top of the first.
10
+ * - Escape pops the topmost modal.
11
+ * - Backdrop click does NOT dismiss. Content owns its own close UI.
12
+ * - Each modal has its own focus trap (installed by ModalFrame).
13
+ *
14
+ * Implementation notes:
15
+ * - Each open() creates a per-modal host <div> under the layer-4 root
16
+ * and mounts a ModalFrame into it. The host isolates modals for clean
17
+ * unmount/remove.
18
+ * - A SINGLE shared backdrop element is inserted into the layer-4 root
19
+ * on the first open and removed on the last close. It is repositioned
20
+ * on every stack change to sit directly BENEATH the topmost modal host
21
+ * (and above all other modal hosts), so stacked modals read as dimmed
22
+ * and clearly non-interactive while the top modal renders clear. The
23
+ * opacity is a single fixed value — depth-scaled opacity (an earlier
24
+ * cut) is no longer meaningful because only the "layer beneath the
25
+ * top" is ever being dimmed. Per-modal backdrops were the phase-5
26
+ * first cut; they compounded (2 modals ≈ 0.75, 3 ≈ 0.88, …) and were
27
+ * both unbounded and expensive.
28
+ * - The manager owns a single document-level Escape listener, installed
29
+ * lazily on first open and removed when the stack empties. This is
30
+ * simpler than per-modal listeners and avoids "which listener wins"
31
+ * ordering puzzles when modals stack.
32
+ * - close() is idempotent: calling it after the modal has been removed
33
+ * is a no-op, which makes it safe for content components to call from
34
+ * both a close button and an "async action finished" callback.
35
+ */
36
+ import { mount, unmount } from 'svelte';
37
+ import ModalFrame from './ModalFrame.svelte';
38
+ import { getLayerRoot } from './roots';
39
+ const stack = [];
40
+ let escapeInstalled = false;
41
+ let backdrop = null;
42
+ /** Single fixed backdrop opacity. The backdrop is repositioned beneath
43
+ * the topmost modal on every stack change, so underlying modals appear
44
+ * dimmed (visually communicating they're non-interactive) while the top
45
+ * modal sits above the dim. Depth-scaled opacity is therefore obsolete:
46
+ * only one "layer beneath the top" is ever being dimmed. */
47
+ const BACKDROP_OPACITY = 0.5;
48
+ function syncBackdrop() {
49
+ const root = getLayerRoot('modal');
50
+ if (stack.length === 0) {
51
+ if (backdrop) {
52
+ backdrop.remove();
53
+ backdrop = null;
54
+ }
55
+ return;
56
+ }
57
+ if (!backdrop) {
58
+ backdrop = document.createElement('div');
59
+ backdrop.className = 'sh3-modal-backdrop';
60
+ backdrop.style.position = 'absolute';
61
+ backdrop.style.inset = '0';
62
+ backdrop.style.pointerEvents = 'auto';
63
+ backdrop.style.transition = 'background-color 120ms ease';
64
+ backdrop.style.background = `rgba(0, 0, 0, ${BACKDROP_OPACITY})`;
65
+ }
66
+ // Place the backdrop directly before the topmost modal host so every
67
+ // modal beneath it is dimmed while the top modal renders clear above.
68
+ const topHost = stack[stack.length - 1].host;
69
+ root.insertBefore(backdrop, topHost);
70
+ }
71
+ function onDocumentKeydown(e) {
72
+ if (e.key !== 'Escape')
73
+ return;
74
+ if (stack.length === 0)
75
+ return;
76
+ e.stopPropagation();
77
+ e.preventDefault();
78
+ stack[stack.length - 1].handle.close();
79
+ }
80
+ function ensureEscapeListener() {
81
+ if (escapeInstalled)
82
+ return;
83
+ escapeInstalled = true;
84
+ document.addEventListener('keydown', onDocumentKeydown, true);
85
+ }
86
+ function removeEscapeListenerIfIdle() {
87
+ if (stack.length > 0)
88
+ return;
89
+ if (!escapeInstalled)
90
+ return;
91
+ escapeInstalled = false;
92
+ document.removeEventListener('keydown', onDocumentKeydown, true);
93
+ }
94
+ function removeEntry(entry) {
95
+ const idx = stack.indexOf(entry);
96
+ if (idx < 0)
97
+ return; // already closed — idempotent
98
+ stack.splice(idx, 1);
99
+ unmount(entry.frame);
100
+ entry.host.remove();
101
+ syncBackdrop();
102
+ removeEscapeListenerIfIdle();
103
+ }
104
+ function openModal(Content, props, options) {
105
+ const root = getLayerRoot('modal');
106
+ const host = document.createElement('div');
107
+ host.className = 'sh3-modal-host';
108
+ host.style.position = 'absolute';
109
+ host.style.inset = '0';
110
+ host.style.pointerEvents = 'auto';
111
+ root.appendChild(host);
112
+ const entry = {};
113
+ const handle = {
114
+ close: () => removeEntry(entry),
115
+ };
116
+ const frame = mount(ModalFrame, {
117
+ target: host,
118
+ props: {
119
+ Content: Content,
120
+ contentProps: (props !== null && props !== void 0 ? props : {}),
121
+ close: handle.close,
122
+ boxStyle: options === null || options === void 0 ? void 0 : options.boxStyle,
123
+ },
124
+ });
125
+ entry.host = host;
126
+ entry.frame = frame;
127
+ entry.handle = handle;
128
+ stack.push(entry);
129
+ syncBackdrop();
130
+ ensureEscapeListener();
131
+ return handle;
132
+ }
133
+ function closeAll() {
134
+ while (stack.length > 0) {
135
+ removeEntry(stack[stack.length - 1]);
136
+ }
137
+ }
138
+ export const modalManager = {
139
+ open: openModal,
140
+ closeAll,
141
+ };
@@ -0,0 +1,9 @@
1
+ import { type Component } from 'svelte';
2
+ import type { PopupHandle, PopupOptions } from './types';
3
+ export interface PopupManager {
4
+ show<P extends Record<string, unknown>>(Content: Component<P & {
5
+ close: () => void;
6
+ }>, options: PopupOptions, props?: P): PopupHandle;
7
+ close(): void;
8
+ }
9
+ export declare const popupManager: PopupManager;
@@ -0,0 +1,108 @@
1
+ /*
2
+ * Popup manager — anchored, non-stacking, outside-click-dismissable.
3
+ *
4
+ * Public API:
5
+ * popupManager.show(Content, { anchor, placement? }, props?) → PopupHandle
6
+ * popupManager.close()
7
+ *
8
+ * Semantics (from docs/design/layout.md):
9
+ * - Popups do NOT stack. Opening a second popup dismisses the first.
10
+ * - Clicking outside the popup dismisses it.
11
+ * - Pressing Escape dismisses it.
12
+ * - The caller provides an HTMLElement anchor; the popup positions
13
+ * itself relative to the anchor's current viewport rect.
14
+ *
15
+ * Implementation notes:
16
+ * - The manager keeps at most one active entry. show() closes any
17
+ * prior entry before opening a new one — so callers can wire a
18
+ * menu button to `shell.popup.show(...)` without worrying about
19
+ * toggling themselves.
20
+ * - Dismissal listeners (pointerdown for outside-click, keydown for
21
+ * Escape) are installed when the popup opens and removed on close.
22
+ * Outside-click detection uses the mounted frame element's DOM
23
+ * containment check, so nested popups-inside-content still click-
24
+ * through without closing (there are no nested popups in phase 5,
25
+ * but the check is cheap and correct).
26
+ * - close() is idempotent.
27
+ */
28
+ import { mount, unmount } from 'svelte';
29
+ import PopupFrame from './PopupFrame.svelte';
30
+ import { getLayerRoot } from './roots';
31
+ let current = null;
32
+ function onDocumentPointerDown(e) {
33
+ if (!current)
34
+ return;
35
+ const target = e.target;
36
+ if (target && current.host.contains(target))
37
+ return;
38
+ current.handle.close();
39
+ }
40
+ function onDocumentKeydown(e) {
41
+ if (!current)
42
+ return;
43
+ if (e.key !== 'Escape')
44
+ return;
45
+ e.stopPropagation();
46
+ e.preventDefault();
47
+ current.handle.close();
48
+ }
49
+ function installDismissListeners() {
50
+ // `true` capture phase so we see the event before view-level handlers
51
+ // that might stopPropagation.
52
+ document.addEventListener('pointerdown', onDocumentPointerDown, true);
53
+ document.addEventListener('keydown', onDocumentKeydown, true);
54
+ }
55
+ function removeDismissListeners() {
56
+ document.removeEventListener('pointerdown', onDocumentPointerDown, true);
57
+ document.removeEventListener('keydown', onDocumentKeydown, true);
58
+ }
59
+ function removeEntry(entry) {
60
+ if (current !== entry)
61
+ return; // already closed / superseded
62
+ current = null;
63
+ removeDismissListeners();
64
+ unmount(entry.frame);
65
+ entry.host.remove();
66
+ }
67
+ function showPopup(Content, options, props) {
68
+ // Non-stacking: dismiss any existing popup first.
69
+ if (current)
70
+ removeEntry(current);
71
+ const root = getLayerRoot('popup');
72
+ const host = document.createElement('div');
73
+ host.className = 'sh3-popup-host';
74
+ host.style.position = 'absolute';
75
+ host.style.inset = '0';
76
+ host.style.pointerEvents = 'none'; // only the frame captures pointer events
77
+ root.appendChild(host);
78
+ const anchorRect = options.anchor.getBoundingClientRect();
79
+ const entry = {};
80
+ const handle = {
81
+ close: () => removeEntry(entry),
82
+ };
83
+ const frame = mount(PopupFrame, {
84
+ target: host,
85
+ props: {
86
+ Content: Content,
87
+ contentProps: (props !== null && props !== void 0 ? props : {}),
88
+ anchorRect,
89
+ close: handle.close,
90
+ },
91
+ });
92
+ entry.host = host;
93
+ entry.frame = frame;
94
+ entry.handle = handle;
95
+ current = entry;
96
+ // Defer listener install by a microtask so the same pointerdown that
97
+ // opened the popup (from a button click) doesn't instantly dismiss it.
98
+ queueMicrotask(installDismissListeners);
99
+ return handle;
100
+ }
101
+ function closeCurrent() {
102
+ if (current)
103
+ removeEntry(current);
104
+ }
105
+ export const popupManager = {
106
+ show: showPopup,
107
+ close: closeCurrent,
108
+ };
@@ -0,0 +1,4 @@
1
+ import type { OverlayLayer } from './types';
2
+ export declare function registerLayerRoot(layer: OverlayLayer, el: HTMLElement): void;
3
+ export declare function unregisterLayerRoot(layer: OverlayLayer): void;
4
+ export declare function getLayerRoot(layer: OverlayLayer): HTMLElement;
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Layer root registry.
3
+ *
4
+ * Shell.svelte owns the six overlay root <div>s (one per layer). Overlay
5
+ * managers — which are plain TypeScript modules, not Svelte components —
6
+ * need DOM references to those roots so they can append transient content
7
+ * (modals, popups, toasts) into the correct stacking context.
8
+ *
9
+ * Shell.svelte calls `registerLayerRoot(name, el)` on each root during its
10
+ * own mount effect. Managers call `getLayerRoot(name)` lazily the first
11
+ * time they need to open something, which is always *after* Shell has
12
+ * rendered because overlay triggers originate from views mounted into the
13
+ * layout tree. No race; no DOM queries.
14
+ *
15
+ * Unregister is exposed too so tests and hot-reload can reset the registry.
16
+ */
17
+ const roots = {};
18
+ export function registerLayerRoot(layer, el) {
19
+ roots[layer] = el;
20
+ }
21
+ export function unregisterLayerRoot(layer) {
22
+ delete roots[layer];
23
+ }
24
+ export function getLayerRoot(layer) {
25
+ const el = roots[layer];
26
+ if (!el) {
27
+ throw new Error(`Overlay layer "${layer}" root is not registered — ` +
28
+ `Shell.svelte must mount before opening overlays on this layer.`);
29
+ }
30
+ return el;
31
+ }
@@ -0,0 +1,6 @@
1
+ import type { ToastHandle, ToastOptions } from './types';
2
+ export interface ToastManager {
3
+ notify(message: string, options?: ToastOptions): ToastHandle;
4
+ clear(): void;
5
+ }
6
+ export declare const toastManager: ToastManager;
@@ -0,0 +1,93 @@
1
+ /*
2
+ * Toast manager — auto-dismissing non-interactive notifications.
3
+ *
4
+ * Public API:
5
+ * toastManager.notify(message, options?) → ToastHandle
6
+ * toastManager.clear()
7
+ *
8
+ * Semantics (from docs/design/layout.md):
9
+ * - Toasts queue and stack vertically at the bottom-right of the shell.
10
+ * - Each toast auto-dismisses after `duration` ms (default 3000).
11
+ * `duration: Infinity` pins the toast until the caller calls close().
12
+ * - Clicking a toast dismisses it immediately.
13
+ * - Level styling: info / warn / error / success.
14
+ *
15
+ * Implementation notes:
16
+ * - A lazy layout container is appended to the layer-5 root on first
17
+ * notify; it's a flex column anchored to the bottom-right with a
18
+ * small gap between toasts.
19
+ * - Each toast is a standalone mount — simpler than a single list
20
+ * component tracking an array, and naturally handles independent
21
+ * fade-in animations per item.
22
+ * - The manager tracks entries for `clear()` and for idempotent close.
23
+ */
24
+ import { mount, unmount } from 'svelte';
25
+ import ToastItem from './ToastItem.svelte';
26
+ import { getLayerRoot } from './roots';
27
+ const entries = new Set();
28
+ let container = null;
29
+ function ensureContainer() {
30
+ if (container && container.isConnected)
31
+ return container;
32
+ const root = getLayerRoot('toast');
33
+ container = document.createElement('div');
34
+ container.className = 'sh3-toast-stack';
35
+ container.style.position = 'absolute';
36
+ container.style.right = '16px';
37
+ container.style.bottom = '16px';
38
+ container.style.display = 'flex';
39
+ container.style.flexDirection = 'column-reverse';
40
+ container.style.gap = '6px';
41
+ container.style.pointerEvents = 'none';
42
+ root.appendChild(container);
43
+ return container;
44
+ }
45
+ function removeEntry(entry) {
46
+ if (!entries.has(entry))
47
+ return;
48
+ entries.delete(entry);
49
+ if (entry.timer !== null) {
50
+ clearTimeout(entry.timer);
51
+ entry.timer = null;
52
+ }
53
+ unmount(entry.instance);
54
+ entry.host.remove();
55
+ }
56
+ function notify(message, options = {}) {
57
+ var _a, _b;
58
+ const level = (_a = options.level) !== null && _a !== void 0 ? _a : 'info';
59
+ const duration = (_b = options.duration) !== null && _b !== void 0 ? _b : 3000;
60
+ const parent = ensureContainer();
61
+ const host = document.createElement('div');
62
+ host.className = 'sh3-toast-host';
63
+ parent.appendChild(host);
64
+ const entry = {};
65
+ const handle = {
66
+ close: () => removeEntry(entry),
67
+ };
68
+ const instance = mount(ToastItem, {
69
+ target: host,
70
+ props: {
71
+ message,
72
+ level,
73
+ close: handle.close,
74
+ },
75
+ });
76
+ entry.host = host;
77
+ entry.instance = instance;
78
+ entry.handle = handle;
79
+ entry.timer =
80
+ Number.isFinite(duration) && duration > 0
81
+ ? setTimeout(() => removeEntry(entry), duration)
82
+ : null;
83
+ entries.add(entry);
84
+ return handle;
85
+ }
86
+ function clear() {
87
+ for (const entry of [...entries])
88
+ removeEntry(entry);
89
+ }
90
+ export const toastManager = {
91
+ notify,
92
+ clear,
93
+ };
@@ -0,0 +1,31 @@
1
+ export type OverlayLayer = 'floating' | 'drag-preview' | 'popup' | 'modal' | 'toast' | 'command';
2
+ /** A handle returned by every overlay opener. Calling close() is idempotent. */
3
+ export interface OverlayHandle {
4
+ close(): void;
5
+ }
6
+ export type ModalHandle = OverlayHandle;
7
+ export type PopupHandle = OverlayHandle;
8
+ export type ToastHandle = OverlayHandle;
9
+ export type ToastLevel = 'info' | 'warn' | 'error' | 'success';
10
+ /** Where a popup should sit relative to its anchor. Phase 5 ships bottom-start. */
11
+ export type PopupPlacement = 'bottom-start';
12
+ export interface PopupOptions {
13
+ anchor: HTMLElement;
14
+ placement?: PopupPlacement;
15
+ }
16
+ export interface ToastOptions {
17
+ level?: ToastLevel;
18
+ /** Auto-dismiss after this many ms. `Infinity` disables auto-dismiss. */
19
+ duration?: number;
20
+ }
21
+ export interface ModalOptions {
22
+ /**
23
+ * Inline style string applied to the modal's dialog box. Lets callers
24
+ * override the default centered-auto-sized layout for custom sizing
25
+ * and positioning. Setting `position: absolute; top: …; left: …`
26
+ * escapes the frame's grid centering and places the box at the given
27
+ * viewport-relative coordinates. Useful for test scaffolding and for
28
+ * views like non-centered palettes or inspectors.
29
+ */
30
+ boxStyle?: string;
31
+ }
@@ -0,0 +1,15 @@
1
+ /*
2
+ * Overlay API types — shared between layer managers.
3
+ *
4
+ * The "layer" concept comes from docs/design/layout.md: overlays live
5
+ * above the docked layout in an explicit numbered stack (0 = docked,
6
+ * 1 = floating, 2 = drag preview, 3 = popup, 4 = modal, 5 = toast,
7
+ * 6 = command palette). Phase 5 wires up layers 3/4/5; the rest are
8
+ * stubbed as DOM roots in Shell.svelte but have no managers yet.
9
+ *
10
+ * No component in the codebase writes a z-index directly — the only
11
+ * z-index values live on the overlay root divs in Shell.svelte driven
12
+ * by the --shell-z-layer-N tokens. Overlay content is appended into the
13
+ * corresponding layer root and inherits its stacking context.
14
+ */
15
+ export {};
File without changes