@monstermann/signals-modal 0.4.3 → 0.4.5
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 +2011 -0
- package/dist/anchor/getAnchorElement.d.mts +30 -0
- package/dist/anchor/getAnchorElement.mjs +30 -0
- package/dist/anchor/getAnchorMeasurement.d.mts +39 -1
- package/dist/anchor/getAnchorMeasurement.mjs +37 -0
- package/dist/anchor/setAnchorElement.d.mts +26 -0
- package/dist/anchor/setAnchorElement.mjs +26 -0
- package/dist/anchor/withAnchorElement.d.mts +31 -0
- package/dist/anchor/withAnchorElement.mjs +31 -1
- package/dist/anchor/withAnchorMeasurement.d.mts +44 -1
- package/dist/anchor/withAnchorMeasurement.mjs +45 -3
- package/dist/anchor/withMouseAnchor.d.mts +35 -1
- package/dist/anchor/withMouseAnchor.mjs +36 -3
- package/dist/createModal.d.mts +29 -0
- package/dist/createModal.mjs +29 -0
- package/dist/floating/getFloatingElement.d.mts +30 -0
- package/dist/floating/getFloatingElement.mjs +30 -0
- package/dist/floating/getFloatingMeasurement.d.mts +39 -1
- package/dist/floating/getFloatingMeasurement.mjs +37 -0
- package/dist/floating/setFloatingElement.d.mts +26 -0
- package/dist/floating/setFloatingElement.mjs +26 -0
- package/dist/floating/withFloatingElement.d.mts +31 -0
- package/dist/floating/withFloatingElement.mjs +31 -1
- package/dist/floating/withFloatingMeasurement.d.mts +42 -1
- package/dist/floating/withFloatingMeasurement.mjs +43 -3
- package/dist/groups/getDialogs.d.mts +29 -0
- package/dist/groups/getDialogs.mjs +29 -0
- package/dist/groups/getGroupsForModal.d.mts +29 -0
- package/dist/groups/getGroupsForModal.mjs +29 -0
- package/dist/groups/getModalsForGroup.d.mts +29 -0
- package/dist/groups/getModalsForGroup.mjs +29 -0
- package/dist/groups/getPopovers.d.mts +29 -0
- package/dist/groups/getPopovers.mjs +29 -0
- package/dist/groups/getTooltips.d.mts +29 -0
- package/dist/groups/getTooltips.mjs +29 -0
- package/dist/groups/isDialog.d.mts +29 -0
- package/dist/groups/isDialog.mjs +29 -0
- package/dist/groups/isModalInGroup.d.mts +29 -0
- package/dist/groups/isModalInGroup.mjs +29 -0
- package/dist/groups/isPopover.d.mts +29 -0
- package/dist/groups/isPopover.mjs +29 -0
- package/dist/groups/isTooltip.d.mts +29 -0
- package/dist/groups/isTooltip.mjs +29 -0
- package/dist/groups/modalGroups.mjs +42 -0
- package/dist/groups/withModalGroups.d.mts +30 -0
- package/dist/groups/withModalGroups.mjs +30 -1
- package/dist/position/getModalPlacement.d.mts +50 -0
- package/dist/position/getModalPlacement.mjs +49 -0
- package/dist/position/getModalPosition.d.mts +59 -0
- package/dist/position/getModalPosition.mjs +58 -0
- package/dist/position/withBoundary.d.mts +32 -1
- package/dist/position/withBoundary.mjs +33 -3
- package/dist/position/withPlacement.d.mts +78 -1
- package/dist/position/withPlacement.mjs +78 -1
- package/dist/position/withPosition.d.mts +67 -1
- package/dist/position/withPosition.mjs +68 -2
- package/dist/scroll/withCloseOnScroll.d.mts +37 -0
- package/dist/scroll/withCloseOnScroll.mjs +37 -1
- package/dist/status/closeAllModals.d.mts +33 -0
- package/dist/status/closeAllModals.mjs +33 -0
- package/dist/status/closeLastModal.d.mts +18 -0
- package/dist/status/closeLastModal.mjs +18 -0
- package/dist/status/closeModal.d.mts +28 -0
- package/dist/status/closeModal.mjs +28 -0
- package/dist/status/getClosedModals.d.mts +32 -0
- package/dist/status/getClosedModals.mjs +32 -0
- package/dist/status/getClosingModals.d.mts +36 -0
- package/dist/status/getClosingModals.mjs +36 -0
- package/dist/status/getModalStatus.d.mts +31 -0
- package/dist/status/getModalStatus.mjs +30 -0
- package/dist/status/getOpenModals.d.mts +36 -0
- package/dist/status/getOpenModals.mjs +36 -0
- package/dist/status/getOpenedModals.d.mts +32 -0
- package/dist/status/getOpenedModals.mjs +32 -0
- package/dist/status/getOpeningModals.d.mts +36 -0
- package/dist/status/getOpeningModals.mjs +36 -0
- package/dist/status/getVisibleModals.d.mts +36 -0
- package/dist/status/getVisibleModals.mjs +36 -0
- package/dist/status/internals.mjs +15 -6
- package/dist/status/isAnyModalClosed.d.mts +32 -0
- package/dist/status/isAnyModalClosed.mjs +32 -0
- package/dist/status/isAnyModalClosing.d.mts +35 -0
- package/dist/status/isAnyModalClosing.mjs +35 -0
- package/dist/status/isAnyModalOpen.d.mts +32 -0
- package/dist/status/isAnyModalOpen.mjs +32 -0
- package/dist/status/isAnyModalOpened.d.mts +32 -0
- package/dist/status/isAnyModalOpened.mjs +32 -0
- package/dist/status/isAnyModalOpening.d.mts +35 -0
- package/dist/status/isAnyModalOpening.mjs +35 -0
- package/dist/status/isAnyModalVisible.d.mts +32 -0
- package/dist/status/isAnyModalVisible.mjs +32 -0
- package/dist/status/isModalClosed.d.mts +28 -0
- package/dist/status/isModalClosed.mjs +28 -0
- package/dist/status/isModalClosing.d.mts +32 -0
- package/dist/status/isModalClosing.mjs +32 -0
- package/dist/status/isModalOpen.d.mts +28 -0
- package/dist/status/isModalOpen.mjs +28 -0
- package/dist/status/isModalOpened.d.mts +30 -0
- package/dist/status/isModalOpened.mjs +30 -0
- package/dist/status/isModalOpening.d.mts +30 -0
- package/dist/status/isModalOpening.mjs +30 -0
- package/dist/status/isModalVisible.d.mts +30 -0
- package/dist/status/isModalVisible.mjs +30 -0
- package/dist/status/onModalClosed.d.mts +33 -2
- package/dist/status/onModalClosed.mjs +31 -1
- package/dist/status/onModalClosing.d.mts +33 -2
- package/dist/status/onModalClosing.mjs +31 -1
- package/dist/status/onModalOpened.d.mts +31 -0
- package/dist/status/onModalOpened.mjs +31 -1
- package/dist/status/onModalOpening.d.mts +31 -0
- package/dist/status/onModalOpening.mjs +31 -1
- package/dist/status/openModal.d.mts +26 -0
- package/dist/status/openModal.mjs +26 -0
- package/dist/status/setModalStatus.d.mts +29 -0
- package/dist/status/setModalStatus.mjs +28 -0
- package/dist/status/withModalStatus.d.mts +41 -0
- package/dist/status/withModalStatus.mjs +43 -3
- package/dist/utils/closeLastModalOnClickOutside.d.mts +18 -0
- package/dist/utils/closeLastModalOnClickOutside.mjs +18 -0
- package/dist/utils/closeLastModalOnEsc.d.mts +18 -0
- package/dist/utils/closeLastModalOnEsc.mjs +18 -0
- package/dist/utils/syncModalGroupsToBody.d.mts +37 -0
- package/dist/utils/syncModalGroupsToBody.mjs +38 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -2,8 +2,2019 @@
|
|
|
2
2
|
|
|
3
3
|
<h1>signals-modal</h1>
|
|
4
4
|
|
|
5
|
+
 
