sh3-core 0.6.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 (242) hide show
  1. package/README.md +9 -0
  2. package/dist/Shell.svelte +283 -0
  3. package/dist/Shell.svelte.d.ts +5 -0
  4. package/dist/api.d.ts +28 -0
  5. package/dist/api.js +50 -0
  6. package/dist/app/admin/ApiKeysView.svelte +169 -0
  7. package/dist/app/admin/ApiKeysView.svelte.d.ts +3 -0
  8. package/dist/app/admin/AuthSettingsView.svelte +105 -0
  9. package/dist/app/admin/AuthSettingsView.svelte.d.ts +3 -0
  10. package/dist/app/admin/SystemView.svelte +73 -0
  11. package/dist/app/admin/SystemView.svelte.d.ts +3 -0
  12. package/dist/app/admin/UsersView.svelte +188 -0
  13. package/dist/app/admin/UsersView.svelte.d.ts +3 -0
  14. package/dist/app/admin/adminApp.d.ts +7 -0
  15. package/dist/app/admin/adminApp.js +25 -0
  16. package/dist/app/admin/adminShard.svelte.d.ts +4 -0
  17. package/dist/app/admin/adminShard.svelte.js +62 -0
  18. package/dist/app/store/InstalledView.svelte +246 -0
  19. package/dist/app/store/InstalledView.svelte.d.ts +3 -0
  20. package/dist/app/store/StoreView.svelte +522 -0
  21. package/dist/app/store/StoreView.svelte.d.ts +3 -0
  22. package/dist/app/store/storeApp.d.ts +10 -0
  23. package/dist/app/store/storeApp.js +26 -0
  24. package/dist/app/store/storeShard.svelte.d.ts +38 -0
  25. package/dist/app/store/storeShard.svelte.js +218 -0
  26. package/dist/apps/lifecycle.d.ts +42 -0
  27. package/dist/apps/lifecycle.js +184 -0
  28. package/dist/apps/registry.svelte.d.ts +40 -0
  29. package/dist/apps/registry.svelte.js +59 -0
  30. package/dist/apps/terminal/manifest.d.ts +8 -0
  31. package/dist/apps/terminal/manifest.js +13 -0
  32. package/dist/apps/terminal/terminal-app.d.ts +7 -0
  33. package/dist/apps/terminal/terminal-app.js +14 -0
  34. package/dist/apps/types.d.ts +93 -0
  35. package/dist/apps/types.js +10 -0
  36. package/dist/artifact.d.ts +32 -0
  37. package/dist/artifact.js +1 -0
  38. package/dist/assets/SH3.png +0 -0
  39. package/dist/assets/icons.svg +1126 -0
  40. package/dist/assets.d.ts +13 -0
  41. package/dist/auth/GuestBanner.svelte +134 -0
  42. package/dist/auth/GuestBanner.svelte.d.ts +3 -0
  43. package/dist/auth/SignInWall.svelte +203 -0
  44. package/dist/auth/SignInWall.svelte.d.ts +7 -0
  45. package/dist/auth/auth.svelte.d.ts +69 -0
  46. package/dist/auth/auth.svelte.js +165 -0
  47. package/dist/auth/index.d.ts +2 -0
  48. package/dist/auth/index.js +1 -0
  49. package/dist/auth/types.d.ts +41 -0
  50. package/dist/auth/types.js +6 -0
  51. package/dist/build.d.ts +49 -0
  52. package/dist/build.js +236 -0
  53. package/dist/contract.d.ts +20 -0
  54. package/dist/contract.js +28 -0
  55. package/dist/createShell.d.ts +24 -0
  56. package/dist/createShell.js +131 -0
  57. package/dist/documents/backends.d.ts +17 -0
  58. package/dist/documents/backends.js +156 -0
  59. package/dist/documents/config.d.ts +7 -0
  60. package/dist/documents/config.js +27 -0
  61. package/dist/documents/handle.d.ts +6 -0
  62. package/dist/documents/handle.js +154 -0
  63. package/dist/documents/http-backend.d.ts +22 -0
  64. package/dist/documents/http-backend.js +78 -0
  65. package/dist/documents/index.d.ts +6 -0
  66. package/dist/documents/index.js +8 -0
  67. package/dist/documents/notifications.d.ts +9 -0
  68. package/dist/documents/notifications.js +39 -0
  69. package/dist/documents/types.d.ts +97 -0
  70. package/dist/documents/types.js +12 -0
  71. package/dist/env/client.d.ts +44 -0
  72. package/dist/env/client.js +106 -0
  73. package/dist/env/index.d.ts +2 -0
  74. package/dist/env/index.js +1 -0
  75. package/dist/env/types.d.ts +12 -0
  76. package/dist/env/types.js +8 -0
  77. package/dist/host-entry.d.ts +13 -0
  78. package/dist/host-entry.js +17 -0
  79. package/dist/host.d.ts +15 -0
  80. package/dist/host.js +86 -0
  81. package/dist/index.d.ts +4 -0
  82. package/dist/index.js +14 -0
  83. package/dist/layout/DragPreview.svelte +63 -0
  84. package/dist/layout/DragPreview.svelte.d.ts +3 -0
  85. package/dist/layout/LayoutRenderer.svelte +262 -0
  86. package/dist/layout/LayoutRenderer.svelte.d.ts +6 -0
  87. package/dist/layout/SlotContainer.svelte +140 -0
  88. package/dist/layout/SlotContainer.svelte.d.ts +8 -0
  89. package/dist/layout/SlotDropZone.svelte +122 -0
  90. package/dist/layout/SlotDropZone.svelte.d.ts +8 -0
  91. package/dist/layout/drag.svelte.d.ts +45 -0
  92. package/dist/layout/drag.svelte.js +200 -0
  93. package/dist/layout/inspection.d.ts +72 -0
  94. package/dist/layout/inspection.js +209 -0
  95. package/dist/layout/ops.d.ts +100 -0
  96. package/dist/layout/ops.js +310 -0
  97. package/dist/layout/slotHostPool.svelte.d.ts +36 -0
  98. package/dist/layout/slotHostPool.svelte.js +229 -0
  99. package/dist/layout/store.svelte.d.ts +39 -0
  100. package/dist/layout/store.svelte.js +153 -0
  101. package/dist/layout/tree-walk.d.ts +15 -0
  102. package/dist/layout/tree-walk.js +33 -0
  103. package/dist/layout/types.d.ts +108 -0
  104. package/dist/layout/types.js +25 -0
  105. package/dist/migrations/shell-rename.d.ts +16 -0
  106. package/dist/migrations/shell-rename.js +48 -0
  107. package/dist/overlays/ModalFrame.svelte +87 -0
  108. package/dist/overlays/ModalFrame.svelte.d.ts +10 -0
  109. package/dist/overlays/PopupFrame.svelte +85 -0
  110. package/dist/overlays/PopupFrame.svelte.d.ts +10 -0
  111. package/dist/overlays/ToastItem.svelte +77 -0
  112. package/dist/overlays/ToastItem.svelte.d.ts +9 -0
  113. package/dist/overlays/focusTrap.d.ts +1 -0
  114. package/dist/overlays/focusTrap.js +64 -0
  115. package/dist/overlays/modal.d.ts +9 -0
  116. package/dist/overlays/modal.js +141 -0
  117. package/dist/overlays/popup.d.ts +9 -0
  118. package/dist/overlays/popup.js +108 -0
  119. package/dist/overlays/roots.d.ts +4 -0
  120. package/dist/overlays/roots.js +31 -0
  121. package/dist/overlays/toast.d.ts +6 -0
  122. package/dist/overlays/toast.js +93 -0
  123. package/dist/overlays/types.d.ts +31 -0
  124. package/dist/overlays/types.js +15 -0
  125. package/dist/platform/index.d.ts +10 -0
  126. package/dist/platform/index.js +33 -0
  127. package/dist/platform/tauri-backend.d.ts +15 -0
  128. package/dist/platform/tauri-backend.js +58 -0
  129. package/dist/primitives/.gitkeep +0 -0
  130. package/dist/primitives/ResizableSplitter.svelte +333 -0
  131. package/dist/primitives/ResizableSplitter.svelte.d.ts +35 -0
  132. package/dist/primitives/TabbedPanel.svelte +305 -0
  133. package/dist/primitives/TabbedPanel.svelte.d.ts +50 -0
  134. package/dist/primitives/base.css +42 -0
  135. package/dist/registry/client.d.ts +74 -0
  136. package/dist/registry/client.js +117 -0
  137. package/dist/registry/index.d.ts +13 -0
  138. package/dist/registry/index.js +14 -0
  139. package/dist/registry/installer.d.ts +53 -0
  140. package/dist/registry/installer.js +168 -0
  141. package/dist/registry/integrity.d.ts +32 -0
  142. package/dist/registry/integrity.js +92 -0
  143. package/dist/registry/loader.d.ts +50 -0
  144. package/dist/registry/loader.js +145 -0
  145. package/dist/registry/schema.d.ts +47 -0
  146. package/dist/registry/schema.js +185 -0
  147. package/dist/registry/storage.d.ts +37 -0
  148. package/dist/registry/storage.js +101 -0
  149. package/dist/registry/types.d.ts +262 -0
  150. package/dist/registry/types.js +14 -0
  151. package/dist/server-shard/types.d.ts +67 -0
  152. package/dist/server-shard/types.js +13 -0
  153. package/dist/sh3core-shard/ShellHome.svelte +192 -0
  154. package/dist/sh3core-shard/ShellHome.svelte.d.ts +3 -0
  155. package/dist/sh3core-shard/ShellTitle.svelte +171 -0
  156. package/dist/sh3core-shard/ShellTitle.svelte.d.ts +3 -0
  157. package/dist/sh3core-shard/sh3coreShard.svelte.d.ts +2 -0
  158. package/dist/sh3core-shard/sh3coreShard.svelte.js +53 -0
  159. package/dist/shards/activate.svelte.d.ts +52 -0
  160. package/dist/shards/activate.svelte.js +186 -0
  161. package/dist/shards/registry.d.ts +4 -0
  162. package/dist/shards/registry.js +28 -0
  163. package/dist/shards/types.d.ts +207 -0
  164. package/dist/shards/types.js +20 -0
  165. package/dist/shell-shard/InputLine.svelte +133 -0
  166. package/dist/shell-shard/InputLine.svelte.d.ts +11 -0
  167. package/dist/shell-shard/ScrollbackView.svelte +47 -0
  168. package/dist/shell-shard/ScrollbackView.svelte.d.ts +7 -0
  169. package/dist/shell-shard/Terminal.svelte +122 -0
  170. package/dist/shell-shard/Terminal.svelte.d.ts +8 -0
  171. package/dist/shell-shard/entries/PromptEntry.svelte +25 -0
  172. package/dist/shell-shard/entries/PromptEntry.svelte.d.ts +7 -0
  173. package/dist/shell-shard/entries/RichEntry.svelte +19 -0
  174. package/dist/shell-shard/entries/RichEntry.svelte.d.ts +8 -0
  175. package/dist/shell-shard/entries/StatusEntry.svelte +22 -0
  176. package/dist/shell-shard/entries/StatusEntry.svelte.d.ts +7 -0
  177. package/dist/shell-shard/entries/TextEntry.svelte +25 -0
  178. package/dist/shell-shard/entries/TextEntry.svelte.d.ts +7 -0
  179. package/dist/shell-shard/manifest.d.ts +2 -0
  180. package/dist/shell-shard/manifest.js +11 -0
  181. package/dist/shell-shard/protocol.d.ts +90 -0
  182. package/dist/shell-shard/protocol.js +11 -0
  183. package/dist/shell-shard/registry.d.ts +69 -0
  184. package/dist/shell-shard/registry.js +47 -0
  185. package/dist/shell-shard/rich/AppCard.svelte +25 -0
  186. package/dist/shell-shard/rich/AppCard.svelte.d.ts +10 -0
  187. package/dist/shell-shard/rich/AppsTable.svelte +29 -0
  188. package/dist/shell-shard/rich/AppsTable.svelte.d.ts +12 -0
  189. package/dist/shell-shard/rich/EnvTable.svelte +27 -0
  190. package/dist/shell-shard/rich/EnvTable.svelte.d.ts +8 -0
  191. package/dist/shell-shard/rich/HelpTable.svelte +29 -0
  192. package/dist/shell-shard/rich/HelpTable.svelte.d.ts +12 -0
  193. package/dist/shell-shard/rich/HistoryList.svelte +37 -0
  194. package/dist/shell-shard/rich/HistoryList.svelte.d.ts +9 -0
  195. package/dist/shell-shard/rich/ShardsTable.svelte +28 -0
  196. package/dist/shell-shard/rich/ShardsTable.svelte.d.ts +12 -0
  197. package/dist/shell-shard/rich/ViewsTable.svelte +31 -0
  198. package/dist/shell-shard/rich/ViewsTable.svelte.d.ts +13 -0
  199. package/dist/shell-shard/rich/ZoneTree.svelte +19 -0
  200. package/dist/shell-shard/rich/ZoneTree.svelte.d.ts +8 -0
  201. package/dist/shell-shard/rich/ZonesTable.svelte +27 -0
  202. package/dist/shell-shard/rich/ZonesTable.svelte.d.ts +11 -0
  203. package/dist/shell-shard/scrollback.svelte.d.ts +36 -0
  204. package/dist/shell-shard/scrollback.svelte.js +43 -0
  205. package/dist/shell-shard/session-client.svelte.d.ts +23 -0
  206. package/dist/shell-shard/session-client.svelte.js +120 -0
  207. package/dist/shell-shard/shellShard.svelte.d.ts +2 -0
  208. package/dist/shell-shard/shellShard.svelte.js +139 -0
  209. package/dist/shell-shard/verbs/apps.d.ts +3 -0
  210. package/dist/shell-shard/verbs/apps.js +50 -0
  211. package/dist/shell-shard/verbs/clear.d.ts +2 -0
  212. package/dist/shell-shard/verbs/clear.js +7 -0
  213. package/dist/shell-shard/verbs/help.d.ts +2 -0
  214. package/dist/shell-shard/verbs/help.js +21 -0
  215. package/dist/shell-shard/verbs/history.d.ts +2 -0
  216. package/dist/shell-shard/verbs/history.js +20 -0
  217. package/dist/shell-shard/verbs/index.d.ts +2 -0
  218. package/dist/shell-shard/verbs/index.js +29 -0
  219. package/dist/shell-shard/verbs/session.d.ts +5 -0
  220. package/dist/shell-shard/verbs/session.js +65 -0
  221. package/dist/shell-shard/verbs/shards.d.ts +2 -0
  222. package/dist/shell-shard/verbs/shards.js +14 -0
  223. package/dist/shell-shard/verbs/views.d.ts +4 -0
  224. package/dist/shell-shard/verbs/views.js +90 -0
  225. package/dist/shell-shard/verbs/zones.d.ts +3 -0
  226. package/dist/shell-shard/verbs/zones.js +38 -0
  227. package/dist/shellRuntime.svelte.d.ts +27 -0
  228. package/dist/shellRuntime.svelte.js +27 -0
  229. package/dist/state/backends.d.ts +26 -0
  230. package/dist/state/backends.js +99 -0
  231. package/dist/state/manage.d.ts +14 -0
  232. package/dist/state/manage.js +40 -0
  233. package/dist/state/types.d.ts +55 -0
  234. package/dist/state/types.js +17 -0
  235. package/dist/state/zones.svelte.d.ts +53 -0
  236. package/dist/state/zones.svelte.js +141 -0
  237. package/dist/theme.d.ts +28 -0
  238. package/dist/theme.js +92 -0
  239. package/dist/tokens.css +102 -0
  240. package/dist/version.d.ts +2 -0
  241. package/dist/version.js +2 -0
  242. package/package.json +60 -0
