@stackone/malachite 2.23.3 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +7 -7
- package/dist/components/ActionMenu.js +103 -87
- package/dist/components/ActionMenu.js.map +1 -1
- package/dist/components/AppLogo.js.map +1 -1
- package/dist/components/Dropdown.js +374 -360
- package/dist/components/Dropdown.js.map +1 -1
- package/dist/components/MultiSelect.js +295 -284
- package/dist/components/MultiSelect.js.map +1 -1
- package/dist/components/Search.js +17 -14
- package/dist/components/Search.js.map +1 -1
- package/dist/components/Tabs.js +52 -31
- package/dist/components/Tabs.js.map +1 -1
- package/dist/components/Toolbar.js +47 -14
- package/dist/components/Toolbar.js.map +1 -1
- package/dist/components/Tooltip.js +55 -55
- package/dist/components/Tooltip.js.map +1 -1
- package/dist/components/Typography/EllipsisText.js +32 -17
- package/dist/components/Typography/EllipsisText.js.map +1 -1
- package/dist/components/controlWidth.js +5 -0
- package/dist/components/controlWidth.js.map +1 -0
- package/dist/components/floatingMenuGeometry.js +71 -0
- package/dist/components/floatingMenuGeometry.js.map +1 -0
- package/dist/components/portalOverlay.js +25 -23
- package/dist/components/portalOverlay.js.map +1 -1
- package/dist/components/queryInputGeometry.js +6 -6
- package/dist/components/queryInputGeometry.js.map +1 -1
- package/dist/index.d.ts +52 -3
- package/dist/index.js +360 -356
- package/package.json +1 -1
- package/dist/components/dropdownPanelPosition.js +0 -38
- package/dist/components/dropdownPanelPosition.js.map +0 -1
|
@@ -1,25 +1,58 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
const
|
|
1
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
2
|
+
const p = 200, _ = 160, d = 200, i = 260, x = 8, I = {
|
|
3
3
|
none: "",
|
|
4
4
|
compact: "px-[12px] py-[8px]",
|
|
5
5
|
default: "px-[16px] py-[12px]"
|
|
6
|
-
},
|
|
7
|
-
children:
|
|
8
|
-
|
|
6
|
+
}, T = ({
|
|
7
|
+
children: l,
|
|
8
|
+
minWidth: e = d,
|
|
9
|
+
className: o = "",
|
|
10
|
+
style: t
|
|
11
|
+
}) => /* @__PURE__ */ s(
|
|
12
|
+
"div",
|
|
13
|
+
{
|
|
14
|
+
className: o,
|
|
15
|
+
style: { flex: `100 1 ${i}px`, minWidth: e, ...t },
|
|
16
|
+
children: l
|
|
17
|
+
}
|
|
18
|
+
), f = ({
|
|
19
|
+
children: l,
|
|
20
|
+
width: e = p,
|
|
21
|
+
minWidth: o = _,
|
|
22
|
+
grow: t = !0,
|
|
23
|
+
className: a = "",
|
|
24
|
+
style: r
|
|
25
|
+
}) => /* @__PURE__ */ s("div", { className: a, style: { flex: `${t ? 1 : 0} 1 ${e}px`, minWidth: o, ...r }, children: l }), c = ({
|
|
26
|
+
children: l,
|
|
27
|
+
divider: e = !1,
|
|
9
28
|
padding: o = "default",
|
|
10
|
-
|
|
11
|
-
|
|
29
|
+
layout: t = "plain",
|
|
30
|
+
className: a = "",
|
|
31
|
+
style: r
|
|
12
32
|
}) => {
|
|
13
|
-
const
|
|
33
|
+
const n = [
|
|
14
34
|
"w-full bg-[var(--malachite-card-background)]",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
35
|
+
I[o],
|
|
36
|
+
e ? "border-0 border-b border-solid border-[var(--malachite-card-border)]" : "",
|
|
37
|
+
a
|
|
18
38
|
].filter(Boolean).join(" ");
|
|
19
|
-
return /* @__PURE__ */
|
|
39
|
+
return /* @__PURE__ */ s("div", { className: n, style: { ...t === "filters" ? {
|
|
40
|
+
display: "flex",
|
|
41
|
+
alignItems: "center",
|
|
42
|
+
flexWrap: "wrap",
|
|
43
|
+
gap: x
|
|
44
|
+
} : {}, ...r }, children: l });
|
|
20
45
|
};
|
|
46
|
+
c.Fill = T;
|
|
47
|
+
c.Item = f;
|
|
21
48
|
export {
|
|
22
|
-
|
|
23
|
-
|
|
49
|
+
i as TOOLBAR_FILL_BASIS_PX,
|
|
50
|
+
d as TOOLBAR_FILL_MIN_WIDTH_PX,
|
|
51
|
+
_ as TOOLBAR_FILTER_MIN_WIDTH_PX,
|
|
52
|
+
p as TOOLBAR_FILTER_WIDTH_PX,
|
|
53
|
+
c as Toolbar,
|
|
54
|
+
T as ToolbarFill,
|
|
55
|
+
f as ToolbarItem,
|
|
56
|
+
c as default
|
|
24
57
|
};
|
|
25
58
|
//# sourceMappingURL=Toolbar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.js","sources":["../../src/components/Toolbar.tsx"],"sourcesContent":["import React from 'react';\n\nexport interface ToolbarProps {\n children?: React.ReactNode;\n /** Draw a bottom divider — for a bar that sits above scrolling/list content. */\n divider?: boolean;\n /** Padding preset (applies to both axes). `none` for a bar that must sit flush with\n * the content it pins over — the consumer then owns the gutter. */\n padding?: 'none' | 'compact' | 'default';\n className?: string;\n style?: React.CSSProperties;\n}\n\
|
|
1
|
+
{"version":3,"file":"Toolbar.js","sources":["../../src/components/Toolbar.tsx"],"sourcesContent":["import React from 'react';\n\nexport const TOOLBAR_FILTER_WIDTH_PX = 200;\n\nexport const TOOLBAR_FILTER_MIN_WIDTH_PX = 160;\n\nexport const TOOLBAR_FILL_MIN_WIDTH_PX = 200;\n\nexport const TOOLBAR_FILL_BASIS_PX = 260;\n\nconst TOOLBAR_GAP_PX = 8;\n\nexport interface ToolbarProps {\n children?: React.ReactNode;\n /** Draw a bottom divider — for a bar that sits above scrolling/list content. */\n divider?: boolean;\n /** Padding preset (applies to both axes). `none` for a bar that must sit flush with\n * the content it pins over — the consumer then owns the gutter. */\n padding?: 'none' | 'compact' | 'default';\n layout?: 'plain' | 'filters';\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface ToolbarFillProps {\n children?: React.ReactNode;\n minWidth?: number;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface ToolbarItemProps {\n children?: React.ReactNode;\n width?: number;\n minWidth?: number;\n grow?: boolean;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst PADDING_CLASSES: Record<NonNullable<ToolbarProps['padding']>, string> = {\n none: '',\n compact: 'px-[12px] py-[8px]',\n default: 'px-[16px] py-[12px]',\n};\n\nconst ToolbarFill: React.FC<ToolbarFillProps> = ({\n children,\n minWidth = TOOLBAR_FILL_MIN_WIDTH_PX,\n className = '',\n style,\n}) => (\n <div\n className={className}\n style={{ flex: `100 1 ${TOOLBAR_FILL_BASIS_PX}px`, minWidth, ...style }}\n >\n {children}\n </div>\n);\n\nconst ToolbarItem: React.FC<ToolbarItemProps> = ({\n children,\n width = TOOLBAR_FILTER_WIDTH_PX,\n minWidth = TOOLBAR_FILTER_MIN_WIDTH_PX,\n grow = true,\n className = '',\n style,\n}) => (\n <div className={className} style={{ flex: `${grow ? 1 : 0} 1 ${width}px`, minWidth, ...style }}>\n {children}\n </div>\n);\n\ninterface ToolbarComponent extends React.FC<ToolbarProps> {\n Fill: typeof ToolbarFill;\n Item: typeof ToolbarItem;\n}\n\nconst Toolbar = (({\n children,\n divider = false,\n padding = 'default',\n layout = 'plain',\n className = '',\n style,\n}) => {\n const classes = [\n 'w-full bg-[var(--malachite-card-background)]',\n PADDING_CLASSES[padding],\n divider ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const layoutStyle: React.CSSProperties =\n layout === 'filters'\n ? {\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: TOOLBAR_GAP_PX,\n }\n : {};\n\n return (\n <div className={classes} style={{ ...layoutStyle, ...style }}>\n {children}\n </div>\n );\n}) as ToolbarComponent;\n\nToolbar.Fill = ToolbarFill;\nToolbar.Item = ToolbarItem;\n\nexport default Toolbar;\nexport { Toolbar, ToolbarFill, ToolbarItem };\n"],"names":["TOOLBAR_FILTER_WIDTH_PX","TOOLBAR_FILTER_MIN_WIDTH_PX","TOOLBAR_FILL_MIN_WIDTH_PX","TOOLBAR_FILL_BASIS_PX","TOOLBAR_GAP_PX","PADDING_CLASSES","ToolbarFill","children","minWidth","className","style","jsx","ToolbarItem","width","grow","Toolbar","divider","padding","layout","classes"],"mappings":";AAEO,MAAMA,IAA0B,KAE1BC,IAA8B,KAE9BC,IAA4B,KAE5BC,IAAwB,KAE/BC,IAAiB,GA8BjBC,IAAwE;AAAA,EAC1E,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AACb,GAEMC,IAA0C,CAAC;AAAA,EAC7C,UAAAC;AAAA,EACA,UAAAC,IAAWN;AAAA,EACX,WAAAO,IAAY;AAAA,EACZ,OAAAC;AACJ,MACI,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,WAAAF;AAAA,IACA,OAAO,EAAE,MAAM,SAASN,CAAqB,MAAM,UAAAK,GAAU,GAAGE,EAAA;AAAA,IAE/D,UAAAH;AAAA,EAAA;AACL,GAGEK,IAA0C,CAAC;AAAA,EAC7C,UAAAL;AAAA,EACA,OAAAM,IAAQb;AAAA,EACR,UAAAQ,IAAWP;AAAA,EACX,MAAAa,IAAO;AAAA,EACP,WAAAL,IAAY;AAAA,EACZ,OAAAC;AACJ,wBACK,OAAA,EAAI,WAAAD,GAAsB,OAAO,EAAE,MAAM,GAAGK,IAAO,IAAI,CAAC,MAAMD,CAAK,MAAM,UAAAL,GAAU,GAAGE,EAAA,GAClF,UAAAH,EAAA,CACL,GAQEQ,IAAW,CAAC;AAAA,EACd,UAAAR;AAAA,EACA,SAAAS,IAAU;AAAA,EACV,SAAAC,IAAU;AAAA,EACV,QAAAC,IAAS;AAAA,EACT,WAAAT,IAAY;AAAA,EACZ,OAAAC;AACJ,MAAM;AACF,QAAMS,IAAU;AAAA,IACZ;AAAA,IACAd,EAAgBY,CAAO;AAAA,IACvBD,IAAU,yEAAyE;AAAA,IACnFP;AAAA,EAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAYb,SACI,gBAAAE,EAAC,OAAA,EAAI,WAAWQ,GAAS,OAAO,EAAE,GAVlCD,MAAW,YACL;AAAA,IACI,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,KAAKd;AAAA,EAAA,IAET,CAAA,GAG4C,GAAGM,EAAA,GAChD,UAAAH,EAAA,CACL;AAER;AAEAQ,EAAQ,OAAOT;AACfS,EAAQ,OAAOH;"}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import { jsx as l, jsxs as
|
|
2
|
-
import
|
|
3
|
-
import { createPortal as
|
|
4
|
-
import { ensureOverlayStyles as
|
|
5
|
-
import { useTopLayer as
|
|
6
|
-
const
|
|
1
|
+
import { jsx as l, jsxs as V, Fragment as X } from "react/jsx-runtime";
|
|
2
|
+
import E, { useState as x, useRef as p, useCallback as D, useId as J, useEffect as P, useInsertionEffect as Q } from "react";
|
|
3
|
+
import { createPortal as Z } from "react-dom";
|
|
4
|
+
import { ensureOverlayStyles as ee, overlayIdentity as te } from "./portalOverlay.js";
|
|
5
|
+
import { useTopLayer as ne } from "./topLayer.js";
|
|
6
|
+
const re = new RegExp("(?<=[/\\\\.\\-_?&#=:@])"), oe = (n) => n.split(re).map((i, f) => /* @__PURE__ */ V(E.Fragment, { children: [
|
|
7
7
|
i,
|
|
8
8
|
/* @__PURE__ */ l("wbr", {})
|
|
9
|
-
] }, f)),
|
|
9
|
+
] }, f)), ie = {
|
|
10
10
|
minWidth: 0,
|
|
11
11
|
overflow: "hidden"
|
|
12
|
-
},
|
|
12
|
+
}, $ = {
|
|
13
13
|
flex: 1,
|
|
14
14
|
minWidth: 0
|
|
15
|
-
},
|
|
15
|
+
}, C = 8, pe = ({
|
|
16
16
|
text: n,
|
|
17
17
|
children: i,
|
|
18
18
|
delay: f = 1,
|
|
19
|
-
wrapChildren:
|
|
20
|
-
triggerAs:
|
|
21
|
-
placement:
|
|
22
|
-
isShrinkable:
|
|
19
|
+
wrapChildren: H = !1,
|
|
20
|
+
triggerAs: j = "div",
|
|
21
|
+
placement: k = "top",
|
|
22
|
+
isShrinkable: R = !1,
|
|
23
23
|
maxWidth: m = "320px",
|
|
24
|
-
fill:
|
|
24
|
+
fill: h = !1,
|
|
25
25
|
shouldShow: c,
|
|
26
26
|
describesTrigger: L = !0
|
|
27
27
|
}) => {
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const z = R || h ? { ...R ? ie : {}, ...h ? $ : {} } : void 0, [t, g] = x(!1), [d, N] = x(!1), u = p(null), r = p(null), o = D(() => {
|
|
29
|
+
u.current && (clearTimeout(u.current), u.current = null), r.current !== null && (cancelAnimationFrame(r.current), r.current = null);
|
|
30
30
|
}, []), T = () => {
|
|
31
|
-
|
|
32
|
-
r.current = null,
|
|
31
|
+
N(!0), r.current !== null && cancelAnimationFrame(r.current), r.current = requestAnimationFrame(() => {
|
|
32
|
+
r.current = null, g(!0);
|
|
33
33
|
});
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
const F =
|
|
37
|
-
e.stopPropagation(), !(!s || c && !c()) && (o(),
|
|
34
|
+
}, v = p(null), y = p(null);
|
|
35
|
+
ne(v, t);
|
|
36
|
+
const F = J(), s = n != null && n !== "" && n !== !1, O = (e) => {
|
|
37
|
+
e.stopPropagation(), !(!s || c && !c()) && (o(), u.current = setTimeout(() => {
|
|
38
38
|
T();
|
|
39
39
|
}, f * 1e3));
|
|
40
|
-
},
|
|
41
|
-
e.stopPropagation(), o(),
|
|
42
|
-
}, Y = () => {
|
|
43
|
-
!s || c && !c() || (o(), T());
|
|
40
|
+
}, Y = (e) => {
|
|
41
|
+
e.stopPropagation(), o(), g(!1);
|
|
44
42
|
}, U = () => {
|
|
45
|
-
o(),
|
|
46
|
-
},
|
|
43
|
+
!s || c && !c() || (o(), T());
|
|
44
|
+
}, q = () => {
|
|
45
|
+
o(), g(!1);
|
|
46
|
+
}, [, I] = x({});
|
|
47
47
|
P(() => {
|
|
48
48
|
if (!t)
|
|
49
49
|
return () => {
|
|
@@ -58,10 +58,10 @@ const ne = new RegExp("(?<=[/\\\\.\\-_?&#=:@])"), re = (n) => n.split(ne).map((i
|
|
|
58
58
|
}, [t, o]), P(() => {
|
|
59
59
|
t && I({});
|
|
60
60
|
}, [t]);
|
|
61
|
-
const
|
|
62
|
-
if (!
|
|
61
|
+
const G = () => {
|
|
62
|
+
if (!y.current)
|
|
63
63
|
return { display: "none" };
|
|
64
|
-
const e =
|
|
64
|
+
const e = y.current.getBoundingClientRect(), a = {
|
|
65
65
|
position: "fixed",
|
|
66
66
|
display: "flex",
|
|
67
67
|
width: "max-content",
|
|
@@ -85,13 +85,13 @@ const ne = new RegExp("(?<=[/\\\\.\\-_?&#=:@])"), re = (n) => n.split(ne).map((i
|
|
|
85
85
|
transition: "opacity 150ms ease-in-out, transform 150ms ease-in-out, visibility 150ms ease-in-out"
|
|
86
86
|
}, b = () => {
|
|
87
87
|
var _;
|
|
88
|
-
const
|
|
88
|
+
const w = e.left + e.width / 2, A = ((_ = v.current) == null ? void 0 : _.getBoundingClientRect().width) ?? 0;
|
|
89
89
|
if (A === 0)
|
|
90
|
-
return
|
|
91
|
-
const B = A / 2, M =
|
|
92
|
-
return M > W ?
|
|
90
|
+
return w;
|
|
91
|
+
const B = A / 2, M = C + B, W = window.innerWidth - C - B;
|
|
92
|
+
return M > W ? w : Math.min(Math.max(w, M), W);
|
|
93
93
|
};
|
|
94
|
-
switch (
|
|
94
|
+
switch (k) {
|
|
95
95
|
case "top":
|
|
96
96
|
return {
|
|
97
97
|
...a,
|
|
@@ -128,37 +128,37 @@ const ne = new RegExp("(?<=[/\\\\.\\-_?&#=:@])"), re = (n) => n.split(ne).map((i
|
|
|
128
128
|
transform: `translate(-50%, -100%) ${t ? "scale(1)" : "scale(0.95)"}`
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
}, S = s &&
|
|
132
|
-
|
|
133
|
-
s &&
|
|
134
|
-
}, [s,
|
|
135
|
-
const
|
|
131
|
+
}, S = s && d && L ? F : void 0;
|
|
132
|
+
Q(() => {
|
|
133
|
+
s && d && ee();
|
|
134
|
+
}, [s, d]);
|
|
135
|
+
const K = H || !E.isValidElement(i) ? /* @__PURE__ */ l("span", { "aria-describedby": S, style: h ? $ : void 0, children: i }) : E.cloneElement(i, {
|
|
136
136
|
"aria-describedby": [i.props["aria-describedby"], S].filter(Boolean).join(" ") || void 0
|
|
137
137
|
});
|
|
138
|
-
return /* @__PURE__ */
|
|
138
|
+
return /* @__PURE__ */ V(X, { children: [
|
|
139
139
|
/* @__PURE__ */ l(
|
|
140
|
-
|
|
140
|
+
j,
|
|
141
141
|
{
|
|
142
|
-
ref:
|
|
142
|
+
ref: y,
|
|
143
143
|
className: "relative flex items-center",
|
|
144
|
-
style:
|
|
145
|
-
onMouseEnter:
|
|
146
|
-
onMouseLeave:
|
|
147
|
-
onFocus:
|
|
148
|
-
onBlur:
|
|
149
|
-
children:
|
|
144
|
+
style: z,
|
|
145
|
+
onMouseEnter: O,
|
|
146
|
+
onMouseLeave: Y,
|
|
147
|
+
onFocus: U,
|
|
148
|
+
onBlur: q,
|
|
149
|
+
children: K
|
|
150
150
|
}
|
|
151
151
|
),
|
|
152
|
-
s &&
|
|
152
|
+
s && d && Z(
|
|
153
153
|
/* @__PURE__ */ l(
|
|
154
154
|
"div",
|
|
155
155
|
{
|
|
156
|
-
ref:
|
|
156
|
+
ref: v,
|
|
157
157
|
id: F,
|
|
158
158
|
role: "tooltip",
|
|
159
159
|
"aria-hidden": L ? void 0 : !0,
|
|
160
|
-
...
|
|
161
|
-
style:
|
|
160
|
+
...te("tooltip"),
|
|
161
|
+
style: G(),
|
|
162
162
|
children: /* @__PURE__ */ l(
|
|
163
163
|
"span",
|
|
164
164
|
{
|
|
@@ -166,7 +166,7 @@ const ne = new RegExp("(?<=[/\\\\.\\-_?&#=:@])"), re = (n) => n.split(ne).map((i
|
|
|
166
166
|
minWidth: 0,
|
|
167
167
|
overflowWrap: "anywhere"
|
|
168
168
|
},
|
|
169
|
-
children: typeof n == "string" ?
|
|
169
|
+
children: typeof n == "string" ? oe(n) : n
|
|
170
170
|
}
|
|
171
171
|
)
|
|
172
172
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.js","sources":["../../src/components/Tooltip.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useId, useInsertionEffect, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ensureOverlayStyles, overlayIdentity } from './portalOverlay';\nimport { useTopLayer } from './topLayer';\n\n// Split after each delimiter so long values (URLs, dotted paths) wrap at \"/\" or \".\"\n// instead of mid-token. <wbr> is copy-safe (a zero-width space would corrupt a copied\n// URL); overflow-wrap still handles a single run too long to fit.\nconst WRAP_AFTER = /(?<=[/\\\\.\\-_?&#=:@])/;\nconst withBreakOpportunities = (value: string): React.ReactNode =>\n value.split(WRAP_AFTER).map((chunk, i) => (\n <React.Fragment key={i}>\n {chunk}\n <wbr />\n </React.Fragment>\n ));\n\ninterface TooltipProps {\n text: React.ReactNode | string;\n children: React.ReactNode;\n delay?: number;\n wrapChildren?: boolean;\n placement?: 'top' | 'bottom' | 'left' | 'right';\n isShrinkable?: boolean;\n fill?: boolean;\n /** Max width of tooltip. Default: 320px */\n maxWidth?: number | string;\n /** Called synchronously when the trigger is hovered/focused; return false to\n * suppress the tooltip for this interaction. Lets wrappers defer expensive\n * checks (e.g. truncation measurement) to interaction time instead of mount. */\n shouldShow?: () => boolean;\n triggerAs?: 'div' | 'span';\n /** Whether the tooltip acts as the trigger's accessible description. False where the\n * trigger already points at the same sentence on screen, so it is not announced twice. */\n describesTrigger?: boolean;\n}\n\nconst SHRINKABLE_STYLE: React.CSSProperties = {\n minWidth: 0,\n overflow: 'hidden',\n};\n\nconst FILL_STYLE: React.CSSProperties = {\n flex: 1,\n minWidth: 0,\n};\n\n/** Kept clear of the viewport edge so a clamped tooltip does not sit flush against it. */\nconst VIEWPORT_MARGIN = 8;\n\nconst Tooltip: React.FC<TooltipProps> = ({\n text,\n children,\n delay = 1,\n wrapChildren = false,\n triggerAs = 'div',\n placement = 'top',\n isShrinkable = false,\n maxWidth = '320px',\n fill = false,\n shouldShow,\n describesTrigger = true,\n}) => {\n const triggerStyle =\n isShrinkable || fill\n ? { ...(isShrinkable ? SHRINKABLE_STYLE : {}), ...(fill ? FILL_STYLE : {}) }\n : undefined;\n\n const [isVisible, setIsVisible] = useState(false);\n // Portal mounts on first show, not on mount: an at-rest tooltip otherwise\n // costs a hidden document.body node plus a getBoundingClientRect per render —\n // multiplied by every row in a large table.\n const [hasShown, setHasShown] = useState(false);\n const timeoutRef = useRef<NodeJS.Timeout | null>(null);\n const showFrameRef = useRef<number | null>(null);\n\n const cancelPendingShow = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n if (showFrameRef.current !== null) {\n cancelAnimationFrame(showFrameRef.current);\n showFrameRef.current = null;\n }\n }, []);\n\n const scheduleVisible = () => {\n // Two steps so the portal mounts hidden first and the fade-in transition\n // still runs on the very first show. The frame is tracked so leave/blur/\n // unmount can cancel a show that is already past its delay.\n setHasShown(true);\n if (showFrameRef.current !== null) {\n cancelAnimationFrame(showFrameRef.current);\n }\n showFrameRef.current = requestAnimationFrame(() => {\n showFrameRef.current = null;\n setIsVisible(true);\n });\n };\n const tooltipRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n\n // Tied to visibility, not mount: the node is latched into the DOM after its first show, and\n // re-entering on each show keeps a tooltip above the panel it is annotating.\n useTopLayer(tooltipRef, isVisible);\n\n const tooltipId = useId();\n\n const hasText = text !== null && text !== undefined && text !== '' && text !== false;\n\n const handleMouseEnter = (e: React.MouseEvent) => {\n e.stopPropagation();\n\n if (!hasText || (shouldShow && !shouldShow())) {\n return;\n }\n\n cancelPendingShow();\n\n timeoutRef.current = setTimeout(() => {\n scheduleVisible();\n }, delay * 1000);\n };\n\n const handleMouseLeave = (e: React.MouseEvent) => {\n e.stopPropagation();\n\n cancelPendingShow();\n setIsVisible(false);\n };\n\n const handleFocus = () => {\n if (!hasText || (shouldShow && !shouldShow())) {\n return;\n }\n\n cancelPendingShow();\n scheduleVisible();\n };\n\n const handleBlur = () => {\n cancelPendingShow();\n setIsVisible(false);\n };\n\n const [, forceUpdate] = useState({});\n\n useEffect(() => {\n // Only a VISIBLE tooltip needs to track scroll/resize; keeping global\n // listeners per mounted instance made every scroll event fan out across\n // every tooltip on the page.\n if (!isVisible) {\n return () => {\n cancelPendingShow();\n };\n }\n const handleUpdate = () => {\n forceUpdate({});\n };\n\n window.addEventListener('scroll', handleUpdate, true);\n window.addEventListener('resize', handleUpdate);\n\n return () => {\n cancelPendingShow();\n window.removeEventListener('scroll', handleUpdate, true);\n window.removeEventListener('resize', handleUpdate);\n };\n }, [isVisible, cancelPendingShow]);\n\n // The first render that mounts the tooltip has no measured width yet, so the clamp below\n // cannot run on it. One extra pass once it is in the DOM gives the clamp its measurement\n // — before the opacity transition finishes, so nothing is seen sliding into place.\n useEffect(() => {\n if (isVisible) {\n forceUpdate({});\n }\n }, [isVisible]);\n\n const getTooltipStyles = (): React.CSSProperties => {\n if (!triggerRef.current) {\n return { display: 'none' };\n }\n\n const rect = triggerRef.current.getBoundingClientRect();\n\n const baseStyles: React.CSSProperties = {\n position: 'fixed',\n display: 'flex',\n width: 'max-content',\n maxWidth: typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth,\n minWidth: '32px',\n minHeight: '32px',\n padding: '8px 12px',\n alignItems: 'center',\n gap: '8px',\n borderRadius: '12px',\n backgroundColor: 'var(--malachite-tooltip-background, rgb(59, 59, 59))',\n color: 'var(--malachite-tooltip-foreground, rgb(255, 255, 255))',\n boxShadow: 'var(--malachite-tooltip-shadow, 0px 0px 10px 0px rgba(0, 0, 0, 0.20))',\n fontSize: '14px',\n lineHeight: '1.4',\n whiteSpace: 'normal',\n textAlign: 'left',\n pointerEvents: 'none',\n opacity: isVisible ? 1 : 0,\n visibility: isVisible ? 'visible' : 'hidden',\n transition:\n 'opacity 150ms ease-in-out, transform 150ms ease-in-out, visibility 150ms ease-in-out',\n };\n\n // A trigger near the viewport edge would otherwise centre a wide tooltip half off\n // screen, where the panel or the window crops it. Clamping the CENTRE keeps the\n // `translateX(-50%)` placement honest: the box stays put, it just stops short.\n const centeredLeft = (): number => {\n const desired = rect.left + rect.width / 2;\n const width = tooltipRef.current?.getBoundingClientRect().width ?? 0;\n\n if (width === 0) {\n return desired;\n }\n\n const half = width / 2;\n const min = VIEWPORT_MARGIN + half;\n const max = window.innerWidth - VIEWPORT_MARGIN - half;\n\n // A tooltip wider than the viewport has no in-bounds centre; leave it centred\n // rather than pinning it to a nonsensical one.\n return min > max ? desired : Math.min(Math.max(desired, min), max);\n };\n\n switch (placement) {\n case 'top':\n return {\n ...baseStyles,\n top: rect.top - 8,\n left: centeredLeft(),\n transform: `translate(-50%, -100%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n case 'bottom':\n return {\n ...baseStyles,\n top: rect.bottom + 8,\n left: centeredLeft(),\n transform: `translateX(-50%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n case 'left':\n return {\n ...baseStyles,\n top: rect.top + rect.height / 2,\n left: rect.left - 8,\n transform: `translate(-100%, -50%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n case 'right':\n return {\n ...baseStyles,\n top: rect.top + rect.height / 2,\n left: rect.right + 8,\n transform: `translateY(-50%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n default:\n return {\n ...baseStyles,\n top: rect.top - 8,\n left: centeredLeft(),\n transform: `translate(-50%, -100%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n }\n };\n\n // Only reference the tooltip id once the portal can exist — a dangling\n // aria-describedby (text set, never shown) confuses assistive tech.\n const describedBy = hasText && hasShown && describesTrigger ? tooltipId : undefined;\n useInsertionEffect(() => {\n if (hasText && hasShown) {\n ensureOverlayStyles();\n }\n }, [hasText, hasShown]);\n const renderedChildren =\n wrapChildren || !React.isValidElement(children) ? (\n <span aria-describedby={describedBy}>{children}</span>\n ) : (\n React.cloneElement(children as React.ReactElement, {\n 'aria-describedby':\n [(children as React.ReactElement).props['aria-describedby'], describedBy]\n .filter(Boolean)\n .join(' ') || undefined,\n })\n );\n\n const Trigger = triggerAs;\n\n // Create the tooltip content without its own shadow root\n return (\n <>\n <Trigger\n ref={triggerRef}\n className=\"relative flex items-center\"\n style={triggerStyle}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n {renderedChildren}\n </Trigger>\n\n {hasText &&\n hasShown &&\n createPortal(\n <div\n ref={tooltipRef}\n id={tooltipId}\n role=\"tooltip\"\n // Nothing references it, and the sentence is already on screen and\n // described: left in the tree it is a second copy to read past.\n aria-hidden={describesTrigger ? undefined : true}\n {...overlayIdentity('tooltip')}\n style={getTooltipStyles()}\n >\n {/* min-w-0 + overflow-wrap let long values wrap within maxWidth. */}\n <span\n style={{\n minWidth: 0,\n overflowWrap: 'anywhere',\n }}\n >\n {typeof text === 'string' ? withBreakOpportunities(text) : text}\n </span>\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nexport default Tooltip;\n"],"names":["WRAP_AFTER","withBreakOpportunities","value","chunk","i","jsxs","React","SHRINKABLE_STYLE","FILL_STYLE","VIEWPORT_MARGIN","Tooltip","text","children","delay","wrapChildren","triggerAs","placement","isShrinkable","maxWidth","fill","shouldShow","describesTrigger","triggerStyle","isVisible","setIsVisible","useState","hasShown","setHasShown","timeoutRef","useRef","showFrameRef","cancelPendingShow","useCallback","scheduleVisible","tooltipRef","triggerRef","useTopLayer","tooltipId","useId","hasText","handleMouseEnter","handleMouseLeave","handleFocus","handleBlur","forceUpdate","useEffect","handleUpdate","getTooltipStyles","rect","baseStyles","centeredLeft","desired","width","_a","half","min","max","describedBy","useInsertionEffect","ensureOverlayStyles","renderedChildren","jsx","Fragment","createPortal","overlayIdentity"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Tooltip.js","sources":["../../src/components/Tooltip.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useId, useInsertionEffect, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ensureOverlayStyles, overlayIdentity } from './portalOverlay';\nimport { useTopLayer } from './topLayer';\n\n// Split after each delimiter so long values (URLs, dotted paths) wrap at \"/\" or \".\"\n// instead of mid-token. <wbr> is copy-safe (a zero-width space would corrupt a copied\n// URL); overflow-wrap still handles a single run too long to fit.\nconst WRAP_AFTER = /(?<=[/\\\\.\\-_?&#=:@])/;\nconst withBreakOpportunities = (value: string): React.ReactNode =>\n value.split(WRAP_AFTER).map((chunk, i) => (\n <React.Fragment key={i}>\n {chunk}\n <wbr />\n </React.Fragment>\n ));\n\ninterface TooltipProps {\n text: React.ReactNode | string;\n children: React.ReactNode;\n delay?: number;\n wrapChildren?: boolean;\n placement?: 'top' | 'bottom' | 'left' | 'right';\n isShrinkable?: boolean;\n fill?: boolean;\n /** Max width of tooltip. Default: 320px */\n maxWidth?: number | string;\n /** Called synchronously when the trigger is hovered/focused; return false to\n * suppress the tooltip for this interaction. Lets wrappers defer expensive\n * checks (e.g. truncation measurement) to interaction time instead of mount. */\n shouldShow?: () => boolean;\n triggerAs?: 'div' | 'span';\n /** Whether the tooltip acts as the trigger's accessible description. False where the\n * trigger already points at the same sentence on screen, so it is not announced twice. */\n describesTrigger?: boolean;\n}\n\nconst SHRINKABLE_STYLE: React.CSSProperties = {\n minWidth: 0,\n overflow: 'hidden',\n};\n\nconst FILL_STYLE: React.CSSProperties = {\n flex: 1,\n minWidth: 0,\n};\n\n/** Kept clear of the viewport edge so a clamped tooltip does not sit flush against it. */\nconst VIEWPORT_MARGIN = 8;\n\nconst Tooltip: React.FC<TooltipProps> = ({\n text,\n children,\n delay = 1,\n wrapChildren = false,\n triggerAs = 'div',\n placement = 'top',\n isShrinkable = false,\n maxWidth = '320px',\n fill = false,\n shouldShow,\n describesTrigger = true,\n}) => {\n const triggerStyle =\n isShrinkable || fill\n ? { ...(isShrinkable ? SHRINKABLE_STYLE : {}), ...(fill ? FILL_STYLE : {}) }\n : undefined;\n\n const [isVisible, setIsVisible] = useState(false);\n // Portal mounts on first show, not on mount: an at-rest tooltip otherwise\n // costs a hidden document.body node plus a getBoundingClientRect per render —\n // multiplied by every row in a large table.\n const [hasShown, setHasShown] = useState(false);\n const timeoutRef = useRef<NodeJS.Timeout | null>(null);\n const showFrameRef = useRef<number | null>(null);\n\n const cancelPendingShow = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n if (showFrameRef.current !== null) {\n cancelAnimationFrame(showFrameRef.current);\n showFrameRef.current = null;\n }\n }, []);\n\n const scheduleVisible = () => {\n // Two steps so the portal mounts hidden first and the fade-in transition\n // still runs on the very first show. The frame is tracked so leave/blur/\n // unmount can cancel a show that is already past its delay.\n setHasShown(true);\n if (showFrameRef.current !== null) {\n cancelAnimationFrame(showFrameRef.current);\n }\n showFrameRef.current = requestAnimationFrame(() => {\n showFrameRef.current = null;\n setIsVisible(true);\n });\n };\n const tooltipRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n\n // Tied to visibility, not mount: the node is latched into the DOM after its first show, and\n // re-entering on each show keeps a tooltip above the panel it is annotating.\n useTopLayer(tooltipRef, isVisible);\n\n const tooltipId = useId();\n\n const hasText = text !== null && text !== undefined && text !== '' && text !== false;\n\n const handleMouseEnter = (e: React.MouseEvent) => {\n e.stopPropagation();\n\n if (!hasText || (shouldShow && !shouldShow())) {\n return;\n }\n\n cancelPendingShow();\n\n timeoutRef.current = setTimeout(() => {\n scheduleVisible();\n }, delay * 1000);\n };\n\n const handleMouseLeave = (e: React.MouseEvent) => {\n e.stopPropagation();\n\n cancelPendingShow();\n setIsVisible(false);\n };\n\n const handleFocus = () => {\n if (!hasText || (shouldShow && !shouldShow())) {\n return;\n }\n\n cancelPendingShow();\n scheduleVisible();\n };\n\n const handleBlur = () => {\n cancelPendingShow();\n setIsVisible(false);\n };\n\n const [, forceUpdate] = useState({});\n\n useEffect(() => {\n // Only a VISIBLE tooltip needs to track scroll/resize; keeping global\n // listeners per mounted instance made every scroll event fan out across\n // every tooltip on the page.\n if (!isVisible) {\n return () => {\n cancelPendingShow();\n };\n }\n const handleUpdate = () => {\n forceUpdate({});\n };\n\n window.addEventListener('scroll', handleUpdate, true);\n window.addEventListener('resize', handleUpdate);\n\n return () => {\n cancelPendingShow();\n window.removeEventListener('scroll', handleUpdate, true);\n window.removeEventListener('resize', handleUpdate);\n };\n }, [isVisible, cancelPendingShow]);\n\n // The first render that mounts the tooltip has no measured width yet, so the clamp below\n // cannot run on it. One extra pass once it is in the DOM gives the clamp its measurement\n // — before the opacity transition finishes, so nothing is seen sliding into place.\n useEffect(() => {\n if (isVisible) {\n forceUpdate({});\n }\n }, [isVisible]);\n\n const getTooltipStyles = (): React.CSSProperties => {\n if (!triggerRef.current) {\n return { display: 'none' };\n }\n\n const rect = triggerRef.current.getBoundingClientRect();\n\n const baseStyles: React.CSSProperties = {\n position: 'fixed',\n display: 'flex',\n width: 'max-content',\n maxWidth: typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth,\n minWidth: '32px',\n minHeight: '32px',\n padding: '8px 12px',\n alignItems: 'center',\n gap: '8px',\n borderRadius: '12px',\n backgroundColor: 'var(--malachite-tooltip-background, rgb(59, 59, 59))',\n color: 'var(--malachite-tooltip-foreground, rgb(255, 255, 255))',\n boxShadow: 'var(--malachite-tooltip-shadow, 0px 0px 10px 0px rgba(0, 0, 0, 0.20))',\n fontSize: '14px',\n lineHeight: '1.4',\n whiteSpace: 'normal',\n textAlign: 'left',\n pointerEvents: 'none',\n opacity: isVisible ? 1 : 0,\n visibility: isVisible ? 'visible' : 'hidden',\n transition:\n 'opacity 150ms ease-in-out, transform 150ms ease-in-out, visibility 150ms ease-in-out',\n };\n\n // A trigger near the viewport edge would otherwise centre a wide tooltip half off\n // screen, where the panel or the window crops it. Clamping the CENTRE keeps the\n // `translateX(-50%)` placement honest: the box stays put, it just stops short.\n const centeredLeft = (): number => {\n const desired = rect.left + rect.width / 2;\n const width = tooltipRef.current?.getBoundingClientRect().width ?? 0;\n\n if (width === 0) {\n return desired;\n }\n\n const half = width / 2;\n const min = VIEWPORT_MARGIN + half;\n const max = window.innerWidth - VIEWPORT_MARGIN - half;\n\n // A tooltip wider than the viewport has no in-bounds centre; leave it centred\n // rather than pinning it to a nonsensical one.\n return min > max ? desired : Math.min(Math.max(desired, min), max);\n };\n\n switch (placement) {\n case 'top':\n return {\n ...baseStyles,\n top: rect.top - 8,\n left: centeredLeft(),\n transform: `translate(-50%, -100%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n case 'bottom':\n return {\n ...baseStyles,\n top: rect.bottom + 8,\n left: centeredLeft(),\n transform: `translateX(-50%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n case 'left':\n return {\n ...baseStyles,\n top: rect.top + rect.height / 2,\n left: rect.left - 8,\n transform: `translate(-100%, -50%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n case 'right':\n return {\n ...baseStyles,\n top: rect.top + rect.height / 2,\n left: rect.right + 8,\n transform: `translateY(-50%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n default:\n return {\n ...baseStyles,\n top: rect.top - 8,\n left: centeredLeft(),\n transform: `translate(-50%, -100%) ${isVisible ? 'scale(1)' : 'scale(0.95)'}`,\n };\n }\n };\n\n // Only reference the tooltip id once the portal can exist — a dangling\n // aria-describedby (text set, never shown) confuses assistive tech.\n const describedBy = hasText && hasShown && describesTrigger ? tooltipId : undefined;\n useInsertionEffect(() => {\n if (hasText && hasShown) {\n ensureOverlayStyles();\n }\n }, [hasText, hasShown]);\n const renderedChildren =\n wrapChildren || !React.isValidElement(children) ? (\n <span aria-describedby={describedBy} style={fill ? FILL_STYLE : undefined}>\n {children}\n </span>\n ) : (\n React.cloneElement(children as React.ReactElement, {\n 'aria-describedby':\n [(children as React.ReactElement).props['aria-describedby'], describedBy]\n .filter(Boolean)\n .join(' ') || undefined,\n })\n );\n\n const Trigger = triggerAs;\n\n // Create the tooltip content without its own shadow root\n return (\n <>\n <Trigger\n ref={triggerRef}\n className=\"relative flex items-center\"\n style={triggerStyle}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n {renderedChildren}\n </Trigger>\n\n {hasText &&\n hasShown &&\n createPortal(\n <div\n ref={tooltipRef}\n id={tooltipId}\n role=\"tooltip\"\n // Nothing references it, and the sentence is already on screen and\n // described: left in the tree it is a second copy to read past.\n aria-hidden={describesTrigger ? undefined : true}\n {...overlayIdentity('tooltip')}\n style={getTooltipStyles()}\n >\n {/* min-w-0 + overflow-wrap let long values wrap within maxWidth. */}\n <span\n style={{\n minWidth: 0,\n overflowWrap: 'anywhere',\n }}\n >\n {typeof text === 'string' ? withBreakOpportunities(text) : text}\n </span>\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nexport default Tooltip;\n"],"names":["WRAP_AFTER","withBreakOpportunities","value","chunk","i","jsxs","React","SHRINKABLE_STYLE","FILL_STYLE","VIEWPORT_MARGIN","Tooltip","text","children","delay","wrapChildren","triggerAs","placement","isShrinkable","maxWidth","fill","shouldShow","describesTrigger","triggerStyle","isVisible","setIsVisible","useState","hasShown","setHasShown","timeoutRef","useRef","showFrameRef","cancelPendingShow","useCallback","scheduleVisible","tooltipRef","triggerRef","useTopLayer","tooltipId","useId","hasText","handleMouseEnter","handleMouseLeave","handleFocus","handleBlur","forceUpdate","useEffect","handleUpdate","getTooltipStyles","rect","baseStyles","centeredLeft","desired","width","_a","half","min","max","describedBy","useInsertionEffect","ensureOverlayStyles","renderedChildren","jsx","Fragment","createPortal","overlayIdentity"],"mappings":"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"}
|
|
@@ -1,27 +1,42 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as m } from "react";
|
|
3
|
+
import u from "../Tooltip.js";
|
|
4
|
+
import { getFontSize as h, getTextColor as x } from "./textStyles.js";
|
|
5
|
+
const g = ({
|
|
6
|
+
children: n,
|
|
7
|
+
tooltip: t,
|
|
8
|
+
maxWidth: s = "100%",
|
|
9
|
+
color: p = "primary",
|
|
10
|
+
size: o,
|
|
11
|
+
tooltipWhenTruncated: c = !1,
|
|
12
|
+
className: f = "",
|
|
13
|
+
style: a = {}
|
|
11
14
|
}) => {
|
|
12
|
-
const
|
|
13
|
-
color:
|
|
14
|
-
|
|
15
|
+
const d = {
|
|
16
|
+
color: x(p),
|
|
17
|
+
...o ? { fontSize: h(o) } : {},
|
|
18
|
+
maxWidth: s,
|
|
15
19
|
overflow: "hidden",
|
|
16
20
|
whiteSpace: "nowrap",
|
|
17
21
|
textOverflow: "ellipsis",
|
|
18
22
|
display: "inline-block",
|
|
19
23
|
verticalAlign: "top",
|
|
20
|
-
...
|
|
21
|
-
},
|
|
22
|
-
return
|
|
24
|
+
...a
|
|
25
|
+
}, r = m(null), l = /* @__PURE__ */ i("span", { ref: r, className: f, style: d, children: n });
|
|
26
|
+
return t ? /* @__PURE__ */ i(
|
|
27
|
+
u,
|
|
28
|
+
{
|
|
29
|
+
text: t,
|
|
30
|
+
isShrinkable: !0,
|
|
31
|
+
shouldShow: c ? () => {
|
|
32
|
+
const e = r.current;
|
|
33
|
+
return !!e && e.scrollWidth > e.clientWidth;
|
|
34
|
+
} : void 0,
|
|
35
|
+
children: l
|
|
36
|
+
}
|
|
37
|
+
) : l;
|
|
23
38
|
};
|
|
24
39
|
export {
|
|
25
|
-
|
|
40
|
+
g as default
|
|
26
41
|
};
|
|
27
42
|
//# sourceMappingURL=EllipsisText.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EllipsisText.js","sources":["../../../src/components/Typography/EllipsisText.tsx"],"sourcesContent":["import React from 'react';\nimport Tooltip from '../Tooltip';\nimport type { TextColor } from './Text';\nimport { getTextColor } from './textStyles';\n\nexport interface EllipsisTextProps {\n children: React.ReactNode;\n tooltip?: React.ReactNode | string;\n /**\n * Defaults to filling the container. Pass a fixed width only when the text should\n * truncate before its container runs out of room (e.g. a column with a hard cap).\n */\n maxWidth?: string;\n color?: TextColor;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst EllipsisText: React.FC<EllipsisTextProps> = ({\n children,\n tooltip,\n maxWidth = '100%',\n color = 'primary',\n className = '',\n style = {},\n}) => {\n const ellipsisStyles: React.CSSProperties = {\n color: getTextColor(color),\n maxWidth,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n display: 'inline-block',\n verticalAlign: 'top',\n ...style,\n };\n\n const textElement = (\n <span className={className} style={ellipsisStyles}>\n {children}\n </span>\n );\n\n if (tooltip) {\n // Without `isShrinkable` the tooltip wrapper is floored at min-content and a percentage `maxWidth` never truncates.\n return (\n <Tooltip
|
|
1
|
+
{"version":3,"file":"EllipsisText.js","sources":["../../../src/components/Typography/EllipsisText.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport Tooltip from '../Tooltip';\nimport type { TextColor } from './Text';\nimport type { FontSize } from './textStyles';\nimport { getFontSize, getTextColor } from './textStyles';\n\nexport interface EllipsisTextProps {\n children: React.ReactNode;\n tooltip?: React.ReactNode | string;\n /**\n * Defaults to filling the container. Pass a fixed width only when the text should\n * truncate before its container runs out of room (e.g. a column with a hard cap).\n */\n maxWidth?: string;\n color?: TextColor;\n size?: FontSize;\n /**\n * Show `tooltip` only when the text is actually cut off. Opt-in, because `tooltip` is any\n * node: a caller repeating the label wants this, and one supplying something the label does\n * not say — a full path, a timestamp — would lose it.\n */\n tooltipWhenTruncated?: boolean;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst EllipsisText: React.FC<EllipsisTextProps> = ({\n children,\n tooltip,\n maxWidth = '100%',\n color = 'primary',\n size,\n tooltipWhenTruncated = false,\n className = '',\n style = {},\n}) => {\n const ellipsisStyles: React.CSSProperties = {\n color: getTextColor(color),\n ...(size ? { fontSize: getFontSize(size) } : {}),\n maxWidth,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n display: 'inline-block',\n verticalAlign: 'top',\n ...style,\n };\n\n const textRef = useRef<HTMLSpanElement>(null);\n\n const textElement = (\n <span ref={textRef} className={className} style={ellipsisStyles}>\n {children}\n </span>\n );\n\n if (tooltip) {\n // Measured on hover, not at mount: what fits depends on the container and on webfonts\n // that land after `DOMContentLoaded`, so a value read once is wrong for the rest of the\n // page's life.\n // Without `isShrinkable` the tooltip wrapper is floored at min-content and a percentage `maxWidth` never truncates.\n return (\n <Tooltip\n text={tooltip}\n isShrinkable\n shouldShow={\n tooltipWhenTruncated\n ? () => {\n const node = textRef.current;\n return !!node && node.scrollWidth > node.clientWidth;\n }\n : undefined\n }\n >\n {textElement}\n </Tooltip>\n );\n }\n\n return textElement;\n};\n\nexport default EllipsisText;\n"],"names":["EllipsisText","children","tooltip","maxWidth","color","size","tooltipWhenTruncated","className","style","ellipsisStyles","getTextColor","getFontSize","textRef","useRef","textElement","jsx","Tooltip","node"],"mappings":";;;;AA0BA,MAAMA,IAA4C,CAAC;AAAA,EAC/C,UAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,OAAAC,IAAQ;AAAA,EACR,MAAAC;AAAA,EACA,sBAAAC,IAAuB;AAAA,EACvB,WAAAC,IAAY;AAAA,EACZ,OAAAC,IAAQ,CAAA;AACZ,MAAM;AACF,QAAMC,IAAsC;AAAA,IACxC,OAAOC,EAAaN,CAAK;AAAA,IACzB,GAAIC,IAAO,EAAE,UAAUM,EAAYN,CAAI,EAAA,IAAM,CAAA;AAAA,IAC7C,UAAAF;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,SAAS;AAAA,IACT,eAAe;AAAA,IACf,GAAGK;AAAA,EAAA,GAGDI,IAAUC,EAAwB,IAAI,GAEtCC,sBACD,QAAA,EAAK,KAAKF,GAAS,WAAAL,GAAsB,OAAOE,GAC5C,UAAAR,GACL;AAGJ,SAAIC,IAMI,gBAAAa;AAAA,IAACC;AAAA,IAAA;AAAA,MACG,MAAMd;AAAA,MACN,cAAY;AAAA,MACZ,YACII,IACM,MAAM;AACF,cAAMW,IAAOL,EAAQ;AACrB,eAAO,CAAC,CAACK,KAAQA,EAAK,cAAcA,EAAK;AAAA,MAC7C,IACA;AAAA,MAGT,UAAAH;AAAA,IAAA;AAAA,EAAA,IAKNA;AACX;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlWidth.js","sources":["../../src/components/controlWidth.ts"],"sourcesContent":["import type React from 'react';\n\nexport type ControlWidth = string | number;\n\n// `'auto'` is `MultiSelect`'s default and means \"no width asked for\", so it is passed over\n// rather than clamped: `max-width: 100%` on a control nobody sized is a change to every one\n// of them, and `width: auto` is the block default anyway.\nexport const controlWidthStyle = (width?: ControlWidth): React.CSSProperties | undefined =>\n width === undefined || width === 'auto'\n ? undefined\n : { width: typeof width === 'number' ? `${width}px` : width, maxWidth: '100%' };\n"],"names":["controlWidthStyle","width"],"mappings":"AAOO,MAAMA,IAAoB,CAACC,MAC9BA,MAAU,UAAaA,MAAU,SAC3B,SACA,EAAE,OAAO,OAAOA,KAAU,WAAW,GAAGA,CAAK,OAAOA,GAAO,UAAU,OAAA;"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const U = 8, X = 160, O = 180, D = {
|
|
2
|
+
standard: {
|
|
3
|
+
width: "trigger",
|
|
4
|
+
minWidth: 160,
|
|
5
|
+
align: "left",
|
|
6
|
+
gap: 10,
|
|
7
|
+
radius: 12,
|
|
8
|
+
padding: 4,
|
|
9
|
+
shadow: "0px 2px 5px 0px rgba(0, 0, 0, 0.1)",
|
|
10
|
+
background: "var(--malachite-card-background, rgb(255, 255, 255))",
|
|
11
|
+
border: "1px solid var(--malachite-card-border, rgb(232, 232, 232))"
|
|
12
|
+
},
|
|
13
|
+
options: {
|
|
14
|
+
width: "content",
|
|
15
|
+
minWidth: 180,
|
|
16
|
+
maxWidth: 280,
|
|
17
|
+
align: "right",
|
|
18
|
+
gap: 14,
|
|
19
|
+
radius: 10,
|
|
20
|
+
padding: 8,
|
|
21
|
+
shadow: "0px 4px 10px 0px rgba(0, 0, 0, 0.1)",
|
|
22
|
+
background: "var(--malachite-card-background, rgb(255, 255, 255))",
|
|
23
|
+
border: "1px solid var(--malachite-card-border, rgb(232, 232, 232))"
|
|
24
|
+
}
|
|
25
|
+
}, T = 400, M = ({
|
|
26
|
+
triggerRect: t,
|
|
27
|
+
preset: a,
|
|
28
|
+
minWidth: o,
|
|
29
|
+
contentWidth: s,
|
|
30
|
+
menuHeight: i,
|
|
31
|
+
viewportWidth: r,
|
|
32
|
+
viewportHeight: e
|
|
33
|
+
}) => {
|
|
34
|
+
const n = D[a], l = r - 16, g = Math.max(n.minWidth, o ?? 0), p = Math.min(l, Math.max(n.maxWidth ?? l, g)), u = n.width === "trigger" ? t.width : s ?? p, h = Math.max(0, Math.min(Math.max(u, g), p)), c = n.align === "right" ? t.right - h : t.left, P = n.align === "right" ? t.left : t.right - h, N = 8, f = r - h - 8, I = (E) => E >= N && E <= f;
|
|
35
|
+
let d;
|
|
36
|
+
I(c) ? d = c : I(P) ? d = P : d = Math.max(N, Math.min(c, f));
|
|
37
|
+
const m = e - t.bottom - n.gap - 8, x = t.top - n.gap - 8, _ = i > 0 && i > m && x > m, b = Math.max(0, Math.min(T, _ ? x : m)), W = i > 0 ? Math.min(i, b) : 0;
|
|
38
|
+
return { top: Math.max(
|
|
39
|
+
8,
|
|
40
|
+
_ ? t.top - n.gap - W : t.bottom + n.gap
|
|
41
|
+
), left: d, width: h, maxHeight: b, openUp: _ };
|
|
42
|
+
}, A = (t) => {
|
|
43
|
+
if (!t || t.style.width !== "")
|
|
44
|
+
return;
|
|
45
|
+
const a = t.querySelectorAll('button, [role="menuitem"]');
|
|
46
|
+
let o = 0;
|
|
47
|
+
if (a.forEach((e) => {
|
|
48
|
+
o = Math.max(o, e.scrollWidth);
|
|
49
|
+
}), o === 0)
|
|
50
|
+
return;
|
|
51
|
+
const s = getComputedStyle(t), i = (e) => Number.parseFloat(e) || 0, r = i(s.paddingLeft) + i(s.paddingRight) + i(s.borderLeftWidth) + i(s.borderRightWidth);
|
|
52
|
+
return Math.ceil(o + r);
|
|
53
|
+
}, G = (t, a) => {
|
|
54
|
+
if (!t)
|
|
55
|
+
return M({ ...a, menuHeight: 0 });
|
|
56
|
+
const o = `${M({ ...a, menuHeight: 0 }).width}px`;
|
|
57
|
+
return t.style.width !== o && (t.style.width = o), M({ ...a, menuHeight: t.offsetHeight });
|
|
58
|
+
}, y = (t, a, o) => t.bottom < 0 || t.top > o || t.right < 0 || t.left > a, H = (t) => `${t.top},${t.left},${t.width},${t.height}`;
|
|
59
|
+
export {
|
|
60
|
+
T as MENU_MAX_HEIGHT_PX,
|
|
61
|
+
X as MENU_MIN_WIDTH_PX,
|
|
62
|
+
O as MENU_OPTIONS_MIN_WIDTH_PX,
|
|
63
|
+
D as MENU_SPECS,
|
|
64
|
+
U as MENU_VIEWPORT_PADDING_PX,
|
|
65
|
+
M as computeMenuGeometry,
|
|
66
|
+
y as isTriggerOffscreen,
|
|
67
|
+
A as measureContentWidth,
|
|
68
|
+
G as measureMenuGeometry,
|
|
69
|
+
H as rectSignature
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=floatingMenuGeometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floatingMenuGeometry.js","sources":["../../src/components/floatingMenuGeometry.ts"],"sourcesContent":["// Figma: `Dropdown Component - Item List` fills its trigger, 10px below — 444 (68:2789),\n// 200 (2343:2201), 414 (1437:2986). `Dropdown Component - Options List` (213:4320) is a\n// fixed 280px, 14px below. Figma declares no trigger width and no floor; 160 and 400 are ours.\n\nexport const MENU_VIEWPORT_PADDING_PX = 8;\n\nexport const MENU_MIN_WIDTH_PX = 160;\n\n// Figma draws the Options menu at a flat 280. Taken as a ceiling rather than a width: a kebab\n// of four short verbs then carries 130px of air, and every kebab in a consuming app is the same\n// width whatever it holds. 180 is the floor those menus sized themselves to before this preset.\nexport const MENU_OPTIONS_MIN_WIDTH_PX = 180;\n\nexport type MenuPreset = 'standard' | 'options';\n\nexport interface MenuSpec {\n /** `'trigger'` fills the control that opened it; `'content'` sizes to the widest item. */\n width: 'trigger' | 'content';\n /** Where this preset stops shrinking. */\n minWidth: number;\n /** Where a content-sized one stops growing. A caller's `minWidth` still raises past it. */\n maxWidth?: number;\n align: 'left' | 'right';\n gap: number;\n radius: number;\n padding: number;\n shadow: string;\n background: string;\n border: string;\n}\n\nexport const MENU_SPECS: Record<MenuPreset, MenuSpec> = {\n standard: {\n width: 'trigger',\n minWidth: MENU_MIN_WIDTH_PX,\n align: 'left',\n gap: 10,\n radius: 12,\n padding: 4,\n shadow: '0px 2px 5px 0px rgba(0, 0, 0, 0.1)',\n background: 'var(--malachite-card-background, rgb(255, 255, 255))',\n border: '1px solid var(--malachite-card-border, rgb(232, 232, 232))',\n },\n options: {\n width: 'content',\n minWidth: MENU_OPTIONS_MIN_WIDTH_PX,\n maxWidth: 280,\n align: 'right',\n gap: 14,\n radius: 10,\n padding: 8,\n shadow: '0px 4px 10px 0px rgba(0, 0, 0, 0.1)',\n background: 'var(--malachite-card-background, rgb(255, 255, 255))',\n border: '1px solid var(--malachite-card-border, rgb(232, 232, 232))',\n },\n};\n\nexport const MENU_MAX_HEIGHT_PX = 400;\n\nexport interface MenuGeometry {\n top: number;\n left: number;\n width: number;\n maxHeight: number;\n openUp: boolean;\n}\n\nexport interface MenuGeometryInput {\n triggerRect: Pick<DOMRect, 'top' | 'left' | 'right' | 'bottom' | 'width'>;\n preset: MenuPreset;\n minWidth?: number;\n /** The widest item, for a content-sized preset. Absent until the menu has been laid out. */\n contentWidth?: number;\n menuHeight: number;\n viewportWidth: number;\n viewportHeight: number;\n}\n\nexport const computeMenuGeometry = ({\n triggerRect,\n preset,\n minWidth,\n contentWidth,\n menuHeight,\n viewportWidth,\n viewportHeight,\n}: MenuGeometryInput): MenuGeometry => {\n const spec = MENU_SPECS[preset];\n const available = viewportWidth - MENU_VIEWPORT_PADDING_PX * 2;\n\n const floor = Math.max(spec.minWidth, minWidth ?? 0);\n const ceiling = Math.min(available, Math.max(spec.maxWidth ?? available, floor));\n const natural = spec.width === 'trigger' ? triggerRect.width : (contentWidth ?? ceiling);\n const width = Math.max(0, Math.min(Math.max(natural, floor), ceiling));\n\n const preferredLeft = spec.align === 'right' ? triggerRect.right - width : triggerRect.left;\n const oppositeLeft = spec.align === 'right' ? triggerRect.left : triggerRect.right - width;\n const minLeft = MENU_VIEWPORT_PADDING_PX;\n const maxLeft = viewportWidth - width - MENU_VIEWPORT_PADDING_PX;\n const fits = (candidate: number) => candidate >= minLeft && candidate <= maxLeft;\n\n let left: number;\n if (fits(preferredLeft)) {\n left = preferredLeft;\n } else if (fits(oppositeLeft)) {\n left = oppositeLeft;\n } else {\n left = Math.max(minLeft, Math.min(preferredLeft, maxLeft));\n }\n\n // Which side, then how much of it. \"More room above\" is not \"enough room above\", so the\n // height is clamped to whichever side won. Clamping `top` instead keeps the menu on screen\n // by painting it over its own trigger, which also swallows the click that closes it.\n const roomBelow = viewportHeight - triggerRect.bottom - spec.gap - MENU_VIEWPORT_PADDING_PX;\n const roomAbove = triggerRect.top - spec.gap - MENU_VIEWPORT_PADDING_PX;\n const openUp = menuHeight > 0 && menuHeight > roomBelow && roomAbove > roomBelow;\n\n const maxHeight = Math.max(0, Math.min(MENU_MAX_HEIGHT_PX, openUp ? roomAbove : roomBelow));\n const height = menuHeight > 0 ? Math.min(menuHeight, maxHeight) : 0;\n\n const top = Math.max(\n MENU_VIEWPORT_PADDING_PX,\n openUp ? triggerRect.top - spec.gap - height : triggerRect.bottom + spec.gap,\n );\n\n return { top, left, width, maxHeight, openUp };\n};\n\n// The height decides whether the menu opens upwards, and it is only meaningful at the width the\n// menu will actually have — so on the pass that first sizes the panel the width is written\n// before the height is read. The guard is what keeps that out of the steady state: every later\n// call finds the width already set and writes nothing, so a `ResizeObserver` callback does not\n// resize what it is observing (Chrome's \"undelivered notifications\" error) and a per-frame\n// reposition does not force a reflow. After the first pass this is a pure read.\n// A content-sized preset needs the width the panel chose for itself, which is only readable\n// while no width has been written to it — i.e. on the pass that opens the menu. The caller keeps\n// it from there, because after the first write `offsetWidth` reports what we wrote, not what the\n// items want.\nexport const measureContentWidth = (panel: HTMLElement | null): number | undefined => {\n if (!panel || panel.style.width !== '') {\n return undefined;\n }\n\n // The rows, not the panel. Each label carries `min-width: 0` and `overflow: hidden` so it\n // can ellipsise, which also means it contributes nothing to the panel's intrinsic width —\n // measuring the panel itself returns a box the size of its own padding. `scrollWidth` on a\n // clipped row is the width the row wanted.\n const rows = panel.querySelectorAll<HTMLElement>('button, [role=\"menuitem\"]');\n let widest = 0;\n rows.forEach((row) => {\n widest = Math.max(widest, row.scrollWidth);\n });\n\n if (widest === 0) {\n return undefined;\n }\n\n // The panel is border-box, so the width we hand back has to carry its own padding and rule.\n // Each read is defaulted: a computed style can come back empty — jsdom never expands the\n // `border` shorthand — and one NaN here would make the whole width NaN, which CSS drops,\n // leaving the panel unsized with no sign of why.\n const styles = getComputedStyle(panel);\n const edge = (value: string) => Number.parseFloat(value) || 0;\n const chrome =\n edge(styles.paddingLeft) +\n edge(styles.paddingRight) +\n edge(styles.borderLeftWidth) +\n edge(styles.borderRightWidth);\n\n return Math.ceil(widest + chrome);\n};\n\nexport const measureMenuGeometry = (\n panel: HTMLElement | null,\n input: Omit<MenuGeometryInput, 'menuHeight'>,\n): MenuGeometry => {\n if (!panel) {\n return computeMenuGeometry({ ...input, menuHeight: 0 });\n }\n\n const cssWidth = `${computeMenuGeometry({ ...input, menuHeight: 0 }).width}px`;\n if (panel.style.width !== cssWidth) {\n panel.style.width = cssWidth;\n }\n\n return computeMenuGeometry({ ...input, menuHeight: panel.offsetHeight });\n};\n\nexport const isTriggerOffscreen = (\n rect: Pick<DOMRect, 'top' | 'left' | 'right' | 'bottom'>,\n viewportWidth: number,\n viewportHeight: number,\n): boolean =>\n rect.bottom < 0 || rect.top > viewportHeight || rect.right < 0 || rect.left > viewportWidth;\n\nexport const rectSignature = (rect: Pick<DOMRect, 'top' | 'left' | 'width' | 'height'>): string =>\n `${rect.top},${rect.left},${rect.width},${rect.height}`;\n"],"names":["MENU_VIEWPORT_PADDING_PX","MENU_MIN_WIDTH_PX","MENU_OPTIONS_MIN_WIDTH_PX","MENU_SPECS","MENU_MAX_HEIGHT_PX","computeMenuGeometry","triggerRect","preset","minWidth","contentWidth","menuHeight","viewportWidth","viewportHeight","spec","available","floor","ceiling","natural","width","preferredLeft","oppositeLeft","minLeft","maxLeft","fits","candidate","left","roomBelow","roomAbove","openUp","maxHeight","height","measureContentWidth","panel","rows","widest","row","styles","edge","value","chrome","measureMenuGeometry","input","cssWidth","isTriggerOffscreen","rect","rectSignature"],"mappings":"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"}
|
|
@@ -1,35 +1,37 @@
|
|
|
1
|
-
import { injectStyleSheet as
|
|
2
|
-
const c = "data-malachite-overlay",
|
|
1
|
+
import { injectStyleSheet as o } from "./injectStyleSheet.js";
|
|
2
|
+
const c = "data-malachite-overlay", e = {
|
|
3
3
|
dropdown: "malachite-dropdown-surface",
|
|
4
4
|
multiselect: "malachite-multiselect-surface",
|
|
5
5
|
actionmenu: "malachite-actionmenu-surface",
|
|
6
6
|
tooltip: "malachite-tip-surface",
|
|
7
7
|
sidepanel: "malachite-drawer-surface",
|
|
8
8
|
modal: "malachite-modal-surface"
|
|
9
|
-
},
|
|
10
|
-
className: t
|
|
11
|
-
[c]:
|
|
12
|
-
}), s = "malachite-overlay-styles",
|
|
13
|
-
`.${
|
|
14
|
-
`.${
|
|
15
|
-
],
|
|
16
|
-
`.${
|
|
17
|
-
],
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
}, h = (t) => ({
|
|
10
|
+
className: e[t],
|
|
11
|
+
[c]: t
|
|
12
|
+
}), s = "malachite-overlay-styles", R = 1e3, i = 2147483646, a = "data-malachite-elevated", n = (t) => Object.values(e).map((l) => `.${l}:popover-open${t}`).join(", "), r = "inset: auto; margin: 0; border: 0; padding: 0; width: auto; height: auto; overflow: visible; background: none; color: inherit;", E = [
|
|
13
|
+
`.${e.dropdown}, .${e.multiselect}, .${e.actionmenu} { z-index: 2147483646; }`,
|
|
14
|
+
`.${e.tooltip} { z-index: 2147483647; }`
|
|
15
|
+
], d = "malachite-overlay-menu-box", m = [
|
|
16
|
+
`.${e.dropdown}, .${e.dropdown} *, .${e.multiselect}, .${e.multiselect} *, .${e.actionmenu}, .${e.actionmenu} * { box-sizing: border-box; }`
|
|
17
|
+
], S = () => (o(d, m), o(s, E)), u = "malachite-overlay-elevated", _ = [
|
|
18
|
+
`.${e.sidepanel}[${a}], .${e.modal}[${a}] { z-index: ${i}; }`
|
|
19
|
+
], y = () => o(u, _), L = "malachite-overlay-top-layer", p = [
|
|
20
|
+
`${n("")} { ${r} }`,
|
|
21
|
+
`${n("::backdrop")} { display: none; }`
|
|
22
|
+
], A = () => {
|
|
23
|
+
const t = o(L, p);
|
|
24
|
+
return t && t.cssRules.length > 0 ? t : null;
|
|
23
25
|
};
|
|
24
26
|
export {
|
|
25
27
|
c as OVERLAY_ATTR,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
e as OVERLAY_CLASS,
|
|
29
|
+
a as OVERLAY_ELEVATED_ATTR,
|
|
30
|
+
R as OVERLAY_Z_BASE,
|
|
29
31
|
i as OVERLAY_Z_ELEVATED,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
y as ensureElevatedOverlayStyles,
|
|
33
|
+
S as ensureOverlayStyles,
|
|
34
|
+
A as ensureTopLayerStyles,
|
|
35
|
+
h as overlayIdentity
|
|
34
36
|
};
|
|
35
37
|
//# sourceMappingURL=portalOverlay.js.map
|