Поддержка браузеров
wmkit поставляется в ES2022 (target: es2022 в tsup), ESM + CJS, без полифиллов и без рантайм-зависимостей. Нижнюю планку задают платформенные API, которых касается каждый слой, а не синтаксис, — поэтому ответ зависит от того, какую часть пакета вы на самом деле импортируете.
Поддерживаемые минимальные версии
| Что вы импортируете | Chrome / Edge | Safari | Firefox | Чем задано |
|---|---|---|---|---|
| ядро (машина состояний) без именованных раскладок | 94 | 15.4 | 93 | целевая платформа сборки ES2022 |
ядро с saveLayout / getLayout / setLayout | 98 | 15.4 | 94 | structuredClone; старые движки копируют раскладки через JSON, см. ниже |
attachDesktop (перетаскивание, ресайз, снэп, клавиатура, a11y) | 98 | 15.4 | 94 | по-прежнему определяют ES2022 и structuredClone |
themes/glass.css, themes/light.css | 111 | 16.2 | 113 | color-mix() в превью снэпа |
themes/retro.css | 98 | 15.4 | 94 | только обычные рамки и градиенты |
@surdeddd/wmkit/persist | 98 | 15.4 | 94 | как у ядра; если localStorage нет или он бросает исключения, плагин ничего не делает |
@surdeddd/wmkit/popout | 98 | 15.4 | 94 | всплывающее окно window.open везде; для picture-in-picture нужны Chrome/Edge 116+ или Firefox 151+ |
@surdeddd/wmkit/dock | 98 | 15.4 | 94 | как у attachDesktop; MutationObserver помечает поздние окна |
Адаптеры добавляют только то, что требует их фреймворк: React >= 18, Vue >= 3.3, Svelte >= 4, Solid >= 1.8, Angular >= 16.
DOM API, которые нужны контроллеру, — захват указателя, ResizeObserver, requestAnimationFrame — появились за годы до целевой ES2022, поэтому на практике планку они никогда не задают.
Если коротко: библиотека работает во всех браузерах начиная с начала 2022 года; импорт встроенной стеклянной темы поднимает планку до весны 2023-го. Стилизуйте окна сами — и строка про темы исчезнет совсем.
Платформенные API и что бывает без них
| API | Кто использует | Что без него |
|---|---|---|
Pointer Events + setPointerCapture | src/dom/drag.ts, src/dom/resize.ts, разделители панелей | нет перетаскивания и ресайза; управление с клавиатуры и ядро продолжают работать |
ResizeObserver | отслеживание вьюпорта в attachDesktop | проверяется наличие — рабочий стол измеряется один раз при привязке; когда его размер меняется, вызывайте wm.setViewport() сами |
requestAnimationFrame | группировка ввода указателя по кадрам при перетаскивании и ресайзе | обязателен |
structuredClone | именованные раскладки в src/core/manager.ts | раскладки копируются через JSON: функции в meta пропадают, Date превращаются в строки, а Infinity — в null; остальные методы ядра не затронуты |
Element.animate | FLIP-призраки при сворачивании и восстановлении | проверяется наличие — анимация пропускается, состояние всё равно меняется |
Element.moveBefore | пересборка скина в src/dom/controller.ts | проверяется наличие — контент переносится через append, поэтому iframe внутри пересобранного окна перезагружается (в Chromium 133+ он продолжает работать) |
matchMedia | определение грубого указателя и reduced motion | проверяется наличие — откат к значениям по умолчанию для точного указателя |
localStorage | хранилище persist по умолчанию | читается внутри try/catch; плагин перестаёт что-либо делать, или передайте своё хранилище |
reportError | ошибки persist, когда нет onError | проверяется наличие — ошибка молча отбрасывается |
CSSStyleSheet.replaceSync (constructable stylesheets) | <wm-desktop>.styles, теневые скины из @surdeddd/wmkit/chrome | <wm-desktop>.styles пропускает CSS-строки (Safari до 16.4); теневой скин переходит на элемент <style> |
document.adoptedStyleSheets | копирование стилей в popout | проверяется наличие — копируются только document.styleSheets |
documentPictureInPicture | popout (target: 'pip', и 'auto', когда он есть) | 'auto' откатывается на всплывающее окно; isPopoutSupported('pip') возвращает false |
window.open | popout (target: 'window') | isPopoutSupported() возвращает false, когда нет ни того, ни другого; popout() отклоняется с понятной ошибкой |
getScreenDetails (Window Management API) | опция screen в popout, listScreens() | проверяется наличие — всплывающее окно открывается там, где браузер ставит его по умолчанию, а listScreens() разрешается в null; то же самое происходит, когда в разрешении отказано |
Ничто в src/core не трогает window или document, поэтому менеджер можно создавать, менять, сериализовать и восстанавливать через hydrate во время SSR. Документ нужен только attachDesktop и хелперам привязки из адаптеров — вызывайте их после монтирования.
Возможности CSS во встроенных темах
| Возможность | Где | Запасной вариант |
|---|---|---|
color-mix() | заливка и рамка превью снэпа (glass.css, light.css) | превью рисуется без стилей; переопределите [data-wm-snap-preview] статическим цветом |
backdrop-filter | размытие окна и тайтлбара | деградирует до плоской полупрозрачной панели |
contain: layout style | элемент окна | только подсказка для производительности |
отдельные свойства translate / scale | кейфреймы открытия и блокировки модалкой | анимация пропускается |
prefers-reduced-motion | каждая тема | анимаций меньше, но никогда не больше |
Все темы — это чистые кастомные свойства поверх атрибутов data-wm-*, так что, заменив тему своим CSS, вы снимаете все требования из этой таблицы.
Тестовая матрица
CI на каждый push прогоняет полный набор end-to-end тестов в:
- Chromium (Playwright
Desktop Chrome) - Firefox (Playwright
Desktop Firefox) - WebKit (Playwright
Desktop Safari) - мобильном Chromium (Playwright
Pixel 7, тач и грубый указатель)
Юнит-тесты идут в Node, а смоук-тесты адаптеров и DOM — в jsdom.
Тач и указатель
Грубые указатели (pointer: coarse) автоматически получают более крупные хит-зоны ресайза (16 px по краям и 24 px в углах вместо 8 и 12), более широкий порог снэпа (20 px вместо 12), более крупные угловые зоны снэпа (96 px вместо 64) и порог магнетизма 12 px вместо 8. Любое из этого переопределяется через hitAreas, snap и magnetism в attachDesktop.
Контекстное меню тайтлбара срабатывает и на правый клик, и на долгое нажатие, поэтому onTitlebarContextMenu одинаково работает с обоими типами ввода.
Известные пробелы
popoutоткрывает всплывающее окно в любом движке; picture-in-picture есть в Chrome и Edge 116+ и Firefox 151+, и только в десктопных браузерах. ПроверяйтеisPopoutSupported(), прежде чем показывать кнопку: браузер может отключить и то, и другое.- Без
structuredCloneименованные раскладки копируются через JSON, а при этом пропадают функции иDateпревращаются в строки. Держитеmetaи расширения JSON-безопасными, подключите полифилл или храните выводserialize()сами. - Эталоны визуальной регрессии генерируются на macOS и в CI пропускаются, поэтому различия в рендеринге ловятся вручную, а не пайплайном.