@@ -0,0 +1,58 @@
1
+ /*
2
+ * TauriStoreBackend — implements the sh3 Backend interface using
3
+ * @tauri-apps/plugin-store. Each zone gets its own .json store file
4
+ * (e.g. "workspace.json", "user.json") in Tauri's app data directory.
5
+ *
6
+ * tauri-plugin-store v2 keeps an in-memory cache and flushes to disk
7
+ * automatically. We pre-load the full store into a local Map during
8
+ * init(), then serve reads/lists synchronously from that cache —
9
+ * matching the Backend interface contract. Writes go to both the
10
+ * local cache and the Tauri store (fire-and-forget async).
11
+ */
12
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
13
+ if (kind === "m") throw new TypeError("Private method is not writable");
14
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
15
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
16
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
17
+ };
18
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
19
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
20
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
21
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
22
+ };
23
+ var _TauriStoreBackend_store, _TauriStoreBackend_cache;
24
+ import { LazyStore } from '@tauri-apps/plugin-store';
25
+ export class TauriStoreBackend {
26
+ constructor(zoneName) {
27
+ _TauriStoreBackend_store.set(this, void 0);
28
+ _TauriStoreBackend_cache.set(this, new Map());
29
+ __classPrivateFieldSet(this, _TauriStoreBackend_store, new LazyStore(`${zoneName}.json`, { defaults: {}, autoSave: true }), "f");
30
+ }
31
+ read(shardId) {
32
+ return __classPrivateFieldGet(this, _TauriStoreBackend_cache, "f").get(shardId);
33
+ }
34
+ write(shardId, value) {
35
+ __classPrivateFieldGet(this, _TauriStoreBackend_cache, "f").set(shardId, value);
36
+ // Fire-and-forget — autoSave flushes to disk.
37
+ __classPrivateFieldGet(this, _TauriStoreBackend_store, "f").set(shardId, value).catch((e) => console.warn('SH3: store write failed', e));
38
+ }
39
+ delete(shardId) {
40
+ __classPrivateFieldGet(this, _TauriStoreBackend_cache, "f").delete(shardId);
41
+ __classPrivateFieldGet(this, _TauriStoreBackend_store, "f").delete(shardId).catch((e) => console.warn('SH3: store delete failed', e));
42
+ }
43
+ list() {
44
+ return [...__classPrivateFieldGet(this, _TauriStoreBackend_cache, "f").keys()];
45
+ }
46
+ /**
47
+ * Load the store from disk into the local cache. Must be called once
48
+ * before read/list return meaningful data. Called by the platform
49
+ * resolver at boot.
50
+ */
51
+ async init() {
52
+ const entries = await __classPrivateFieldGet(this, _TauriStoreBackend_store, "f").entries();
53
+ for (const [key, value] of entries) {
54
+ __classPrivateFieldGet(this, _TauriStoreBackend_cache, "f").set(key, value);
55
+ }
56
+ }
57
+ }
58
+ _TauriStoreBackend_store = new WeakMap(), _TauriStoreBackend_cache = new WeakMap();
File without changes
@@ -0,0 +1,333 @@
1
+ <script lang="ts">
2
+ /*
3
+ * ResizableSplitter — a generic N-pane split container with drag handles.
4
+ *
5
+ * Used by <LayoutRenderer> to implement `split` nodes. Also available as a
6
+ * standalone primitive for shards that need internal split UI.
7
+ *
8
+ * Sizing model mirrors docs/design/layout.md:
9
+ * - Each pane has a size value + a mode ('fr' | 'px').
10
+ * - 'fr' panes are proportional flex-grow children and absorb window
11
+ * resize deltas and drag deltas against each other.
12
+ * - 'px' panes are pixel-pinned (flex: 0 0 Npx) and stay fixed during
13
+ * window resize; dragging a handle adjacent to a px pane resizes the
14
+ * px pane in absolute pixels.
15
+ *
16
+ * `sizes` is bindable so the parent (layout tree) can observe user drags.
17
+ * Phase 2 does not yet persist sizes — phase 7 wires that up.
18
+ */
19
+
20
+ import type { Snippet } from 'svelte';
21
+ import type { SizeMode, SplitDirection } from '../layout/types';
22
+
23
+ const MIN_PX = 40;
24
+ const COLLAPSED_PX = 28;
25
+
26
+ let {
27
+ direction,
28
+ sizes,
29
+ pinned,
30
+ collapsed,
31
+ count,
32
+ pane,
33
+ onResize,
34
+ onCollapseToggle,
35
+ }: {
36
+ direction: SplitDirection;
37
+ /**
38
+ * Per-pane sizes, read-only. The splitter computes flex bases
39
+ * from this array but does not mutate it — writes go out through
40
+ * `onResize`. Treating sizes as read-only keeps the primitive
41
+ * decoupled from how the caller stores its layout, and sidesteps
42
+ * Svelte 5's `ownership_invalid_mutation` warning that fires when
43
+ * a child component writes into a prop it didn't own.
44
+ */
45
+ sizes: number[];
46
+ pinned?: SizeMode[];
47
+ /** Per-pane collapsed state. Omitted entries default to false. */
48
+ collapsed?: boolean[];
49
+ /** Number of panes — `sizes.length` should match. */
50
+ count: number;
51
+ /** Snippet invoked once per pane with the pane index. */
52
+ pane: Snippet<[number]>;
53
+ /**
54
+ * Called whenever the splitter wants to update a pane's size.
55
+ * The parent is expected to write the value back into whatever
56
+ * it stores sizes in. A single per-index callback (rather than a
57
+ * whole-array setter) matches the drag math, which updates at
58
+ * most two panes per move, and avoids allocating a new array on
59
+ * every pointermove frame.
60
+ */
61
+ onResize?: (index: number, value: number) => void;
62
+ /** Called when a collapsed pane's header is clicked to toggle. */
63
+ onCollapseToggle?: (index: number, collapsed: boolean) => void;
64
+ } = $props();
65
+
66
+ let container: HTMLDivElement;
67
+
68
+ const modeOf = (i: number): SizeMode => pinned?.[i] ?? 'fr';
69
+ const isCollapsed = (i: number): boolean => collapsed?.[i] ?? false;
70
+
71
+ /** CSS `flex` shorthand for pane i. */
72
+ function flexFor(i: number): string {
73
+ if (isCollapsed(i)) return `0 0 ${COLLAPSED_PX}px`;
74
+ if (modeOf(i) === 'px') return `0 0 ${Math.max(MIN_PX, sizes[i])}px`;
75
+ // Proportional: grow = sizes[i], shrink = 1, basis = 0
76
+ return `${Math.max(0.0001, sizes[i])} 1 0`;
77
+ }
78
+
79
+ type DragState = {
80
+ handleIndex: number; // boundary between child handleIndex and handleIndex+1
81
+ startClient: number; // pointer x/y at drag start
82
+ startSizes: number[]; // sizes snapshot at drag start
83
+ containerPx: number; // container length along split axis
84
+ totalFr: number; // sum of 'fr' sizes at drag start
85
+ frAvailPx: number; // pixels available to fr children at drag start
86
+ };
87
+
88
+ let drag: DragState | null = $state(null);
89
+
90
+ function beginDrag(e: PointerEvent, handleIndex: number) {
91
+ // Disable resize handles adjacent to collapsed panes.
92
+ if (isCollapsed(handleIndex) || isCollapsed(handleIndex + 1)) return;
93
+
94
+ e.preventDefault();
95
+ (e.target as HTMLElement).setPointerCapture(e.pointerId);
96
+
97
+ const rect = container.getBoundingClientRect();
98
+ const containerPx = direction === 'horizontal' ? rect.width : rect.height;
99
+
100
+ // Sum fr weights and subtract pixel-pinned pane sizes to get the pixel
101
+ // space the fr children collectively occupy.
102
+ let totalFr = 0;
103
+ let pxUsed = 0;
104
+ for (let i = 0; i < sizes.length; i++) {
105
+ if (modeOf(i) === 'fr') totalFr += sizes[i];
106
+ else pxUsed += Math.max(MIN_PX, sizes[i]);
107
+ }
108
+
109
+ drag = {
110
+ handleIndex,
111
+ startClient: direction === 'horizontal' ? e.clientX : e.clientY,
112
+ startSizes: sizes.slice(),
113
+ containerPx,
114
+ totalFr,
115
+ frAvailPx: Math.max(1, containerPx - pxUsed),
116
+ };
117
+ }
118
+
119
+ function moveDrag(e: PointerEvent) {
120
+ if (!drag) return;
121
+ const client = direction === 'horizontal' ? e.clientX : e.clientY;
122
+ const deltaPx = client - drag.startClient;
123
+
124
+ const a = drag.handleIndex;
125
+ const b = a + 1;
126
+ const modeA = modeOf(a);
127
+ const modeB = modeOf(b);
128
+
129
+ // Send updates through onResize rather than mutating the prop
130
+ // directly. Writing into `sizes` would trip Svelte 5's ownership
131
+ // warning; the parent owns the array and re-derives it for us.
132
+ const frPerPx = drag.totalFr / drag.frAvailPx;
133
+
134
+ if (modeA === 'fr' && modeB === 'fr') {
135
+ // Convert delta px to fr; clamp both sides to MIN_PX worth of fr.
136
+ // Positive deltaFr grows pane a and shrinks pane b, so:
137
+ // - upper bound: deltaFr ≤ startSizes[b] - minFr (stop when b hits min)
138
+ // - lower bound: deltaFr ≥ -(startSizes[a] - minFr) (stop when a hits min)
139
+ const minFr = MIN_PX * frPerPx;
140
+ const deltaFr = deltaPx * frPerPx;
141
+ const maxDelta = drag.startSizes[b] - minFr;
142
+ const minDelta = -(drag.startSizes[a] - minFr);
143
+ const clamped = Math.min(Math.max(deltaFr, minDelta), maxDelta);
144
+ onResize?.(a, drag.startSizes[a] + clamped);
145
+ onResize?.(b, drag.startSizes[b] - clamped);
146
+ } else if (modeA === 'px' && modeB === 'fr') {
147
+ const maxDelta = drag.frAvailPx - MIN_PX; // fr side must keep MIN_PX
148
+ const minDelta = MIN_PX - drag.startSizes[a];
149
+ onResize?.(
150
+ a,
151
+ drag.startSizes[a] + Math.min(Math.max(deltaPx, minDelta), maxDelta),
152
+ );
153
+ } else if (modeA === 'fr' && modeB === 'px') {
154
+ const maxDelta = drag.startSizes[b] - MIN_PX;
155
+ const minDelta = -(drag.frAvailPx - MIN_PX);
156
+ onResize?.(
157
+ b,
158
+ drag.startSizes[b] - Math.min(Math.max(deltaPx, minDelta), maxDelta),
159
+ );
160
+ } else {
161
+ // both px
162
+ const maxDelta = drag.startSizes[b] - MIN_PX;
163
+ const minDelta = -(drag.startSizes[a] - MIN_PX);
164
+ const clamped = Math.min(Math.max(deltaPx, minDelta), maxDelta);
165
+ onResize?.(a, drag.startSizes[a] + clamped);
166
+ onResize?.(b, drag.startSizes[b] - clamped);
167
+ }
168
+ }
169
+
170
+ function endDrag(e: PointerEvent) {
171
+ if (!drag) return;
172
+ (e.target as HTMLElement).releasePointerCapture(e.pointerId);
173
+ drag = null;
174
+ }
175
+ </script>
176
+
177
+ <div
178
+ class="splitter"
179
+ class:horizontal={direction === 'horizontal'}
180
+ class:vertical={direction === 'vertical'}
181
+ bind:this={container}
182
+ >
183
+ {#each Array(count) as _, i (i)}
184
+ <div
185
+ class="splitter-pane"
186
+ class:collapsed={isCollapsed(i)}
187
+ style="flex: {flexFor(i)};"
188
+ >
189
+ {#if isCollapsed(i)}
190
+ <button
191
+ type="button"
192
+ class="collapse-header"
193
+ class:horizontal={direction === 'horizontal'}
194
+ class:vertical={direction === 'vertical'}
195
+ onclick={() => onCollapseToggle?.(i, false)}
196
+ aria-label="Expand pane"
197
+ >
198
+ <span class="collapse-icon">{direction === 'horizontal' ? '▸' : '▾'}</span>
199
+ </button>
200
+ {:else}
201
+ {#if onCollapseToggle}
202
+ <button
203
+ type="button"
204
+ class="collapse-header expanded"
205
+ class:horizontal={direction === 'horizontal'}
206
+ class:vertical={direction === 'vertical'}
207
+ onclick={() => onCollapseToggle?.(i, true)}
208
+ aria-label="Collapse pane"
209
+ >
210
+ <span class="collapse-icon">{direction === 'horizontal' ? '◂' : '▴'}</span>
211
+ </button>
212
+ {/if}
213
+ <div class="pane-content">
214
+ {@render pane(i)}
215
+ </div>
216
+ {/if}
217
+ </div>
218
+ {#if i < count - 1}
219
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
220
+ <div
221
+ class="splitter-handle"
222
+ class:dragging={drag?.handleIndex === i}
223
+ class:disabled={isCollapsed(i) || isCollapsed(i + 1)}
224
+ onpointerdown={(e) => beginDrag(e, i)}
225
+ onpointermove={moveDrag}
226
+ onpointerup={endDrag}
227
+ onpointercancel={endDrag}
228
+ role="separator"
229
+ aria-orientation={direction === 'horizontal' ? 'vertical' : 'horizontal'}
230
+ ></div>
231
+ {/if}
232
+ {/each}
233
+ </div>
234
+
235
+ <style>
236
+ .splitter {
237
+ display: flex;
238
+ width: 100%;
239
+ height: 100%;
240
+ min-width: 0;
241
+ min-height: 0;
242
+ }
243
+ .splitter.horizontal { flex-direction: row; }
244
+ .splitter.vertical { flex-direction: column; }
245
+
246
+ .splitter-pane {
247
+ position: relative;
248
+ min-width: 0;
249
+ min-height: 0;
250
+ overflow: hidden;
251
+ display: flex;
252
+ }
253
+ .horizontal > .splitter-pane { flex-direction: row; }
254
+ .vertical > .splitter-pane { flex-direction: column; }
255
+ .splitter-pane.collapsed {
256
+ overflow: visible;
257
+ }
258
+ .pane-content {
259
+ flex: 1 1 0;
260
+ position: relative;
261
+ min-width: 0;
262
+ min-height: 0;
263
+ overflow: hidden;
264
+ }
265
+
266
+ .collapse-header {
267
+ appearance: none;
268
+ flex: 0 0 auto;
269
+ display: flex;
270
+ align-items: center;
271
+ justify-content: center;
272
+ background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
273
+ border: none;
274
+ color: var(--shell-fg-muted);
275
+ cursor: pointer;
276
+ padding: 0;
277
+ font-size: 10px;
278
+ }
279
+ .collapse-header:hover {
280
+ color: var(--shell-fg);
281
+ background: var(--shell-accent-muted);
282
+ }
283
+ /* Suppress misleading hover feedback during drag-reorganize. */
284
+ :global(body[data-dragging]) .collapse-header {
285
+ pointer-events: none;
286
+ }
287
+ .collapse-header.horizontal {
288
+ width: 100%;
289
+ height: 100%;
290
+ writing-mode: vertical-rl;
291
+ }
292
+ .collapse-header.vertical {
293
+ width: 100%;
294
+ height: 100%;
295
+ }
296
+ .collapse-header.expanded.horizontal {
297
+ width: 16px;
298
+ height: 100%;
299
+ border-right: 1px solid var(--shell-border);
300
+ }
301
+ .collapse-header.expanded.vertical {
302
+ width: 100%;
303
+ height: 16px;
304
+ border-bottom: 1px solid var(--shell-border);
305
+ }
306
+
307
+ .splitter-handle {
308
+ flex: 0 0 auto;
309
+ background: var(--shell-border);
310
+ transition: background-color 120ms ease;
311
+ touch-action: none;
312
+ }
313
+ .splitter-handle:hover,
314
+ .splitter-handle.dragging {
315
+ background: var(--shell-accent);
316
+ }
317
+ :global(body[data-dragging]) .splitter-handle {
318
+ pointer-events: none;
319
+ }
320
+ .splitter-handle.disabled {
321
+ cursor: default;
322
+ pointer-events: none;
323
+ }
324
+
325
+ .horizontal > .splitter-handle {
326
+ width: 4px;
327
+ cursor: col-resize;
328
+ }
329
+ .vertical > .splitter-handle {
330
+ height: 4px;
331
+ cursor: row-resize;
332
+ }
333
+ </style>
@@ -0,0 +1,35 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { SizeMode, SplitDirection } from '../layout/types';
3
+ type $$ComponentProps = {
4
+ direction: SplitDirection;
5
+ /**
6
+ * Per-pane sizes, read-only. The splitter computes flex bases
7
+ * from this array but does not mutate it — writes go out through
8
+ * `onResize`. Treating sizes as read-only keeps the primitive
9
+ * decoupled from how the caller stores its layout, and sidesteps
10
+ * Svelte 5's `ownership_invalid_mutation` warning that fires when
11
+ * a child component writes into a prop it didn't own.
12
+ */
13
+ sizes: number[];
14
+ pinned?: SizeMode[];
15
+ /** Per-pane collapsed state. Omitted entries default to false. */
16
+ collapsed?: boolean[];
17
+ /** Number of panes — `sizes.length` should match. */
18
+ count: number;
19
+ /** Snippet invoked once per pane with the pane index. */
20
+ pane: Snippet<[number]>;
21
+ /**
22
+ * Called whenever the splitter wants to update a pane's size.
23
+ * The parent is expected to write the value back into whatever
24
+ * it stores sizes in. A single per-index callback (rather than a
25
+ * whole-array setter) matches the drag math, which updates at
26
+ * most two panes per move, and avoids allocating a new array on
27
+ * every pointermove frame.
28
+ */
29
+ onResize?: (index: number, value: number) => void;
30
+ /** Called when a collapsed pane's header is clicked to toggle. */
31
+ onCollapseToggle?: (index: number, collapsed: boolean) => void;
32
+ };
33
+ declare const ResizableSplitter: import("svelte").Component<$$ComponentProps, {}, "">;
34
+ type ResizableSplitter = ReturnType<typeof ResizableSplitter>;
35
+ export default ResizableSplitter;