@surdeddd/wmkit 0.8.0 → 0.9.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 (52) hide show
  1. package/README.md +23 -1
  2. package/README.ru.md +23 -1
  3. package/dist/angular.cjs +3 -3
  4. package/dist/angular.d.cts +2 -2
  5. package/dist/angular.d.ts +2 -2
  6. package/dist/angular.js +1 -1
  7. package/dist/{binder-B625OrjD.d.cts → binder-DGoj0xG1.d.cts} +1 -1
  8. package/dist/{binder-CpGY8Wye.d.ts → binder-Lo13iTVB.d.ts} +1 -1
  9. package/dist/chrome.cjs +122 -0
  10. package/dist/chrome.cjs.map +1 -0
  11. package/dist/chrome.d.cts +25 -0
  12. package/dist/chrome.d.ts +25 -0
  13. package/dist/chrome.js +114 -0
  14. package/dist/chrome.js.map +1 -0
  15. package/dist/{chunk-MGWCKHTZ.js → chunk-TUGQX3CX.js} +179 -17
  16. package/dist/chunk-TUGQX3CX.js.map +1 -0
  17. package/dist/{chunk-DINVOL6Z.cjs → chunk-ZWUVWRUS.cjs} +179 -17
  18. package/dist/chunk-ZWUVWRUS.cjs.map +1 -0
  19. package/dist/gestures.d.cts +1 -1
  20. package/dist/gestures.d.ts +1 -1
  21. package/dist/index.cjs +10 -10
  22. package/dist/index.d.cts +3 -3
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +1 -1
  25. package/dist/react.cjs +3 -3
  26. package/dist/react.d.cts +2 -2
  27. package/dist/react.d.ts +2 -2
  28. package/dist/react.js +1 -1
  29. package/dist/{shared-BBXgEeIa.d.ts → shared-BoHXlPCu.d.ts} +34 -1
  30. package/dist/{shared-DU_87nY9.d.cts → shared-DdGFz3oy.d.cts} +34 -1
  31. package/dist/solid.cjs +3 -3
  32. package/dist/solid.d.cts +2 -2
  33. package/dist/solid.d.ts +2 -2
  34. package/dist/solid.js +1 -1
  35. package/dist/svelte.cjs +3 -3
  36. package/dist/svelte.d.cts +2 -2
  37. package/dist/svelte.d.ts +2 -2
  38. package/dist/svelte.js +1 -1
  39. package/dist/themes/retro.css +8 -0
  40. package/dist/themes.cjs +8747 -0
  41. package/dist/themes.cjs.map +1 -0
  42. package/dist/themes.d.cts +12 -0
  43. package/dist/themes.d.ts +12 -0
  44. package/dist/themes.js +8742 -0
  45. package/dist/themes.js.map +1 -0
  46. package/dist/vue.cjs +3 -3
  47. package/dist/vue.d.cts +2 -2
  48. package/dist/vue.d.ts +2 -2
  49. package/dist/vue.js +1 -1
  50. package/package.json +44 -7
  51. package/dist/chunk-DINVOL6Z.cjs.map +0 -1
  52. package/dist/chunk-MGWCKHTZ.js.map +0 -1
package/README.md CHANGED
@@ -68,7 +68,7 @@ The desktop element becomes the coordinate space. Your markup stays yours — wm
68
68
  | Attribute | Meaning |
69
69
  | --- | --- |
70
70
  | `data-wm-drag` | drag handle (usually the titlebar); double-click toggles maximize |
71
- | `data-wm-title` | window title node, linked via `aria-labelledby` |
71
+ | `data-wm-title` | window title node; its text follows the state, and it is linked via `aria-labelledby` when it shares a root with the window |
72
72
  | `data-wm-close` / `data-wm-minimize` / `data-wm-maximize` | control buttons, wired by delegation |
73
73
  | `data-wm-content` | scrollable content area (styled by themes) |
74
74
 
