@stackone/malachite 2.71.0 → 2.72.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 +3 -3
- package/dist/components/Accordion.js +59 -53
- package/dist/components/Accordion.js.map +1 -1
- package/dist/components/Button.js +36 -31
- package/dist/components/Button.js.map +1 -1
- package/dist/components/SidePanel.js +124 -106
- package/dist/components/SidePanel.js.map +1 -1
- package/dist/index.d.ts +14 -2
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
|
@@ -1,148 +1,165 @@
|
|
|
1
|
-
import { jsx as e, jsxs as
|
|
2
|
-
import { useId as
|
|
3
|
-
import { createPortal as
|
|
4
|
-
import { ShadowRootWrapper as
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { useOverlayBehaviour as
|
|
10
|
-
import { OVERLAY_ELEVATED_ATTR as
|
|
11
|
-
const
|
|
12
|
-
open:
|
|
13
|
-
onClose:
|
|
14
|
-
title:
|
|
15
|
-
subtitle:
|
|
16
|
-
|
|
1
|
+
import { jsx as e, jsxs as r } from "react/jsx-runtime";
|
|
2
|
+
import { useId as V, useState as B, useRef as u, useEffect as Z } from "react";
|
|
3
|
+
import { createPortal as ee } from "react-dom";
|
|
4
|
+
import { ShadowRootWrapper as re } from "../ShadowRootWrapper.js";
|
|
5
|
+
import le from "./CalloutStrip.js";
|
|
6
|
+
import ae from "./CustomIcons/ArrowLeftIcon.js";
|
|
7
|
+
import te from "./CustomIcons/DismissIcon.js";
|
|
8
|
+
import C from "./Typography/EllipsisText.js";
|
|
9
|
+
import { useOverlayBehaviour as ie, OVERLAY_ICON_BUTTON_CLASSES as L } from "./overlayBehaviour.js";
|
|
10
|
+
import { OVERLAY_ELEVATED_ATTR as ne, overlayIdentity as j } from "./portalOverlay.js";
|
|
11
|
+
const M = 200, se = (a) => typeof a == "number" ? `${a}px` : a, ve = ({
|
|
12
|
+
open: a,
|
|
13
|
+
onClose: d,
|
|
14
|
+
title: s,
|
|
15
|
+
subtitle: o,
|
|
16
|
+
subtitlePlacement: W = "inline",
|
|
17
|
+
titleExtra: x,
|
|
17
18
|
description: m,
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
toolbar: f,
|
|
20
|
+
headerDivider: D = !1,
|
|
21
|
+
icon: h,
|
|
20
22
|
headerExtra: b,
|
|
21
|
-
footer:
|
|
22
|
-
onBack:
|
|
23
|
-
maxWidth:
|
|
24
|
-
"aria-label":
|
|
23
|
+
footer: v,
|
|
24
|
+
onBack: N,
|
|
25
|
+
maxWidth: F = 1080,
|
|
26
|
+
"aria-label": X,
|
|
25
27
|
"aria-labelledby": y,
|
|
26
|
-
bodyPadding:
|
|
27
|
-
stacking:
|
|
28
|
+
bodyPadding: g = !0,
|
|
29
|
+
stacking: Y = "default",
|
|
28
30
|
callouts: p,
|
|
29
|
-
renderLink:
|
|
30
|
-
children:
|
|
31
|
+
renderLink: q,
|
|
32
|
+
children: w
|
|
31
33
|
}) => {
|
|
32
|
-
const T =
|
|
33
|
-
ref:
|
|
34
|
-
isTopmost:
|
|
35
|
-
zIndex:
|
|
36
|
-
elevated:
|
|
37
|
-
} =
|
|
38
|
-
open:
|
|
39
|
-
onClose:
|
|
40
|
-
elevated:
|
|
34
|
+
const T = V(), I = V(), [S, k] = B(!1), [U, R] = B(!1), i = u(null), l = u(null), $ = u(null), {
|
|
35
|
+
ref: G,
|
|
36
|
+
isTopmost: H,
|
|
37
|
+
zIndex: J,
|
|
38
|
+
elevated: K
|
|
39
|
+
} = ie({
|
|
40
|
+
open: a,
|
|
41
|
+
onClose: d,
|
|
42
|
+
elevated: Y === "above-app-overlays",
|
|
41
43
|
hostRef: $
|
|
42
44
|
});
|
|
43
|
-
if (
|
|
44
|
-
i.current = null,
|
|
45
|
-
})) : (
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
i.current !== null && (cancelAnimationFrame(i.current), i.current = null),
|
|
49
|
-
}), [
|
|
45
|
+
if (Z(() => (a ? (R(!0), l.current && (clearTimeout(l.current), l.current = null), i.current = requestAnimationFrame(() => {
|
|
46
|
+
i.current = null, k(!0);
|
|
47
|
+
})) : (k(!1), l.current = setTimeout(() => {
|
|
48
|
+
l.current = null, R(!1);
|
|
49
|
+
}, M)), () => {
|
|
50
|
+
i.current !== null && (cancelAnimationFrame(i.current), i.current = null), l.current && (clearTimeout(l.current), l.current = null);
|
|
51
|
+
}), [a]), !U)
|
|
50
52
|
return null;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
+
const t = p == null ? void 0 : p.filter((n) => n.message.trim()), A = !!(t != null && t.length), Q = g ? /* @__PURE__ */ e("div", { className: A ? "p-[28px]" : "py-[28px]", children: w }) : w, E = W === "below" && !!o, _ = /* @__PURE__ */ e(
|
|
54
|
+
"span",
|
|
55
|
+
{
|
|
56
|
+
className: E ? "flex min-w-0 shrink" : "flex min-w-0 max-w-full shrink-0",
|
|
57
|
+
children: /* @__PURE__ */ e(
|
|
58
|
+
C,
|
|
59
|
+
{
|
|
60
|
+
tooltip: s,
|
|
61
|
+
tooltipWhenTruncated: !0,
|
|
62
|
+
tooltipPlacement: "bottom",
|
|
63
|
+
className: "min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold",
|
|
64
|
+
children: s
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
), z = o ? /* @__PURE__ */ e(
|
|
69
|
+
C,
|
|
70
|
+
{
|
|
71
|
+
tooltip: o,
|
|
72
|
+
tooltipWhenTruncated: !0,
|
|
73
|
+
tooltipPlacement: "bottom",
|
|
74
|
+
color: "secondary",
|
|
75
|
+
className: "min-w-0 text-[13px]",
|
|
76
|
+
children: o
|
|
77
|
+
}
|
|
78
|
+
) : null, O = x ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: x }) : null, P = b ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-baseline", children: b }) : null;
|
|
79
|
+
return ee(
|
|
53
80
|
// Host carries the stacking context — ShadowRootWrapper's `isolation` would
|
|
54
81
|
// otherwise flatten our z-index and let sticky page elements paint over us.
|
|
55
82
|
/* @__PURE__ */ e(
|
|
56
|
-
|
|
83
|
+
re,
|
|
57
84
|
{
|
|
58
85
|
hostRef: $,
|
|
59
|
-
hostStyle: { position: "relative", zIndex:
|
|
60
|
-
hostProps:
|
|
61
|
-
children: /* @__PURE__ */
|
|
86
|
+
hostStyle: { position: "relative", zIndex: J },
|
|
87
|
+
hostProps: K ? { ...j("sidepanel"), [ne]: "" } : j("sidepanel"),
|
|
88
|
+
children: /* @__PURE__ */ r("div", { className: "fixed inset-0 z-[1000]", children: [
|
|
62
89
|
/* @__PURE__ */ e(
|
|
63
90
|
"div",
|
|
64
91
|
{
|
|
65
92
|
"aria-hidden": "true",
|
|
66
|
-
onClick:
|
|
67
|
-
className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${
|
|
93
|
+
onClick: d,
|
|
94
|
+
className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${S ? "opacity-100" : "opacity-0"}`
|
|
68
95
|
}
|
|
69
96
|
),
|
|
70
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ r(
|
|
71
98
|
"div",
|
|
72
99
|
{
|
|
73
|
-
ref:
|
|
100
|
+
ref: G,
|
|
74
101
|
role: "dialog",
|
|
75
|
-
"aria-modal":
|
|
102
|
+
"aria-modal": H ? "true" : void 0,
|
|
76
103
|
"aria-describedby": [
|
|
77
|
-
...(
|
|
104
|
+
...(t ?? []).map((n, c) => `${T}-${c}`),
|
|
78
105
|
m ? I : null
|
|
79
106
|
].filter(Boolean).join(" ") || void 0,
|
|
80
107
|
tabIndex: -1,
|
|
81
|
-
"aria-label": y ? void 0 :
|
|
108
|
+
"aria-label": y ? void 0 : X ?? (typeof s == "string" ? s : void 0),
|
|
82
109
|
"aria-labelledby": y,
|
|
83
110
|
className: "absolute top-[8px] right-[8px] bottom-[8px] flex flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-lg)]",
|
|
84
111
|
style: {
|
|
85
|
-
width: `min(calc(100% - 16px), ${
|
|
112
|
+
width: `min(calc(100% - 16px), ${se(F)})`,
|
|
86
113
|
// Inline: Tailwind translate utilities silently break inside
|
|
87
114
|
// shadow roots (see CLAUDE.md Shadow DOM caveats).
|
|
88
|
-
transform:
|
|
89
|
-
transition: `transform ${
|
|
115
|
+
transform: S ? "translateX(0)" : "translateX(calc(100% + 16px))",
|
|
116
|
+
transition: `transform ${M}ms ease-in-out`
|
|
90
117
|
},
|
|
91
118
|
children: [
|
|
92
|
-
/* @__PURE__ */
|
|
119
|
+
/* @__PURE__ */ r(
|
|
93
120
|
"div",
|
|
94
121
|
{
|
|
95
|
-
className: `flex flex-col gap-[20px] px-[20px] py-[18px] ${
|
|
122
|
+
className: `flex flex-col gap-[20px] px-[20px] py-[18px] ${D ? "border-0 border-b border-solid border-[var(--malachite-card-border)]" : ""}`,
|
|
96
123
|
children: [
|
|
97
|
-
/* @__PURE__ */
|
|
98
|
-
|
|
124
|
+
/* @__PURE__ */ r("div", { className: "flex items-center gap-[12px]", children: [
|
|
125
|
+
N ? /* @__PURE__ */ e(
|
|
99
126
|
"button",
|
|
100
127
|
{
|
|
101
128
|
type: "button",
|
|
102
129
|
"aria-label": "Back",
|
|
103
|
-
onClick:
|
|
104
|
-
className:
|
|
105
|
-
children: /* @__PURE__ */ e(
|
|
130
|
+
onClick: N,
|
|
131
|
+
className: L,
|
|
132
|
+
children: /* @__PURE__ */ e(ae, { size: 16 })
|
|
106
133
|
}
|
|
107
134
|
) : null,
|
|
108
|
-
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
-
/* @__PURE__ */
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
{
|
|
115
|
-
tooltip: o,
|
|
116
|
-
tooltipWhenTruncated: !0,
|
|
117
|
-
tooltipPlacement: "bottom",
|
|
118
|
-
className: "min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold",
|
|
119
|
-
children: o
|
|
120
|
-
}
|
|
121
|
-
) }),
|
|
122
|
-
d ? /* @__PURE__ */ e(
|
|
123
|
-
z,
|
|
124
|
-
{
|
|
125
|
-
tooltip: d,
|
|
126
|
-
tooltipWhenTruncated: !0,
|
|
127
|
-
tooltipPlacement: "bottom",
|
|
128
|
-
color: "secondary",
|
|
129
|
-
className: "min-w-0 text-[13px]",
|
|
130
|
-
children: d
|
|
131
|
-
}
|
|
132
|
-
) : null
|
|
135
|
+
h ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: h }) : null,
|
|
136
|
+
E ? /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 items-center gap-[12px]", children: [
|
|
137
|
+
/* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 flex-col gap-[2px]", children: [
|
|
138
|
+
/* @__PURE__ */ r("div", { className: "flex min-w-0 items-baseline gap-[8px]", children: [
|
|
139
|
+
_,
|
|
140
|
+
O
|
|
133
141
|
] }),
|
|
134
|
-
|
|
142
|
+
z
|
|
135
143
|
] }),
|
|
136
|
-
|
|
144
|
+
P
|
|
145
|
+
] }) : /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 items-baseline gap-[12px]", children: [
|
|
146
|
+
/* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 items-baseline gap-[8px]", children: [
|
|
147
|
+
/* @__PURE__ */ r("div", { className: "flex min-w-0 items-baseline gap-[8px]", children: [
|
|
148
|
+
_,
|
|
149
|
+
z
|
|
150
|
+
] }),
|
|
151
|
+
O
|
|
152
|
+
] }),
|
|
153
|
+
P
|
|
137
154
|
] }),
|
|
138
155
|
/* @__PURE__ */ e(
|
|
139
156
|
"button",
|
|
140
157
|
{
|
|
141
158
|
type: "button",
|
|
142
159
|
"aria-label": "Close",
|
|
143
|
-
onClick:
|
|
144
|
-
className:
|
|
145
|
-
children: /* @__PURE__ */ e(
|
|
160
|
+
onClick: d,
|
|
161
|
+
className: L,
|
|
162
|
+
children: /* @__PURE__ */ e(te, { size: 10 })
|
|
146
163
|
}
|
|
147
164
|
)
|
|
148
165
|
] }),
|
|
@@ -157,26 +174,27 @@ const P = 200, ee = (t) => typeof t == "number" ? `${t}px` : t, me = ({
|
|
|
157
174
|
]
|
|
158
175
|
}
|
|
159
176
|
),
|
|
160
|
-
/* @__PURE__ */
|
|
177
|
+
f ? /* @__PURE__ */ e("div", { className: "shrink-0 px-[16px] pt-[16px] pb-[8px]", children: f }) : null,
|
|
178
|
+
/* @__PURE__ */ r(
|
|
161
179
|
"div",
|
|
162
180
|
{
|
|
163
|
-
className: `min-h-0 flex-1 overflow-y-auto ${
|
|
181
|
+
className: `min-h-0 flex-1 overflow-y-auto ${g && !A ? "px-[28px]" : ""}`,
|
|
164
182
|
children: [
|
|
165
|
-
|
|
166
|
-
|
|
183
|
+
t == null ? void 0 : t.map((n, c) => /* @__PURE__ */ e(
|
|
184
|
+
le,
|
|
167
185
|
{
|
|
168
|
-
id: `${T}-${
|
|
186
|
+
id: `${T}-${c}`,
|
|
169
187
|
type: n.type,
|
|
170
188
|
message: n.message,
|
|
171
|
-
renderLink:
|
|
189
|
+
renderLink: q
|
|
172
190
|
},
|
|
173
|
-
|
|
191
|
+
c
|
|
174
192
|
)),
|
|
175
|
-
|
|
193
|
+
Q
|
|
176
194
|
]
|
|
177
195
|
}
|
|
178
196
|
),
|
|
179
|
-
|
|
197
|
+
v ? /* @__PURE__ */ e("div", { className: "border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]", children: v }) : null
|
|
180
198
|
]
|
|
181
199
|
}
|
|
182
200
|
)
|
|
@@ -187,7 +205,7 @@ const P = 200, ee = (t) => typeof t == "number" ? `${t}px` : t, me = ({
|
|
|
187
205
|
);
|
|
188
206
|
};
|
|
189
207
|
export {
|
|
190
|
-
|
|
191
|
-
|
|
208
|
+
ve as SidePanel,
|
|
209
|
+
ve as default
|
|
192
210
|
};
|
|
193
211
|
//# sourceMappingURL=SidePanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SidePanel.js","sources":["../../src/components/SidePanel.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ShadowRootWrapper } from '../ShadowRootWrapper';\nimport type { AlertType } from './Alert';\nimport CalloutStrip from './CalloutStrip';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport DismissIcon from './CustomIcons/DismissIcon';\nimport type { RenderLink } from './PageLayout/types';\nimport EllipsisText from './Typography/EllipsisText';\nimport { OVERLAY_ICON_BUTTON_CLASSES, useOverlayBehaviour } from './overlayBehaviour';\nimport { OVERLAY_ELEVATED_ATTR, overlayIdentity } from './portalOverlay';\n\nexport interface SidePanelProps {\n open: boolean;\n /** Dismiss handler — close button, ESC, or overlay click. */\n onClose: () => void;\n title: React.ReactNode;\n /** Secondary text, inline after the title. */\n subtitle?: React.ReactNode;\n /** Content at the end of the title row, after the subtitle (e.g. a status tag). */\n titleExtra?: React.ReactNode;\n /** Block paragraph below the title row, spanning the header width. Announced as the panel's description. */\n description?: React.ReactNode;\n /** Divider under the header. Default: false. */\n headerDivider?: boolean;\n /** Leading header slot, typically a logo or icon. */\n icon?: React.ReactNode;\n /** Content pinned right in the header, before the close button. */\n headerExtra?: React.ReactNode;\n footer?: React.ReactNode;\n /** Renders a back button before the header icon. */\n onBack?: () => void;\n /** Maximum panel width. Default: 1080. */\n maxWidth?: number | string;\n /** Accessible dialog name; required when `title` isn't a plain string. */\n 'aria-label'?: string;\n /** ID of a visible element naming the dialog (alternative to `aria-label`). */\n 'aria-labelledby'?: string;\n /** Whether the body gets default padding. Default: true. */\n bodyPadding?: boolean;\n /** `above-app-overlays` lifts the overlay stack clear of chrome pinned near max-int. */\n stacking?: 'default' | 'above-app-overlays';\n /** Full-width Alert bands at the top of the body, above `children`, in order. Unaffected by\n * `bodyPadding`, and announced ahead of `description`. The message is markdown. */\n callouts?: { type?: AlertType; message: string }[];\n /** Routes root-relative links in `callouts` through the app's router; see `MarkdownBlock`. */\n renderLink?: RenderLink;\n children: React.ReactNode;\n}\n\nconst TRANSITION_MS = 200;\n\nconst toCssSize = (value: number | string): string =>\n typeof value === 'number' ? `${value}px` : value;\n\n/**\n * A right-hand slide-in overlay panel (drawer) for inspecting or editing an entity\n * without leaving the page. Portals to `document.body`, locks background scroll and\n * traps keyboard focus while open (restoring both on close), dismisses on ESC\n * (topmost open overlay only), overlay click or the close button, and exposes header\n * (back/icon/title/subtitle/extra), scrollable body and optional footer slots.\n */\nconst SidePanel: React.FC<SidePanelProps> = ({\n open,\n onClose,\n title,\n subtitle,\n titleExtra,\n description,\n headerDivider = false,\n icon,\n headerExtra,\n footer,\n onBack,\n maxWidth = 1080,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n bodyPadding = true,\n stacking = 'default',\n callouts,\n renderLink,\n children,\n}) => {\n const calloutId = useId();\n const descriptionId = useId();\n const [isVisible, setIsVisible] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const frameRef = useRef<number | null>(null);\n const unmountTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const {\n ref: handlePanelRef,\n isTopmost,\n zIndex,\n elevated,\n } = useOverlayBehaviour({\n open,\n onClose,\n elevated: stacking === 'above-app-overlays',\n hostRef,\n });\n\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n setIsVisible(true);\n });\n } else {\n setIsVisible(false);\n unmountTimerRef.current = setTimeout(() => {\n unmountTimerRef.current = null;\n setIsMounted(false);\n }, TRANSITION_MS);\n }\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n };\n }, [open]);\n\n if (!isMounted) {\n return null;\n }\n\n const shownCallouts = callouts?.filter((callout) => callout.message.trim());\n const hasCallouts = !!shownCallouts?.length;\n const paddedBody = bodyPadding ? (\n <div className={hasCallouts ? 'p-[28px]' : 'py-[28px]'}>{children}</div>\n ) : (\n children\n );\n\n return createPortal(\n // Host carries the stacking context — ShadowRootWrapper's `isolation` would\n // otherwise flatten our z-index and let sticky page elements paint over us.\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={{ position: 'relative', zIndex }}\n hostProps={\n elevated\n ? { ...overlayIdentity('sidepanel'), [OVERLAY_ELEVATED_ATTR]: '' }\n : overlayIdentity('sidepanel')\n }\n >\n <div className=\"fixed inset-0 z-[1000]\">\n <div\n aria-hidden=\"true\"\n onClick={onClose}\n className={`absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${\n isVisible ? 'opacity-100' : 'opacity-0'\n }`}\n />\n <div\n ref={handlePanelRef}\n role=\"dialog\"\n // Only the topmost overlay may claim it, or a screen reader can still\n // browse the one underneath.\n aria-modal={isTopmost ? 'true' : undefined}\n aria-describedby={\n [\n ...(shownCallouts ?? []).map((_, index) => `${calloutId}-${index}`),\n description ? descriptionId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n tabIndex={-1}\n // Prefer aria-labelledby; only fall back to aria-label when it's absent.\n aria-label={\n ariaLabelledBy\n ? undefined\n : (ariaLabel ?? (typeof title === 'string' ? title : undefined))\n }\n aria-labelledby={ariaLabelledBy}\n className=\"absolute top-[8px] right-[8px] bottom-[8px] flex flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-lg)]\"\n style={{\n width: `min(calc(100% - 16px), ${toCssSize(maxWidth)})`,\n // Inline: Tailwind translate utilities silently break inside\n // shadow roots (see CLAUDE.md Shadow DOM caveats).\n transform: isVisible ? 'translateX(0)' : 'translateX(calc(100% + 16px))',\n transition: `transform ${TRANSITION_MS}ms ease-in-out`,\n }}\n >\n <div\n className={`flex flex-col gap-[20px] px-[20px] py-[18px] ${\n headerDivider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]'\n : ''\n }`}\n >\n <div className=\"flex items-center gap-[12px]\">\n {onBack ? (\n <button\n type=\"button\"\n aria-label=\"Back\"\n onClick={onBack}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <ArrowLeftIcon size={16} />\n </button>\n ) : null}\n {icon ? (\n <span className=\"flex shrink-0 items-center\">{icon}</span>\n ) : null}\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[12px]\">\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[8px]\">\n <div className=\"flex min-w-0 items-baseline gap-[8px]\">\n <span className=\"flex min-w-0 max-w-full shrink-0\">\n <EllipsisText\n tooltip={title}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n className=\"min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold\"\n >\n {title}\n </EllipsisText>\n </span>\n {subtitle ? (\n <EllipsisText\n tooltip={subtitle}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n color=\"secondary\"\n className=\"min-w-0 text-[13px]\"\n >\n {subtitle}\n </EllipsisText>\n ) : null}\n </div>\n {titleExtra ? (\n <span className=\"flex shrink-0 items-center\">\n {titleExtra}\n </span>\n ) : null}\n </div>\n {headerExtra ? (\n <span className=\"flex shrink-0 items-baseline\">\n {headerExtra}\n </span>\n ) : null}\n </div>\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={onClose}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <DismissIcon size={10} />\n </button>\n </div>\n {description ? (\n <div\n id={descriptionId}\n className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\"\n >\n {description}\n </div>\n ) : null}\n </div>\n {/* Callouts move the horizontal padding inward so their strips run full-bleed. */}\n <div\n className={`min-h-0 flex-1 overflow-y-auto ${bodyPadding && !hasCallouts ? 'px-[28px]' : ''}`}\n >\n {shownCallouts?.map((callout, index) => (\n <CalloutStrip\n key={index}\n id={`${calloutId}-${index}`}\n type={callout.type}\n message={callout.message}\n renderLink={renderLink}\n />\n ))}\n {paddedBody}\n </div>\n {footer ? (\n <div className=\"border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]\">\n {footer}\n </div>\n ) : null}\n </div>\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default SidePanel;\nexport { SidePanel };\n"],"names":["TRANSITION_MS","toCssSize","value","SidePanel","open","onClose","title","subtitle","titleExtra","description","headerDivider","icon","headerExtra","footer","onBack","maxWidth","ariaLabel","ariaLabelledBy","bodyPadding","stacking","callouts","renderLink","children","calloutId","useId","descriptionId","isVisible","setIsVisible","useState","isMounted","setIsMounted","frameRef","useRef","unmountTimerRef","hostRef","handlePanelRef","isTopmost","zIndex","elevated","useOverlayBehaviour","useEffect","shownCallouts","callout","hasCallouts","paddedBody","jsx","createPortal","ShadowRootWrapper","overlayIdentity","OVERLAY_ELEVATED_ATTR","jsxs","_","index","OVERLAY_ICON_BUTTON_CLASSES","ArrowLeftIcon","EllipsisText","DismissIcon","CalloutStrip"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SidePanel.js","sources":["../../src/components/SidePanel.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ShadowRootWrapper } from '../ShadowRootWrapper';\nimport type { AlertType } from './Alert';\nimport CalloutStrip from './CalloutStrip';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport DismissIcon from './CustomIcons/DismissIcon';\nimport type { RenderLink } from './PageLayout/types';\nimport EllipsisText from './Typography/EllipsisText';\nimport { OVERLAY_ICON_BUTTON_CLASSES, useOverlayBehaviour } from './overlayBehaviour';\nimport { OVERLAY_ELEVATED_ATTR, overlayIdentity } from './portalOverlay';\n\nexport interface SidePanelProps {\n open: boolean;\n /** Dismiss handler — close button, ESC, or overlay click. */\n onClose: () => void;\n title: React.ReactNode;\n subtitle?: React.ReactNode;\n /** `below` stacks the subtitle under the title, so neither truncates the other. */\n subtitlePlacement?: 'inline' | 'below';\n /** Content at the end of the title row, after the subtitle (e.g. a status tag). */\n titleExtra?: React.ReactNode;\n /** Block paragraph below the title row, spanning the header width. Announced as the panel's description. */\n description?: React.ReactNode;\n /** Pinned between the header and the scrolling body. */\n toolbar?: React.ReactNode;\n /** Divider under the header. Default: false. */\n headerDivider?: boolean;\n /** Leading header slot, typically a logo or icon. */\n icon?: React.ReactNode;\n /** Content pinned right in the header, before the close button. */\n headerExtra?: React.ReactNode;\n footer?: React.ReactNode;\n /** Renders a back button before the header icon. */\n onBack?: () => void;\n /** Maximum panel width. Default: 1080. */\n maxWidth?: number | string;\n /** Accessible dialog name; required when `title` isn't a plain string. */\n 'aria-label'?: string;\n /** ID of a visible element naming the dialog (alternative to `aria-label`). */\n 'aria-labelledby'?: string;\n /** Whether the body gets default padding. Default: true. */\n bodyPadding?: boolean;\n /** `above-app-overlays` lifts the overlay stack clear of chrome pinned near max-int. */\n stacking?: 'default' | 'above-app-overlays';\n /** Full-width Alert bands at the top of the body, above `children`, in order. Unaffected by\n * `bodyPadding`, and announced ahead of `description`. The message is markdown. */\n callouts?: { type?: AlertType; message: string }[];\n /** Routes root-relative links in `callouts` through the app's router; see `MarkdownBlock`. */\n renderLink?: RenderLink;\n children: React.ReactNode;\n}\n\nconst TRANSITION_MS = 200;\n\nconst toCssSize = (value: number | string): string =>\n typeof value === 'number' ? `${value}px` : value;\n\n/**\n * A right-hand slide-in overlay panel (drawer) for inspecting or editing an entity\n * without leaving the page. Portals to `document.body`, locks background scroll and\n * traps keyboard focus while open (restoring both on close), dismisses on ESC\n * (topmost open overlay only), overlay click or the close button, and exposes header\n * (back/icon/title/subtitle/extra), scrollable body and optional footer slots.\n */\nconst SidePanel: React.FC<SidePanelProps> = ({\n open,\n onClose,\n title,\n subtitle,\n subtitlePlacement = 'inline',\n titleExtra,\n description,\n toolbar,\n headerDivider = false,\n icon,\n headerExtra,\n footer,\n onBack,\n maxWidth = 1080,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n bodyPadding = true,\n stacking = 'default',\n callouts,\n renderLink,\n children,\n}) => {\n const calloutId = useId();\n const descriptionId = useId();\n const [isVisible, setIsVisible] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const frameRef = useRef<number | null>(null);\n const unmountTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const {\n ref: handlePanelRef,\n isTopmost,\n zIndex,\n elevated,\n } = useOverlayBehaviour({\n open,\n onClose,\n elevated: stacking === 'above-app-overlays',\n hostRef,\n });\n\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n setIsVisible(true);\n });\n } else {\n setIsVisible(false);\n unmountTimerRef.current = setTimeout(() => {\n unmountTimerRef.current = null;\n setIsMounted(false);\n }, TRANSITION_MS);\n }\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n };\n }, [open]);\n\n if (!isMounted) {\n return null;\n }\n\n const shownCallouts = callouts?.filter((callout) => callout.message.trim());\n const hasCallouts = !!shownCallouts?.length;\n const paddedBody = bodyPadding ? (\n <div className={hasCallouts ? 'p-[28px]' : 'py-[28px]'}>{children}</div>\n ) : (\n children\n );\n\n const subtitleBelow = subtitlePlacement === 'below' && !!subtitle;\n const titleNode = (\n <span\n className={subtitleBelow ? 'flex min-w-0 shrink' : 'flex min-w-0 max-w-full shrink-0'}\n >\n <EllipsisText\n tooltip={title}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n className=\"min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold\"\n >\n {title}\n </EllipsisText>\n </span>\n );\n const subtitleNode = subtitle ? (\n <EllipsisText\n tooltip={subtitle}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n color=\"secondary\"\n className=\"min-w-0 text-[13px]\"\n >\n {subtitle}\n </EllipsisText>\n ) : null;\n const titleExtraNode = titleExtra ? (\n <span className=\"flex shrink-0 items-center\">{titleExtra}</span>\n ) : null;\n const headerExtraNode = headerExtra ? (\n <span className=\"flex shrink-0 items-baseline\">{headerExtra}</span>\n ) : null;\n\n return createPortal(\n // Host carries the stacking context — ShadowRootWrapper's `isolation` would\n // otherwise flatten our z-index and let sticky page elements paint over us.\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={{ position: 'relative', zIndex }}\n hostProps={\n elevated\n ? { ...overlayIdentity('sidepanel'), [OVERLAY_ELEVATED_ATTR]: '' }\n : overlayIdentity('sidepanel')\n }\n >\n <div className=\"fixed inset-0 z-[1000]\">\n <div\n aria-hidden=\"true\"\n onClick={onClose}\n className={`absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${\n isVisible ? 'opacity-100' : 'opacity-0'\n }`}\n />\n <div\n ref={handlePanelRef}\n role=\"dialog\"\n // Only the topmost overlay may claim it, or a screen reader can still\n // browse the one underneath.\n aria-modal={isTopmost ? 'true' : undefined}\n aria-describedby={\n [\n ...(shownCallouts ?? []).map((_, index) => `${calloutId}-${index}`),\n description ? descriptionId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n tabIndex={-1}\n // Prefer aria-labelledby; only fall back to aria-label when it's absent.\n aria-label={\n ariaLabelledBy\n ? undefined\n : (ariaLabel ?? (typeof title === 'string' ? title : undefined))\n }\n aria-labelledby={ariaLabelledBy}\n className=\"absolute top-[8px] right-[8px] bottom-[8px] flex flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-lg)]\"\n style={{\n width: `min(calc(100% - 16px), ${toCssSize(maxWidth)})`,\n // Inline: Tailwind translate utilities silently break inside\n // shadow roots (see CLAUDE.md Shadow DOM caveats).\n transform: isVisible ? 'translateX(0)' : 'translateX(calc(100% + 16px))',\n transition: `transform ${TRANSITION_MS}ms ease-in-out`,\n }}\n >\n <div\n className={`flex flex-col gap-[20px] px-[20px] py-[18px] ${\n headerDivider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]'\n : ''\n }`}\n >\n <div className=\"flex items-center gap-[12px]\">\n {onBack ? (\n <button\n type=\"button\"\n aria-label=\"Back\"\n onClick={onBack}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <ArrowLeftIcon size={16} />\n </button>\n ) : null}\n {icon ? (\n <span className=\"flex shrink-0 items-center\">{icon}</span>\n ) : null}\n {subtitleBelow ? (\n <div className=\"flex min-w-0 flex-1 items-center gap-[12px]\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-[2px]\">\n <div className=\"flex min-w-0 items-baseline gap-[8px]\">\n {titleNode}\n {titleExtraNode}\n </div>\n {subtitleNode}\n </div>\n {headerExtraNode}\n </div>\n ) : (\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[12px]\">\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[8px]\">\n <div className=\"flex min-w-0 items-baseline gap-[8px]\">\n {titleNode}\n {subtitleNode}\n </div>\n {titleExtraNode}\n </div>\n {headerExtraNode}\n </div>\n )}\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={onClose}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <DismissIcon size={10} />\n </button>\n </div>\n {description ? (\n <div\n id={descriptionId}\n className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\"\n >\n {description}\n </div>\n ) : null}\n </div>\n {toolbar ? (\n <div className=\"shrink-0 px-[16px] pt-[16px] pb-[8px]\">{toolbar}</div>\n ) : null}\n {/* Callouts move the horizontal padding inward so their strips run full-bleed. */}\n <div\n className={`min-h-0 flex-1 overflow-y-auto ${bodyPadding && !hasCallouts ? 'px-[28px]' : ''}`}\n >\n {shownCallouts?.map((callout, index) => (\n <CalloutStrip\n key={index}\n id={`${calloutId}-${index}`}\n type={callout.type}\n message={callout.message}\n renderLink={renderLink}\n />\n ))}\n {paddedBody}\n </div>\n {footer ? (\n <div className=\"border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]\">\n {footer}\n </div>\n ) : null}\n </div>\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default SidePanel;\nexport { SidePanel };\n"],"names":["TRANSITION_MS","toCssSize","value","SidePanel","open","onClose","title","subtitle","subtitlePlacement","titleExtra","description","toolbar","headerDivider","icon","headerExtra","footer","onBack","maxWidth","ariaLabel","ariaLabelledBy","bodyPadding","stacking","callouts","renderLink","children","calloutId","useId","descriptionId","isVisible","setIsVisible","useState","isMounted","setIsMounted","frameRef","useRef","unmountTimerRef","hostRef","handlePanelRef","isTopmost","zIndex","elevated","useOverlayBehaviour","useEffect","shownCallouts","callout","hasCallouts","paddedBody","jsx","subtitleBelow","titleNode","EllipsisText","subtitleNode","titleExtraNode","headerExtraNode","createPortal","ShadowRootWrapper","overlayIdentity","OVERLAY_ELEVATED_ATTR","jsxs","_","index","OVERLAY_ICON_BUTTON_CLASSES","ArrowLeftIcon","DismissIcon","CalloutStrip"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,11 @@ declare interface AccordionBaseProps {
|
|
|
51
51
|
* be interactive (e.g. a Checkbox) without nesting a button inside a button.
|
|
52
52
|
*/
|
|
53
53
|
trailing?: default_2.ReactNode;
|
|
54
|
+
/** Before the title, outside the toggle button. */
|
|
55
|
+
leading?: default_2.ReactNode;
|
|
56
|
+
arrowPosition?: 'start' | 'end';
|
|
57
|
+
/** `false` keeps an open row on the card ground. */
|
|
58
|
+
highlightExpanded?: boolean;
|
|
54
59
|
defaultExpanded?: boolean;
|
|
55
60
|
isExpanded?: boolean;
|
|
56
61
|
onToggle?: (expanded: boolean) => void;
|
|
@@ -408,6 +413,8 @@ declare interface ButtonProps extends default_2.ButtonHTMLAttributes<HTMLButtonE
|
|
|
408
413
|
contentAlign?: 'center' | 'start';
|
|
409
414
|
/** Fills the container's width. */
|
|
410
415
|
flexGrow?: boolean;
|
|
416
|
+
/** `wide` holds a 120px floor for a primary action. */
|
|
417
|
+
width?: 'auto' | 'wide';
|
|
411
418
|
fill?: boolean;
|
|
412
419
|
tooltip?: string;
|
|
413
420
|
tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';
|
|
@@ -438,7 +445,9 @@ export declare type ButtonVariant = 'filled' | 'outline'
|
|
|
438
445
|
* acts on what it produced. Provenance, not a severity: it says who is being asked, not
|
|
439
446
|
* that anything is wrong.
|
|
440
447
|
*/
|
|
441
|
-
| 'assistant' | 'destructive' | 'success' | 'warning' | 'error' | 'ghost'
|
|
448
|
+
| 'assistant' | 'destructive' | 'success' | 'warning' | 'error' | 'ghost'
|
|
449
|
+
/** Text only, in the accent colour, for a secondary action beside a primary one. */
|
|
450
|
+
| 'quiet' | 'no-style';
|
|
442
451
|
|
|
443
452
|
export declare const Card: default_2.FC<CardProps>;
|
|
444
453
|
|
|
@@ -4680,12 +4689,15 @@ export declare interface SidePanelProps {
|
|
|
4680
4689
|
/** Dismiss handler — close button, ESC, or overlay click. */
|
|
4681
4690
|
onClose: () => void;
|
|
4682
4691
|
title: default_2.ReactNode;
|
|
4683
|
-
/** Secondary text, inline after the title. */
|
|
4684
4692
|
subtitle?: default_2.ReactNode;
|
|
4693
|
+
/** `below` stacks the subtitle under the title, so neither truncates the other. */
|
|
4694
|
+
subtitlePlacement?: 'inline' | 'below';
|
|
4685
4695
|
/** Content at the end of the title row, after the subtitle (e.g. a status tag). */
|
|
4686
4696
|
titleExtra?: default_2.ReactNode;
|
|
4687
4697
|
/** Block paragraph below the title row, spanning the header width. Announced as the panel's description. */
|
|
4688
4698
|
description?: default_2.ReactNode;
|
|
4699
|
+
/** Pinned between the header and the scrolling body. */
|
|
4700
|
+
toolbar?: default_2.ReactNode;
|
|
4689
4701
|
/** Divider under the header. Default: false. */
|
|
4690
4702
|
headerDivider?: boolean;
|
|
4691
4703
|
/** Leading header slot, typically a logo or icon. */
|