|
|
6
|
+
|
|
5
7
|
**Composable modal management.**
|
|
6
8
|
|
|
7
9
|
[Documentation](https://MichaelOstermann.github.io/signals-modal)
|
|
8
10
|
|
|
9
11
|
</div>
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const modal = createModal("key", () => {
|
|
17
|
+
const { $status } = withModalStatus();
|
|
18
|
+
|
|
19
|
+
const $anchorElement = withAnchorElement();
|
|
20
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
21
|
+
$anchorElement,
|
|
22
|
+
$status,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const $floatingElement = withFloatingElement();
|
|
26
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
27
|
+
$floatingElement,
|
|
28
|
+
$status,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const $boundary = withBoundary({
|
|
32
|
+
$status,
|
|
33
|
+
transform: (rect) => rect,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const $placement = withPlacement({
|
|
37
|
+
placement: "down-center",
|
|
38
|
+
$anchorMeasurement,
|
|
39
|
+
$boundary,
|
|
40
|
+
$floatingMeasurement,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const $position = withPosition({
|
|
44
|
+
$anchorMeasurement,
|
|
45
|
+
$boundary,
|
|
46
|
+
$floatingMeasurement,
|
|
47
|
+
$placement,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
$anchorElement,
|
|
52
|
+
$floatingElement,
|
|
53
|
+
$position,
|
|
54
|
+
$status,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const anchor = document.querySelector(".anchor");
|
|
59
|
+
const floating = document.querySelector(".popover");
|
|
60
|
+
|
|
61
|
+
// Directly access the returned properties:
|
|
62
|
+
modal.$anchor(anchor);
|
|
63
|
+
modal.$floating(floating);
|
|
64
|
+
modal.$status("opened");
|
|
65
|
+
const { floatingX, floatingY, maxHeight, maxWidth } = modal.$position();
|
|
66
|
+
|
|
67
|
+
// Or use the global utilities:
|
|
68
|
+
setAnchorElement("key", anchor);
|
|
69
|
+
setFloatingElement("key", floating);
|
|
70
|
+
setModalStatus("key", "opened");
|
|
71
|
+
const { floatingX, floatingY, maxHeight, maxWidth } = getModalPosition("key");
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
```sh [npm]
|
|
77
|
+
npm install @monstermann/signals-modal
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```sh [pnpm]
|
|
81
|
+
pnpm add @monstermann/signals-modal
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```sh [yarn]
|
|
85
|
+
yarn add @monstermann/signals-modal
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```sh [bun]
|
|
89
|
+
bun add @monstermann/signals-modal
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Anchor
|
|
93
|
+
|
|
94
|
+
### getAnchorElement
|
|
95
|
+
|
|
96
|
+

|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
function getAnchorElement(key: string): HTMLElement | undefined;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Retrieves the current anchor element for the given `key`.
|
|
103
|
+
|
|
104
|
+
#### Example
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import {
|
|
108
|
+
createModal,
|
|
109
|
+
withAnchorElement,
|
|
110
|
+
setAnchorElement,
|
|
111
|
+
getAnchorElement,
|
|
112
|
+
} from "@monstermann/signals-modal";
|
|
113
|
+
|
|
114
|
+
createModal("key", () => {
|
|
115
|
+
withAnchorElement();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
setAnchorElement("key", document.querySelector(".anchor"));
|
|
119
|
+
getAnchorElement("key"); // HTMLElement
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### getAnchorMeasurement
|
|
123
|
+
|
|
124
|
+

|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
function getAnchorMeasurement(key: string): Rect;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Retrieves the current result of `withAnchorMeasurement` or `withMouseAnchor`, falling back to an empty `Rect`.
|
|
131
|
+
|
|
132
|
+
#### Example
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import {
|
|
136
|
+
createModal,
|
|
137
|
+
withAnchorElement,
|
|
138
|
+
withModalStatus,
|
|
139
|
+
withAnchorMeasurement,
|
|
140
|
+
getAnchorMeasurement,
|
|
141
|
+
} from "@monstermann/signals-modal";
|
|
142
|
+
|
|
143
|
+
createModal("key", () => {
|
|
144
|
+
const { $status } = withModalStatus();
|
|
145
|
+
const $anchorElement = withAnchorElement();
|
|
146
|
+
// Memo({ top: number, left: number, width: number, height: number })
|
|
147
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
148
|
+
$status,
|
|
149
|
+
$anchorElement,
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// { top: number, left: number, width: number, height: number }
|
|
154
|
+
getAnchorMeasurement("key");
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### setAnchorElement
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
function setAnchorElement(key: string, element: HTMLElement | null): void;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Sets the current anchor element for the given `key`.
|
|
164
|
+
|
|
165
|
+
#### Example
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import {
|
|
169
|
+
createModal,
|
|
170
|
+
withAnchorElement,
|
|
171
|
+
getAnchorElement,
|
|
172
|
+
} from "@monstermann/signals-modal";
|
|
173
|
+
|
|
174
|
+
createModal("key", () => {
|
|
175
|
+
withAnchorElement();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
setAnchorElement("key", document.querySelector(".anchor"));
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### withAnchorElement
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
function withAnchorElement(
|
|
185
|
+
anchorElement?: HTMLElement,
|
|
186
|
+
): Signal<HTMLElement | null>;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Assigns an anchor element to the current modal. This function must be called inside a `createModal` callback.
|
|
190
|
+
|
|
191
|
+
#### Example
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import {
|
|
195
|
+
createModal,
|
|
196
|
+
withAnchorElement,
|
|
197
|
+
setAnchorElement,
|
|
198
|
+
getAnchorElement,
|
|
199
|
+
} from "@monstermann/signals-modal";
|
|
200
|
+
|
|
201
|
+
createModal("key", () => {
|
|
202
|
+
withAnchorElement();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
setAnchorElement("key", document.querySelector(".anchor"));
|
|
206
|
+
getAnchorElement("key"); // HTMLElement
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### withAnchorMeasurement
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
function withAnchorMeasurement(options: {
|
|
213
|
+
$anchorElement: Reactive<HTMLElement | null>;
|
|
214
|
+
$status: Reactive<ModalStatus>;
|
|
215
|
+
transform?: (rect: Rect) => Rect;
|
|
216
|
+
}): Memo<Rect>;
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Takes an anchor element and continuously measures its position while the modal is visible, to be used to position eg. a popover next to an element. This function must be called inside a `createModal` callback.
|
|
220
|
+
|
|
221
|
+
The optional `transform` option can be used to eg. make the anchor bigger, resulting with a margin between the anchor and floating popover.
|
|
222
|
+
|
|
223
|
+
#### Example
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import {
|
|
227
|
+
createModal,
|
|
228
|
+
withAnchorElement,
|
|
229
|
+
withModalStatus,
|
|
230
|
+
withAnchorMeasurement,
|
|
231
|
+
setAnchorElement,
|
|
232
|
+
setModalStatus,
|
|
233
|
+
} from "@monstermann/signals-modal";
|
|
234
|
+
|
|
235
|
+
createModal("key", () => {
|
|
236
|
+
const { $status } = withModalStatus();
|
|
237
|
+
const $anchorElement = withAnchorElement();
|
|
238
|
+
// Memo({ top: number, left: number, width: number, height: number })
|
|
239
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
240
|
+
$status,
|
|
241
|
+
$anchorElement,
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
setAnchorElement("key", document.querySelector(".anchor"));
|
|
246
|
+
setModalStatus("key", "opened");
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### withMouseAnchor
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
function withMouseAnchor(options: {
|
|
253
|
+
$status: Reactive<ModalStatus>;
|
|
254
|
+
transform?: (rect: Rect) => Rect;
|
|
255
|
+
}): Memo<Rect>;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
This can be used to make the mouse cursor the anchor, instead of an element. This function must be called inside a `createModal` callback.
|
|
259
|
+
|
|
260
|
+
#### Example
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import {
|
|
264
|
+
createModal,
|
|
265
|
+
withModalStatus,
|
|
266
|
+
withMouseAnchor,
|
|
267
|
+
setModalStatus,
|
|
268
|
+
} from "@monstermann/signals-modal";
|
|
269
|
+
|
|
270
|
+
createModal("key", () => {
|
|
271
|
+
const { $status } = withModalStatus();
|
|
272
|
+
// Memo({ top: number, left: number, width: number, height: number })
|
|
273
|
+
const $anchorMeasurement = withMouseAnchor({ $status });
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Updates $anchorMeasurement to the current mouse coordinates (once).
|
|
277
|
+
setModalStatus("key", "opened");
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Core
|
|
281
|
+
|
|
282
|
+
### createModal
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
function createModal(
|
|
286
|
+
key: string,
|
|
287
|
+
setup: () => T,
|
|
288
|
+
): T & {
|
|
289
|
+
key: string;
|
|
290
|
+
dispose: () => void;
|
|
291
|
+
isDisposed: () => boolean;
|
|
292
|
+
onDispose: (dispose: MaybeDispose) => void;
|
|
293
|
+
};
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Creates a new modal.
|
|
297
|
+
|
|
298
|
+
#### Example
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
import { createModal } from "@monstermann/signals-modal";
|
|
302
|
+
|
|
303
|
+
const modal = createModal("key", () => ({}));
|
|
304
|
+
modal.key;
|
|
305
|
+
modal.dispose();
|
|
306
|
+
modal.onDispose(callback);
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### currentModal
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
function currentModal(): {
|
|
313
|
+
key: string;
|
|
314
|
+
dispose: () => void;
|
|
315
|
+
onDispose: (dispose: MaybeDispose) => void;
|
|
316
|
+
};
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Retrieves the current modal.
|
|
320
|
+
|
|
321
|
+
#### Example
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
import { createModal, currentModal } from "@monstermann/signals-modal";
|
|
325
|
+
|
|
326
|
+
createModal(() => {
|
|
327
|
+
const modal = currentModal();
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### onModalDisposed
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
const onModalDisposed: Emitter<string>;
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
An emitter that fires when a modal gets disposed. The emitted value is the modal key.
|
|
338
|
+
|
|
339
|
+
#### Example
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
import { createModal, onModalDisposed } from "@monstermann/signals-modal";
|
|
343
|
+
|
|
344
|
+
const modal = createModal("key", () => {});
|
|
345
|
+
|
|
346
|
+
const stopListening = onModalDisposed((key) => {
|
|
347
|
+
console.log(`Modal ${key} disposed`);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
modal.dispose();
|
|
351
|
+
|
|
352
|
+
stopListening();
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Floating
|
|
356
|
+
|
|
357
|
+
### getFloatingElement
|
|
358
|
+
|
|
359
|
+

|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
function getFloatingElement(key: string): HTMLElement | undefined;
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Retrieves the current floating element for the given `key`.
|
|
366
|
+
|
|
367
|
+
#### Example
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
import {
|
|
371
|
+
createModal,
|
|
372
|
+
withFloatingElement,
|
|
373
|
+
setFloatingElement,
|
|
374
|
+
getFloatingElement,
|
|
375
|
+
} from "@monstermann/signals-modal";
|
|
376
|
+
|
|
377
|
+
createModal("key", () => {
|
|
378
|
+
withFloatingElement();
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
setFloatingElement("key", document.querySelector(".floating"));
|
|
382
|
+
getFloatingElement("key"); // HTMLElement
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### getFloatingMeasurement
|
|
386
|
+
|
|
387
|
+

|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
function getFloatingMeasurement(key: string): Rect;
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Retrieves the current result of `withFloatingMeasurement`, falling back to an empty `Rect`.
|
|
394
|
+
|
|
395
|
+
#### Example
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import {
|
|
399
|
+
createModal,
|
|
400
|
+
withFloatingElement,
|
|
401
|
+
withModalStatus,
|
|
402
|
+
withFloatingMeasurement,
|
|
403
|
+
getFloatingMeasurement,
|
|
404
|
+
} from "@monstermann/signals-modal";
|
|
405
|
+
|
|
406
|
+
createModal("key", () => {
|
|
407
|
+
const { $status } = withModalStatus();
|
|
408
|
+
const $floatingElement = withFloatingElement();
|
|
409
|
+
// Memo({ top: number, left: number, width: number, height: number })
|
|
410
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
411
|
+
$status,
|
|
412
|
+
$floatingElement,
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// { top: number, left: number, width: number, height: number }
|
|
417
|
+
getFloatingMeasurement("key");
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### setFloatingElement
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
function setFloatingElement(key: string, element: HTMLElement | null): void;
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Sets the current floating element for the given `key`.
|
|
427
|
+
|
|
428
|
+
#### Example
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
import {
|
|
432
|
+
createModal,
|
|
433
|
+
withFloatingElement,
|
|
434
|
+
getFloatingElement,
|
|
435
|
+
} from "@monstermann/signals-modal";
|
|
436
|
+
|
|
437
|
+
createModal("key", () => {
|
|
438
|
+
withFloatingElement();
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
setFloatingElement("key", document.querySelector(".floating"));
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### withFloatingElement
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
function withFloatingElement(
|
|
448
|
+
floatingElement?: HTMLElement,
|
|
449
|
+
): Signal<HTMLElement | null>;
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Assigns an floating element to the current modal. This function must be called inside a `createModal` callback.
|
|
453
|
+
|
|
454
|
+
#### Example
|
|
455
|
+
|
|
456
|
+
```ts
|
|
457
|
+
import {
|
|
458
|
+
createModal,
|
|
459
|
+
withFloatingElement,
|
|
460
|
+
setFloatingElement,
|
|
461
|
+
getFloatingElement,
|
|
462
|
+
} from "@monstermann/signals-modal";
|
|
463
|
+
|
|
464
|
+
createModal("key", () => {
|
|
465
|
+
withFloatingElement();
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
setFloatingElement("key", document.querySelector(".floating"));
|
|
469
|
+
getFloatingElement("key"); // HTMLElement
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### withFloatingMeasurement
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
function withFloatingMeasurement(options: {
|
|
476
|
+
$floatingElement: Reactive<HTMLElement | null>;
|
|
477
|
+
$status: Reactive<ModalStatus>;
|
|
478
|
+
transform?: (rect: Rect) => Rect;
|
|
479
|
+
}): Memo<Rect>;
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Takes an floating element and continuously measures its position while the modal is visible, to be used to position eg. a popover next to an element. This function must be called inside a `createModal` callback.
|
|
483
|
+
|
|
484
|
+
#### Example
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
import {
|
|
488
|
+
createModal,
|
|
489
|
+
withFloatingElement,
|
|
490
|
+
withModalStatus,
|
|
491
|
+
withFloatingMeasurement,
|
|
492
|
+
setFloatingElement,
|
|
493
|
+
setModalStatus,
|
|
494
|
+
} from "@monstermann/signals-modal";
|
|
495
|
+
|
|
496
|
+
createModal("key", () => {
|
|
497
|
+
const { $status } = withModalStatus();
|
|
498
|
+
const $floatingElement = withFloatingElement();
|
|
499
|
+
// Memo({ top: number, left: number, width: number, height: number })
|
|
500
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
501
|
+
$status,
|
|
502
|
+
$floatingElement,
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
setFloatingElement("key", document.querySelector(".floating"));
|
|
507
|
+
setModalStatus("key", "opened");
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Groups
|
|
511
|
+
|
|
512
|
+
### getDialogs
|
|
513
|
+
|
|
514
|
+

|
|
515
|
+
|
|
516
|
+
```ts
|
|
517
|
+
function getDialogs(): ReadonlySet<string>;
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Returns all dialog keys from the `modalGroups.dialog` group.
|
|
521
|
+
|
|
522
|
+
#### Example
|
|
523
|
+
|
|
524
|
+
```ts
|
|
525
|
+
import {
|
|
526
|
+
createModal,
|
|
527
|
+
withModalGroups,
|
|
528
|
+
modalGroups,
|
|
529
|
+
getDialogs,
|
|
530
|
+
} from "@monstermann/signals-modal";
|
|
531
|
+
|
|
532
|
+
createModal("key", () => {
|
|
533
|
+
withModalGroups([modalGroups.dialog]);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
getDialogs(); // Set(["key"])
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### getGroupsForModal
|
|
540
|
+
|
|
541
|
+

|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
function getGroupsForModal(key: string): ReadonlySet<string>;
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Returns all groups the given `key` belongs to.
|
|
548
|
+
|
|
549
|
+
#### Example
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
import {
|
|
553
|
+
createModal,
|
|
554
|
+
withModalGroups,
|
|
555
|
+
modalGroups,
|
|
556
|
+
getGroupsForModal,
|
|
557
|
+
} from "@monstermann/signals-modal";
|
|
558
|
+
|
|
559
|
+
createModal("key", () => {
|
|
560
|
+
withModalGroups([modalGroups.dialog]);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
getGroupsForModal("key"); // Set(["dialog"])
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### getModalsForGroup
|
|
567
|
+
|
|
568
|
+

|
|
569
|
+
|
|
570
|
+
```ts
|
|
571
|
+
function getModalsForGroup(group: string): ReadonlySet<string>;
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Returns all keys the given `group` belongs to.
|
|
575
|
+
|
|
576
|
+
#### Example
|
|
577
|
+
|
|
578
|
+
```ts
|
|
579
|
+
import {
|
|
580
|
+
createModal,
|
|
581
|
+
withModalGroups,
|
|
582
|
+
modalGroups,
|
|
583
|
+
getModalsForGroup,
|
|
584
|
+
} from "@monstermann/signals-modal";
|
|
585
|
+
|
|
586
|
+
createModal("key", () => {
|
|
587
|
+
withModalGroups([modalGroups.dialog]);
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
getModalsForGroup(modalGroups.dialog); // Set(["key"])
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### getPopovers
|
|
594
|
+
|
|
595
|
+

|
|
596
|
+
|
|
597
|
+
```ts
|
|
598
|
+
function getPopovers(): ReadonlySet<string>;
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
Returns all popover keys from the `modalGroups.popover` group.
|
|
602
|
+
|
|
603
|
+
#### Example
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
import {
|
|
607
|
+
createModal,
|
|
608
|
+
withModalGroups,
|
|
609
|
+
modalGroups,
|
|
610
|
+
getPopovers,
|
|
611
|
+
} from "@monstermann/signals-modal";
|
|
612
|
+
|
|
613
|
+
createModal("key", () => {
|
|
614
|
+
withModalGroups([modalGroups.popover]);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
getPopovers(); // Set(["key"])
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### getTooltips
|
|
621
|
+
|
|
622
|
+

|
|
623
|
+
|
|
624
|
+
```ts
|
|
625
|
+
function getTooltips(): ReadonlySet<string>;
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Returns all tooltip keys from the `modalGroups.tooltip` group.
|
|
629
|
+
|
|
630
|
+
#### Example
|
|
631
|
+
|
|
632
|
+
```ts
|
|
633
|
+
import {
|
|
634
|
+
createModal,
|
|
635
|
+
withModalGroups,
|
|
636
|
+
modalGroups,
|
|
637
|
+
getTooltips,
|
|
638
|
+
} from "@monstermann/signals-modal";
|
|
639
|
+
|
|
640
|
+
createModal("key", () => {
|
|
641
|
+
withModalGroups([modalGroups.tooltip]);
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
getTooltips(); // Set(["key"])
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### isDialog
|
|
648
|
+
|
|
649
|
+

|
|
650
|
+
|
|
651
|
+
```ts
|
|
652
|
+
function isDialog(key: string): boolean;
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
Returns a boolean indicating whether the given `key` belongs to the `modalGroups.dialog` group.
|
|
656
|
+
|
|
657
|
+
#### Example
|
|
658
|
+
|
|
659
|
+
```ts
|
|
660
|
+
import {
|
|
661
|
+
createModal,
|
|
662
|
+
withModalGroups,
|
|
663
|
+
modalGroups,
|
|
664
|
+
isDialog,
|
|
665
|
+
} from "@monstermann/signals-modal";
|
|
666
|
+
|
|
667
|
+
createModal("key", () => {
|
|
668
|
+
withModalGroups([modalGroups.popover]);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
isDialog("key"); // true
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### isModalInGroup
|
|
675
|
+
|
|
676
|
+

|
|
677
|
+
|
|
678
|
+
```ts
|
|
679
|
+
function isModalInGroup(key: string, group: string): boolean;
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
Returns a boolean indicating whether the given `key` belongs to the `group`.
|
|
683
|
+
|
|
684
|
+
#### Example
|
|
685
|
+
|
|
686
|
+
```ts
|
|
687
|
+
import {
|
|
688
|
+
createModal,
|
|
689
|
+
withModalGroups,
|
|
690
|
+
modalGroups,
|
|
691
|
+
isModalInGroup,
|
|
692
|
+
} from "@monstermann/signals-modal";
|
|
693
|
+
|
|
694
|
+
createModal("key", () => {
|
|
695
|
+
withModalGroups([modalGroups.popover]);
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
isModalInGroup("key", modalGroups.popover); // true
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### isPopover
|
|
702
|
+
|
|
703
|
+

|
|
704
|
+
|
|
705
|
+
```ts
|
|
706
|
+
function isPopover(key: string): boolean;
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
Returns a boolean indicating whether the given `key` belongs to the `modalGroups.popover` group.
|
|
710
|
+
|
|
711
|
+
#### Example
|
|
712
|
+
|
|
713
|
+
```ts
|
|
714
|
+
import {
|
|
715
|
+
createModal,
|
|
716
|
+
withModalGroups,
|
|
717
|
+
modalGroups,
|
|
718
|
+
isPopover,
|
|
719
|
+
} from "@monstermann/signals-modal";
|
|
720
|
+
|
|
721
|
+
createModal("key", () => {
|
|
722
|
+
withModalGroups([modalGroups.popover]);
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
isPopover("key"); // true
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
### isTooltip
|
|
729
|
+
|
|
730
|
+

|
|
731
|
+
|
|
732
|
+
```ts
|
|
733
|
+
function isTooltip(key: string): boolean;
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
Returns a boolean indicating whether the given `key` belongs to the `modalGroups.tooltip` group.
|
|
737
|
+
|
|
738
|
+
#### Example
|
|
739
|
+
|
|
740
|
+
```ts
|
|
741
|
+
import {
|
|
742
|
+
createModal,
|
|
743
|
+
withModalGroups,
|
|
744
|
+
modalGroups,
|
|
745
|
+
isTooltip,
|
|
746
|
+
} from "@monstermann/signals-modal";
|
|
747
|
+
|
|
748
|
+
createModal("key", () => {
|
|
749
|
+
withModalGroups([modalGroups.popover]);
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
isTooltip("key"); // true
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### modalGroups
|
|
756
|
+
|
|
757
|
+
```ts
|
|
758
|
+
const modalGroups = {
|
|
759
|
+
dialog: "dialog",
|
|
760
|
+
popover: "popover",
|
|
761
|
+
tooltip: "tooltip",
|
|
762
|
+
};
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
A record containing common modal groups.
|
|
766
|
+
|
|
767
|
+
### withModalGroups
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
function withModalGroups(groups: Iterable<string>): Memo<ReadonlySet<string>>;
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
Assigns the current modal to a list of groups. Can be used to for example mark the modal as a dialog/popover/tooltip. This function must be called inside a `createModal` callback.
|
|
774
|
+
|
|
775
|
+
#### Example
|
|
776
|
+
|
|
777
|
+
```ts
|
|
778
|
+
import {
|
|
779
|
+
createModal,
|
|
780
|
+
withModalGroups,
|
|
781
|
+
getDialogs,
|
|
782
|
+
getGroupsForModal,
|
|
783
|
+
getModalsForGroup,
|
|
784
|
+
} from "@monstermann/signals-modal";
|
|
785
|
+
|
|
786
|
+
createModal("key", () => {
|
|
787
|
+
withModalGroups(["dialog"]);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
getGroupsForModal("key"); // Set(["dialog"])
|
|
791
|
+
getModalsForGroup("dialog"); // Set(["key"])
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
## Position
|
|
795
|
+
|
|
796
|
+
### getModalPlacement
|
|
797
|
+
|
|
798
|
+
```ts
|
|
799
|
+
function getModalPlacement(key: string): ModalPlacement | undefined;
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
Returns the current placement for the given `key`.
|
|
803
|
+
|
|
804
|
+
#### Example
|
|
805
|
+
|
|
806
|
+
```ts
|
|
807
|
+
import {
|
|
808
|
+
createModal,
|
|
809
|
+
withModalStatus,
|
|
810
|
+
withAnchorElement,
|
|
811
|
+
withAnchorMeasurement,
|
|
812
|
+
withFloatingElement,
|
|
813
|
+
withFloatingMeasurement,
|
|
814
|
+
withBoundary,
|
|
815
|
+
withPlacement,
|
|
816
|
+
getModalPlacement,
|
|
817
|
+
} from "@monstermann/signals-modal";
|
|
818
|
+
|
|
819
|
+
createModal("key", () => {
|
|
820
|
+
const { $status } = withModalStatus();
|
|
821
|
+
const $anchorElement = withAnchorElement();
|
|
822
|
+
const $floatingElement = withFloatingElement();
|
|
823
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
824
|
+
$status,
|
|
825
|
+
$anchorElement,
|
|
826
|
+
});
|
|
827
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
828
|
+
$status,
|
|
829
|
+
$floatingElement,
|
|
830
|
+
});
|
|
831
|
+
const $boundary = withBoundary({ $status });
|
|
832
|
+
const $placement = withPlacement({
|
|
833
|
+
placement: "vertical-center",
|
|
834
|
+
$boundary,
|
|
835
|
+
$anchorMeasurement,
|
|
836
|
+
$floatingMeasurement,
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
getModalPlacement("key"); // up-center | down-center
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### getModalPosition
|
|
844
|
+
|
|
845
|
+

|
|
846
|
+
|
|
847
|
+
```ts
|
|
848
|
+
function getModalPosition(key: string): ModalPosition | undefined;
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
Returns the current result of `withPosition`.
|
|
852
|
+
|
|
853
|
+
#### Example
|
|
854
|
+
|
|
855
|
+
```ts
|
|
856
|
+
import {
|
|
857
|
+
createModal,
|
|
858
|
+
withModalStatus,
|
|
859
|
+
withAnchorElement,
|
|
860
|
+
withAnchorMeasurement,
|
|
861
|
+
withFloatingElement,
|
|
862
|
+
withFloatingMeasurement,
|
|
863
|
+
withBoundary,
|
|
864
|
+
withPlacement,
|
|
865
|
+
withPosition,
|
|
866
|
+
getModalPosition,
|
|
867
|
+
} from "@monstermann/signals-modal";
|
|
868
|
+
|
|
869
|
+
createModal("key", () => {
|
|
870
|
+
const { $status } = withModalStatus();
|
|
871
|
+
const $anchorElement = withAnchorElement();
|
|
872
|
+
const $floatingElement = withFloatingElement();
|
|
873
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
874
|
+
$status,
|
|
875
|
+
$anchorElement,
|
|
876
|
+
});
|
|
877
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
878
|
+
$status,
|
|
879
|
+
$floatingElement,
|
|
880
|
+
});
|
|
881
|
+
const $boundary = withBoundary({ $status });
|
|
882
|
+
const $placement = withPlacement({
|
|
883
|
+
placement: "vertical-center",
|
|
884
|
+
$boundary,
|
|
885
|
+
$anchorMeasurement,
|
|
886
|
+
$floatingMeasurement,
|
|
887
|
+
});
|
|
888
|
+
const $position = withPosition({
|
|
889
|
+
$boundary,
|
|
890
|
+
$placement,
|
|
891
|
+
$anchorMeasurement,
|
|
892
|
+
$floatingMeasurement,
|
|
893
|
+
});
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
getModalPosition("key"); // ModalPosition | undefined
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
### withBoundary
|
|
900
|
+
|
|
901
|
+
```ts
|
|
902
|
+
function withBoundary(options: {
|
|
903
|
+
$status: Reactive<ModalStatus>;
|
|
904
|
+
transform?: (rect: Rect) => Rect;
|
|
905
|
+
}): Memo<Rect>;
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
Constructs a `Rect` resembling the window dimensions, to be fed into `withPlacement` and `withPosition`, used to constrain the floating element to be within the window boundary. This function must be called inside a `createModal` callback.
|
|
909
|
+
|
|
910
|
+
The optional `transform` option can be used to eg. make the `Rect` smaller, increasing the distance between the floating element and the edges of the window.
|
|
911
|
+
|
|
912
|
+
#### Example
|
|
913
|
+
|
|
914
|
+
```ts
|
|
915
|
+
import {
|
|
916
|
+
createModal,
|
|
917
|
+
withModalStatus,
|
|
918
|
+
withBoundary,
|
|
919
|
+
} from "@monstermann/signals-modal";
|
|
920
|
+
|
|
921
|
+
createModal("key", () => {
|
|
922
|
+
const { $status } = withModalStatus();
|
|
923
|
+
const $boundary = withBoundary({ $status });
|
|
924
|
+
});
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
### withPlacement
|
|
928
|
+
|
|
929
|
+
```ts
|
|
930
|
+
function withPlacement(options: {
|
|
931
|
+
placement: ModalPlacementOption;
|
|
932
|
+
$boundary: () => Rect;
|
|
933
|
+
$anchorMeasurement: () => Rect;
|
|
934
|
+
$floatingMeasurement: () => Rect;
|
|
935
|
+
}): Memo<ModalPlacement>;
|
|
936
|
+
|
|
937
|
+
type ModalPlacementOption =
|
|
938
|
+
| "vertical-center"
|
|
939
|
+
| "vertical-left"
|
|
940
|
+
| "vertical-right"
|
|
941
|
+
| "horizontal-center"
|
|
942
|
+
| "horizontal-up"
|
|
943
|
+
| "horizontal-down"
|
|
944
|
+
| "up-center"
|
|
945
|
+
| "down-center"
|
|
946
|
+
| "left-down"
|
|
947
|
+
| "right-down";
|
|
948
|
+
|
|
949
|
+
type ModalPlacement =
|
|
950
|
+
| "down-center"
|
|
951
|
+
| "down-left"
|
|
952
|
+
| "down-right"
|
|
953
|
+
| "left-center"
|
|
954
|
+
| "left-down"
|
|
955
|
+
| "left-up"
|
|
956
|
+
| "right-center"
|
|
957
|
+
| "right-down"
|
|
958
|
+
| "right-up"
|
|
959
|
+
| "up-center"
|
|
960
|
+
| "up-left"
|
|
961
|
+
| "up-right";
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
Takes a `ModalPlacementOption` and resolves it to `ModalPlacement`, picking whichever side has more space. This function must be called inside a `createModal` callback.
|
|
965
|
+
|
|
966
|
+
#### Example
|
|
967
|
+
|
|
968
|
+
```ts
|
|
969
|
+
import {
|
|
970
|
+
createModal,
|
|
971
|
+
withModalStatus,
|
|
972
|
+
withAnchorElement,
|
|
973
|
+
withAnchorMeasurement,
|
|
974
|
+
withFloatingElement,
|
|
975
|
+
withFloatingMeasurement,
|
|
976
|
+
withBoundary,
|
|
977
|
+
withPlacement,
|
|
978
|
+
} from "@monstermann/signals-modal";
|
|
979
|
+
|
|
980
|
+
createModal("key", () => {
|
|
981
|
+
const { $status } = withModalStatus();
|
|
982
|
+
const $anchorElement = withAnchorElement();
|
|
983
|
+
const $floatingElement = withFloatingElement();
|
|
984
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
985
|
+
$status,
|
|
986
|
+
$anchorElement,
|
|
987
|
+
});
|
|
988
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
989
|
+
$status,
|
|
990
|
+
$floatingElement,
|
|
991
|
+
});
|
|
992
|
+
const $boundary = withBoundary({ $status });
|
|
993
|
+
const $placement = withPlacement({
|
|
994
|
+
placement: "vertical-center",
|
|
995
|
+
$boundary,
|
|
996
|
+
$anchorMeasurement,
|
|
997
|
+
$floatingMeasurement,
|
|
998
|
+
});
|
|
999
|
+
});
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
### withPosition
|
|
1003
|
+
|
|
1004
|
+
```ts
|
|
1005
|
+
function withPosition(options: {
|
|
1006
|
+
$boundary: () => Rect;
|
|
1007
|
+
$placement: () => ModalPlacement;
|
|
1008
|
+
$anchorMeasurement: () => Rect;
|
|
1009
|
+
$floatingMeasurement: () => Rect;
|
|
1010
|
+
transform?: (rect: Rect) => Rect;
|
|
1011
|
+
}): Memo<{
|
|
1012
|
+
floatingX: number;
|
|
1013
|
+
floatingY: number;
|
|
1014
|
+
maxHeight: number;
|
|
1015
|
+
maxWidth: number;
|
|
1016
|
+
originX: number;
|
|
1017
|
+
originY: number;
|
|
1018
|
+
}>;
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
Consumes a range of measurements and calculates the final position for the floating element. This function must be called inside a `createModal` callback.
|
|
1022
|
+
|
|
1023
|
+
#### Example
|
|
1024
|
+
|
|
1025
|
+
```ts
|
|
1026
|
+
import {
|
|
1027
|
+
createModal,
|
|
1028
|
+
withModalStatus,
|
|
1029
|
+
withAnchorElement,
|
|
1030
|
+
withAnchorMeasurement,
|
|
1031
|
+
withFloatingElement,
|
|
1032
|
+
withFloatingMeasurement,
|
|
1033
|
+
withBoundary,
|
|
1034
|
+
withPlacement,
|
|
1035
|
+
withPosition,
|
|
1036
|
+
} from "@monstermann/signals-modal";
|
|
1037
|
+
|
|
1038
|
+
createModal("key", () => {
|
|
1039
|
+
const { $status } = withModalStatus();
|
|
1040
|
+
const $anchorElement = withAnchorElement();
|
|
1041
|
+
const $floatingElement = withFloatingElement();
|
|
1042
|
+
const $anchorMeasurement = withAnchorMeasurement({
|
|
1043
|
+
$status,
|
|
1044
|
+
$anchorElement,
|
|
1045
|
+
});
|
|
1046
|
+
const $floatingMeasurement = withFloatingMeasurement({
|
|
1047
|
+
$status,
|
|
1048
|
+
$floatingElement,
|
|
1049
|
+
});
|
|
1050
|
+
const $boundary = withBoundary({ $status });
|
|
1051
|
+
const $placement = withPlacement({
|
|
1052
|
+
placement: "vertical-center",
|
|
1053
|
+
$boundary,
|
|
1054
|
+
$anchorMeasurement,
|
|
1055
|
+
$floatingMeasurement,
|
|
1056
|
+
});
|
|
1057
|
+
const $position = withPosition({
|
|
1058
|
+
$boundary,
|
|
1059
|
+
$placement,
|
|
1060
|
+
$anchorMeasurement,
|
|
1061
|
+
$floatingMeasurement,
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
## Scroll
|
|
1067
|
+
|
|
1068
|
+
### withCloseOnScroll
|
|
1069
|
+
|
|
1070
|
+
```ts
|
|
1071
|
+
function withCloseOnScroll(options: {
|
|
1072
|
+
$anchorElement: Reactive<HTMLElement | null>;
|
|
1073
|
+
$status: Reactive<ModalStatus>;
|
|
1074
|
+
}): void;
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
Automatically closes the modal when any scrollable ancestor of the anchor element is scrolled. This function must be called inside a `createModal` callback.
|
|
1078
|
+
|
|
1079
|
+
The function listens for scroll events on all scrollable parent elements of the anchor element and triggers a close when scrolling occurs. Scroll listeners are only active when the modal is opening or opened (not when closing or closed).
|
|
1080
|
+
|
|
1081
|
+
#### Example
|
|
1082
|
+
|
|
1083
|
+
```ts
|
|
1084
|
+
import {
|
|
1085
|
+
createModal,
|
|
1086
|
+
withModalStatus,
|
|
1087
|
+
withAnchorElement,
|
|
1088
|
+
withCloseOnScroll,
|
|
1089
|
+
} from "@monstermann/signals-modal";
|
|
1090
|
+
|
|
1091
|
+
createModal("key", () => {
|
|
1092
|
+
const { $status } = withModalStatus();
|
|
1093
|
+
const $anchorElement = withAnchorElement();
|
|
1094
|
+
|
|
1095
|
+
withCloseOnScroll({
|
|
1096
|
+
$status,
|
|
1097
|
+
$anchorElement,
|
|
1098
|
+
});
|
|
1099
|
+
});
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
## Status
|
|
1103
|
+
|
|
1104
|
+
### closeAllModals
|
|
1105
|
+
|
|
1106
|
+
```ts
|
|
1107
|
+
function closeAllModals(): void;
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
Closes all modals by setting their status to `"closing"`. Skips modals that are already `"closing"` or `"closed"`.
|
|
1111
|
+
|
|
1112
|
+
#### Example
|
|
1113
|
+
|
|
1114
|
+
```ts
|
|
1115
|
+
import {
|
|
1116
|
+
createModal,
|
|
1117
|
+
withModalStatus,
|
|
1118
|
+
openModal,
|
|
1119
|
+
closeAllModals,
|
|
1120
|
+
} from "@monstermann/signals-modal";
|
|
1121
|
+
|
|
1122
|
+
createModal("modal1", () => {
|
|
1123
|
+
withModalStatus();
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
createModal("modal2", () => {
|
|
1127
|
+
withModalStatus();
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
openModal("modal1");
|
|
1131
|
+
openModal("modal2");
|
|
1132
|
+
closeAllModals();
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
### closeLastModal
|
|
1136
|
+
|
|
1137
|
+
```ts
|
|
1138
|
+
function closeLastModal(): void;
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
Closes the last opened modal by setting its status to `"closing"`.
|
|
1142
|
+
|
|
1143
|
+
#### Example
|
|
1144
|
+
|
|
1145
|
+
```ts
|
|
1146
|
+
import { closeLastModal } from "@monstermann/signals-modal";
|
|
1147
|
+
|
|
1148
|
+
closeLastModal();
|
|
1149
|
+
```
|
|
1150
|
+
|
|
1151
|
+
### closeModal
|
|
1152
|
+
|
|
1153
|
+
```ts
|
|
1154
|
+
function closeModal(key: string): void;
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
Closes a modal by setting its status to `"closing"`. Does nothing if the modal is already `"closing"` or `"closed"`, or if the modal doesn't exist.
|
|
1158
|
+
|
|
1159
|
+
#### Example
|
|
1160
|
+
|
|
1161
|
+
```ts
|
|
1162
|
+
import {
|
|
1163
|
+
createModal,
|
|
1164
|
+
withModalStatus,
|
|
1165
|
+
openModal,
|
|
1166
|
+
closeModal,
|
|
1167
|
+
} from "@monstermann/signals-modal";
|
|
1168
|
+
|
|
1169
|
+
createModal("key", () => {
|
|
1170
|
+
withModalStatus();
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
openModal("key");
|
|
1174
|
+
closeModal("key");
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
### getClosedModals
|
|
1178
|
+
|
|
1179
|
+

|
|
1180
|
+
|
|
1181
|
+
```ts
|
|
1182
|
+
function getClosedModals(): string[];
|
|
1183
|
+
```
|
|
1184
|
+
|
|
1185
|
+
Returns an array of all modal keys with status `"closed"`.
|
|
1186
|
+
|
|
1187
|
+
#### Example
|
|
1188
|
+
|
|
1189
|
+
```ts
|
|
1190
|
+
import {
|
|
1191
|
+
createModal,
|
|
1192
|
+
withModalStatus,
|
|
1193
|
+
getClosedModals,
|
|
1194
|
+
} from "@monstermann/signals-modal";
|
|
1195
|
+
|
|
1196
|
+
createModal("modal1", () => {
|
|
1197
|
+
withModalStatus();
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
createModal("modal2", () => {
|
|
1201
|
+
withModalStatus();
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
getClosedModals(); // ["modal1", "modal2"]
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
### getClosingModals
|
|
1208
|
+
|
|
1209
|
+

|
|
1210
|
+
|
|
1211
|
+
```ts
|
|
1212
|
+
function getClosingModals(): string[];
|
|
1213
|
+
```
|
|
1214
|
+
|
|
1215
|
+
Returns an array of all modal keys with status `"closing"`.
|
|
1216
|
+
|
|
1217
|
+
#### Example
|
|
1218
|
+
|
|
1219
|
+
```ts
|
|
1220
|
+
import {
|
|
1221
|
+
createModal,
|
|
1222
|
+
withModalStatus,
|
|
1223
|
+
closeModal,
|
|
1224
|
+
getClosingModals,
|
|
1225
|
+
} from "@monstermann/signals-modal";
|
|
1226
|
+
|
|
1227
|
+
createModal("modal1", () => {
|
|
1228
|
+
withModalStatus("opened");
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
createModal("modal2", () => {
|
|
1232
|
+
withModalStatus("opened");
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
closeModal("modal1");
|
|
1236
|
+
closeModal("modal2");
|
|
1237
|
+
|
|
1238
|
+
getClosingModals(); // ["modal1", "modal2"]
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
### getModalStatus
|
|
1242
|
+
|
|
1243
|
+

|
|
1244
|
+
|
|
1245
|
+
```ts
|
|
1246
|
+
function getModalStatus(key: string): ModalStatus;
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
Retrieves the current status of a modal. Returns `"closed"` if the modal doesn't exist.
|
|
1250
|
+
|
|
1251
|
+
**ModalStatus** can be one of: `"closed"`, `"opening"`, `"opened"`, or `"closing"`.
|
|
1252
|
+
|
|
1253
|
+
#### Example
|
|
1254
|
+
|
|
1255
|
+
```ts
|
|
1256
|
+
import {
|
|
1257
|
+
createModal,
|
|
1258
|
+
withModalStatus,
|
|
1259
|
+
getModalStatus,
|
|
1260
|
+
} from "@monstermann/signals-modal";
|
|
1261
|
+
|
|
1262
|
+
createModal("key", () => {
|
|
1263
|
+
withModalStatus();
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
getModalStatus("key"); // "closed"
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
### getOpenedModals
|
|
1270
|
+
|
|
1271
|
+

|
|
1272
|
+
|
|
1273
|
+
```ts
|
|
1274
|
+
function getOpenedModals(): string[];
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
Returns an array of all modal keys with status `"opened"`.
|
|
1278
|
+
|
|
1279
|
+
#### Example
|
|
1280
|
+
|
|
1281
|
+
```ts
|
|
1282
|
+
import {
|
|
1283
|
+
createModal,
|
|
1284
|
+
withModalStatus,
|
|
1285
|
+
getOpenedModals,
|
|
1286
|
+
} from "@monstermann/signals-modal";
|
|
1287
|
+
|
|
1288
|
+
createModal("modal1", () => {
|
|
1289
|
+
withModalStatus("opened");
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
createModal("modal2", () => {
|
|
1293
|
+
withModalStatus("opened");
|
|
1294
|
+
});
|
|
1295
|
+
|
|
1296
|
+
getOpenedModals(); // ["modal1", "modal2"]
|
|
1297
|
+
```
|
|
1298
|
+
|
|
1299
|
+
### getOpeningModals
|
|
1300
|
+
|
|
1301
|
+

|
|
1302
|
+
|
|
1303
|
+
```ts
|
|
1304
|
+
function getOpeningModals(): string[];
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
Returns an array of all modal keys with status `"opening"`.
|
|
1308
|
+
|
|
1309
|
+
#### Example
|
|
1310
|
+
|
|
1311
|
+
```ts
|
|
1312
|
+
import {
|
|
1313
|
+
createModal,
|
|
1314
|
+
withModalStatus,
|
|
1315
|
+
openModal,
|
|
1316
|
+
getOpeningModals,
|
|
1317
|
+
} from "@monstermann/signals-modal";
|
|
1318
|
+
|
|
1319
|
+
createModal("modal1", () => {
|
|
1320
|
+
withModalStatus();
|
|
1321
|
+
});
|
|
1322
|
+
|
|
1323
|
+
createModal("modal2", () => {
|
|
1324
|
+
withModalStatus();
|
|
1325
|
+
});
|
|
1326
|
+
|
|
1327
|
+
openModal("modal1");
|
|
1328
|
+
openModal("modal2");
|
|
1329
|
+
|
|
1330
|
+
getOpeningModals(); // ["modal1", "modal2"]
|
|
1331
|
+
```
|
|
1332
|
+
|
|
1333
|
+
### getOpenModals
|
|
1334
|
+
|
|
1335
|
+

|
|
1336
|
+
|
|
1337
|
+
```ts
|
|
1338
|
+
function getOpenModals(): string[];
|
|
1339
|
+
```
|
|
1340
|
+
|
|
1341
|
+
Returns an array of all modal keys with status `"opening"` or `"opened"`.
|
|
1342
|
+
|
|
1343
|
+
#### Example
|
|
1344
|
+
|
|
1345
|
+
```ts
|
|
1346
|
+
import {
|
|
1347
|
+
createModal,
|
|
1348
|
+
withModalStatus,
|
|
1349
|
+
getOpenModals,
|
|
1350
|
+
} from "@monstermann/signals-modal";
|
|
1351
|
+
|
|
1352
|
+
createModal("modal1", () => {
|
|
1353
|
+
withModalStatus("opening");
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
createModal("modal2", () => {
|
|
1357
|
+
withModalStatus("opened");
|
|
1358
|
+
});
|
|
1359
|
+
|
|
1360
|
+
createModal("modal3", () => {
|
|
1361
|
+
withModalStatus("closed");
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
getOpenModals(); // ["modal1", "modal2"]
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
### getVisibleModals
|
|
1368
|
+
|
|
1369
|
+

|
|
1370
|
+
|
|
1371
|
+
```ts
|
|
1372
|
+
function getVisibleModals(): string[];
|
|
1373
|
+
```
|
|
1374
|
+
|
|
1375
|
+
Returns an array of all modal keys that are visible (not `"closed"`). This includes `"opening"`, `"opened"`, and `"closing"` statuses.
|
|
1376
|
+
|
|
1377
|
+
#### Example
|
|
1378
|
+
|
|
1379
|
+
```ts
|
|
1380
|
+
import {
|
|
1381
|
+
createModal,
|
|
1382
|
+
withModalStatus,
|
|
1383
|
+
openModal,
|
|
1384
|
+
getVisibleModals,
|
|
1385
|
+
} from "@monstermann/signals-modal";
|
|
1386
|
+
|
|
1387
|
+
createModal("modal1", () => {
|
|
1388
|
+
withModalStatus();
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1391
|
+
createModal("modal2", () => {
|
|
1392
|
+
withModalStatus();
|
|
1393
|
+
});
|
|
1394
|
+
|
|
1395
|
+
openModal("modal1");
|
|
1396
|
+
openModal("modal2");
|
|
1397
|
+
|
|
1398
|
+
getVisibleModals(); // ["modal1", "modal2"]
|
|
1399
|
+
```
|
|
1400
|
+
|
|
1401
|
+
### isAnyModalClosed
|
|
1402
|
+
|
|
1403
|
+

|
|
1404
|
+
|
|
1405
|
+
```ts
|
|
1406
|
+
function isAnyModalClosed(): boolean;
|
|
1407
|
+
```
|
|
1408
|
+
|
|
1409
|
+
Returns `true` if any modal has status `"closed"`.
|
|
1410
|
+
|
|
1411
|
+
#### Example
|
|
1412
|
+
|
|
1413
|
+
```ts
|
|
1414
|
+
import {
|
|
1415
|
+
createModal,
|
|
1416
|
+
withModalStatus,
|
|
1417
|
+
isAnyModalClosed,
|
|
1418
|
+
} from "@monstermann/signals-modal";
|
|
1419
|
+
|
|
1420
|
+
createModal("modal1", () => {
|
|
1421
|
+
withModalStatus();
|
|
1422
|
+
});
|
|
1423
|
+
|
|
1424
|
+
createModal("modal2", () => {
|
|
1425
|
+
withModalStatus("opened");
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
isAnyModalClosed(); // true
|
|
1429
|
+
```
|
|
1430
|
+
|
|
1431
|
+
### isAnyModalClosing
|
|
1432
|
+
|
|
1433
|
+

|
|
1434
|
+
|
|
1435
|
+
```ts
|
|
1436
|
+
function isAnyModalClosing(): boolean;
|
|
1437
|
+
```
|
|
1438
|
+
|
|
1439
|
+
Returns `true` if any modal has status `"closing"`.
|
|
1440
|
+
|
|
1441
|
+
#### Example
|
|
1442
|
+
|
|
1443
|
+
```ts
|
|
1444
|
+
import {
|
|
1445
|
+
createModal,
|
|
1446
|
+
withModalStatus,
|
|
1447
|
+
closeModal,
|
|
1448
|
+
isAnyModalClosing,
|
|
1449
|
+
} from "@monstermann/signals-modal";
|
|
1450
|
+
|
|
1451
|
+
createModal("modal1", () => {
|
|
1452
|
+
withModalStatus("opened");
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1455
|
+
createModal("modal2", () => {
|
|
1456
|
+
withModalStatus();
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
closeModal("modal1");
|
|
1460
|
+
|
|
1461
|
+
isAnyModalClosing(); // true
|
|
1462
|
+
```
|
|
1463
|
+
|
|
1464
|
+
### isAnyModalOpen
|
|
1465
|
+
|
|
1466
|
+

|
|
1467
|
+
|
|
1468
|
+
```ts
|
|
1469
|
+
function isAnyModalOpen(): boolean;
|
|
1470
|
+
```
|
|
1471
|
+
|
|
1472
|
+
Returns `true` if any modal has status `"opening"` or `"opened"`.
|
|
1473
|
+
|
|
1474
|
+
#### Example
|
|
1475
|
+
|
|
1476
|
+
```ts
|
|
1477
|
+
import {
|
|
1478
|
+
createModal,
|
|
1479
|
+
withModalStatus,
|
|
1480
|
+
isAnyModalOpen,
|
|
1481
|
+
} from "@monstermann/signals-modal";
|
|
1482
|
+
|
|
1483
|
+
createModal("modal1", () => {
|
|
1484
|
+
withModalStatus();
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
createModal("modal2", () => {
|
|
1488
|
+
withModalStatus("opened");
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1491
|
+
isAnyModalOpen(); // true
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
### isAnyModalOpened
|
|
1495
|
+
|
|
1496
|
+

|
|
1497
|
+
|
|
1498
|
+
```ts
|
|
1499
|
+
function isAnyModalOpened(): boolean;
|
|
1500
|
+
```
|
|
1501
|
+
|
|
1502
|
+
Returns `true` if any modal has status `"opened"`.
|
|
1503
|
+
|
|
1504
|
+
#### Example
|
|
1505
|
+
|
|
1506
|
+
```ts
|
|
1507
|
+
import {
|
|
1508
|
+
createModal,
|
|
1509
|
+
withModalStatus,
|
|
1510
|
+
isAnyModalOpened,
|
|
1511
|
+
} from "@monstermann/signals-modal";
|
|
1512
|
+
|
|
1513
|
+
createModal("modal1", () => {
|
|
1514
|
+
withModalStatus();
|
|
1515
|
+
});
|
|
1516
|
+
|
|
1517
|
+
createModal("modal2", () => {
|
|
1518
|
+
withModalStatus("opened");
|
|
1519
|
+
});
|
|
1520
|
+
|
|
1521
|
+
isAnyModalOpened(); // true
|
|
1522
|
+
```
|
|
1523
|
+
|
|
1524
|
+
### isAnyModalOpening
|
|
1525
|
+
|
|
1526
|
+

|
|
1527
|
+
|
|
1528
|
+
```ts
|
|
1529
|
+
function isAnyModalOpening(): boolean;
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
Returns `true` if any modal has status `"opening"`.
|
|
1533
|
+
|
|
1534
|
+
#### Example
|
|
1535
|
+
|
|
1536
|
+
```ts
|
|
1537
|
+
import {
|
|
1538
|
+
createModal,
|
|
1539
|
+
withModalStatus,
|
|
1540
|
+
openModal,
|
|
1541
|
+
isAnyModalOpening,
|
|
1542
|
+
} from "@monstermann/signals-modal";
|
|
1543
|
+
|
|
1544
|
+
createModal("modal1", () => {
|
|
1545
|
+
withModalStatus();
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
createModal("modal2", () => {
|
|
1549
|
+
withModalStatus();
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1552
|
+
openModal("modal1");
|
|
1553
|
+
|
|
1554
|
+
isAnyModalOpening(); // true
|
|
1555
|
+
```
|
|
1556
|
+
|
|
1557
|
+
### isAnyModalVisible
|
|
1558
|
+
|
|
1559
|
+

|
|
1560
|
+
|
|
1561
|
+
```ts
|
|
1562
|
+
function isAnyModalVisible(): boolean;
|
|
1563
|
+
```
|
|
1564
|
+
|
|
1565
|
+
Returns `true` if any modal is visible (not `"closed"`). This includes `"opening"`, `"opened"`, and `"closing"` statuses.
|
|
1566
|
+
|
|
1567
|
+
#### Example
|
|
1568
|
+
|
|
1569
|
+
```ts
|
|
1570
|
+
import {
|
|
1571
|
+
createModal,
|
|
1572
|
+
withModalStatus,
|
|
1573
|
+
isAnyModalVisible,
|
|
1574
|
+
} from "@monstermann/signals-modal";
|
|
1575
|
+
|
|
1576
|
+
createModal("modal1", () => {
|
|
1577
|
+
withModalStatus();
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
createModal("modal2", () => {
|
|
1581
|
+
withModalStatus("opened");
|
|
1582
|
+
});
|
|
1583
|
+
|
|
1584
|
+
isAnyModalVisible(); // true
|
|
1585
|
+
```
|
|
1586
|
+
|
|
1587
|
+
### isModalClosed
|
|
1588
|
+
|
|
1589
|
+

|
|
1590
|
+
|
|
1591
|
+
```ts
|
|
1592
|
+
function isModalClosed(key: string): boolean;
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
Returns `true` if the modal's status is `"closed"` or if the modal doesn't exist.
|
|
1596
|
+
|
|
1597
|
+
#### Example
|
|
1598
|
+
|
|
1599
|
+
```ts
|
|
1600
|
+
import {
|
|
1601
|
+
createModal,
|
|
1602
|
+
withModalStatus,
|
|
1603
|
+
isModalClosed,
|
|
1604
|
+
} from "@monstermann/signals-modal";
|
|
1605
|
+
|
|
1606
|
+
createModal("key", () => {
|
|
1607
|
+
withModalStatus();
|
|
1608
|
+
});
|
|
1609
|
+
|
|
1610
|
+
isModalClosed("key"); // true
|
|
1611
|
+
```
|
|
1612
|
+
|
|
1613
|
+
### isModalClosing
|
|
1614
|
+
|
|
1615
|
+

|
|
1616
|
+
|
|
1617
|
+
```ts
|
|
1618
|
+
function isModalClosing(key: string): boolean;
|
|
1619
|
+
```
|
|
1620
|
+
|
|
1621
|
+
Returns `true` if the modal's status is `"closing"`.
|
|
1622
|
+
|
|
1623
|
+
#### Example
|
|
1624
|
+
|
|
1625
|
+
```ts
|
|
1626
|
+
import {
|
|
1627
|
+
createModal,
|
|
1628
|
+
withModalStatus,
|
|
1629
|
+
openModal,
|
|
1630
|
+
closeModal,
|
|
1631
|
+
isModalClosing,
|
|
1632
|
+
} from "@monstermann/signals-modal";
|
|
1633
|
+
|
|
1634
|
+
createModal("key", () => {
|
|
1635
|
+
const { $status } = withModalStatus();
|
|
1636
|
+
$status("opened");
|
|
1637
|
+
});
|
|
1638
|
+
|
|
1639
|
+
closeModal("key");
|
|
1640
|
+
isModalClosing("key"); // true
|
|
1641
|
+
```
|
|
1642
|
+
|
|
1643
|
+
### isModalOpen
|
|
1644
|
+
|
|
1645
|
+

|
|
1646
|
+
|
|
1647
|
+
```ts
|
|
1648
|
+
function isModalOpen(key: string): boolean;
|
|
1649
|
+
```
|
|
1650
|
+
|
|
1651
|
+
Returns `true` if the modal's status is `"opening"` or `"opened"`.
|
|
1652
|
+
|
|
1653
|
+
#### Example
|
|
1654
|
+
|
|
1655
|
+
```ts
|
|
1656
|
+
import {
|
|
1657
|
+
createModal,
|
|
1658
|
+
withModalStatus,
|
|
1659
|
+
isModalOpen,
|
|
1660
|
+
} from "@monstermann/signals-modal";
|
|
1661
|
+
|
|
1662
|
+
createModal("key", () => {
|
|
1663
|
+
const { $status } = withModalStatus("opening");
|
|
1664
|
+
});
|
|
1665
|
+
|
|
1666
|
+
isModalOpen("key"); // true
|
|
1667
|
+
```
|
|
1668
|
+
|
|
1669
|
+
### isModalOpened
|
|
1670
|
+
|
|
1671
|
+

|
|
1672
|
+
|
|
1673
|
+
```ts
|
|
1674
|
+
function isModalOpened(key: string): boolean;
|
|
1675
|
+
```
|
|
1676
|
+
|
|
1677
|
+
Returns `true` if the modal's status is `"opened"`.
|
|
1678
|
+
|
|
1679
|
+
#### Example
|
|
1680
|
+
|
|
1681
|
+
```ts
|
|
1682
|
+
import {
|
|
1683
|
+
createModal,
|
|
1684
|
+
withModalStatus,
|
|
1685
|
+
openModal,
|
|
1686
|
+
isModalOpened,
|
|
1687
|
+
} from "@monstermann/signals-modal";
|
|
1688
|
+
|
|
1689
|
+
createModal("key", () => {
|
|
1690
|
+
const { $status } = withModalStatus();
|
|
1691
|
+
$status("opened");
|
|
1692
|
+
});
|
|
1693
|
+
|
|
1694
|
+
isModalOpened("key"); // true
|
|
1695
|
+
```
|
|
1696
|
+
|
|
1697
|
+
### isModalOpening
|
|
1698
|
+
|
|
1699
|
+

|
|
1700
|
+
|
|
1701
|
+
```ts
|
|
1702
|
+
function isModalOpening(key: string): boolean;
|
|
1703
|
+
```
|
|
1704
|
+
|
|
1705
|
+
Returns `true` if the modal's status is `"opening"`.
|
|
1706
|
+
|
|
1707
|
+
#### Example
|
|
1708
|
+
|
|
1709
|
+
```ts
|
|
1710
|
+
import {
|
|
1711
|
+
createModal,
|
|
1712
|
+
withModalStatus,
|
|
1713
|
+
openModal,
|
|
1714
|
+
isModalOpening,
|
|
1715
|
+
} from "@monstermann/signals-modal";
|
|
1716
|
+
|
|
1717
|
+
createModal("key", () => {
|
|
1718
|
+
withModalStatus();
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
openModal("key");
|
|
1722
|
+
isModalOpening("key"); // true
|
|
1723
|
+
```
|
|
1724
|
+
|
|
1725
|
+
### isModalVisible
|
|
1726
|
+
|
|
1727
|
+

|
|
1728
|
+
|
|
1729
|
+
```ts
|
|
1730
|
+
function isModalVisible(key: string): boolean;
|
|
1731
|
+
```
|
|
1732
|
+
|
|
1733
|
+
Returns `true` if the modal is visible (not `"closed"`). This includes `"opening"`, `"opened"`, and `"closing"` statuses.
|
|
1734
|
+
|
|
1735
|
+
#### Example
|
|
1736
|
+
|
|
1737
|
+
```ts
|
|
1738
|
+
import {
|
|
1739
|
+
createModal,
|
|
1740
|
+
withModalStatus,
|
|
1741
|
+
openModal,
|
|
1742
|
+
isModalVisible,
|
|
1743
|
+
} from "@monstermann/signals-modal";
|
|
1744
|
+
|
|
1745
|
+
createModal("key", () => {
|
|
1746
|
+
withModalStatus();
|
|
1747
|
+
});
|
|
1748
|
+
|
|
1749
|
+
openModal("key");
|
|
1750
|
+
isModalVisible("key"); // true
|
|
1751
|
+
```
|
|
1752
|
+
|
|
1753
|
+
### onModalClosed
|
|
1754
|
+
|
|
1755
|
+
```ts
|
|
1756
|
+
const onModalClosed: Emitter<string>;
|
|
1757
|
+
```
|
|
1758
|
+
|
|
1759
|
+
An emitter that fires when a modal transitions to the `"closed"` status. The emitted value is the modal key.
|
|
1760
|
+
|
|
1761
|
+
#### Example
|
|
1762
|
+
|
|
1763
|
+
```ts
|
|
1764
|
+
import {
|
|
1765
|
+
createModal,
|
|
1766
|
+
withModalStatus,
|
|
1767
|
+
onModalClosed,
|
|
1768
|
+
} from "@monstermann/signals-modal";
|
|
1769
|
+
|
|
1770
|
+
createModal("key", () => {
|
|
1771
|
+
withModalStatus();
|
|
1772
|
+
});
|
|
1773
|
+
|
|
1774
|
+
const stopListening = onModalClosed((key) => {
|
|
1775
|
+
console.log(`Modal ${key} closed`);
|
|
1776
|
+
});
|
|
1777
|
+
|
|
1778
|
+
stopListening();
|
|
1779
|
+
```
|
|
1780
|
+
|
|
1781
|
+
### onModalClosing
|
|
1782
|
+
|
|
1783
|
+
```ts
|
|
1784
|
+
const onModalClosing: Emitter<string>;
|
|
1785
|
+
```
|
|
1786
|
+
|
|
1787
|
+
An emitter that fires when a modal transitions to the `"closing"` status. The emitted value is the modal key.
|
|
1788
|
+
|
|
1789
|
+
#### Example
|
|
1790
|
+
|
|
1791
|
+
```ts
|
|
1792
|
+
import {
|
|
1793
|
+
createModal,
|
|
1794
|
+
withModalStatus,
|
|
1795
|
+
onModalClosing,
|
|
1796
|
+
} from "@monstermann/signals-modal";
|
|
1797
|
+
|
|
1798
|
+
createModal("key", () => {
|
|
1799
|
+
withModalStatus();
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
const stopListening = onModalClosing((key) => {
|
|
1803
|
+
console.log(`Modal ${key} closing`);
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
stopListening();
|
|
1807
|
+
```
|
|
1808
|
+
|
|
1809
|
+
### onModalOpened
|
|
1810
|
+
|
|
1811
|
+
```ts
|
|
1812
|
+
const onModalOpened: Emitter<string>;
|
|
1813
|
+
```
|
|
1814
|
+
|
|
1815
|
+
An emitter that fires when a modal transitions to the `"opened"` status. The emitted value is the modal key.
|
|
1816
|
+
|
|
1817
|
+
#### Example
|
|
1818
|
+
|
|
1819
|
+
```ts
|
|
1820
|
+
import {
|
|
1821
|
+
createModal,
|
|
1822
|
+
withModalStatus,
|
|
1823
|
+
onModalOpened,
|
|
1824
|
+
} from "@monstermann/signals-modal";
|
|
1825
|
+
|
|
1826
|
+
createModal("key", () => {
|
|
1827
|
+
withModalStatus();
|
|
1828
|
+
});
|
|
1829
|
+
|
|
1830
|
+
const stopListening = onModalOpened((key) => {
|
|
1831
|
+
console.log(`Modal ${key} opened`);
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
stopListening();
|
|
1835
|
+
```
|
|
1836
|
+
|
|
1837
|
+
### onModalOpening
|
|
1838
|
+
|
|
1839
|
+
```ts
|
|
1840
|
+
const onModalOpening: Emitter<string>;
|
|
1841
|
+
```
|
|
1842
|
+
|
|
1843
|
+
An emitter that fires when a modal transitions to the `"opening"` status. The emitted value is the modal key.
|
|
1844
|
+
|
|
1845
|
+
#### Example
|
|
1846
|
+
|
|
1847
|
+
```ts
|
|
1848
|
+
import {
|
|
1849
|
+
createModal,
|
|
1850
|
+
withModalStatus,
|
|
1851
|
+
onModalOpening,
|
|
1852
|
+
} from "@monstermann/signals-modal";
|
|
1853
|
+
|
|
1854
|
+
createModal("key", () => {
|
|
1855
|
+
withModalStatus();
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1858
|
+
const stopListening = onModalOpening((key) => {
|
|
1859
|
+
console.log(`Modal ${key} opening`);
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
stopListening();
|
|
1863
|
+
```
|
|
1864
|
+
|
|
1865
|
+
### openModal
|
|
1866
|
+
|
|
1867
|
+
```ts
|
|
1868
|
+
function openModal(key: string): void;
|
|
1869
|
+
```
|
|
1870
|
+
|
|
1871
|
+
Opens a modal by setting its status to `"opening"`. Does nothing if the modal is already `"opening"` or `"opened"`, or if the modal doesn't exist.
|
|
1872
|
+
|
|
1873
|
+
#### Example
|
|
1874
|
+
|
|
1875
|
+
```ts
|
|
1876
|
+
import {
|
|
1877
|
+
createModal,
|
|
1878
|
+
withModalStatus,
|
|
1879
|
+
openModal,
|
|
1880
|
+
} from "@monstermann/signals-modal";
|
|
1881
|
+
|
|
1882
|
+
createModal("key", () => {
|
|
1883
|
+
withModalStatus();
|
|
1884
|
+
});
|
|
1885
|
+
|
|
1886
|
+
openModal("key");
|
|
1887
|
+
```
|
|
1888
|
+
|
|
1889
|
+
### setModalStatus
|
|
1890
|
+
|
|
1891
|
+
```ts
|
|
1892
|
+
function setModalStatus(key: string, status: ModalStatus): void;
|
|
1893
|
+
```
|
|
1894
|
+
|
|
1895
|
+
Sets the status of a modal. Does nothing if the modal doesn't exist.
|
|
1896
|
+
|
|
1897
|
+
**ModalStatus** can be one of: `"closed"`, `"opening"`, `"opened"`, or `"closing"`.
|
|
1898
|
+
|
|
1899
|
+
#### Example
|
|
1900
|
+
|
|
1901
|
+
```ts
|
|
1902
|
+
import {
|
|
1903
|
+
createModal,
|
|
1904
|
+
withModalStatus,
|
|
1905
|
+
setModalStatus,
|
|
1906
|
+
} from "@monstermann/signals-modal";
|
|
1907
|
+
|
|
1908
|
+
createModal("key", () => {
|
|
1909
|
+
withModalStatus();
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
setModalStatus("key", "opened");
|
|
1913
|
+
```
|
|
1914
|
+
|
|
1915
|
+
### withModalStatus
|
|
1916
|
+
|
|
1917
|
+
```ts
|
|
1918
|
+
function withModalStatus(status: ModalStatus = "closed"): {
|
|
1919
|
+
$status: Signal<ModalStatus>;
|
|
1920
|
+
$isOpen: Memo<boolean>;
|
|
1921
|
+
close: () => void;
|
|
1922
|
+
open: () => void;
|
|
1923
|
+
};
|
|
1924
|
+
```
|
|
1925
|
+
|
|
1926
|
+
Creates and returns a status signal for the current modal. This function must be called inside a `createModal` callback.
|
|
1927
|
+
|
|
1928
|
+
The optional `status` parameter sets the initial status of the modal (defaults to `"closed"`).
|
|
1929
|
+
|
|
1930
|
+
**ModalStatus** can be one of: `"closed"`, `"opening"`, `"opened"`, or `"closing"`.
|
|
1931
|
+
|
|
1932
|
+
#### Example
|
|
1933
|
+
|
|
1934
|
+
```ts
|
|
1935
|
+
import { createModal, withModalStatus } from "@monstermann/signals-modal";
|
|
1936
|
+
|
|
1937
|
+
// Default to "closed"
|
|
1938
|
+
createModal("modal1", () => {
|
|
1939
|
+
const { $status } = withModalStatus();
|
|
1940
|
+
console.log($status()); // "closed"
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
// Start with a different initial status
|
|
1944
|
+
createModal("modal2", () => {
|
|
1945
|
+
const { $status } = withModalStatus("opened");
|
|
1946
|
+
console.log($status()); // "opened"
|
|
1947
|
+
|
|
1948
|
+
// Update the status
|
|
1949
|
+
$status("closing");
|
|
1950
|
+
});
|
|
1951
|
+
```
|
|
1952
|
+
|
|
1953
|
+
## Utils
|
|
1954
|
+
|
|
1955
|
+
### closeLastModalOnClickOutside
|
|
1956
|
+
|
|
1957
|
+
```ts
|
|
1958
|
+
function closeLastModalOnClickOutside(): void;
|
|
1959
|
+
```
|
|
1960
|
+
|
|
1961
|
+
Sets up a global `mousedown` listener that closes the last opened modal when clicked outside the floating element.
|
|
1962
|
+
|
|
1963
|
+
#### Example
|
|
1964
|
+
|
|
1965
|
+
```ts
|
|
1966
|
+
import { closeLastModalOnClickOutside } from "@monstermann/signals-modal";
|
|
1967
|
+
|
|
1968
|
+
closeLastModalOnClickOutside();
|
|
1969
|
+
```
|
|
1970
|
+
|
|
1971
|
+
### closeLastModalOnEsc
|
|
1972
|
+
|
|
1973
|
+
```ts
|
|
1974
|
+
function closeLastModalOnEsc(): void;
|
|
1975
|
+
```
|
|
1976
|
+
|
|
1977
|
+
Sets up a global `keydown` listener that closes the last opened modal when `esc` is pressed, unless the target was an editable element such as `<input>`.
|
|
1978
|
+
|
|
1979
|
+
#### Example
|
|
1980
|
+
|
|
1981
|
+
```ts
|
|
1982
|
+
import { closeLastModalOnEsc } from "@monstermann/signals-modal";
|
|
1983
|
+
|
|
1984
|
+
closeLastModalOnEsc();
|
|
1985
|
+
```
|
|
1986
|
+
|
|
1987
|
+
### syncModalGroupsToBody
|
|
1988
|
+
|
|
1989
|
+
```ts
|
|
1990
|
+
function syncModalGroupsToBody(): void;
|
|
1991
|
+
```
|
|
1992
|
+
|
|
1993
|
+
Sets up a global `Effect` that adds `has-${group}` class names to `document.body` for opened modals.
|
|
1994
|
+
|
|
1995
|
+
#### Example
|
|
1996
|
+
|
|
1997
|
+
```ts
|
|
1998
|
+
import {
|
|
1999
|
+
createModal,
|
|
2000
|
+
withModalGroups,
|
|
2001
|
+
withModalStatus,
|
|
2002
|
+
syncModalGroupsToBody,
|
|
2003
|
+
openModal,
|
|
2004
|
+
closeModal,
|
|
2005
|
+
} from "@monstermann/signals-modal";
|
|
2006
|
+
|
|
2007
|
+
syncModalGroupsToBody();
|
|
2008
|
+
|
|
2009
|
+
const modal = createModal("key", () => {
|
|
2010
|
+
const $groups = withModalGroups(["dialog"]);
|
|
2011
|
+
const { $status } = withModalStatus();
|
|
2012
|
+
return { $groups, $status };
|
|
2013
|
+
});
|
|
2014
|
+
|
|
2015
|
+
document.body.classList; // []
|
|
2016
|
+
openModal("key");
|
|
2017
|
+
document.body.classList; // ["has-dialog"]
|
|
2018
|
+
closeModal("key");
|
|
2019
|
+
document.body.classList; // []
|
|
2020
|
+
```
|