@@ -339,6 +339,28 @@ attachDesktop(wm, root, { gestures: [touchGestures({ swipe: { workspaces: 4 } })
339
339
 
340
340
  A gesture is just a function that takes a `GestureContext` and returns its teardown, so your own gestures cooperate with the built-in drag and resize through the same `claim`/`busy` pair — see [docs/api.md](docs/api.md).
341
341
 
342
+ ### `skin(spec)`, `defaultSkin`, `barebones` — `@surdeddd/wmkit/chrome`
343
+
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. 802 B brotlied.
345
+
346
+ ```js
347
+ import { attachDesktop } from '@surdeddd/wmkit'
348
+ import { skin } from '@surdeddd/wmkit/chrome'
349
+
350
+ const mine = skin({
351
+ name: 'mine',
352
+ template:
353
+ '<section><header data-wm-drag><span data-wm-title>{{title}}</span>' +
354
+ '<button data-wm-close aria-label="Close {{title}}"></button></header>' +
355
+ '<div data-wm-content></div></section>',
356
+ })
357
+
358
+ const desktop = attachDesktop(wm, root, { skins: { mine } })
359
+ desktop.mountWindow('notes', 'mine').content.append(myApp)
360
+ ```
361
+
362
+ `data-wm-close`, `data-wm-minimize`, `data-wm-maximize`, `data-wm-restore`, `data-wm-center`, `data-wm-send-back`, `data-wm-snap="left"` and `data-wm-to-workspace="2"` are read straight off your markup. Every `{{placeholder}}` is HTML-escaped. `shadow: true` seals the chrome inside an open shadow root without losing grouping, focus trapping or the accessible name — see [docs/recipes.md](docs/recipes.md).
363
+
342
364
  ### `createDevtools(wm, options?)` — `@surdeddd/wmkit/devtools`
343
365
 
344
366
  An opt-in panel that shows the live window table, an event log and the manager controls, so you can see what the state machine is doing without a debugger. It follows the manager, never the DOM, so it works with any adapter or none.
package/README.ru.md CHANGED
@@ -64,7 +64,7 @@ desktop.attachWindow(win.id, el, { removeOnClose: true })
64
64
  | Атрибут | Смысл |
65
65
  | --- | --- |
66
66
  | `data-wm-drag` | ручка перетаскивания (обычно тайтлбар); двойной клик — toggle maximize |
67
- | `data-wm-title` | узел заголовка, связывается через `aria-labelledby` |
67
+ | `data-wm-title` | узел заголовка: его текст следует за состоянием, а связь через `aria-labelledby` ставится, когда узел лежит в том же корне, что и окно |
68
68
  | `data-wm-close` / `data-wm-minimize` / `data-wm-maximize` | кнопки управления, работают через делегирование |
69
69
  | `data-wm-content` | скроллируемая область контента |
70
70
 
@@ -275,6 +275,28 @@ attachDesktop(wm, root, { gestures: [touchGestures({ swipe: { workspaces: 4 } })
275
275
 
276
276
  Жест — это просто функция: принимает `GestureContext`, возвращает свою отписку. Свои жесты уживаются со встроенными драгом и ресайзом через ту же пару `claim`/`busy` — подробности в [docs/api.md](docs/api.md).
277
277
 
278
+ ### `skin(spec)`, `defaultSkin`, `barebones` — `@surdeddd/wmkit/chrome`
279
+
280
+ Собирает само окно из строки разметки: можно принести свою обвязку и свои кнопки, не написав ни одного обработчика. 802 Б в brotli.
281
+
282
+ ```js
283
+ import { attachDesktop } from '@surdeddd/wmkit'
284
+ import { skin } from '@surdeddd/wmkit/chrome'
285
+
286
+ const mine = skin({
287
+ name: 'mine',
288
+ template:
289
+ '<section><header data-wm-drag><span data-wm-title>{{title}}</span>' +
290
+ '<button data-wm-close aria-label="Закрыть {{title}}"></button></header>' +
291
+ '<div data-wm-content></div></section>',
292
+ })
293
+
294
+ const desktop = attachDesktop(wm, root, { skins: { mine } })
295
+ desktop.mountWindow('notes', 'mine').content.append(myApp)
296
+ ```
297
+
298
+ `data-wm-close`, `data-wm-minimize`, `data-wm-maximize`, `data-wm-restore`, `data-wm-center`, `data-wm-send-back`, `data-wm-snap="left"` и `data-wm-to-workspace="2"` читаются прямо из вашей разметки. Каждая подстановка `{{...}}` экранируется. `shadow: true` запечатывает обвязку в открытом теневом корне, не теряя ни группировку, ни ловушку фокуса, ни доступное имя — подробности в [docs/recipes.md](docs/recipes.md).
299
+
278
300
  ### `createDevtools(wm, options?)` — `@surdeddd/wmkit/devtools`
279
301
 
280
302
  Панель, которую подключают по желанию: живая таблица окон, журнал событий и управление менеджером — чтобы видеть, что делает машина состояний, без отладчика. Она следит за менеджером, а не за DOM, поэтому работает с любым адаптером и без него.
package/dist/angular.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkDINVOL6Z_cjs = require('./chunk-DINVOL6Z.cjs');
3
+ var chunkZWUVWRUS_cjs = require('./chunk-ZWUVWRUS.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 = chunkDINVOL6Z_cjs.createWindowManager(options);
17
+ const wm = chunkZWUVWRUS_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 = chunkDINVOL6Z_cjs.createDesktopBinder(wm, options);
32
+ const binder = chunkZWUVWRUS_cjs.createDesktopBinder(wm, options);
33
33
  onDestroy(() => binder.destroy());
34
34
  return {
35
35
  binder,
@@ -1,7 +1,7 @@
1
1
  import { Signal } from '@angular/core';
2
2
  import { W as WindowManager, M as ManagerOptions, a as ManagerState, b as WindowState } from './types-jG2lHGcA.cjs';
3
- import { D as DesktopBinder } from './binder-B625OrjD.cjs';
4
- import { W as WindowAttachOptions, D as DesktopOptions } from './shared-DU_87nY9.cjs';
3
+ import { D as DesktopBinder } from './binder-DGoj0xG1.cjs';
4
+ import { W as WindowAttachOptions, D as DesktopOptions } from './shared-DdGFz3oy.cjs';
5
5
 
6
6
  declare function useWindowManager(options?: ManagerOptions): WindowManager;
7
7
  declare function useWmState(wm: WindowManager): Signal<ManagerState>;
package/dist/angular.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Signal } from '@angular/core';
2
2
  import { W as WindowManager, M as ManagerOptions, a as ManagerState, b as WindowState } from './types-jG2lHGcA.js';
3
- import { D as DesktopBinder } from './binder-CpGY8Wye.js';
4
- import { W as WindowAttachOptions, D as DesktopOptions } from './shared-BBXgEeIa.js';
3
+ import { D as DesktopBinder } from './binder-Lo13iTVB.js';
4
+ import { W as WindowAttachOptions, D as DesktopOptions } from './shared-BoHXlPCu.js';
5
5
 
6
6
  declare function useWindowManager(options?: ManagerOptions): WindowManager;
7
7
  declare function useWmState(wm: WindowManager): Signal<ManagerState>;
package/dist/angular.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createWindowManager, createDesktopBinder } from './chunk-MGWCKHTZ.js';
1
+ import { createWindowManager, createDesktopBinder } from './chunk-TUGQX3CX.js';
2
2
  import './chunk-5XVIC5LH.js';
3
3
  import { signal, computed, inject, DestroyRef } from '@angular/core';
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { W as WindowManager } from './types-jG2lHGcA.cjs';
2
- import { a as DesktopController, W as WindowAttachOptions, D as DesktopOptions } from './shared-DU_87nY9.cjs';
2
+ import { a as DesktopController, W as WindowAttachOptions, D as DesktopOptions } from './shared-DdGFz3oy.cjs';
3
3
 
4
4
  interface DesktopBinder {
5
5
  wm: WindowManager;
@@ -1,5 +1,5 @@
1
1
  import { W as WindowManager } from './types-jG2lHGcA.js';
2
- import { a as DesktopController, W as WindowAttachOptions, D as DesktopOptions } from './shared-BBXgEeIa.js';
2
+ import { a as DesktopController, W as WindowAttachOptions, D as DesktopOptions } from './shared-BoHXlPCu.js';
3
3
 
4
4
  interface DesktopBinder {
5
5
  wm: WindowManager;
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ // src/plugins/chrome/messages.ts
4
+ var chromeMessages = {
5
+ minimize: "Minimize",
6
+ maximize: "Maximize",
7
+ close: "Close"
8
+ };
9
+ var chromeMessagesRu = {
10
+ minimize: "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
11
+ maximize: "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
12
+ close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"
13
+ };
14
+
15
+ // src/plugins/chrome/template.ts
16
+ var ESCAPES = {
17
+ "&": "&amp;",
18
+ "<": "&lt;",
19
+ ">": "&gt;",
20
+ '"': "&quot;",
21
+ "'": "&#39;"
22
+ };
23
+ function escapeHtml(value) {
24
+ return value.replace(/[&<>"']/g, (char) => ESCAPES[char]);
25
+ }
26
+ function compileTemplate(template) {
27
+ const parts = template.split(/\{\{\s*([a-z]+)\s*\}\}/i);
28
+ return (values) => parts.map((part, index) => index % 2 === 0 ? part : escapeHtml(values[part] ?? "")).join("");
29
+ }
30
+
31
+ // src/plugins/chrome/index.ts
32
+ var SLOT = "[data-wm-content]";
33
+ var SLOT_PATTERN = /data-wm-content\b/g;
34
+ var BAD_SLOT_COUNT = "wmkit: a skin template needs exactly one [data-wm-content]";
35
+ var BAD_STRUCTURE = "wmkit: a skin template needs a single root element that holds its [data-wm-content]";
36
+ var UNSCOPED_STYLES = "wmkit: a skin with styles needs a name to scope them to";
37
+ function valuesOf(win) {
38
+ const variant = win.meta.variant;
39
+ return {
40
+ id: win.id,
41
+ title: win.title,
42
+ stage: win.stage,
43
+ layer: win.layer,
44
+ workspace: String(win.workspace),
45
+ variant: typeof variant === "string" ? variant : ""
46
+ };
47
+ }
48
+ function injectStyles(doc, name, styles) {
49
+ if (doc.head.querySelector(`style[data-wm-skin-styles="${name}"]`)) return;
50
+ const tag = doc.createElement("style");
51
+ tag.dataset.wmSkinStyles = name;
52
+ tag.textContent = styles;
53
+ doc.head.append(tag);
54
+ }
55
+ function skin(spec) {
56
+ if ((spec.template.match(SLOT_PATTERN) ?? []).length !== 1) throw new Error(BAD_SLOT_COUNT);
57
+ if (spec.styles !== void 0 && spec.name === void 0) throw new Error(UNSCOPED_STYLES);
58
+ const render = compileTemplate(spec.template);
59
+ const sheets = /* @__PURE__ */ new WeakMap();
60
+ function adopt(root, doc, css) {
61
+ if (typeof CSSStyleSheet.prototype.replaceSync !== "function") {
62
+ const tag = doc.createElement("style");
63
+ tag.textContent = css;
64
+ root.prepend(tag);
65
+ return;
66
+ }
67
+ let sheet = sheets.get(doc);
68
+ if (!sheet) {
69
+ sheet = new CSSStyleSheet();
70
+ sheet.replaceSync(css);
71
+ sheets.set(doc, sheet);
72
+ }
73
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
74
+ }
75
+ return ({ doc, window: win }) => {
76
+ const holder = doc.createElement("template");
77
+ holder.innerHTML = render(valuesOf(win));
78
+ const built = holder.content.firstElementChild;
79
+ const slot = built === null ? null : built.matches(SLOT) ? built : built.querySelector(SLOT);
80
+ if (built === null || slot === null) throw new Error(BAD_STRUCTURE);
81
+ if (spec.shadow !== true) {
82
+ if (spec.name !== void 0) built.dataset.wmSkin = spec.name;
83
+ if (spec.styles !== void 0) injectStyles(doc, spec.name, spec.styles);
84
+ return { element: built, content: slot };
85
+ }
86
+ const element = doc.createElement("div");
87
+ if (spec.name !== void 0) element.dataset.wmSkin = spec.name;
88
+ const root = element.attachShadow({ mode: "open" });
89
+ const projection = doc.createElement("slot");
90
+ if (slot === built) root.append(projection);
91
+ else {
92
+ slot.replaceWith(projection);
93
+ root.append(...built.childNodes);
94
+ }
95
+ if (spec.styles !== void 0) adopt(root, doc, spec.styles);
96
+ const content = doc.createElement("div");
97
+ content.dataset.wmContent = "";
98
+ element.append(content);
99
+ return { element, content };
100
+ };
101
+ }
102
+ function windowChrome(messages = chromeMessages) {
103
+ return skin({
104
+ name: "wmkit",
105
+ template: `<section><header data-wm-drag><span data-wm-title>{{title}}</span><span data-wm-controls><button type="button" data-wm-minimize aria-label="${messages.minimize}"></button><button type="button" data-wm-maximize aria-label="${messages.maximize}"></button><button type="button" data-wm-close aria-label="${messages.close}"></button></span></header><div data-wm-content></div></section>`
106
+ });
107
+ }
108
+ var defaultSkin = windowChrome();
109
+ var barebones = skin({
110
+ name: "barebones",
111
+ template: "<section><header data-wm-drag><span data-wm-title>{{title}}</span></header><div data-wm-content></div></section>"
112
+ });
113
+
114
+ exports.barebones = barebones;
115
+ exports.chromeMessages = chromeMessages;
116
+ exports.chromeMessagesRu = chromeMessagesRu;
117
+ exports.compileTemplate = compileTemplate;
118
+ exports.defaultSkin = defaultSkin;
119
+ exports.skin = skin;
120
+ exports.windowChrome = windowChrome;
121
+ //# sourceMappingURL=chrome.cjs.map
122
+ //# sourceMappingURL=chrome.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/chrome/messages.ts","../src/plugins/chrome/template.ts","../src/plugins/chrome/index.ts"],"names":[],"mappings":"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","file":"chrome.cjs","sourcesContent":["export interface ChromeMessages {\n minimize: string\n maximize: string\n close: string\n}\n\nexport const chromeMessages: ChromeMessages = {\n minimize: 'Minimize',\n maximize: 'Maximize',\n close: 'Close',\n}\n\nexport const chromeMessagesRu: ChromeMessages = {\n minimize: 'Свернуть',\n maximize: 'Развернуть',\n close: 'Закрыть',\n}\n","const ESCAPES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n}\n\nfunction escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (char) => ESCAPES[char] as string)\n}\n\nexport function compileTemplate(template: string): (values: Record<string, string>) => string {\n const parts = template.split(/\\{\\{\\s*([a-z]+)\\s*\\}\\}/i)\n return (values) =>\n parts.map((part, index) => (index % 2 === 0 ? part : escapeHtml(values[part] ?? ''))).join('')\n}\n","import type { WindowState } from '../../core/types'\nimport type { SkinMount, WindowSkin } from '../../dom/shared'\nimport { type ChromeMessages, chromeMessages } from './messages'\nimport { compileTemplate } from './template'\n\nexport type { ChromeMessages } from './messages'\nexport { chromeMessages, chromeMessagesRu } from './messages'\nexport { compileTemplate } from './template'\n\nexport interface SkinSpec {\n template: string\n styles?: string\n shadow?: boolean\n name?: string\n}\n\nconst SLOT = '[data-wm-content]'\nconst SLOT_PATTERN = /data-wm-content\\b/g\n\nconst BAD_SLOT_COUNT = 'wmkit: a skin template needs exactly one [data-wm-content]'\nconst BAD_STRUCTURE =\n 'wmkit: a skin template needs a single root element that holds its [data-wm-content]'\nconst UNSCOPED_STYLES = 'wmkit: a skin with styles needs a name to scope them to'\n\nfunction valuesOf(win: WindowState): Record<string, string> {\n const variant = win.meta.variant\n return {\n id: win.id,\n title: win.title,\n stage: win.stage,\n layer: win.layer,\n workspace: String(win.workspace),\n variant: typeof variant === 'string' ? variant : '',\n }\n}\n\nfunction injectStyles(doc: Document, name: string, styles: string): void {\n if (doc.head.querySelector(`style[data-wm-skin-styles=\"${name}\"]`)) return\n const tag = doc.createElement('style')\n tag.dataset.wmSkinStyles = name\n tag.textContent = styles\n doc.head.append(tag)\n}\n\nexport function skin(spec: SkinSpec): WindowSkin {\n if ((spec.template.match(SLOT_PATTERN) ?? []).length !== 1) throw new Error(BAD_SLOT_COUNT)\n if (spec.styles !== undefined && spec.name === undefined) throw new Error(UNSCOPED_STYLES)\n const render = compileTemplate(spec.template)\n const sheets = new WeakMap<Document, CSSStyleSheet>()\n\n function adopt(root: ShadowRoot, doc: Document, css: string): void {\n if (typeof CSSStyleSheet.prototype.replaceSync !== 'function') {\n const tag = doc.createElement('style')\n tag.textContent = css\n root.prepend(tag)\n return\n }\n let sheet = sheets.get(doc)\n if (!sheet) {\n sheet = new CSSStyleSheet()\n sheet.replaceSync(css)\n sheets.set(doc, sheet)\n }\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet]\n }\n\n return ({ doc, window: win }): SkinMount => {\n const holder = doc.createElement('template')\n holder.innerHTML = render(valuesOf(win))\n const built = holder.content.firstElementChild as HTMLElement | null\n const slot =\n built === null ? null : built.matches(SLOT) ? built : built.querySelector<HTMLElement>(SLOT)\n if (built === null || slot === null) throw new Error(BAD_STRUCTURE)\n\n if (spec.shadow !== true) {\n if (spec.name !== undefined) built.dataset.wmSkin = spec.name\n if (spec.styles !== undefined) injectStyles(doc, spec.name as string, spec.styles)\n return { element: built, content: slot }\n }\n\n const element = doc.createElement('div')\n if (spec.name !== undefined) element.dataset.wmSkin = spec.name\n const root = element.attachShadow({ mode: 'open' })\n const projection = doc.createElement('slot')\n if (slot === built) root.append(projection)\n else {\n slot.replaceWith(projection)\n root.append(...built.childNodes)\n }\n if (spec.styles !== undefined) adopt(root, doc, spec.styles)\n const content = doc.createElement('div')\n content.dataset.wmContent = ''\n element.append(content)\n return { element, content }\n }\n}\n\nexport function windowChrome(messages: ChromeMessages = chromeMessages): WindowSkin {\n return skin({\n name: 'wmkit',\n template:\n '<section>' +\n '<header data-wm-drag>' +\n '<span data-wm-title>{{title}}</span>' +\n '<span data-wm-controls>' +\n `<button type=\"button\" data-wm-minimize aria-label=\"${messages.minimize}\"></button>` +\n `<button type=\"button\" data-wm-maximize aria-label=\"${messages.maximize}\"></button>` +\n `<button type=\"button\" data-wm-close aria-label=\"${messages.close}\"></button>` +\n '</span>' +\n '</header>' +\n '<div data-wm-content></div>' +\n '</section>',\n })\n}\n\nexport const defaultSkin: WindowSkin = windowChrome()\n\nexport const barebones: WindowSkin = skin({\n name: 'barebones',\n template:\n '<section>' +\n '<header data-wm-drag><span data-wm-title>{{title}}</span></header>' +\n '<div data-wm-content></div>' +\n '</section>',\n})\n"]}
@@ -0,0 +1,25 @@
1
+ import { l as WindowSkin } from './shared-DdGFz3oy.cjs';
2
+ import './types-jG2lHGcA.cjs';
3
+
4
+ interface ChromeMessages {
5
+ minimize: string;
6
+ maximize: string;
7
+ close: string;
8
+ }
9
+ declare const chromeMessages: ChromeMessages;
10
+ declare const chromeMessagesRu: ChromeMessages;
11
+
12
+ declare function compileTemplate(template: string): (values: Record<string, string>) => string;
13
+
14
+ interface SkinSpec {
15
+ template: string;
16
+ styles?: string;
17
+ shadow?: boolean;
18
+ name?: string;
19
+ }
20
+ declare function skin(spec: SkinSpec): WindowSkin;
21
+ declare function windowChrome(messages?: ChromeMessages): WindowSkin;
22
+ declare const defaultSkin: WindowSkin;
23
+ declare const barebones: WindowSkin;
24
+
25
+ export { type ChromeMessages, type SkinSpec, barebones, chromeMessages, chromeMessagesRu, compileTemplate, defaultSkin, skin, windowChrome };
@@ -0,0 +1,25 @@
1
+ import { l as WindowSkin } from './shared-BoHXlPCu.js';
2
+ import './types-jG2lHGcA.js';
3
+
4
+ interface ChromeMessages {
5
+ minimize: string;
6
+ maximize: string;
7
+ close: string;
8
+ }
9
+ declare const chromeMessages: ChromeMessages;
10
+ declare const chromeMessagesRu: ChromeMessages;
11
+
12
+ declare function compileTemplate(template: string): (values: Record<string, string>) => string;
13
+
14
+ interface SkinSpec {
15
+ template: string;
16
+ styles?: string;
17
+ shadow?: boolean;
18
+ name?: string;
19
+ }
20
+ declare function skin(spec: SkinSpec): WindowSkin;
21
+ declare function windowChrome(messages?: ChromeMessages): WindowSkin;
22
+ declare const defaultSkin: WindowSkin;
23
+ declare const barebones: WindowSkin;
24
+
25
+ export { type ChromeMessages, type SkinSpec, barebones, chromeMessages, chromeMessagesRu, compileTemplate, defaultSkin, skin, windowChrome };
package/dist/chrome.js ADDED
@@ -0,0 +1,114 @@
1
+ // src/plugins/chrome/messages.ts
2
+ var chromeMessages = {
3
+ minimize: "Minimize",
4
+ maximize: "Maximize",
5
+ close: "Close"
6
+ };
7
+ var chromeMessagesRu = {
8
+ minimize: "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
9
+ maximize: "\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
10
+ close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"
11
+ };
12
+
13
+ // src/plugins/chrome/template.ts
14
+ var ESCAPES = {
15
+ "&": "&amp;",
16
+ "<": "&lt;",
17
+ ">": "&gt;",
18
+ '"': "&quot;",
19
+ "'": "&#39;"
20
+ };
21
+ function escapeHtml(value) {
22
+ return value.replace(/[&<>"']/g, (char) => ESCAPES[char]);
23
+ }
24
+ function compileTemplate(template) {
25
+ const parts = template.split(/\{\{\s*([a-z]+)\s*\}\}/i);
26
+ return (values) => parts.map((part, index) => index % 2 === 0 ? part : escapeHtml(values[part] ?? "")).join("");
27
+ }
28
+
29
+ // src/plugins/chrome/index.ts
30
+ var SLOT = "[data-wm-content]";
31
+ var SLOT_PATTERN = /data-wm-content\b/g;
32
+ var BAD_SLOT_COUNT = "wmkit: a skin template needs exactly one [data-wm-content]";
33
+ var BAD_STRUCTURE = "wmkit: a skin template needs a single root element that holds its [data-wm-content]";
34
+ var UNSCOPED_STYLES = "wmkit: a skin with styles needs a name to scope them to";
35
+ function valuesOf(win) {
36
+ const variant = win.meta.variant;
37
+ return {
38
+ id: win.id,
39
+ title: win.title,
40
+ stage: win.stage,
41
+ layer: win.layer,
42
+ workspace: String(win.workspace),
43
+ variant: typeof variant === "string" ? variant : ""
44
+ };
45
+ }
46
+ function injectStyles(doc, name, styles) {
47
+ if (doc.head.querySelector(`style[data-wm-skin-styles="${name}"]`)) return;
48
+ const tag = doc.createElement("style");
49
+ tag.dataset.wmSkinStyles = name;
50
+ tag.textContent = styles;
51
+ doc.head.append(tag);
52
+ }
53
+ function skin(spec) {
54
+ if ((spec.template.match(SLOT_PATTERN) ?? []).length !== 1) throw new Error(BAD_SLOT_COUNT);
55
+ if (spec.styles !== void 0 && spec.name === void 0) throw new Error(UNSCOPED_STYLES);
56
+ const render = compileTemplate(spec.template);
57
+ const sheets = /* @__PURE__ */ new WeakMap();
58
+ function adopt(root, doc, css) {
59
+ if (typeof CSSStyleSheet.prototype.replaceSync !== "function") {
60
+ const tag = doc.createElement("style");
61
+ tag.textContent = css;
62
+ root.prepend(tag);
63
+ return;
64
+ }
65
+ let sheet = sheets.get(doc);
66
+ if (!sheet) {
67
+ sheet = new CSSStyleSheet();
68
+ sheet.replaceSync(css);
69
+ sheets.set(doc, sheet);
70
+ }
71
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
72
+ }
73
+ return ({ doc, window: win }) => {
74
+ const holder = doc.createElement("template");
75
+ holder.innerHTML = render(valuesOf(win));
76
+ const built = holder.content.firstElementChild;
77
+ const slot = built === null ? null : built.matches(SLOT) ? built : built.querySelector(SLOT);
78
+ if (built === null || slot === null) throw new Error(BAD_STRUCTURE);
79
+ if (spec.shadow !== true) {
80
+ if (spec.name !== void 0) built.dataset.wmSkin = spec.name;
81
+ if (spec.styles !== void 0) injectStyles(doc, spec.name, spec.styles);
82
+ return { element: built, content: slot };
83
+ }
84
+ const element = doc.createElement("div");
85
+ if (spec.name !== void 0) element.dataset.wmSkin = spec.name;
86
+ const root = element.attachShadow({ mode: "open" });
87
+ const projection = doc.createElement("slot");
88
+ if (slot === built) root.append(projection);
89
+ else {
90
+ slot.replaceWith(projection);
91
+ root.append(...built.childNodes);
92
+ }
93
+ if (spec.styles !== void 0) adopt(root, doc, spec.styles);
94
+ const content = doc.createElement("div");
95
+ content.dataset.wmContent = "";
96
+ element.append(content);
97
+ return { element, content };
98
+ };
99
+ }
100
+ function windowChrome(messages = chromeMessages) {
101
+ return skin({
102
+ name: "wmkit",
103
+ template: `<section><header data-wm-drag><span data-wm-title>{{title}}</span><span data-wm-controls><button type="button" data-wm-minimize aria-label="${messages.minimize}"></button><button type="button" data-wm-maximize aria-label="${messages.maximize}"></button><button type="button" data-wm-close aria-label="${messages.close}"></button></span></header><div data-wm-content></div></section>`
104
+ });
105
+ }
106
+ var defaultSkin = windowChrome();
107
+ var barebones = skin({
108
+ name: "barebones",
109
+ template: "<section><header data-wm-drag><span data-wm-title>{{title}}</span></header><div data-wm-content></div></section>"
110
+ });
111
+
112
+ export { barebones, chromeMessages, chromeMessagesRu, compileTemplate, defaultSkin, skin, windowChrome };
113
+ //# sourceMappingURL=chrome.js.map
114
+ //# sourceMappingURL=chrome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/chrome/messages.ts","../src/plugins/chrome/template.ts","../src/plugins/chrome/index.ts"],"names":[],"mappings":";AAMO,IAAM,cAAA,GAAiC;AAAA,EAC5C,QAAA,EAAU,UAAA;AAAA,EACV,QAAA,EAAU,UAAA;AAAA,EACV,KAAA,EAAO;AACT;AAEO,IAAM,gBAAA,GAAmC;AAAA,EAC9C,QAAA,EAAU,kDAAA;AAAA,EACV,QAAA,EAAU,8DAAA;AAAA,EACV,KAAA,EAAO;AACT;;;AChBA,IAAM,OAAA,GAAkC;AAAA,EACtC,GAAA,EAAK,OAAA;AAAA,EACL,GAAA,EAAK,MAAA;AAAA,EACL,GAAA,EAAK,MAAA;AAAA,EACL,GAAA,EAAK,QAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AAEA,SAAS,WAAW,KAAA,EAAuB;AACzC,EAAA,OAAO,MAAM,OAAA,CAAQ,UAAA,EAAY,CAAC,IAAA,KAAS,OAAA,CAAQ,IAAI,CAAW,CAAA;AACpE;AAEO,SAAS,gBAAgB,QAAA,EAA8D;AAC5F,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,yBAAyB,CAAA;AACtD,EAAA,OAAO,CAAC,MAAA,KACN,KAAA,CAAM,IAAI,CAAC,IAAA,EAAM,UAAW,KAAA,GAAQ,CAAA,KAAM,IAAI,IAAA,GAAO,UAAA,CAAW,OAAO,IAAI,CAAA,IAAK,EAAE,CAAE,CAAA,CAAE,KAAK,EAAE,CAAA;AACjG;;;ACAA,IAAM,IAAA,GAAO,mBAAA;AACb,IAAM,YAAA,GAAe,oBAAA;AAErB,IAAM,cAAA,GAAiB,4DAAA;AACvB,IAAM,aAAA,GACJ,qFAAA;AACF,IAAM,eAAA,GAAkB,yDAAA;AAExB,SAAS,SAAS,GAAA,EAA0C;AAC1D,EAAA,MAAM,OAAA,GAAU,IAAI,IAAA,CAAK,OAAA;AACzB,EAAA,OAAO;AAAA,IACL,IAAI,GAAA,CAAI,EAAA;AAAA,IACR,OAAO,GAAA,CAAI,KAAA;AAAA,IACX,OAAO,GAAA,CAAI,KAAA;AAAA,IACX,OAAO,GAAA,CAAI,KAAA;AAAA,IACX,SAAA,EAAW,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AAAA,IAC/B,OAAA,EAAS,OAAO,OAAA,KAAY,QAAA,GAAW,OAAA,GAAU;AAAA,GACnD;AACF;AAEA,SAAS,YAAA,CAAa,GAAA,EAAe,IAAA,EAAc,MAAA,EAAsB;AACvE,EAAA,IAAI,IAAI,IAAA,CAAK,aAAA,CAAc,CAAA,2BAAA,EAA8B,IAAI,IAAI,CAAA,EAAG;AACpE,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,aAAA,CAAc,OAAO,CAAA;AACrC,EAAA,GAAA,CAAI,QAAQ,YAAA,GAAe,IAAA;AAC3B,EAAA,GAAA,CAAI,WAAA,GAAc,MAAA;AAClB,EAAA,GAAA,CAAI,IAAA,CAAK,OAAO,GAAG,CAAA;AACrB;AAEO,SAAS,KAAK,IAAA,EAA4B;AAC/C,EAAA,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,KAAA,CAAM,YAAY,CAAA,IAAK,EAAC,EAAG,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,cAAc,CAAA;AAC1F,EAAA,IAAI,IAAA,CAAK,WAAW,MAAA,IAAa,IAAA,CAAK,SAAS,MAAA,EAAW,MAAM,IAAI,KAAA,CAAM,eAAe,CAAA;AACzF,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,QAAQ,CAAA;AAC5C,EAAA,MAAM,MAAA,uBAAa,OAAA,EAAiC;AAEpD,EAAA,SAAS,KAAA,CAAM,IAAA,EAAkB,GAAA,EAAe,GAAA,EAAmB;AACjE,IAAA,IAAI,OAAO,aAAA,CAAc,SAAA,CAAU,WAAA,KAAgB,UAAA,EAAY;AAC7D,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,aAAA,CAAc,OAAO,CAAA;AACrC,MAAA,GAAA,CAAI,WAAA,GAAc,GAAA;AAClB,MAAA,IAAA,CAAK,QAAQ,GAAG,CAAA;AAChB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,KAAA,GAAQ,IAAI,aAAA,EAAc;AAC1B,MAAA,KAAA,CAAM,YAAY,GAAG,CAAA;AACrB,MAAA,MAAA,CAAO,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IACvB;AACA,IAAA,IAAA,CAAK,kBAAA,GAAqB,CAAC,GAAG,IAAA,CAAK,oBAAoB,KAAK,CAAA;AAAA,EAC9D;AAEA,EAAA,OAAO,CAAC,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAI,KAAiB;AAC1C,IAAA,MAAM,MAAA,GAAS,GAAA,CAAI,aAAA,CAAc,UAAU,CAAA;AAC3C,IAAA,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,QAAA,CAAS,GAAG,CAAC,CAAA;AACvC,IAAA,MAAM,KAAA,GAAQ,OAAO,OAAA,CAAQ,iBAAA;AAC7B,IAAA,MAAM,IAAA,GACJ,KAAA,KAAU,IAAA,GAAO,IAAA,GAAO,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,KAAA,GAAQ,KAAA,CAAM,aAAA,CAA2B,IAAI,CAAA;AAC7F,IAAA,IAAI,UAAU,IAAA,IAAQ,IAAA,KAAS,MAAM,MAAM,IAAI,MAAM,aAAa,CAAA;AAElE,IAAA,IAAI,IAAA,CAAK,WAAW,IAAA,EAAM;AACxB,MAAA,IAAI,KAAK,IAAA,KAAS,MAAA,EAAW,KAAA,CAAM,OAAA,CAAQ,SAAS,IAAA,CAAK,IAAA;AACzD,MAAA,IAAI,IAAA,CAAK,WAAW,MAAA,EAAW,YAAA,CAAa,KAAK,IAAA,CAAK,IAAA,EAAgB,KAAK,MAAM,CAAA;AACjF,MAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,IAAA,EAAK;AAAA,IACzC;AAEA,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,aAAA,CAAc,KAAK,CAAA;AACvC,IAAA,IAAI,KAAK,IAAA,KAAS,MAAA,EAAW,OAAA,CAAQ,OAAA,CAAQ,SAAS,IAAA,CAAK,IAAA;AAC3D,IAAA,MAAM,OAAO,OAAA,CAAQ,YAAA,CAAa,EAAE,IAAA,EAAM,QAAQ,CAAA;AAClD,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,aAAA,CAAc,MAAM,CAAA;AAC3C,IAAA,IAAI,IAAA,KAAS,KAAA,EAAO,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA;AAAA,SACrC;AACH,MAAA,IAAA,CAAK,YAAY,UAAU,CAAA;AAC3B,MAAA,IAAA,CAAK,MAAA,CAAO,GAAG,KAAA,CAAM,UAAU,CAAA;AAAA,IACjC;AACA,IAAA,IAAI,KAAK,MAAA,KAAW,MAAA,QAAiB,IAAA,EAAM,GAAA,EAAK,KAAK,MAAM,CAAA;AAC3D,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,aAAA,CAAc,KAAK,CAAA;AACvC,IAAA,OAAA,CAAQ,QAAQ,SAAA,GAAY,EAAA;AAC5B,IAAA,OAAA,CAAQ,OAAO,OAAO,CAAA;AACtB,IAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAAA,EAC5B,CAAA;AACF;AAEO,SAAS,YAAA,CAAa,WAA2B,cAAA,EAA4B;AAClF,EAAA,OAAO,IAAA,CAAK;AAAA,IACV,IAAA,EAAM,OAAA;AAAA,IACN,QAAA,EACE,+IAIsD,QAAA,CAAS,QAAQ,iEACjB,QAAA,CAAS,QAAQ,CAAA,2DAAA,EACpB,QAAA,CAAS,KAAK,CAAA,gEAAA;AAAA,GAKpE,CAAA;AACH;AAEO,IAAM,cAA0B,YAAA;AAEhC,IAAM,YAAwB,IAAA,CAAK;AAAA,EACxC,IAAA,EAAM,WAAA;AAAA,EACN,QAAA,EACE;AAIJ,CAAC","file":"chrome.js","sourcesContent":["export interface ChromeMessages {\n minimize: string\n maximize: string\n close: string\n}\n\nexport const chromeMessages: ChromeMessages = {\n minimize: 'Minimize',\n maximize: 'Maximize',\n close: 'Close',\n}\n\nexport const chromeMessagesRu: ChromeMessages = {\n minimize: 'Свернуть',\n maximize: 'Развернуть',\n close: 'Закрыть',\n}\n","const ESCAPES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n}\n\nfunction escapeHtml(value: string): string {\n return value.replace(/[&<>\"']/g, (char) => ESCAPES[char] as string)\n}\n\nexport function compileTemplate(template: string): (values: Record<string, string>) => string {\n const parts = template.split(/\\{\\{\\s*([a-z]+)\\s*\\}\\}/i)\n return (values) =>\n parts.map((part, index) => (index % 2 === 0 ? part : escapeHtml(values[part] ?? ''))).join('')\n}\n","import type { WindowState } from '../../core/types'\nimport type { SkinMount, WindowSkin } from '../../dom/shared'\nimport { type ChromeMessages, chromeMessages } from './messages'\nimport { compileTemplate } from './template'\n\nexport type { ChromeMessages } from './messages'\nexport { chromeMessages, chromeMessagesRu } from './messages'\nexport { compileTemplate } from './template'\n\nexport interface SkinSpec {\n template: string\n styles?: string\n shadow?: boolean\n name?: string\n}\n\nconst SLOT = '[data-wm-content]'\nconst SLOT_PATTERN = /data-wm-content\\b/g\n\nconst BAD_SLOT_COUNT = 'wmkit: a skin template needs exactly one [data-wm-content]'\nconst BAD_STRUCTURE =\n 'wmkit: a skin template needs a single root element that holds its [data-wm-content]'\nconst UNSCOPED_STYLES = 'wmkit: a skin with styles needs a name to scope them to'\n\nfunction valuesOf(win: WindowState): Record<string, string> {\n const variant = win.meta.variant\n return {\n id: win.id,\n title: win.title,\n stage: win.stage,\n layer: win.layer,\n workspace: String(win.workspace),\n variant: typeof variant === 'string' ? variant : '',\n }\n}\n\nfunction injectStyles(doc: Document, name: string, styles: string): void {\n if (doc.head.querySelector(`style[data-wm-skin-styles=\"${name}\"]`)) return\n const tag = doc.createElement('style')\n tag.dataset.wmSkinStyles = name\n tag.textContent = styles\n doc.head.append(tag)\n}\n\nexport function skin(spec: SkinSpec): WindowSkin {\n if ((spec.template.match(SLOT_PATTERN) ?? []).length !== 1) throw new Error(BAD_SLOT_COUNT)\n if (spec.styles !== undefined && spec.name === undefined) throw new Error(UNSCOPED_STYLES)\n const render = compileTemplate(spec.template)\n const sheets = new WeakMap<Document, CSSStyleSheet>()\n\n function adopt(root: ShadowRoot, doc: Document, css: string): void {\n if (typeof CSSStyleSheet.prototype.replaceSync !== 'function') {\n const tag = doc.createElement('style')\n tag.textContent = css\n root.prepend(tag)\n return\n }\n let sheet = sheets.get(doc)\n if (!sheet) {\n sheet = new CSSStyleSheet()\n sheet.replaceSync(css)\n sheets.set(doc, sheet)\n }\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet]\n }\n\n return ({ doc, window: win }): SkinMount => {\n const holder = doc.createElement('template')\n holder.innerHTML = render(valuesOf(win))\n const built = holder.content.firstElementChild as HTMLElement | null\n const slot =\n built === null ? null : built.matches(SLOT) ? built : built.querySelector<HTMLElement>(SLOT)\n if (built === null || slot === null) throw new Error(BAD_STRUCTURE)\n\n if (spec.shadow !== true) {\n if (spec.name !== undefined) built.dataset.wmSkin = spec.name\n if (spec.styles !== undefined) injectStyles(doc, spec.name as string, spec.styles)\n return { element: built, content: slot }\n }\n\n const element = doc.createElement('div')\n if (spec.name !== undefined) element.dataset.wmSkin = spec.name\n const root = element.attachShadow({ mode: 'open' })\n const projection = doc.createElement('slot')\n if (slot === built) root.append(projection)\n else {\n slot.replaceWith(projection)\n root.append(...built.childNodes)\n }\n if (spec.styles !== undefined) adopt(root, doc, spec.styles)\n const content = doc.createElement('div')\n content.dataset.wmContent = ''\n element.append(content)\n return { element, content }\n }\n}\n\nexport function windowChrome(messages: ChromeMessages = chromeMessages): WindowSkin {\n return skin({\n name: 'wmkit',\n template:\n '<section>' +\n '<header data-wm-drag>' +\n '<span data-wm-title>{{title}}</span>' +\n '<span data-wm-controls>' +\n `<button type=\"button\" data-wm-minimize aria-label=\"${messages.minimize}\"></button>` +\n `<button type=\"button\" data-wm-maximize aria-label=\"${messages.maximize}\"></button>` +\n `<button type=\"button\" data-wm-close aria-label=\"${messages.close}\"></button>` +\n '</span>' +\n '</header>' +\n '<div data-wm-content></div>' +\n '</section>',\n })\n}\n\nexport const defaultSkin: WindowSkin = windowChrome()\n\nexport const barebones: WindowSkin = skin({\n name: 'barebones',\n template:\n '<section>' +\n '<header data-wm-drag><span data-wm-title>{{title}}</span></header>' +\n '<div data-wm-content></div>' +\n '</section>',\n})\n"]}