@surdeddd/wmkit 0.4.0 → 0.4.1

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Headless window manager for the web.** Draggable, resizable, snappable windows with a taskbar model, keyboard accessibility and state persistence — for vanilla JS and every major framework.
4
4
 
5
- [Русская версия](./README.ru.md) · [Live demo](https://wmkit.vercel.app) · [Mirror (Pages)](https://surdeddd.github.io/wmkit/) · [GitHub](https://github.com/Surdeddd/wmkit)
5
+ [Русская версия](./README.ru.md) · [Live demo](https://wmkit.vercel.app) · [Mirror (Pages)](https://surdeddd.github.io/wmkit/) · [Docs](./docs/README.md) · [GitHub](https://github.com/Surdeddd/wmkit)
6
6
 
7
7
  [![CI](https://github.com/Surdeddd/wmkit/actions/workflows/ci.yml/badge.svg)](https://github.com/Surdeddd/wmkit/actions/workflows/ci.yml)
8
8
  [![npm](https://img.shields.io/npm/v/@surdeddd/wmkit)](https://www.npmjs.com/package/@surdeddd/wmkit)
@@ -346,6 +346,18 @@ Skip the import entirely and the library stays headless: state attributes (`data
346
346
 
347
347
  The core never touches `window`/`document` — create managers and even `hydrate()` state on the server, then call `attachDesktop` after mount. `persist` no-ops without usable storage.
348
348
 
349
+ ## Documentation
350
+
351
+ This README is the tour. The reference lives in [`docs/`](./docs/README.md):
352
+
353
+ | Page | What is in it |
354
+ | --- | --- |
355
+ | [API reference](./docs/api.md) | every export, option, method, event and type |
356
+ | [Adapters](./docs/adapters.md) | complete React, Vue, Svelte, Solid and Angular integrations |
357
+ | [Theming](./docs/theming.md) | `data-wm-*` contract, CSS variables, writing a theme from scratch |
358
+ | [Recipes](./docs/recipes.md) | taskbar, modals, persistence, workspaces, SSR, testing, performance |
359
+ | [Browser support](./docs/browser-support.md) | baselines per entry point and what degrades where |
360
+
349
361
  ## Comparison
350
362
 
351
363
  | | wmkit | WinBox | jsPanel4 | Dockview | Zag floating-panel |
package/README.ru.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Headless оконный менеджер для веба.** Перетаскиваемые окна с ресайзом, снэпом, таскбаром, клавиатурной доступностью и персистом состояния — для vanilla JS и всех основных фреймворков.
4
4
 
5
- [English version](./README.md) · [Живое демо](https://wmkit.vercel.app) · [Зеркало (Pages)](https://surdeddd.github.io/wmkit/) · [GitHub](https://github.com/Surdeddd/wmkit)
5
+ [English version](./README.md) · [Живое демо](https://wmkit.vercel.app) · [Зеркало (Pages)](https://surdeddd.github.io/wmkit/) · [Документация](./docs/README.md) · [GitHub](https://github.com/Surdeddd/wmkit)
6
6
 
7
7
  [![wmkit — живой демо-десктоп](https://raw.githubusercontent.com/Surdeddd/wmkit/main/.github/assets/hero.png)](https://surdeddd.github.io/wmkit/)
8
8
 
@@ -73,7 +73,140 @@ desktop.attachWindow(win.id, el, { removeOnClose: true })
73
73
 
74
74
  ## Адаптеры
75
75
 
76
- Примеры для React, Vue, Svelte, Solid и Angular в [английском README](./README.md#react) и на [лендинге](https://surdeddd.github.io/wmkit/) (табы «Фреймворки»). Принцип один: контент окна живёт в дереве вашего фреймворка, никакого innerHTML.
76
+ Каждый адаптер тонкая обёртка над тем же ядром и тем же DOM-контроллером, около 60 строк. Они нужны только чтобы привязаться и отвязаться в нужный момент жизненного цикла компонента. Контент окна всегда живёт в дереве вашего фреймворка: никакого innerHTML, порталов и переноса узлов.
77
+
78
+ ### React
79
+
80
+ ```tsx
81
+ import { useWindowManager, useDesktop, useWmState, useWmWindowRef } from '@surdeddd/wmkit/react'
82
+
83
+ function Desktop() {
84
+ const wm = useWindowManager()
85
+ const { ref, binder } = useDesktop(wm)
86
+ const state = useWmState(wm)
87
+
88
+ return (
89
+ <div ref={ref} style={{ position: 'relative', height: '100vh' }}>
90
+ <button type="button" onClick={() => wm.open({ title: 'Окно' })}>открыть</button>
91
+ {state.order.map((id) => (
92
+ <Win key={id} binder={binder} win={state.windows[id]} />
93
+ ))}
94
+ </div>
95
+ )
96
+ }
97
+
98
+ function Win({ binder, win }) {
99
+ const ref = useWmWindowRef(binder, win.id, { removeOnClose: true })
100
+ return (
101
+ <section ref={ref}>
102
+ <header data-wm-drag><span data-wm-title>{win.title}</span></header>
103
+ <div data-wm-content>ваше дерево компонентов</div>
104
+ </section>
105
+ )
106
+ }
107
+ ```
108
+
109
+ ### Vue
110
+
111
+ ```vue
112
+ <script setup lang="ts">
113
+ import { ref } from 'vue'
114
+ import { useWindowManager, useDesktop, useWmWindowEl } from '@surdeddd/wmkit/vue'
115
+
116
+ const host = ref<HTMLElement>()
117
+ const panel = ref<HTMLElement>()
118
+ const wm = useWindowManager()
119
+ const binder = useDesktop(wm, host)
120
+ useWmWindowEl(binder, 'notes', panel)
121
+ wm.open({ id: 'notes', title: 'Заметки' })
122
+ </script>
123
+
124
+ <template>
125
+ <div ref="host" style="position: relative; height: 100vh">
126
+ <section ref="panel">
127
+ <header data-wm-drag><span data-wm-title>Заметки</span></header>
128
+ <div data-wm-content>композаблы</div>
129
+ </section>
130
+ </div>
131
+ </template>
132
+ ```
133
+
134
+ ### Svelte
135
+
136
+ ```svelte
137
+ <script lang="ts">
138
+ import { createManager, createDesktop, wmWindowStore } from '@surdeddd/wmkit/svelte'
139
+
140
+ const wm = createManager()
141
+ const dk = createDesktop(wm)
142
+ wm.open({ id: 'notes', title: 'Заметки' })
143
+ const notes = wmWindowStore(wm, 'notes')
144
+ </script>
145
+
146
+ <div use:dk.desktop style="position: relative; height: 100vh">
147
+ <section use:dk.window={{ id: 'notes' }}>
148
+ <header data-wm-drag><span data-wm-title>{$notes?.title}</span></header>
149
+ <div data-wm-content>сторы и экшены</div>
150
+ </section>
151
+ </div>
152
+ ```
153
+
154
+ ### Solid
155
+
156
+ ```tsx
157
+ import { useWindowManager, createDesktop, useWmState } from '@surdeddd/wmkit/solid'
158
+
159
+ function Desktop() {
160
+ const wm = useWindowManager()
161
+ const dk = createDesktop(wm)
162
+ const state = useWmState(wm)
163
+ wm.open({ id: 'notes', title: 'Заметки' })
164
+
165
+ return (
166
+ <div ref={dk.desktop} style={{ position: 'relative', height: '100vh' }}>
167
+ <section ref={dk.window('notes')}>
168
+ <header data-wm-drag><span data-wm-title>Заметки</span></header>
169
+ <div data-wm-content>{state().order.length} окон</div>
170
+ </section>
171
+ </div>
172
+ )
173
+ }
174
+ ```
175
+
176
+ ### Angular
177
+
178
+ ```ts
179
+ import { Component, ElementRef, afterNextRender, viewChild } from '@angular/core'
180
+ import { useWindowManager, createDesktop, useWmState } from '@surdeddd/wmkit/angular'
181
+
182
+ @Component({
183
+ selector: 'app-desktop',
184
+ template: `
185
+ <div #host style="position: relative; height: 100vh">
186
+ <section #panel>
187
+ <header data-wm-drag><span data-wm-title>Заметки</span></header>
188
+ <div data-wm-content>{{ state().order.length }} окон</div>
189
+ </section>
190
+ </div>`,
191
+ })
192
+ export class DesktopComponent {
193
+ private host = viewChild.required<ElementRef>('host')
194
+ private panel = viewChild.required<ElementRef>('panel')
195
+ wm = useWindowManager()
196
+ state = useWmState(this.wm)
197
+
198
+ constructor() {
199
+ const dk = createDesktop(this.wm)
200
+ afterNextRender(() => {
201
+ dk.desktop(this.host().nativeElement)
202
+ this.wm.open({ id: 'notes', title: 'Заметки' })
203
+ dk.window('notes')(this.panel().nativeElement)
204
+ })
205
+ }
206
+ }
207
+ ```
208
+
209
+ Полные примеры с таскбаром, модалками и сигнатурами всех хуков — в [docs/adapters.md](./docs/adapters.md).
77
210
 
78
211
  ## API ядра — кратко
79
212
 
package/dist/angular.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk3KZZOLHW_cjs = require('./chunk-3KZZOLHW.cjs');
3
+ var chunkTJ6QOOJ2_cjs = require('./chunk-TJ6QOOJ2.cjs');
4
4
  var core = require('@angular/core');
5
5
 
6
6
  function onDestroy(dispose) {
@@ -13,7 +13,7 @@ function onDestroy(dispose) {
13
13
  destroyRef?.onDestroy(dispose);
14
14
  }
15
15
  function useWindowManager(options) {
16
- const wm = chunk3KZZOLHW_cjs.createWindowManager(options);
16
+ const wm = chunkTJ6QOOJ2_cjs.createWindowManager(options);
17
17
  onDestroy(() => wm.destroy());
18
18
  return wm;
19
19
  }
@@ -28,7 +28,7 @@ function useWmWindow(wm, id) {
28
28
  return core.computed(() => state().windows[id]);
29
29
  }
30
30
  function createDesktop(wm, options) {
31
- const binder = chunk3KZZOLHW_cjs.createDesktopBinder(wm, options);
31
+ const binder = chunkTJ6QOOJ2_cjs.createDesktopBinder(wm, options);
32
32
  onDestroy(() => binder.destroy());
33
33
  return {
34
34
  binder,
package/dist/angular.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createWindowManager, createDesktopBinder } from './chunk-FPZDAKNP.js';
1
+ import { createWindowManager, createDesktopBinder } from './chunk-OOEDFA7K.js';
2
2
  import { signal, computed, inject, DestroyRef } from '@angular/core';
3
3
 
4
4
  function onDestroy(dispose) {
@@ -1504,6 +1504,7 @@ var SNAP_SHORTCUTS = {
1504
1504
  ArrowLeft: "left",
1505
1505
  ArrowRight: "right"
1506
1506
  };
1507
+ var LANDMARK_TAGS = /* @__PURE__ */ new Set(["header", "footer", "aside", "nav"]);
1507
1508
  var FOCUSABLE_SELECTOR = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
1508
1509
  function attachDesktop(wm, element, options = {}) {
1509
1510
  const doc = element.ownerDocument;
@@ -1778,6 +1779,9 @@ function attachDesktop(wm, element, options = {}) {
1778
1779
  }
1779
1780
  const handle = typeof windowOptions.handle === "string" ? windowElement.querySelector(windowOptions.handle) : windowOptions.handle ?? windowElement.querySelector("[data-wm-drag]");
1780
1781
  attached.handle = handle;
1782
+ if (handle && !handle.hasAttribute("role") && LANDMARK_TAGS.has(handle.localName)) {
1783
+ handle.setAttribute("role", "presentation");
1784
+ }
1781
1785
  const onPointerDownFocus = () => {
1782
1786
  wm.focus(id);
1783
1787
  };
@@ -1983,5 +1987,5 @@ function createDesktopBinder(wm, options = {}) {
1983
1987
  }
1984
1988
 
1985
1989
  export { applyAspect, attachDesktop, boundsEqual, clamp, clampSize, clampToViewport, createAnnouncer, createDesktopBinder, createEmitter, createWindowManager, defaultMessages, detectSnapZone, flipFromTarget, flipToTarget, magnetize, prefersReducedMotion, zoneBounds };
1986
- //# sourceMappingURL=chunk-FPZDAKNP.js.map
1987
- //# sourceMappingURL=chunk-FPZDAKNP.js.map
1990
+ //# sourceMappingURL=chunk-OOEDFA7K.js.map
1991
+ //# sourceMappingURL=chunk-OOEDFA7K.js.map