@surdeddd/wmkit 0.9.1 → 0.10.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.
- package/README.md +17 -8
- package/README.ru.md +16 -5
- package/dist/angular.cjs +3 -3
- package/dist/angular.js +1 -1
- package/dist/{chunk-TUGQX3CX.js → chunk-V7OTLDVK.js} +67 -18
- package/dist/chunk-V7OTLDVK.js.map +1 -0
- package/dist/{chunk-ZWUVWRUS.cjs → chunk-VHS2YX3A.cjs} +67 -18
- package/dist/chunk-VHS2YX3A.cjs.map +1 -0
- package/dist/index.cjs +10 -10
- package/dist/index.js +1 -1
- package/dist/react.cjs +3 -3
- package/dist/react.js +1 -1
- package/dist/solid.cjs +3 -3
- package/dist/solid.js +1 -1
- package/dist/svelte.cjs +3 -3
- package/dist/svelte.js +1 -1
- package/dist/themes/amber.css +2 -1
- package/dist/themes/aqua.css +3 -2
- package/dist/themes/blueprint.css +2 -1
- package/dist/themes/brutalist.css +1 -0
- package/dist/themes/candy.css +2 -1
- package/dist/themes/carbon.css +1 -0
- package/dist/themes/forest.css +1 -0
- package/dist/themes/frost.css +4 -3
- package/dist/themes/glass.css +1 -0
- package/dist/themes/light.css +4 -3
- package/dist/themes/neon.css +1 -0
- package/dist/themes/noir.css +1 -0
- package/dist/themes/paper.css +2 -1
- package/dist/themes/retro.css +9 -3
- package/dist/themes/synth.css +1 -0
- package/dist/themes/terminal.css +1 -0
- package/dist/themes.cjs +72 -30
- package/dist/themes.cjs.map +1 -1
- package/dist/themes.js +72 -30
- package/dist/themes.js.map +1 -1
- package/dist/vue.cjs +3 -3
- package/dist/vue.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-TUGQX3CX.js.map +0 -1
- package/dist/chunk-ZWUVWRUS.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
- 🪟 **Full window lifecycle** — open, close, focus, minimize, maximize, restore, drag, 8-direction resize
|
|
16
16
|
- 🧠 **Headless core** — a serializable state machine plus a DOM controller; bring your own markup or use the glass theme
|
|
17
|
+
- 🧱 **Your window, your markup** — build the whole frame from a template string, wire its buttons by attribute, and swap the skin on a live window without losing what it was showing
|
|
17
18
|
- ⚛️ **Official adapters** — `@surdeddd/wmkit/react`, `/vue`, `/svelte`, `/solid`, `/angular`, all thin sugar over one core
|
|
18
19
|
- 🗃️ **Tab groups** — drop one titlebar onto another and the windows share a frame, dockview style; the tab order is yours to reorder
|
|
19
20
|
- ⊞ **Snap zones** — halves, quarters, thirds and drag-to-top maximize with a live preview
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
- 💾 **Persistence** — one call to serialize the desktop, one call to restore it, with versioned migrations
|
|
27
28
|
- 🎨 **Sixteen themes** — glass, light, retro, terminal, paper, neon, aqua, frost, candy, carbon, brutalist, blueprint, amber, noir, forest, synth — or bring your own CSS
|
|
28
29
|
- 🖼️ **Popout** *(experimental)* — send a window into Document Picture-in-Picture
|
|
29
|
-
- 📦 **Zero dependencies**, strict TypeScript, ESM + CJS,
|
|
30
|
+
- 📦 **Zero dependencies**, strict TypeScript, ESM + CJS, under 15 kB brotli core
|
|
30
31
|
|
|
31
32
|
## Install
|
|
32
33
|
|
|
@@ -328,7 +329,7 @@ Moves a window's content into a [Document Picture-in-Picture](https://developer.
|
|
|
328
329
|
|
|
329
330
|
### `pinch(options?)`, `swipe(options?)`, `touchGestures(options?)` — `@surdeddd/wmkit/gestures`
|
|
330
331
|
|
|
331
|
-
Two-finger gestures, opt-in so the core never pays for them: pinch a window to resize it around the point between your fingers, swipe two fingers sideways to change workspace. 1.
|
|
332
|
+
Two-finger gestures, opt-in so the core never pays for them: pinch a window to resize it around the point between your fingers, swipe two fingers sideways to change workspace. 1.47 kB brotlied.
|
|
332
333
|
|
|
333
334
|
```js
|
|
334
335
|
import { attachDesktop } from '@surdeddd/wmkit'
|
|
@@ -341,7 +342,7 @@ A gesture is just a function that takes a `GestureContext` and returns its teard
|
|
|
341
342
|
|
|
342
343
|
### `skin(spec)`, `defaultSkin`, `barebones` — `@surdeddd/wmkit/chrome`
|
|
343
344
|
|
|
344
|
-
Builds the window itself from a markup string, so a consumer can ship their own chrome and their own buttons without writing a single listener.
|
|
345
|
+
Builds the window itself from a markup string, so a consumer can ship their own chrome and their own buttons without writing a single listener. 1.02 kB brotlied.
|
|
345
346
|
|
|
346
347
|
```js
|
|
347
348
|
import { attachDesktop } from '@surdeddd/wmkit'
|
|
@@ -394,9 +395,17 @@ Rows are patched in place rather than re-rendered, so keyboard focus inside the
|
|
|
394
395
|
}
|
|
395
396
|
```
|
|
396
397
|
|
|
397
|
-
Fifteen more ready-made themes ship alongside — `light`, `retro`, `terminal`, `paper`, `neon`, `aqua`, `frost`, `candy`, `carbon`, `brutalist`, `blueprint`, `amber`, `noir`, `forest` and `synth`. They all style the same `data-wm-*` attributes, so switching is a one-line import swap, and every one of them ships 24px pointer targets plus `prefers-reduced-motion` and `forced-colors` blocks.
|
|
398
|
+
Fifteen more ready-made themes ship alongside — `light`, `retro`, `terminal`, `paper`, `neon`, `aqua`, `frost`, `candy`, `carbon`, `brutalist`, `blueprint`, `amber`, `noir`, `forest` and `synth`. They all style the same `data-wm-*` attributes, so switching is a one-line import swap, and every one of them ships 24px pointer targets plus `prefers-reduced-motion` and `forced-colors` blocks. Every one is also held to WCAG AA contrast by a browser test that measures the rendered pixels of the demo under all sixteen.
|
|
398
399
|
|
|
399
|
-
|
|
400
|
+
Three layers, from the widest to the narrowest:
|
|
401
|
+
|
|
402
|
+
| layer | reaches | changes |
|
|
403
|
+
| --- | --- | --- |
|
|
404
|
+
| theme | every window | the tokens |
|
|
405
|
+
| variant | one window | the tokens, through `data-wm-variant` |
|
|
406
|
+
| skin | one window | the markup itself |
|
|
407
|
+
|
|
408
|
+
A theme and a variant repaint what is there; a skin replaces it. Set `meta.variant` for the first two and `meta.skin` for the third — see [docs/theming.md](docs/theming.md).
|
|
400
409
|
|
|
401
410
|
Skip the import entirely and the library stays headless: state attributes (`data-wm-stage`, `data-wm-focused`, `data-wm-dragging`, `data-wm-flash`, `[hidden]`) are yours to style.
|
|
402
411
|
|
|
@@ -413,7 +422,7 @@ This README is the tour. The reference lives in [`docs/`](./docs/README.md):
|
|
|
413
422
|
| [API reference](./docs/api.md) | every export, option, method, event and type |
|
|
414
423
|
| [Adapters](./docs/adapters.md) | complete React, Vue, Svelte, Solid and Angular integrations |
|
|
415
424
|
| [Theming](./docs/theming.md) | `data-wm-*` contract, CSS variables, writing a theme from scratch |
|
|
416
|
-
| [Recipes](./docs/recipes.md) | taskbar, modals, persistence, workspaces, SSR, testing, performance |
|
|
425
|
+
| [Recipes](./docs/recipes.md) | building a window from scratch, taskbar, modals, persistence, workspaces, SSR, testing, performance |
|
|
417
426
|
| [Browser support](./docs/browser-support.md) | baselines per entry point and what degrades where |
|
|
418
427
|
|
|
419
428
|
## Comparison
|
|
@@ -434,8 +443,8 @@ This README is the tour. The reference lives in [`docs/`](./docs/README.md):
|
|
|
434
443
|
|
|
435
444
|
## Quality
|
|
436
445
|
|
|
437
|
-
-
|
|
438
|
-
-
|
|
446
|
+
- 565 unit tests: **100%** line/branch/function/statement coverage on the core state machine, the chrome plugin and persistence, with enforced floors on the DOM layer and the adapters
|
|
447
|
+
- 550+ Playwright scenarios on Chromium, Firefox, WebKit and mobile emulation: drag, 8-way resize, snap, magnetism, workspaces, undo after drag, keyboard, touch, persistence across reloads, 50-window stress, modal traps, axe accessibility scans, visual regression screenshots
|
|
439
448
|
- performance benchmarks run in CI on every push (`vitest bench`): 1 000 windows open in ~150 ms, a move among 50 windows costs ~1.2 µs, a full 100-step undo/redo sweep ~52 µs
|
|
440
449
|
- `publint` + `@arethetypeswrong/cli` validate the published package, `size-limit` guards bundle budgets
|
|
441
450
|
|
package/README.ru.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- 🪟 **Полный жизненный цикл окна** — открытие, закрытие, фокус, сворачивание, разворачивание, восстановление, drag, ресайз в 8 направлениях
|
|
12
12
|
- 🧠 **Headless-ядро** — сериализуемая стейт-машина плюс DOM-контроллер; своя разметка или готовая стеклянная тема
|
|
13
|
+
- 🧱 **Своё окно, своя разметка** — соберите весь корпус из строки-шаблона, повесьте кнопки атрибутами и меняйте скин на живом окне, не теряя того, что оно показывало
|
|
13
14
|
- ⚛️ **Родные адаптеры** — `@surdeddd/wmkit/react`, `/vue`, `/svelte`, `/solid`, `/angular`, тонкий сахар над одним ядром
|
|
14
15
|
- 🗃️ **Вкладочные группы** — бросьте заголовок на заголовок, и окна начнут делить одну рамку; порядок вкладок можно менять
|
|
15
16
|
- ⊞ **Snap-зоны** — половины, четверти, трети и максимизация от верхнего края с живым превью
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
- 💾 **Персист** — один вызов сериализует рабочий стол, один — восстанавливает, с версионированием и миграциями
|
|
23
24
|
- 🎨 **Шестнадцать тем** — glass, light, retro, terminal, paper, neon, aqua, frost, candy, carbon, brutalist, blueprint, amber, noir, forest, synth — либо полностью свой CSS
|
|
24
25
|
- 🖼️ **Popout** *(experimental)* — вынос окна в Document Picture-in-Picture
|
|
25
|
-
- 📦 **Ноль зависимостей**, строгий TypeScript, ESM + CJS,
|
|
26
|
+
- 📦 **Ноль зависимостей**, строгий TypeScript, ESM + CJS, ядро меньше 15 кБ в brotli
|
|
26
27
|
|
|
27
28
|
## Установка
|
|
28
29
|
|
|
@@ -277,7 +278,7 @@ attachDesktop(wm, root, { gestures: [touchGestures({ swipe: { workspaces: 4 } })
|
|
|
277
278
|
|
|
278
279
|
### `skin(spec)`, `defaultSkin`, `barebones` — `@surdeddd/wmkit/chrome`
|
|
279
280
|
|
|
280
|
-
Собирает само окно из строки разметки: можно принести свою обвязку и свои кнопки, не написав ни одного обработчика.
|
|
281
|
+
Собирает само окно из строки разметки: можно принести свою обвязку и свои кнопки, не написав ни одного обработчика. 1.02 кБ в brotli.
|
|
281
282
|
|
|
282
283
|
```js
|
|
283
284
|
import { attachDesktop } from '@surdeddd/wmkit'
|
|
@@ -323,7 +324,17 @@ panel.destroy()
|
|
|
323
324
|
|
|
324
325
|
Ещё пятнадцать готовых тем: `light`, `retro`, `terminal`, `paper`, `neon`, `aqua`, `frost`, `candy`, `carbon`, `brutalist`, `blueprint`, `amber`, `noir`, `forest`, `synth`. Все стилизуют одни и те же `data-wm-*` атрибуты — переключение = замена одного импорта, и у каждой есть 24px тач-цели плюс блоки `prefers-reduced-motion` и `forced-colors`.
|
|
325
326
|
|
|
326
|
-
|
|
327
|
+
Каждая тема к тому же держит контраст WCAG AA: браузерный тест меряет отрендеренные пиксели демо под всеми шестнадцатью и падает ниже 4.5:1.
|
|
328
|
+
|
|
329
|
+
Три слоя, от самого широкого к самому узкому:
|
|
330
|
+
|
|
331
|
+
| слой | достаёт до | меняет |
|
|
332
|
+
| --- | --- | --- |
|
|
333
|
+
| тема | всех окон | токены |
|
|
334
|
+
| вариант | одного окна | токены, через `data-wm-variant` |
|
|
335
|
+
| скин | одного окна | саму разметку |
|
|
336
|
+
|
|
337
|
+
Тема и вариант перекрашивают то, что есть; скин это заменяет. Для первых двух — `meta.variant`, для третьего — `meta.skin`, подробности в [docs/theming.md](docs/theming.md).
|
|
327
338
|
|
|
328
339
|
## SSR
|
|
329
340
|
|
|
@@ -331,8 +342,8 @@ panel.destroy()
|
|
|
331
342
|
|
|
332
343
|
## Качество
|
|
333
344
|
|
|
334
|
-
-
|
|
335
|
-
-
|
|
345
|
+
- 565 юнит-тестов: **100%** покрытие стейт-машины, chrome-плагина и persist по строкам/веткам/функциям, плюс обязательные пороги на DOM-слой и адаптеры
|
|
346
|
+
- 550+ Playwright-сценариев на Chromium, Firefox, WebKit и мобильной эмуляции: drag, ресайз во все стороны, снэп, магнетизм, рабочие столы, undo после drag, клавиатура, touch, персист через перезагрузку, стресс на 50 окон, модальные ловушки, axe-аудиты доступности, визуальная регрессия по скриншотам
|
|
336
347
|
- перф-бенчмарки в CI на каждый push (`vitest bench`): 1 000 окон открываются за ~150 мс, move среди 50 окон ~1.2 мкс, полный undo/redo-проход на 100 шагов ~52 мкс
|
|
337
348
|
- `publint` + `@arethetypeswrong/cli` проверяют валидность пакета, `size-limit` следит за бюджетами
|
|
338
349
|
|
package/dist/angular.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkVHS2YX3A_cjs = require('./chunk-VHS2YX3A.cjs');
|
|
4
4
|
require('./chunk-BDHFXEJN.cjs');
|
|
5
5
|
var core = require('@angular/core');
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ function onDestroy(dispose) {
|
|
|
14
14
|
destroyRef?.onDestroy(dispose);
|
|
15
15
|
}
|
|
16
16
|
function useWindowManager(options) {
|
|
17
|
-
const wm =
|
|
17
|
+
const wm = chunkVHS2YX3A_cjs.createWindowManager(options);
|
|
18
18
|
onDestroy(() => wm.destroy());
|
|
19
19
|
return wm;
|
|
20
20
|
}
|
|
@@ -29,7 +29,7 @@ function useWmWindow(wm, id) {
|
|
|
29
29
|
return core.computed(() => state().windows[id]);
|
|
30
30
|
}
|
|
31
31
|
function createDesktop(wm, options) {
|
|
32
|
-
const binder =
|
|
32
|
+
const binder = chunkVHS2YX3A_cjs.createDesktopBinder(wm, options);
|
|
33
33
|
onDestroy(() => binder.destroy());
|
|
34
34
|
return {
|
|
35
35
|
binder,
|
package/dist/angular.js
CHANGED
|
@@ -1856,6 +1856,14 @@ var SNAP_ZONES = /* @__PURE__ */ new Set([
|
|
|
1856
1856
|
]);
|
|
1857
1857
|
var LANDMARK_TAGS = /* @__PURE__ */ new Set(["header", "footer", "aside", "nav"]);
|
|
1858
1858
|
var FOCUSABLE_SELECTOR = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
1859
|
+
function firedOn(event) {
|
|
1860
|
+
const path = event.composedPath();
|
|
1861
|
+
const first = path.length > 0 ? path[0] : event.target;
|
|
1862
|
+
return first instanceof Element ? first : null;
|
|
1863
|
+
}
|
|
1864
|
+
function findInWindow(el, selector) {
|
|
1865
|
+
return el.querySelector(selector) ?? el.shadowRoot?.querySelector(selector) ?? null;
|
|
1866
|
+
}
|
|
1859
1867
|
function focusablesOf(el) {
|
|
1860
1868
|
const root = el.shadowRoot;
|
|
1861
1869
|
if (!root) return [...el.querySelectorAll(FOCUSABLE_SELECTOR)];
|
|
@@ -1875,8 +1883,15 @@ function focusablesOf(el) {
|
|
|
1875
1883
|
function dragHandleAt(node, clientX, clientY) {
|
|
1876
1884
|
const handle = node.closest?.("[data-wm-drag]");
|
|
1877
1885
|
if (handle) return handle;
|
|
1878
|
-
const
|
|
1879
|
-
|
|
1886
|
+
const root = node.shadowRoot;
|
|
1887
|
+
if (!root) return null;
|
|
1888
|
+
for (const candidate of root.querySelectorAll("[data-wm-drag]")) {
|
|
1889
|
+
const box = candidate.getBoundingClientRect();
|
|
1890
|
+
if (clientX >= box.left && clientX <= box.right && clientY >= box.top && clientY <= box.bottom) {
|
|
1891
|
+
return candidate;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
return null;
|
|
1880
1895
|
}
|
|
1881
1896
|
function windowElementOf(node) {
|
|
1882
1897
|
const found = node.closest("[data-wm-window]");
|
|
@@ -2117,7 +2132,24 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2117
2132
|
restack(stackTarget, { base: zIndexBase, gap: zIndexGap });
|
|
2118
2133
|
stackRows.length = length;
|
|
2119
2134
|
}
|
|
2135
|
+
let syncing = false;
|
|
2136
|
+
let syncAgain = false;
|
|
2120
2137
|
function syncAll() {
|
|
2138
|
+
if (syncing) {
|
|
2139
|
+
syncAgain = true;
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2142
|
+
syncing = true;
|
|
2143
|
+
try {
|
|
2144
|
+
do {
|
|
2145
|
+
syncAgain = false;
|
|
2146
|
+
syncPass();
|
|
2147
|
+
} while (syncAgain);
|
|
2148
|
+
} finally {
|
|
2149
|
+
syncing = false;
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
function syncPass() {
|
|
2121
2153
|
const state = wm.getState();
|
|
2122
2154
|
const orderChanged = state.order !== lastOrder;
|
|
2123
2155
|
let restyle = null;
|
|
@@ -2141,7 +2173,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2141
2173
|
const attached = registry.get(id);
|
|
2142
2174
|
if (attached && attached.skin !== wanted2) buildSkin(id, wanted2, attached.mountOptions);
|
|
2143
2175
|
}
|
|
2144
|
-
|
|
2176
|
+
syncAgain = true;
|
|
2145
2177
|
return;
|
|
2146
2178
|
}
|
|
2147
2179
|
if (orderChanged) applyStacking(state.order);
|
|
@@ -2200,7 +2232,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2200
2232
|
}
|
|
2201
2233
|
if (!event.ctrlKey && !event.metaKey) return;
|
|
2202
2234
|
if (drag) return;
|
|
2203
|
-
const target = event
|
|
2235
|
+
const target = firedOn(event);
|
|
2204
2236
|
if (target?.closest(interactiveSelector)) return;
|
|
2205
2237
|
if (historyShortcuts && (event.key === "z" || event.key === "Z")) {
|
|
2206
2238
|
event.preventDefault();
|
|
@@ -2231,6 +2263,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2231
2263
|
element.addEventListener("keydown", onDesktopKeydown);
|
|
2232
2264
|
cleanup.push(() => element.removeEventListener("keydown", onDesktopKeydown));
|
|
2233
2265
|
}
|
|
2266
|
+
let rebuilding = false;
|
|
2234
2267
|
function endDrag(cancelled) {
|
|
2235
2268
|
if (drag) drag.finish(cancelled);
|
|
2236
2269
|
}
|
|
@@ -2260,12 +2293,12 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2260
2293
|
windowElement.style.left = "0";
|
|
2261
2294
|
windowElement.style.top = "0";
|
|
2262
2295
|
const lightTitle = windowElement.querySelector("[data-wm-title]");
|
|
2263
|
-
attached.title = lightTitle ?? windowElement
|
|
2296
|
+
attached.title = lightTitle ?? findInWindow(windowElement, "[data-wm-title]");
|
|
2264
2297
|
if (lightTitle) {
|
|
2265
2298
|
if (!lightTitle.id) lightTitle.id = `wmkit-title-${id}`;
|
|
2266
2299
|
windowElement.setAttribute("aria-labelledby", lightTitle.id);
|
|
2267
2300
|
}
|
|
2268
|
-
const handle = typeof windowOptions.handle === "string" ? windowElement
|
|
2301
|
+
const handle = typeof windowOptions.handle === "string" ? findInWindow(windowElement, windowOptions.handle) : windowOptions.handle ?? findInWindow(windowElement, "[data-wm-drag]");
|
|
2269
2302
|
attached.handle = handle;
|
|
2270
2303
|
if (handle && !handle.hasAttribute("role") && LANDMARK_TAGS.has(handle.localName)) {
|
|
2271
2304
|
handle.setAttribute("role", "presentation");
|
|
@@ -2278,7 +2311,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2278
2311
|
() => windowElement.removeEventListener("pointerdown", onPointerDownFocus, true)
|
|
2279
2312
|
);
|
|
2280
2313
|
const onClick = (event) => {
|
|
2281
|
-
const target = event
|
|
2314
|
+
const target = firedOn(event);
|
|
2282
2315
|
if (!target) return;
|
|
2283
2316
|
const current = wm.get(id);
|
|
2284
2317
|
if (!current) return;
|
|
@@ -2326,7 +2359,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2326
2359
|
handle.addEventListener("pointerdown", onHandleDown);
|
|
2327
2360
|
attached.cleanup.push(() => handle.removeEventListener("pointerdown", onHandleDown));
|
|
2328
2361
|
const onDoubleClick = (event) => {
|
|
2329
|
-
const target = event
|
|
2362
|
+
const target = firedOn(event);
|
|
2330
2363
|
if (target?.closest(interactiveSelector)) return;
|
|
2331
2364
|
const current = wm.get(id);
|
|
2332
2365
|
if (current?.maximizable) wm.toggleMaximize(id);
|
|
@@ -2358,7 +2391,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2358
2391
|
}
|
|
2359
2392
|
}
|
|
2360
2393
|
const onWindowKeydown = (event) => {
|
|
2361
|
-
const target = event
|
|
2394
|
+
const target = firedOn(event);
|
|
2362
2395
|
if (target?.closest(interactiveSelector)) return;
|
|
2363
2396
|
const current = wm.get(id);
|
|
2364
2397
|
if (!current) return;
|
|
@@ -2418,7 +2451,7 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2418
2451
|
const detach = () => {
|
|
2419
2452
|
if (detached) return;
|
|
2420
2453
|
detached = true;
|
|
2421
|
-
if (drag?.id === id) endDrag(
|
|
2454
|
+
if (drag?.id === id) endDrag(!rebuilding);
|
|
2422
2455
|
for (const dispose of attached.cleanup) dispose();
|
|
2423
2456
|
for (const resizeHandle of attached.handles) resizeHandle.remove();
|
|
2424
2457
|
registry.delete(id);
|
|
@@ -2454,15 +2487,21 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2454
2487
|
function buildSkin(id, skin, windowOptions) {
|
|
2455
2488
|
const win = wm.get(id);
|
|
2456
2489
|
if (!win) throw new Error(`wmkit: cannot mount unknown window "${id}"`);
|
|
2490
|
+
const build = resolveSkin(skin);
|
|
2457
2491
|
const standing = registry.get(id);
|
|
2458
2492
|
const previous = standing?.mount ?? null;
|
|
2459
|
-
const carried = previous === null ? [] : [...previous.content.childNodes];
|
|
2493
|
+
const carried = previous === null || previous.content.ownerDocument !== doc ? [] : [...previous.content.childNodes];
|
|
2460
2494
|
if (previous !== null) {
|
|
2461
2495
|
registry.delete(id);
|
|
2462
|
-
|
|
2496
|
+
rebuilding = true;
|
|
2497
|
+
try {
|
|
2498
|
+
standing?.release?.();
|
|
2499
|
+
} finally {
|
|
2500
|
+
rebuilding = false;
|
|
2501
|
+
}
|
|
2463
2502
|
previous.element.remove();
|
|
2464
2503
|
}
|
|
2465
|
-
const mount =
|
|
2504
|
+
const mount = build({ doc, id, window: win, actions: createActions(wm, id) });
|
|
2466
2505
|
element.append(mount.element);
|
|
2467
2506
|
const release = attachWindow(id, mount.element, windowOptions);
|
|
2468
2507
|
const attached = registry.get(id);
|
|
@@ -2474,10 +2513,14 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2474
2513
|
previous?.destroy?.();
|
|
2475
2514
|
return mount;
|
|
2476
2515
|
}
|
|
2477
|
-
function mountWindow(id, skin,
|
|
2516
|
+
function mountWindow(id, skin, options2 = {}) {
|
|
2517
|
+
const windowOptions = { removeOnClose: true, ...options2 };
|
|
2478
2518
|
let last = buildSkin(id, skin, windowOptions);
|
|
2519
|
+
let spent = false;
|
|
2479
2520
|
const live = () => {
|
|
2480
|
-
|
|
2521
|
+
if (spent) return last;
|
|
2522
|
+
const now = registry.get(id)?.mount;
|
|
2523
|
+
if (now) last = now;
|
|
2481
2524
|
return last;
|
|
2482
2525
|
};
|
|
2483
2526
|
return {
|
|
@@ -2488,8 +2531,10 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2488
2531
|
return live().content;
|
|
2489
2532
|
},
|
|
2490
2533
|
detach() {
|
|
2534
|
+
if (spent) return;
|
|
2491
2535
|
const mount = live();
|
|
2492
|
-
|
|
2536
|
+
spent = true;
|
|
2537
|
+
if (registry.get(id)?.mount === mount) registry.get(id)?.release?.();
|
|
2493
2538
|
mount.element.remove();
|
|
2494
2539
|
mount.destroy?.();
|
|
2495
2540
|
}
|
|
@@ -2506,6 +2551,10 @@ function attachDesktop(wm, element, options = {}) {
|
|
|
2506
2551
|
for (const [, attached] of registry) {
|
|
2507
2552
|
for (const dispose of attached.cleanup) dispose();
|
|
2508
2553
|
for (const resizeHandle of attached.handles) resizeHandle.remove();
|
|
2554
|
+
if (attached.mount) {
|
|
2555
|
+
attached.mount.element.remove();
|
|
2556
|
+
attached.mount.destroy?.();
|
|
2557
|
+
}
|
|
2509
2558
|
}
|
|
2510
2559
|
registry.clear();
|
|
2511
2560
|
for (const dispose of cleanup) dispose();
|
|
@@ -2571,5 +2620,5 @@ function createDesktopBinder(wm, options = {}) {
|
|
|
2571
2620
|
}
|
|
2572
2621
|
|
|
2573
2622
|
export { attachDesktop, createAnnouncer, createDesktopBinder, createEmitter, createWindowManager, defaultMessages, flipFromTarget, flipToTarget, prefersReducedMotion };
|
|
2574
|
-
//# sourceMappingURL=chunk-
|
|
2575
|
-
//# sourceMappingURL=chunk-
|
|
2623
|
+
//# sourceMappingURL=chunk-V7OTLDVK.js.map
|
|
2624
|
+
//# sourceMappingURL=chunk-V7OTLDVK.js.map
|