@feugene/granularity 0.37.0 → 0.38.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/dist/chunks/devHook-CiqijpNM.js +44 -0
- package/dist/chunks/devHook-CiqijpNM.js.map +1 -0
- package/dist/chunks/{overlayStack-B_UFaFzk.js → overlayStack-DH4Z7am1.js} +6 -27
- package/dist/chunks/overlayStack-DH4Z7am1.js.map +1 -0
- package/dist/chunks/{useModalOverlay-BwX8WEcI.js → useModalOverlay-ACRkflzx.js} +1 -1
- package/dist/chunks/{useModalOverlay-BwX8WEcI.js.map → useModalOverlay-ACRkflzx.js.map} +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BNtpj_P6.js → GrColorPicker-BwzRLs-i.js} +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BNtpj_P6.js.map → GrColorPicker-BwzRLs-i.js.map} +1 -1
- package/dist/components/GrColorPicker/index.js +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BVZEd4yy.js → GrCommandPalette-CnzPuoIM.js} +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BVZEd4yy.js.map → GrCommandPalette-CnzPuoIM.js.map} +1 -1
- package/dist/components/GrCommandPalette/index.js +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-K5ht2cYq.js → GrConfirmDialog-e15nFI8M.js} +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-K5ht2cYq.js.map → GrConfirmDialog-e15nFI8M.js.map} +1 -1
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-Dd2tgMoL.js → GrContextMenu-RpxMHQXH.js} +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-Dd2tgMoL.js.map → GrContextMenu-RpxMHQXH.js.map} +1 -1
- package/dist/components/GrContextMenu/index.js +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-CeJubnKJ.js → GrDialog-DDz_OEhk.js} +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-CeJubnKJ.js.map → GrDialog-DDz_OEhk.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-BArvw1DV.js → GrDialogService-BmXiYmUp.js} +2 -2
- package/dist/components/GrDialogService/chunks/{GrDialogService-BArvw1DV.js.map → GrDialogService-BmXiYmUp.js.map} +1 -1
- package/dist/components/GrDialogService/index.js +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-BBHNgeH0.js → GrDrawer-BRMHhvbd.js} +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-BBHNgeH0.js.map → GrDrawer-BRMHhvbd.js.map} +1 -1
- package/dist/components/GrDrawer/index.js +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-CUlviqMi.js → GrDropdown-cLZuZMEY.js} +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-CUlviqMi.js.map → GrDropdown-cLZuZMEY.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-COOR1LCs.js → GrDropdownMenu-Dxkz_ry4.js} +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-COOR1LCs.js.map → GrDropdownMenu-Dxkz_ry4.js.map} +1 -1
- package/dist/components/GrDropdownMenu/index.js +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-BjYw-uTF.js → GrImageViewer-CcduIFsa.js} +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-BjYw-uTF.js.map → GrImageViewer-CcduIFsa.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrModal/chunks/{GrModal-xIWaJozo.js → GrModal-Cm0mtSXk.js} +1 -1
- package/dist/components/GrModal/chunks/{GrModal-xIWaJozo.js.map → GrModal-Cm0mtSXk.js.map} +1 -1
- package/dist/components/GrModal/index.js +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-BakLcWkX.js → GrPopover-CcWvr1ZA.js} +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-BakLcWkX.js.map → GrPopover-CcWvr1ZA.js.map} +1 -1
- package/dist/components/GrPopover/index.js +1 -1
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-C9Y1ifE_.js → GrPromptDialog-8RxQsOQ_.js} +1 -1
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-C9Y1ifE_.js.map → GrPromptDialog-8RxQsOQ_.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +1 -1
- package/dist/composables/useFloating.js +1 -1
- package/dist/composables/useOverlayLayer.js +35 -6
- package/dist/composables/useOverlayLayer.js.map +1 -1
- package/dist/composables/useVirtualList.js +23 -1
- package/dist/composables/useVirtualList.js.map +1 -1
- package/dist/index.js +13 -13
- package/dist/types/composables/internal/overlayStack.d.ts +11 -0
- package/dist/types/internal/devHook.d.ts +66 -0
- package/dist/web-types.json +1 -1
- package/package.json +1 -1
- package/dist/chunks/overlayStack-B_UFaFzk.js.map +0 -1
|
@@ -15,9 +15,24 @@
|
|
|
15
15
|
* такой объект умеет и слушатель (панель подключается раньше или позже ядра —
|
|
16
16
|
* порядок не гарантирован), а логика эмита при этом живёт в одном месте, здесь.
|
|
17
17
|
*/
|
|
18
|
+
/** Фокус вокруг слоя: то, чего не видно ни в DOM, ни в браузерном инспекторе. */
|
|
19
|
+
export interface GrLayerFocus {
|
|
20
|
+
/** Фокус сейчас внутри слоя. */
|
|
21
|
+
inside: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Вернётся ли фокус при закрытии. Правило нетривиальное — «только если на
|
|
24
|
+
* момент закрытия фокус ещё внутри слоя», — и снаружи непроверяемо.
|
|
25
|
+
*/
|
|
26
|
+
willRestore: boolean;
|
|
27
|
+
/** Куда вернётся: описание элемента, а не ссылка (буфер не должен держать DOM). */
|
|
28
|
+
restoreTo: string | null;
|
|
29
|
+
}
|
|
18
30
|
/** Слой оверлея в том виде, в каком его видит наблюдатель. */
|
|
19
31
|
export interface GrOverlaySnapshot {
|
|
20
32
|
id: number;
|
|
33
|
+
/** Компонент, открывший слой: `GrSelect`, `GrModal`. `null` — слой заведён вне компонента. */
|
|
34
|
+
owner: string | null;
|
|
35
|
+
focus: GrLayerFocus | null;
|
|
21
36
|
modal: boolean;
|
|
22
37
|
/** Верхний слой любого рода: ему адресован Esc. */
|
|
23
38
|
topmostForEscape: boolean;
|
|
@@ -35,6 +50,7 @@ export type GrDevEvent = {
|
|
|
35
50
|
type: 'overlay:push';
|
|
36
51
|
id: number;
|
|
37
52
|
modal: boolean;
|
|
53
|
+
owner: string | null;
|
|
38
54
|
} | {
|
|
39
55
|
type: 'overlay:remove';
|
|
40
56
|
id: number;
|
|
@@ -43,11 +59,61 @@ export type GrDevEvent = {
|
|
|
43
59
|
id: number;
|
|
44
60
|
closed: boolean;
|
|
45
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Окно виртуализатора глазами наблюдателя.
|
|
64
|
+
*
|
|
65
|
+
* Число узлов в DOM браузер покажет и сам; невидимо другое — какие индексы
|
|
66
|
+
* отрисованы, сколько всего элементов и насколько оценка высоты разошлась с
|
|
67
|
+
* замером. Расхождение и есть тихий дефект: список начинает прыгать, а узлов
|
|
68
|
+
* по-прежнему «правильные десятки».
|
|
69
|
+
*/
|
|
70
|
+
export interface GrVirtualListSnapshot {
|
|
71
|
+
/** Компонент, которому принадлежит список. */
|
|
72
|
+
owner: string | null;
|
|
73
|
+
/** `uid` инстанса: панель связывает снимок с выбранным компонентом. */
|
|
74
|
+
uid: number | null;
|
|
75
|
+
total: number;
|
|
76
|
+
rendered: number;
|
|
77
|
+
range: {
|
|
78
|
+
start: number;
|
|
79
|
+
end: number;
|
|
80
|
+
};
|
|
81
|
+
/** Оценка высоты элемента, с которой список считает окно. */
|
|
82
|
+
estimated: number;
|
|
83
|
+
/** Средний фактический замер; `null` — пока ничего не измерено. */
|
|
84
|
+
measured: number | null;
|
|
85
|
+
}
|
|
46
86
|
export interface GrDevHook {
|
|
47
87
|
/** Последние события — чтобы подключившийся позже не начинал с пустого экрана. */
|
|
48
88
|
events: GrDevEvent[];
|
|
49
89
|
listeners: Set<(event: GrDevEvent) => void>;
|
|
90
|
+
/**
|
|
91
|
+
* Глубина буфера, если наблюдатель попросил другую. Ставит её он же: сколько
|
|
92
|
+
* истории нужно, знает только тот, кто её читает.
|
|
93
|
+
*/
|
|
94
|
+
bufferLimit?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Живые виртуализаторы. Реестр, а не событие: окно меняется на каждый кадр
|
|
97
|
+
* прокрутки, и слать его лентой значило бы залить канал.
|
|
98
|
+
*/
|
|
99
|
+
virtualLists?: Set<() => GrVirtualListSnapshot>;
|
|
100
|
+
/**
|
|
101
|
+
* Свежий снимок стека по требованию.
|
|
102
|
+
*
|
|
103
|
+
* События дают картину на момент изменения стека, а часть состояния меняется
|
|
104
|
+
* между ними: фокус уходит из слоя от обычного клика, и ни одного события при
|
|
105
|
+
* этом не случается. Наблюдателю нужно спросить «как сейчас», а не «как было
|
|
106
|
+
* при последнем push».
|
|
107
|
+
*/
|
|
108
|
+
readLayers?: () => GrOverlaySnapshot[];
|
|
50
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Регистрирует виртуализатор в реестре наблюдателя. Возвращает снятие —
|
|
112
|
+
* список обязан исчезнуть вместе с компонентом.
|
|
113
|
+
*/
|
|
114
|
+
export declare function registerGrVirtualList(read: () => GrVirtualListSnapshot): () => void;
|
|
115
|
+
/** Ядро отдаёт наблюдателю читалку стека. Вызывается один раз, из стека слоёв. */
|
|
116
|
+
export declare function provideGrDevLayers(read: () => GrOverlaySnapshot[]): void;
|
|
51
117
|
export declare function emitGrDevEvent(event: GrDevEvent): void;
|
|
52
118
|
/** Сброс канала между тестами: буфер и подписчики живут в `globalThis`. */
|
|
53
119
|
export declare function resetGrDevHook(): void;
|
package/dist/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
|
|
3
3
|
"name": "@feugene/granularity",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.38.0",
|
|
5
5
|
"framework": "vue",
|
|
6
6
|
"js-types-syntax": "typescript",
|
|
7
7
|
"description-markup": "markdown",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feugene/granularity",
|
|
3
3
|
"description": "Granularity design system package with Vue 3 components, consumed via the `@feugene/unocss-preset-granular` preset.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.38.0",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Evgeniy Fureev",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"overlayStack-B_UFaFzk.js","names":[],"sources":["../../src/internal/devHook.ts","../../src/composables/internal/overlayStack.ts"],"sourcesContent":["/**\n * Dev-канал ядра: наружу отдаётся то, чего иначе не увидеть — состояние\n * приватных синглтонов пакета.\n *\n * Первый и пока единственный поставщик — стек слоёв\n * (`composables/internal/overlayStack.ts`). Он приватен намеренно: один список\n * отвечает сразу на три вопроса (кому Esc, кто под `inert`, чья высота), и\n * публичный доступ к нему означал бы обязательство держать эту форму. Канал\n * снимает противоречие: снаружи видно картину, но не рычаги.\n *\n * Существует только под `__GR_DEV__` — вызывающие обязаны обернуть эмит гардом,\n * тогда у потребителя ветка выкидывается вместе с этим модулем.\n *\n * Хук нарочно «глупый»: голые `events` и `listeners` вместо методов. Создать\n * такой объект умеет и слушатель (панель подключается раньше или позже ядра —\n * порядок не гарантирован), а логика эмита при этом живёт в одном месте, здесь.\n */\n\n/** Слой оверлея в том виде, в каком его видит наблюдатель. */\nexport interface GrOverlaySnapshot {\n id: number\n modal: boolean\n /** Верхний слой любого рода: ему адресован Esc. */\n topmostForEscape: boolean\n /** Модальный слой ниже последнего модального — тот, что уходит в `inert`. */\n inert: boolean\n /** Позиция среди модальных, от нуля. У немодальных глубины нет. */\n depth: number | null\n /** Закроется ли слой по Esc прямо сейчас (`closeOnEsc` реактивен). */\n closesOnEscape: boolean\n}\n\nexport type GrDevEvent\n = | { type: 'overlay:sync', layers: GrOverlaySnapshot[] }\n | { type: 'overlay:push', id: number, modal: boolean }\n | { type: 'overlay:remove', id: number }\n | { type: 'overlay:escape', id: number, closed: boolean }\n\nexport interface GrDevHook {\n /** Последние события — чтобы подключившийся позже не начинал с пустого экрана. */\n events: GrDevEvent[]\n listeners: Set<(event: GrDevEvent) => void>\n}\n\ntype GlobalWithDevHook = typeof globalThis & { __GR_DEV_HOOK__?: GrDevHook }\n\n/**\n * Глубина буфера. Полсотни событий покрывают сценарий «открыл окно, поработал,\n * полез в панель» и не превращают буфер в утечку на долгой сессии.\n */\nconst BUFFER_LIMIT = 50\n\nfunction ensureHook(): GrDevHook {\n const target = globalThis as GlobalWithDevHook\n const existing = target.__GR_DEV_HOOK__\n if (existing)\n return existing\n\n const hook: GrDevHook = { events: [], listeners: new Set() }\n target.__GR_DEV_HOOK__ = hook\n return hook\n}\n\nexport function emitGrDevEvent(event: GrDevEvent): void {\n const hook = ensureHook()\n\n hook.events.push(event)\n if (hook.events.length > BUFFER_LIMIT)\n hook.events.splice(0, hook.events.length - BUFFER_LIMIT)\n\n for (const listener of hook.listeners) {\n // Слушатель — чужой код, и его исключение не должно ронять то, за чем он\n // наблюдает: канал обязан быть незаметен для поведения пакета.\n try {\n listener(event)\n }\n catch {\n // ignore\n }\n }\n}\n\n/** Сброс канала между тестами: буфер и подписчики живут в `globalThis`. */\nexport function resetGrDevHook(): void {\n const target = globalThis as GlobalWithDevHook\n target.__GR_DEV_HOOK__ = undefined\n}\n","/**\n * Единый стек слоёв оверлеев: модалки, drawer'ы, просмотрщик, панели селектов,\n * дропдауны, подсказки — всё, что открывается поверх страницы.\n *\n * Список один, и порядок регистрации совпадает с порядком открытия, но из него\n * выводятся **две разные вершины**:\n *\n * - **Esc** → последний слой любого рода. Дропдаун, открытый внутри модалки,\n * обязан закрыться первым — пользователь видит верхним именно его.\n * - **`inert`** → ставится на модальные слои ниже последнего **модального**.\n * Немодальный слой сверху модалку не понижает: иначе окно ушло бы в `inert`\n * вместе со своим же открытым дропдауном и перестало отвечать.\n * - **высота** → `openModalCount()` поднимает floating-панель над окном, из\n * которого её открыли: телепортированная панель лежит рядом с корнем окна,\n * и статический `z-index` дропдауна оставлял её под ним.\n *\n * Вести эти две вершины в двух независимых реестрах нельзя: реестры описывают\n * один и тот же порядок и расходятся молча — достаточно оверлея, который\n * зарегистрировался в одном и забыл про другой.\n *\n * Ловушку фокуса стек не реализует сам, но питает её (`useFocusTrap`): он\n * видит слои из **разных деревьев рендера** (диалоги `useDialogService`\n * монтируются отдельным `render()` в `body`) и знает их корни.\n */\n\nimport type { GrOverlaySnapshot } from '../../internal/devHook'\nimport { emitGrDevEvent } from '../../internal/devHook'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nexport interface OverlayLayer {\n /** Уникальный id зарегистрированного слоя. */\n id: number\n /**\n * Модальный слой: блокирует страницу и участвует в вычислении `inert`.\n * Немодальные (поповеры, меню, подсказки) — только в очереди Esc.\n */\n modal: boolean\n /** Закрывать ли слой по Esc (реактивный геттер: `closeOnEsc` и подобные). */\n shouldClose: () => boolean\n /** Закрыть слой. */\n close: () => void\n /** Уведомление «этот модальный слой сейчас верхний». Только для `modal`. */\n setTopmost?: (isTopmost: boolean) => void\n /**\n * Позиция слоя среди модальных, от нуля. Только для `modal`.\n *\n * От неё считается высота: у всех модальных слоёв один токен\n * (`--gr-z-modal`), и без этой прибавки порядок отрисовки решал бы порядок\n * узлов в портале, а он задаётся **созданием** телепорта, а не открытием\n * слоя. Диалог, объявленный в шаблоне статически, вставал бы под окном,\n * открытым позже, — и получал бы `inert` от стека, оставаясь видимым.\n */\n setDepth?: (depth: number) => void\n /**\n * Корень слоя. Ловушка фокуса нижнего слоя обязана считать его своим:\n * панель селекта, открытого внутри модалки, телепортирована в `body` и лежит\n * вне DOM-поддерева окна, но для пользователя это тот же слой.\n */\n root?: () => HTMLElement | null\n}\n\nconst stack: OverlayLayer[] = []\nlet listening = false\nlet nextId = 1\n\n/**\n * Пересчитывает состояние модальных слоёв: кто верхний и на какой высоте.\n *\n * Обе величины выводятся из одного порядка, поэтому и считаются в одном месте:\n * разъедься они — «верхний» для `inert` и «верхний» для отрисовки перестали бы\n * совпадать, а это ровно тот дефект, из-за которого высота и заведена.\n */\nfunction syncModalLayers(): void {\n const modals = stack.filter(layer => layer.modal)\n const top = modals[modals.length - 1]\n\n modals.forEach((layer, index) => {\n layer.setTopmost?.(layer === top)\n layer.setDepth?.(index)\n })\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:sync', layers: snapshotLayers() })\n}\n\n/**\n * Снимок стека для dev-канала.\n *\n * Считается здесь же, где `syncModalLayers` раздаёт то же самое слоям, и по тем\n * же выражениям: разъедься они — наблюдатель показывал бы картину, которой в\n * пакете нет, и отладка по ней уводила бы в сторону.\n */\nfunction snapshotLayers(): GrOverlaySnapshot[] {\n const modals = stack.filter(layer => layer.modal)\n const topModal = modals[modals.length - 1]\n const top = stack[stack.length - 1]\n\n return stack.map(layer => ({\n id: layer.id,\n modal: layer.modal,\n topmostForEscape: layer === top,\n inert: layer.modal && layer !== topModal,\n depth: layer.modal ? modals.indexOf(layer) : null,\n closesOnEscape: layer.shouldClose(),\n }))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Escape')\n return\n // Esc во время IME-композиции отменяет её, а не закрывает слой.\n if (isComposingEvent(event))\n return\n if (stack.length === 0)\n return\n\n const top = stack[stack.length - 1]\n\n // Гасим всегда, даже если верхний слой не закрывается по Esc: иначе нажатие\n // «провалится» на слой ниже и закроет не то, что видит пользователь.\n event.preventDefault()\n event.stopPropagation()\n if (typeof event.stopImmediatePropagation === 'function')\n event.stopImmediatePropagation()\n\n const closes = top.shouldClose()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:escape', id: top.id, closed: closes })\n\n if (closes)\n top.close()\n}\n\nfunction startListening(): void {\n if (listening)\n return\n if (typeof window === 'undefined')\n return\n // Capture-фаза опережает любые локальные обработчики: Esc обязан достаться\n // верхнему слою, а не тому, кто первым подписался.\n window.addEventListener('keydown', handleKeydown, true)\n listening = true\n}\n\nfunction stopListening(): void {\n if (!listening)\n return\n if (typeof window === 'undefined')\n return\n window.removeEventListener('keydown', handleKeydown, true)\n listening = false\n}\n\n/** Регистрирует слой как верхний и возвращает его id. */\nexport function pushOverlayLayer(layer: Omit<OverlayLayer, 'id'>): number {\n const id = nextId++\n stack.push({ ...layer, id })\n startListening()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:push', id, modal: layer.modal })\n\n syncModalLayers()\n return id\n}\n\n/** Снимает слой со стека (при закрытии или размонтировании). */\nexport function removeOverlayLayer(id: number): void {\n const index = stack.findIndex(item => item.id === id)\n if (index >= 0)\n stack.splice(index, 1)\n if (stack.length === 0)\n stopListening()\n\n if (__GR_DEV__ && index >= 0)\n emitGrDevEvent({ type: 'overlay:remove', id })\n\n syncModalLayers()\n}\n\n/**\n * Корни слоёв, открытых **поверх** данного.\n *\n * Ими ловушка фокуса дополняет свой контейнер: всё, что открыто изнутри слоя\n * (панель селекта, меню, подсказка), лежит в `body` отдельным поддеревом, и\n * без этого списка ловушка утаскивала бы из него фокус обратно в окно.\n */\nexport function layerRootsAbove(id: number): HTMLElement[] {\n const index = stack.findIndex(layer => layer.id === id)\n if (index < 0)\n return []\n\n return stack\n .slice(index + 1)\n .map(layer => layer.root?.() ?? null)\n .filter((root): root is HTMLElement => root !== null)\n}\n\n/** Корни всех зарегистрированных слоёв. */\nexport function allLayerRoots(): HTMLElement[] {\n return stack\n .map(layer => layer.root?.() ?? null)\n .filter((root): root is HTMLElement => root !== null)\n}\n\n/** Сколько слоёв открыто. Для тестов и диагностики. */\nexport function overlayStackSize(): number {\n return stack.length\n}\n\n/**\n * Сколько **модальных** слоёв открыто прямо сейчас.\n *\n * Читает `useFloating`, когда считает высоту панели: панель телепортирована в\n * общий портал и лежит рядом с корнем окна, а не внутри него, поэтому свой\n * стек-контекст её не спасает — высоту приходится брать из порядка слоёв.\n */\nexport function openModalCount(): number {\n return stack.reduce((count, layer) => count + (layer.modal ? 1 : 0), 0)\n}\n\n/**\n * Высота слоя, лежащего внутри открытого окна.\n *\n * Панель телепортирована в общий портал и становится **соседом** корня окна, а\n * не его потомком: собственный stacking-контекст окна её не накрывает, и\n * статический `--gr-z-dropdown` (1000) оставлял её под окном (1100). Слагаемое —\n * число модальных слоёв, поэтому панель встаёт над самым верхним из них, а\n * полноэкранная загрузка (1150) и тосты (1200) остаются сверху.\n *\n * Обратный случай — «поповер снаружи не должен перекрывать окно» — не страдает:\n * пока окно открыто, страница под ним в `inert`, и открыть там поповер нечем.\n */\nexport function floatingLayerZIndex(zIndexVar: string): string {\n const modals = openModalCount()\n\n return modals > 0 ? `calc(var(--gr-z-modal) + ${modals})` : `var(${zIndexVar})`\n}\n\n/**\n * Высота самого модального слоя: базовый токен плюс его позиция в стеке.\n *\n * Нулевая глубина оставляет чистый `var(...)` — у единственного окна на экране\n * в стилях не появляется лишней арифметики.\n */\nexport function modalLayerZIndex(depth: number, zIndexVar = '--gr-z-modal'): string {\n return depth > 0 ? `calc(var(${zIndexVar}) + ${depth})` : `var(${zIndexVar})`\n}\n\n/** Тестовая/служебная очистка стека. */\nexport function resetOverlayStack(): void {\n stack.splice(0, stack.length)\n stopListening()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:sync', layers: [] })\n}\n"],"mappings":"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"}
|