@blockle/blocks-react 3.2.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/display/Divider/divider.css.js +3 -3
- package/dist/components/form/Label/Label.d.ts +1 -1
- package/dist/components/form/Label/Label.d.ts.map +1 -1
- package/dist/components/form/Select/select.css.js +1 -1
- package/dist/components/navigation/Tabs/Tab.d.ts +21 -0
- package/dist/components/navigation/Tabs/Tab.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/Tab.js +138 -0
- package/dist/components/navigation/Tabs/TabIndicator.d.ts +6 -0
- package/dist/components/navigation/Tabs/TabIndicator.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/TabIndicator.js +19 -0
- package/dist/components/navigation/Tabs/TabList.d.ts +10 -0
- package/dist/components/navigation/Tabs/TabList.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/TabList.js +101 -0
- package/dist/components/navigation/Tabs/TabListContext.d.ts +13 -0
- package/dist/components/navigation/Tabs/TabListContext.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/TabListContext.js +6 -0
- package/dist/components/navigation/Tabs/TabNav.d.ts +15 -0
- package/dist/components/navigation/Tabs/TabNav.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/TabNav.js +44 -0
- package/dist/components/navigation/Tabs/TabPanel.d.ts +14 -0
- package/dist/components/navigation/Tabs/TabPanel.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/TabPanel.js +31 -0
- package/dist/components/navigation/Tabs/Tabs.d.ts +13 -0
- package/dist/components/navigation/Tabs/Tabs.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/Tabs.js +33 -0
- package/dist/components/navigation/Tabs/TabsContext.d.ts +13 -0
- package/dist/components/navigation/Tabs/TabsContext.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/TabsContext.js +27 -0
- package/dist/components/navigation/Tabs/tabs.css.d.ts +7 -0
- package/dist/components/navigation/Tabs/tabs.css.d.ts.map +1 -0
- package/dist/components/navigation/Tabs/tabs.css.js +122 -0
- package/dist/components/overlay/Dialog/Dialog.d.ts +1 -1
- package/dist/components/overlay/Dialog/Dialog.d.ts.map +1 -1
- package/dist/components/overlay/Dialog/Dialog.js +9 -7
- package/dist/components/overlay/Drawer/Drawer.d.ts +1 -1
- package/dist/components/overlay/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/overlay/Drawer/Drawer.js +9 -7
- package/dist/components/overlay/Menu/Menu.d.ts +52 -0
- package/dist/components/overlay/Menu/Menu.d.ts.map +1 -0
- package/dist/components/overlay/Menu/Menu.js +273 -0
- package/dist/components/overlay/Menu/menu-utils.d.ts +33 -0
- package/dist/components/overlay/Menu/menu-utils.d.ts.map +1 -0
- package/dist/components/overlay/Menu/menu-utils.js +54 -0
- package/dist/components/overlay/Popover/Popover.d.ts +9 -0
- package/dist/components/overlay/Popover/Popover.d.ts.map +1 -1
- package/dist/components/overlay/Popover/Popover.js +84 -31
- package/dist/components/overlay/Popover/popover-utils.d.ts +32 -1
- package/dist/components/overlay/Popover/popover-utils.d.ts.map +1 -1
- package/dist/components/overlay/Popover/popover-utils.js +77 -22
- package/dist/components/overlay/modalOverlayStack.d.ts +8 -0
- package/dist/components/overlay/modalOverlayStack.d.ts.map +1 -0
- package/dist/components/overlay/modalOverlayStack.js +37 -0
- package/dist/components/overlay/useModalOverlay.d.ts +6 -14
- package/dist/components/overlay/useModalOverlay.d.ts.map +1 -1
- package/dist/components/overlay/useModalOverlay.js +8 -31
- package/dist/components/typography/textOverflow.css.d.ts.map +1 -1
- package/dist/hooks/useModalDialog/useModalDialog.d.ts +5 -0
- package/dist/hooks/useModalDialog/useModalDialog.d.ts.map +1 -1
- package/dist/hooks/useModalDialog/useModalDialog.js +3 -2
- package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.d.ts +5 -0
- package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.d.ts.map +1 -1
- package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.js +31 -16
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/testUtils/browser/contrast.d.ts +6 -2
- package/dist/testUtils/browser/contrast.d.ts.map +1 -1
- package/dist/testUtils/browser/emulateNoAnchorPositioning.d.ts +8 -0
- package/dist/testUtils/browser/emulateNoAnchorPositioning.d.ts.map +1 -0
- package/dist/testUtils/browser/render.d.ts +6 -2
- package/dist/testUtils/browser/render.d.ts.map +1 -1
- package/dist/testUtils/browser/screenshot.d.ts +2 -0
- package/dist/testUtils/browser/screenshot.d.ts.map +1 -0
- package/dist/testUtils/testTheme.css.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -17,7 +17,16 @@ export type PopoverProps = {
|
|
|
17
17
|
* @deprecated Use `placement`, which wins when both are passed
|
|
18
18
|
*/
|
|
19
19
|
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Has no effect, an open popover always keeps its layout up to
|
|
22
|
+
* date
|
|
23
|
+
*/
|
|
20
24
|
sticky?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Caps the popover's height to the room on the side it opens on, so a tall
|
|
27
|
+
* popover stops at the viewport's edge. Give it `overflow: auto` to scroll.
|
|
28
|
+
*/
|
|
29
|
+
limitHeight?: boolean;
|
|
21
30
|
} & HTMLElementProps<HTMLDivElement>;
|
|
22
31
|
export declare const Popover: React.FC<PopoverProps>;
|
|
23
32
|
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Popover/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Popover/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAIjC,MAAM,MAAM,YAAY,GAAG;IACzB,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACnD,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,IAAI,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CAEvB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAcrC,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAgO1C,CAAC"}
|
|
@@ -7,23 +7,33 @@ import { useComponentStyles } from "../../../hooks/useComponentStyles/useCompone
|
|
|
7
7
|
import { useIsomorphicLayoutEffect } from "../../../hooks/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js";
|
|
8
8
|
import { useKeyboard } from "../../../hooks/useKeyboard/useKeyboard.js";
|
|
9
9
|
import { Box } from "../../layout/Box/Box.js";
|
|
10
|
-
import {
|
|
10
|
+
import { getPopoverLayout } from "./popover-utils.js";
|
|
11
|
+
function toPx(value) {
|
|
12
|
+
return value === void 0 ? "" : `${value}px`;
|
|
13
|
+
}
|
|
14
|
+
function applyLayout(element, layout) {
|
|
15
|
+
element.style.left = toPx(layout.x);
|
|
16
|
+
element.style.top = toPx(layout.y);
|
|
17
|
+
element.style.maxWidth = toPx(layout.maxWidth);
|
|
18
|
+
element.style.maxHeight = toPx(layout.maxHeight);
|
|
19
|
+
}
|
|
11
20
|
const Popover = ({
|
|
12
21
|
anchorElement,
|
|
13
22
|
children,
|
|
14
23
|
className,
|
|
24
|
+
limitHeight = false,
|
|
15
25
|
onRequestClose,
|
|
16
26
|
open,
|
|
17
27
|
placement: placementProp,
|
|
18
28
|
position,
|
|
19
29
|
ref,
|
|
20
|
-
sticky,
|
|
30
|
+
sticky: _sticky,
|
|
21
31
|
style,
|
|
22
32
|
...restProps
|
|
23
33
|
}) => {
|
|
24
34
|
const placement = placementProp ?? position ?? "top";
|
|
25
35
|
const popoverRef = useRef(null);
|
|
26
|
-
const [
|
|
36
|
+
const [layout, setLayout] = useState({ x: 0, y: 0 });
|
|
27
37
|
const [visible, setVisible] = useState(open);
|
|
28
38
|
const popoverClassName = useComponentStyles("popover", { root: true }, false);
|
|
29
39
|
const onEscape = useCallback(
|
|
@@ -50,8 +60,14 @@ const Popover = ({
|
|
|
50
60
|
return;
|
|
51
61
|
}
|
|
52
62
|
element.showPopover();
|
|
53
|
-
const
|
|
54
|
-
|
|
63
|
+
const nextLayout = getPopoverLayout(
|
|
64
|
+
placement,
|
|
65
|
+
anchorElement,
|
|
66
|
+
popoverRef,
|
|
67
|
+
limitHeight
|
|
68
|
+
);
|
|
69
|
+
applyLayout(element, nextLayout);
|
|
70
|
+
setLayout(nextLayout);
|
|
55
71
|
} else if (open) {
|
|
56
72
|
setVisible(true);
|
|
57
73
|
} else {
|
|
@@ -71,36 +87,70 @@ const Popover = ({
|
|
|
71
87
|
}
|
|
72
88
|
}, [open, visible]);
|
|
73
89
|
useEffect(() => {
|
|
74
|
-
if (open) {
|
|
75
|
-
const [x, y] = getPopoverPosition(placement, anchorElement, popoverRef);
|
|
76
|
-
setPopoverPosition({ x, y });
|
|
77
|
-
}
|
|
78
|
-
}, [open, anchorElement, placement]);
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
if (!open || !sticky) {
|
|
90
|
+
if (!open || !visible) {
|
|
81
91
|
return;
|
|
82
92
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
93
|
+
let frame = 0;
|
|
94
|
+
function updateLayout() {
|
|
95
|
+
frame = 0;
|
|
96
|
+
if (!popoverRef.current) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const next = getPopoverLayout(
|
|
100
|
+
placement,
|
|
101
|
+
anchorElement,
|
|
102
|
+
popoverRef,
|
|
103
|
+
limitHeight
|
|
104
|
+
);
|
|
105
|
+
setLayout((prev) => {
|
|
106
|
+
if (prev.x === next.x && prev.y === next.y && prev.maxWidth === next.maxWidth && prev.maxHeight === next.maxHeight) {
|
|
87
107
|
return prev;
|
|
88
108
|
}
|
|
89
|
-
return
|
|
109
|
+
return next;
|
|
90
110
|
});
|
|
91
111
|
}
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
function scheduleLayoutUpdate() {
|
|
113
|
+
if (!frame) {
|
|
114
|
+
frame = requestAnimationFrame(updateLayout);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function onScroll(event) {
|
|
118
|
+
if (event.target instanceof Node && popoverRef.current?.contains(event.target)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
scheduleLayoutUpdate();
|
|
122
|
+
}
|
|
123
|
+
updateLayout();
|
|
124
|
+
const { visualViewport } = window;
|
|
125
|
+
const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(scheduleLayoutUpdate);
|
|
126
|
+
if (anchorElement.current) {
|
|
127
|
+
observer?.observe(anchorElement.current);
|
|
128
|
+
}
|
|
129
|
+
if (popoverRef.current) {
|
|
130
|
+
observer?.observe(popoverRef.current);
|
|
131
|
+
}
|
|
132
|
+
window.addEventListener("resize", scheduleLayoutUpdate);
|
|
133
|
+
document.addEventListener("scroll", onScroll, {
|
|
134
|
+
capture: true,
|
|
135
|
+
passive: true
|
|
136
|
+
});
|
|
137
|
+
visualViewport?.addEventListener("resize", scheduleLayoutUpdate);
|
|
94
138
|
return () => {
|
|
95
|
-
|
|
96
|
-
|
|
139
|
+
cancelAnimationFrame(frame);
|
|
140
|
+
observer?.disconnect();
|
|
141
|
+
window.removeEventListener("resize", scheduleLayoutUpdate);
|
|
142
|
+
document.removeEventListener("scroll", onScroll, { capture: true });
|
|
143
|
+
visualViewport?.removeEventListener("resize", scheduleLayoutUpdate);
|
|
97
144
|
};
|
|
98
|
-
}, [placement, anchorElement,
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
145
|
+
}, [open, visible, placement, anchorElement, limitHeight]);
|
|
146
|
+
const onClosingEnd = useCallback(
|
|
147
|
+
(event) => {
|
|
148
|
+
if (!open && event.target === event.currentTarget) {
|
|
149
|
+
setVisible(false);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
[open]
|
|
153
|
+
);
|
|
104
154
|
if (!visible) {
|
|
105
155
|
return null;
|
|
106
156
|
}
|
|
@@ -112,12 +162,15 @@ const Popover = ({
|
|
|
112
162
|
popover: "manual",
|
|
113
163
|
className: classnames(popoverClassName, className),
|
|
114
164
|
position: "absolute",
|
|
115
|
-
onAnimationEnd,
|
|
116
|
-
onTransitionEnd:
|
|
165
|
+
onAnimationEnd: onClosingEnd,
|
|
166
|
+
onTransitionEnd: onClosingEnd,
|
|
167
|
+
onTransitionCancel: onClosingEnd,
|
|
117
168
|
style: {
|
|
118
169
|
...style,
|
|
119
|
-
left:
|
|
120
|
-
top:
|
|
170
|
+
left: layout.x,
|
|
171
|
+
top: layout.y,
|
|
172
|
+
maxWidth: layout.maxWidth,
|
|
173
|
+
maxHeight: layout.maxHeight
|
|
121
174
|
},
|
|
122
175
|
...restProps,
|
|
123
176
|
children
|
|
@@ -35,6 +35,37 @@ export type ComputePopoverPositionOptions = {
|
|
|
35
35
|
* Returns the popover's `left` and `top`, relative to the document
|
|
36
36
|
*/
|
|
37
37
|
export declare function computePopoverPosition({ placement, anchor, popover, viewport, }: ComputePopoverPositionOptions): PopoverPositions;
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Returns the most height the popover's border box can take on the side it
|
|
40
|
+
* opens on, keeping it VIEWPORT_PADDING inside the viewport
|
|
41
|
+
*/
|
|
42
|
+
export declare function computeAvailableHeight({ placement, anchor, popover, viewport, }: ComputePopoverPositionOptions): number;
|
|
43
|
+
/**
|
|
44
|
+
* Returns the most width the popover's border box can take, keeping it
|
|
45
|
+
* VIEWPORT_PADDING inside the viewport on both sides
|
|
46
|
+
*/
|
|
47
|
+
export declare function computeAvailableWidth(viewport: ComputePopoverPositionOptions['viewport']): number;
|
|
48
|
+
export type PopoverLayout = {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
/**
|
|
52
|
+
* The popover's `max-width`: the viewport's width, VIEWPORT_PADDING inside
|
|
53
|
+
* both edges. It follows the popover's `box-sizing`, so padding and border
|
|
54
|
+
* fit too.
|
|
55
|
+
*/
|
|
56
|
+
maxWidth?: number;
|
|
57
|
+
/**
|
|
58
|
+
* The popover's `max-height`, when it is limited to the room it has. It
|
|
59
|
+
* follows the popover's `box-sizing`, so padding and border fit too.
|
|
60
|
+
*/
|
|
61
|
+
maxHeight?: number;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Measures the anchor and popover and returns where to put the popover. A
|
|
65
|
+
* popover wider than the viewport is capped to it, and placed by its capped
|
|
66
|
+
* width. With `limitHeight`, a popover taller than the room on its side is
|
|
67
|
+
* capped to that room, and placed by its capped height.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getPopoverLayout(placement: PopoverPlacement, anchorRef: React.RefObject<HTMLElement | null>, popoverRef: React.RefObject<HTMLElement | null>, limitHeight?: boolean): PopoverLayout;
|
|
39
70
|
export {};
|
|
40
71
|
//# sourceMappingURL=popover-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover-utils.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Popover/popover-utils.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAEtD,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAEvD,KAAK,WAAW,GAAG,OAAO,GAAG,KAAK,CAAC;AAEnC,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,GAAG,WAAW,IAAI,WAAW,EAAE,CAAC;AAE7E,KAAK,IAAI,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,KAAK,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,6BAA6B,GAAG;IAC1C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,wDAAwD;IACxD,MAAM,EAAE,IAAI,CAAC;IACb,kEAAkE;IAClE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,MAAM,EACN,OAAO,EACP,QAAQ,GACT,EAAE,6BAA6B,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"popover-utils.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Popover/popover-utils.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAEtD,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAEvD,KAAK,WAAW,GAAG,OAAO,GAAG,KAAK,CAAC;AAEnC,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,GAAG,WAAW,IAAI,WAAW,EAAE,CAAC;AAE7E,KAAK,IAAI,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,KAAK,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,6BAA6B,GAAG;IAC1C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,wDAAwD;IACxD,MAAM,EAAE,IAAI,CAAC;IACb,kEAAkE;IAClE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,MAAM,EACN,OAAO,EACP,QAAQ,GACT,EAAE,6BAA6B,GAAG,gBAAgB,CAgDlD;AA0CD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,MAAM,EACN,OAAO,EACP,QAAQ,GACT,EAAE,6BAA6B,GAAG,MAAM,CAgBxC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,6BAA6B,CAAC,UAAU,CAAC,GAClD,MAAM,CAER;AAyCD,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,gBAAgB,EAC3B,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAC9C,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAC/C,WAAW,UAAQ,GAClB,aAAa,CAyFf"}
|
|
@@ -11,7 +11,11 @@ function computePopoverPosition({
|
|
|
11
11
|
let left;
|
|
12
12
|
let top;
|
|
13
13
|
if (side === "top" || side === "bottom") {
|
|
14
|
-
top =
|
|
14
|
+
top = holdInViewport(
|
|
15
|
+
side === "top" ? anchor.top - margin.bottom - popover.height : anchor.top + anchor.height + margin.top,
|
|
16
|
+
popover.height,
|
|
17
|
+
viewport.height
|
|
18
|
+
);
|
|
15
19
|
left = alignOnCrossAxis(
|
|
16
20
|
edge,
|
|
17
21
|
anchor.left,
|
|
@@ -20,7 +24,11 @@ function computePopoverPosition({
|
|
|
20
24
|
viewport.width
|
|
21
25
|
);
|
|
22
26
|
} else {
|
|
23
|
-
left =
|
|
27
|
+
left = holdInViewport(
|
|
28
|
+
side === "left" ? anchor.left - margin.right - popover.width : anchor.left + anchor.width + margin.left,
|
|
29
|
+
popover.width,
|
|
30
|
+
viewport.width
|
|
31
|
+
);
|
|
24
32
|
top = alignOnCrossAxis(
|
|
25
33
|
edge,
|
|
26
34
|
anchor.top,
|
|
@@ -56,6 +64,25 @@ function flipSide(side, anchor, popover, viewport) {
|
|
|
56
64
|
}
|
|
57
65
|
return side;
|
|
58
66
|
}
|
|
67
|
+
function computeAvailableHeight({
|
|
68
|
+
placement,
|
|
69
|
+
anchor,
|
|
70
|
+
popover,
|
|
71
|
+
viewport
|
|
72
|
+
}) {
|
|
73
|
+
const [preferredSide] = placement.split("-");
|
|
74
|
+
const side = flipSide(preferredSide, anchor, popover, viewport);
|
|
75
|
+
let available = viewport.height - VIEWPORT_PADDING * 2;
|
|
76
|
+
if (side === "top") {
|
|
77
|
+
available = anchor.top - popover.margin.bottom - VIEWPORT_PADDING;
|
|
78
|
+
} else if (side === "bottom") {
|
|
79
|
+
available = viewport.height - VIEWPORT_PADDING - (anchor.top + anchor.height) - popover.margin.top;
|
|
80
|
+
}
|
|
81
|
+
return Math.max(0, available);
|
|
82
|
+
}
|
|
83
|
+
function computeAvailableWidth(viewport) {
|
|
84
|
+
return Math.max(0, viewport.width - VIEWPORT_PADDING * 2);
|
|
85
|
+
}
|
|
59
86
|
function alignOnCrossAxis(edge, anchorStart, anchorSize, popoverSize, viewportSize) {
|
|
60
87
|
let start = anchorStart + (anchorSize - popoverSize) / 2;
|
|
61
88
|
if (edge === "start") {
|
|
@@ -63,46 +90,74 @@ function alignOnCrossAxis(edge, anchorStart, anchorSize, popoverSize, viewportSi
|
|
|
63
90
|
} else if (edge === "end") {
|
|
64
91
|
start = anchorStart + anchorSize - popoverSize;
|
|
65
92
|
}
|
|
93
|
+
return holdInViewport(start, popoverSize, viewportSize);
|
|
94
|
+
}
|
|
95
|
+
function holdInViewport(start, popoverSize, viewportSize) {
|
|
66
96
|
const max = viewportSize - VIEWPORT_PADDING - popoverSize;
|
|
67
97
|
return Math.max(VIEWPORT_PADDING, Math.min(start, max));
|
|
68
98
|
}
|
|
69
|
-
function
|
|
99
|
+
function getPopoverLayout(placement, anchorRef, popoverRef, limitHeight = false) {
|
|
70
100
|
if (!anchorRef.current || !popoverRef.current) {
|
|
71
|
-
return
|
|
101
|
+
return { x: 0, y: 0 };
|
|
72
102
|
}
|
|
103
|
+
const element = popoverRef.current;
|
|
73
104
|
const anchorRect = anchorRef.current.getBoundingClientRect();
|
|
74
|
-
const popoverRect =
|
|
75
|
-
const popoverStyles = getComputedStyle(
|
|
76
|
-
const [
|
|
105
|
+
const popoverRect = element.getBoundingClientRect();
|
|
106
|
+
const popoverStyles = getComputedStyle(element);
|
|
107
|
+
const [measuredWidth, measuredHeight] = getOriginalElementSize(
|
|
77
108
|
popoverStyles,
|
|
78
109
|
popoverRect.width,
|
|
79
110
|
popoverRect.height
|
|
80
111
|
);
|
|
112
|
+
const style = (property) => cssValueToNumber(popoverStyles.getPropertyValue(property));
|
|
113
|
+
const borderY = style("border-top-width") + style("border-bottom-width");
|
|
114
|
+
const isContentBox = popoverStyles.boxSizing === "content-box";
|
|
115
|
+
const height = limitHeight ? Math.max(measuredHeight, element.scrollHeight + borderY) : measuredHeight;
|
|
81
116
|
const { documentElement } = document;
|
|
82
|
-
|
|
117
|
+
const viewport = {
|
|
118
|
+
width: documentElement.clientWidth,
|
|
119
|
+
height: documentElement.clientHeight,
|
|
120
|
+
scrollX: documentElement.scrollLeft,
|
|
121
|
+
scrollY: documentElement.scrollTop
|
|
122
|
+
};
|
|
123
|
+
const availableWidth = computeAvailableWidth(viewport);
|
|
124
|
+
const options = {
|
|
83
125
|
placement,
|
|
84
126
|
anchor: anchorRect,
|
|
85
127
|
popover: {
|
|
86
|
-
width,
|
|
128
|
+
width: Math.min(measuredWidth, availableWidth),
|
|
87
129
|
height,
|
|
88
130
|
margin: {
|
|
89
|
-
top:
|
|
90
|
-
right:
|
|
91
|
-
bottom:
|
|
92
|
-
|
|
93
|
-
),
|
|
94
|
-
left: cssValueToNumber(popoverStyles.getPropertyValue("margin-left"))
|
|
131
|
+
top: style("margin-top"),
|
|
132
|
+
right: style("margin-right"),
|
|
133
|
+
bottom: style("margin-bottom"),
|
|
134
|
+
left: style("margin-left")
|
|
95
135
|
}
|
|
96
136
|
},
|
|
97
|
-
viewport
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
137
|
+
viewport
|
|
138
|
+
};
|
|
139
|
+
const paddingAndBorderX = isContentBox ? style("padding-left") + style("padding-right") + style("border-left-width") + style("border-right-width") : 0;
|
|
140
|
+
const maxWidth = Math.max(0, availableWidth - paddingAndBorderX);
|
|
141
|
+
if (!limitHeight) {
|
|
142
|
+
const [x2, y2] = computePopoverPosition(options);
|
|
143
|
+
return { x: x2, y: y2, maxWidth };
|
|
144
|
+
}
|
|
145
|
+
const availableHeight = computeAvailableHeight(options);
|
|
146
|
+
const [x, y] = computePopoverPosition({
|
|
147
|
+
...options,
|
|
148
|
+
popover: { ...options.popover, height: Math.min(height, availableHeight) }
|
|
103
149
|
});
|
|
150
|
+
const paddingAndBorderY = isContentBox ? style("padding-top") + style("padding-bottom") + borderY : 0;
|
|
151
|
+
return {
|
|
152
|
+
x,
|
|
153
|
+
y,
|
|
154
|
+
maxWidth,
|
|
155
|
+
maxHeight: Math.max(0, availableHeight - paddingAndBorderY)
|
|
156
|
+
};
|
|
104
157
|
}
|
|
105
158
|
export {
|
|
159
|
+
computeAvailableHeight,
|
|
160
|
+
computeAvailableWidth,
|
|
106
161
|
computePopoverPosition,
|
|
107
|
-
|
|
162
|
+
getPopoverLayout
|
|
108
163
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Puts a modal overlay on the stack of open ones while `open` is true, and
|
|
3
|
+
* returns whether it is the top one: the one opened last, wherever it is
|
|
4
|
+
* mounted. Like the browser's top layer, which shows each modal dialog above
|
|
5
|
+
* the ones shown before it, the order does not follow the React tree.
|
|
6
|
+
*/
|
|
7
|
+
export declare const useIsTopModalOverlay: (open: boolean) => boolean;
|
|
8
|
+
//# sourceMappingURL=modalOverlayStack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modalOverlayStack.d.ts","sourceRoot":"","sources":["../../../src/components/overlay/modalOverlayStack.ts"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,OAAO,KAAG,OAoBpD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useSyncExternalStore } from "react";
|
|
3
|
+
import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js";
|
|
4
|
+
let stack = [];
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
const setStack = (next) => {
|
|
7
|
+
stack = next;
|
|
8
|
+
for (const listener of listeners) {
|
|
9
|
+
listener();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const subscribe = (listener) => {
|
|
13
|
+
listeners.add(listener);
|
|
14
|
+
return () => {
|
|
15
|
+
listeners.delete(listener);
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const useIsTopModalOverlay = (open) => {
|
|
19
|
+
const [token] = useState(() => ({}));
|
|
20
|
+
useIsomorphicLayoutEffect(() => {
|
|
21
|
+
if (!open) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
setStack([...stack, token]);
|
|
25
|
+
return () => {
|
|
26
|
+
setStack(stack.filter((item) => item !== token));
|
|
27
|
+
};
|
|
28
|
+
}, [open, token]);
|
|
29
|
+
return useSyncExternalStore(
|
|
30
|
+
subscribe,
|
|
31
|
+
() => stack.at(-1) === token,
|
|
32
|
+
() => false
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
useIsTopModalOverlay
|
|
37
|
+
};
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { RequestCloseReason } from './requestCloseReason.js';
|
|
2
|
-
type DialogContextValue = {
|
|
3
|
-
setEnabled: (active: boolean) => void;
|
|
4
|
-
};
|
|
5
|
-
export declare const DialogContext: import('react').Context<DialogContextValue | undefined>;
|
|
6
|
-
export declare const useNestedDialog: (open: boolean) => boolean;
|
|
7
2
|
type UseDialogCloseRequestsOptions = {
|
|
8
3
|
enabled: boolean;
|
|
9
4
|
onRequestClose: (reason: RequestCloseReason) => void;
|
|
@@ -19,17 +14,14 @@ type UseModalOverlayOptions = Omit<UseDialogCloseRequestsOptions, 'enabled'> & {
|
|
|
19
14
|
* closed, the body does not scroll, and an Escape, close request or click
|
|
20
15
|
* outside requests to close.
|
|
21
16
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
17
|
+
* Only the modal overlay opened last handles Escape and clicks outside, so a
|
|
18
|
+
* click in a Dialog or Drawer does not close the ones below it, whether it is
|
|
19
|
+
* nested in them or mounted elsewhere.
|
|
25
20
|
*/
|
|
26
21
|
export declare const useModalOverlay: (dialogRef: React.RefObject<HTMLDialogElement | null>, { open, onRequestClose, ...handlers }: UseModalOverlayOptions) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
onKeyDownCapture: (event: React.KeyboardEvent<HTMLDialogElement>) => void;
|
|
31
|
-
onCancel: (event: React.SyntheticEvent<HTMLDialogElement>) => void;
|
|
32
|
-
};
|
|
22
|
+
onKeyDown: (event: React.KeyboardEvent<HTMLDialogElement>) => void;
|
|
23
|
+
onKeyDownCapture: (event: React.KeyboardEvent<HTMLDialogElement>) => void;
|
|
24
|
+
onCancel: (event: React.SyntheticEvent<HTMLDialogElement>) => void;
|
|
33
25
|
};
|
|
34
26
|
export {};
|
|
35
27
|
//# sourceMappingURL=useModalOverlay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModalOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/overlay/useModalOverlay.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useModalOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/overlay/useModalOverlay.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;IAC1D,gBAAgB,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;IACjE,QAAQ,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;CACvD,CAAC;AA6EF,KAAK,sBAAsB,GAAG,IAAI,CAAC,6BAA6B,EAAE,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAC1B,WAAW,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,EACpD,uCAAuC,sBAAsB;uBA/D/B,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC;8BAR3D,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC;sBA2BlB,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC;CA2DrE,CAAC"}
|
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { useRef } from "react";
|
|
3
3
|
import { useClickOutside } from "../../hooks/useClickOutside/useClickOutside.js";
|
|
4
4
|
import { usePreventBodyScroll } from "../../hooks/usePreventBodyScroll/usePreventBodyScroll.js";
|
|
5
5
|
import { useRestoreFocus } from "../../hooks/useRestoreFocus/useRestoreFocus.js";
|
|
6
|
-
|
|
7
|
-
void 0
|
|
8
|
-
);
|
|
9
|
-
const useNestedDialog = (open) => {
|
|
10
|
-
const parentDialog = useContext(DialogContext);
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
if (!parentDialog || !open) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
parentDialog.setEnabled(false);
|
|
16
|
-
return () => {
|
|
17
|
-
parentDialog.setEnabled(true);
|
|
18
|
-
};
|
|
19
|
-
}, [parentDialog, open]);
|
|
20
|
-
return !!parentDialog;
|
|
21
|
-
};
|
|
6
|
+
import { useIsTopModalOverlay } from "./modalOverlayStack.js";
|
|
22
7
|
const useDialogCloseRequests = ({
|
|
23
8
|
enabled,
|
|
24
9
|
onRequestClose,
|
|
@@ -63,23 +48,15 @@ const useDialogCloseRequests = ({
|
|
|
63
48
|
};
|
|
64
49
|
};
|
|
65
50
|
const useModalOverlay = (dialogRef, { open, onRequestClose, ...handlers }) => {
|
|
66
|
-
const [enabled, setEnabled] = useState(true);
|
|
67
|
-
const [contextValue] = useState(() => ({ setEnabled }));
|
|
68
51
|
useRestoreFocus(open);
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
usePreventBodyScroll(open);
|
|
53
|
+
const isTop = useIsTopModalOverlay(open);
|
|
54
|
+
const enabled = open && isTop;
|
|
71
55
|
useClickOutside(dialogRef, () => onRequestClose("outside-click"), {
|
|
72
|
-
enabled
|
|
73
|
-
});
|
|
74
|
-
const closeRequestProps = useDialogCloseRequests({
|
|
75
|
-
enabled: open && enabled,
|
|
76
|
-
onRequestClose,
|
|
77
|
-
...handlers
|
|
56
|
+
enabled
|
|
78
57
|
});
|
|
79
|
-
return {
|
|
58
|
+
return useDialogCloseRequests({ enabled, onRequestClose, ...handlers });
|
|
80
59
|
};
|
|
81
60
|
export {
|
|
82
|
-
|
|
83
|
-
useModalOverlay,
|
|
84
|
-
useNestedDialog
|
|
61
|
+
useModalOverlay
|
|
85
62
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textOverflow.css.d.ts","sourceRoot":"","sources":["../../../src/components/typography/textOverflow.css.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"textOverflow.css.d.ts","sourceRoot":"","sources":["../../../src/components/typography/textOverflow.css.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,SAAS,mCAYrB,CAAC;AAEF,eAAO,MAAM,QAAQ,QASnB,CAAC"}
|
|
@@ -5,9 +5,14 @@
|
|
|
5
5
|
* The dialog also closes whenever the effect is cleaned up while open, such as
|
|
6
6
|
* when React hides it in an <Activity> or unmounts it, so it never lingers in
|
|
7
7
|
* the top layer. Revealing it again shows it as modal.
|
|
8
|
+
*
|
|
9
|
+
* Render `openAttribute` as the dialog's `open` attribute. It is `open` on the
|
|
10
|
+
* first render, so a server-rendered open dialog hydrates without a mismatch,
|
|
11
|
+
* and never changes after it, so React leaves the attribute to this hook.
|
|
8
12
|
*/
|
|
9
13
|
export declare const useModalDialog: (dialogRef: React.RefObject<HTMLDialogElement | null>, open: boolean) => {
|
|
10
14
|
visible: boolean;
|
|
11
15
|
onAnimationEnd: () => void;
|
|
16
|
+
openAttribute: boolean;
|
|
12
17
|
};
|
|
13
18
|
//# sourceMappingURL=useModalDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModalDialog.d.ts","sourceRoot":"","sources":["../../../src/hooks/useModalDialog/useModalDialog.ts"],"names":[],"mappings":"AAOA
|
|
1
|
+
{"version":3,"file":"useModalDialog.d.ts","sourceRoot":"","sources":["../../../src/hooks/useModalDialog/useModalDialog.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GACzB,WAAW,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,EACpD,MAAM,OAAO;;;;CAiDd,CAAC"}
|
|
@@ -4,6 +4,7 @@ import { useState, useCallback } from "react";
|
|
|
4
4
|
import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.js";
|
|
5
5
|
const useModalDialog = (dialogRef, open) => {
|
|
6
6
|
const [visible, setVisible] = useState(open);
|
|
7
|
+
const [openAttribute] = useState(open);
|
|
7
8
|
useIsomorphicLayoutEffect(() => {
|
|
8
9
|
const dialog = dialogRef.current;
|
|
9
10
|
if (open && visible) {
|
|
@@ -11,7 +12,7 @@ const useModalDialog = (dialogRef, open) => {
|
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
13
14
|
if (dialog.open) {
|
|
14
|
-
dialog.
|
|
15
|
+
dialog.removeAttribute("open");
|
|
15
16
|
}
|
|
16
17
|
dialog.showModal();
|
|
17
18
|
return () => {
|
|
@@ -32,7 +33,7 @@ const useModalDialog = (dialogRef, open) => {
|
|
|
32
33
|
setVisible(false);
|
|
33
34
|
}
|
|
34
35
|
}, [open]);
|
|
35
|
-
return { visible, onAnimationEnd };
|
|
36
|
+
return { visible, onAnimationEnd, openAttribute };
|
|
36
37
|
};
|
|
37
38
|
export {
|
|
38
39
|
useModalDialog
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prevents the body from scrolling while enabled. Any number of callers can
|
|
3
|
+
* be enabled at once: the first locks the body, and the body's styles and
|
|
4
|
+
* scroll position are restored once the last one is disabled or unmounts.
|
|
5
|
+
*/
|
|
1
6
|
export declare const usePreventBodyScroll: (enabled?: boolean) => void;
|
|
2
7
|
//# sourceMappingURL=usePreventBodyScroll.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePreventBodyScroll.d.ts","sourceRoot":"","sources":["../../../src/hooks/usePreventBodyScroll/usePreventBodyScroll.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"usePreventBodyScroll.d.ts","sourceRoot":"","sources":["../../../src/hooks/usePreventBodyScroll/usePreventBodyScroll.ts"],"names":[],"mappings":"AAuCA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,iBAAc,SAqBlD,CAAC"}
|