bubble-toolbar 0.0.0-stage → 1.0.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/CHANGELOG.md +3 -0
- package/LICENSE +21 -0
- package/README.md +314 -2
- package/dist/index.d.mts +203 -0
- package/dist/index.d.ts +203 -0
- package/dist/index.js +615 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +586 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles.css +195 -0
- package/package.json +89 -5
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
// src/activity.ts
|
|
2
|
+
import {
|
|
3
|
+
createContext,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
useEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
useState
|
|
10
|
+
} from "react";
|
|
11
|
+
var BubbleActivityContext = createContext(null);
|
|
12
|
+
var useBubbleActivity = () => {
|
|
13
|
+
const activity = useContext(BubbleActivityContext);
|
|
14
|
+
if (!activity) {
|
|
15
|
+
throw new Error("useBubbleActivity must be used inside a BubbleGroup or BubbleToolbar.Group.");
|
|
16
|
+
}
|
|
17
|
+
return activity;
|
|
18
|
+
};
|
|
19
|
+
var useGroupActivity = (externalBusy) => {
|
|
20
|
+
const [pending, setPending] = useState(0);
|
|
21
|
+
const mounted = useRef(true);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
mounted.current = true;
|
|
24
|
+
return () => {
|
|
25
|
+
mounted.current = false;
|
|
26
|
+
};
|
|
27
|
+
}, []);
|
|
28
|
+
const run = useCallback(async (task) => {
|
|
29
|
+
if (mounted.current) {
|
|
30
|
+
setPending((count) => count + 1);
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return await task();
|
|
34
|
+
} finally {
|
|
35
|
+
if (mounted.current) {
|
|
36
|
+
setPending((count) => count - 1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
const isBusy = externalBusy || pending > 0;
|
|
41
|
+
return useMemo(() => ({ isBusy, run }), [isBusy, run]);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/BubbleGroup.tsx
|
|
45
|
+
import { forwardRef } from "react";
|
|
46
|
+
|
|
47
|
+
// src/context.ts
|
|
48
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
49
|
+
var defaultContextValue = {
|
|
50
|
+
size: "md",
|
|
51
|
+
theme: "glass",
|
|
52
|
+
blurred: true,
|
|
53
|
+
blurAmount: 16,
|
|
54
|
+
itemGap: 8,
|
|
55
|
+
bordered: true,
|
|
56
|
+
shadow: true
|
|
57
|
+
};
|
|
58
|
+
var BubbleToolbarContext = createContext2(defaultContextValue);
|
|
59
|
+
var useBubbleToolbar = () => {
|
|
60
|
+
return useContext2(BubbleToolbarContext);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/utils/children.ts
|
|
64
|
+
import { Children, Fragment, isValidElement } from "react";
|
|
65
|
+
function getValidChildren(children) {
|
|
66
|
+
const result = [];
|
|
67
|
+
Children.forEach(children, (child) => {
|
|
68
|
+
if (child === null || child === void 0 || typeof child === "boolean") {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (isValidElement(child) && child.type === Fragment) {
|
|
72
|
+
const fragmentChildren = getValidChildren(child.props.children);
|
|
73
|
+
result.push(...fragmentChildren);
|
|
74
|
+
} else {
|
|
75
|
+
result.push(child);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/utils/styles.ts
|
|
82
|
+
function resolveSize(size) {
|
|
83
|
+
if (typeof size === "number") {
|
|
84
|
+
return size;
|
|
85
|
+
}
|
|
86
|
+
switch (size) {
|
|
87
|
+
case "sm":
|
|
88
|
+
return 40;
|
|
89
|
+
case "lg":
|
|
90
|
+
return 56;
|
|
91
|
+
default:
|
|
92
|
+
return 48;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function formatPx(val) {
|
|
96
|
+
return typeof val === "number" ? `${val}px` : val;
|
|
97
|
+
}
|
|
98
|
+
function getGlassStyles(theme, blurred, blurAmount, bordered, shadow) {
|
|
99
|
+
const blurVal = formatPx(blurAmount);
|
|
100
|
+
let background;
|
|
101
|
+
let borderColor;
|
|
102
|
+
let color;
|
|
103
|
+
switch (theme) {
|
|
104
|
+
case "dark":
|
|
105
|
+
background = blurred ? "rgba(24, 24, 27, 0.72)" : "rgba(24, 24, 27, 0.95)";
|
|
106
|
+
borderColor = "rgba(255, 255, 255, 0.12)";
|
|
107
|
+
color = "#f4f4f5";
|
|
108
|
+
break;
|
|
109
|
+
case "light":
|
|
110
|
+
background = blurred ? "rgba(255, 255, 255, 0.75)" : "rgba(255, 255, 255, 0.95)";
|
|
111
|
+
borderColor = "rgba(0, 0, 0, 0.08)";
|
|
112
|
+
color = "#18181b";
|
|
113
|
+
break;
|
|
114
|
+
case "auto":
|
|
115
|
+
background = "var(--bubble-bg, rgba(255, 255, 255, 0.75))";
|
|
116
|
+
borderColor = "var(--bubble-border, rgba(0, 0, 0, 0.08))";
|
|
117
|
+
color = "var(--bubble-fg, #18181b)";
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
background = blurred ? "rgba(255, 255, 255, 0.65)" : "rgba(255, 255, 255, 0.92)";
|
|
121
|
+
borderColor = "rgba(255, 255, 255, 0.4)";
|
|
122
|
+
color = "#09090b";
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
const boxShadow = typeof shadow === "string" ? shadow : shadow ? "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.06)" : "none";
|
|
126
|
+
return {
|
|
127
|
+
backgroundColor: background,
|
|
128
|
+
backdropFilter: blurred ? `blur(${blurVal}) saturate(180%)` : void 0,
|
|
129
|
+
WebkitBackdropFilter: blurred ? `blur(${blurVal}) saturate(180%)` : void 0,
|
|
130
|
+
border: bordered ? `1px solid ${borderColor}` : "none",
|
|
131
|
+
boxShadow,
|
|
132
|
+
color,
|
|
133
|
+
transition: "all 0.25s cubic-bezier(0.16, 1, 0.3, 1)"
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/BubbleGroup.tsx
|
|
138
|
+
import { jsx } from "react/jsx-runtime";
|
|
139
|
+
var BubbleGroup = forwardRef(
|
|
140
|
+
({
|
|
141
|
+
children,
|
|
142
|
+
shape: explicitShape,
|
|
143
|
+
size: explicitSize,
|
|
144
|
+
itemGap: explicitItemGap,
|
|
145
|
+
busy = false,
|
|
146
|
+
activityColors,
|
|
147
|
+
activityDuration,
|
|
148
|
+
className = "",
|
|
149
|
+
style,
|
|
150
|
+
...rest
|
|
151
|
+
}, ref) => {
|
|
152
|
+
const context = useBubbleToolbar();
|
|
153
|
+
const activity = useGroupActivity(Boolean(context.busy || busy));
|
|
154
|
+
const colors = activityColors ?? context.activityColors ?? ["#22d3ee", "#8b5cf6", "#ec4899"];
|
|
155
|
+
const duration = activityDuration ?? context.activityDuration ?? 2.4;
|
|
156
|
+
const validChildren = getValidChildren(children);
|
|
157
|
+
const count = validChildren.length;
|
|
158
|
+
const computedShape = explicitShape || (count <= 1 ? "circle" : "pill");
|
|
159
|
+
const effectiveSize = resolveSize(explicitSize || context.size);
|
|
160
|
+
const effectiveItemGap = explicitItemGap !== void 0 ? explicitItemGap : context.itemGap;
|
|
161
|
+
const glassStyles = getGlassStyles(
|
|
162
|
+
context.theme,
|
|
163
|
+
context.blurred,
|
|
164
|
+
context.blurAmount,
|
|
165
|
+
context.bordered,
|
|
166
|
+
context.shadow
|
|
167
|
+
);
|
|
168
|
+
const isCircle = computedShape === "circle";
|
|
169
|
+
const groupStyles = {
|
|
170
|
+
"--bubble-activity-color-1": colors[0],
|
|
171
|
+
"--bubble-activity-color-2": colors[1],
|
|
172
|
+
"--bubble-activity-color-3": colors[2],
|
|
173
|
+
"--bubble-activity-duration": `${Number.isFinite(duration) && duration > 0 ? duration : 2.4}s`,
|
|
174
|
+
...glassStyles,
|
|
175
|
+
height: `${effectiveSize}px`,
|
|
176
|
+
boxSizing: "border-box",
|
|
177
|
+
display: "inline-flex",
|
|
178
|
+
alignItems: "center",
|
|
179
|
+
flexShrink: 0,
|
|
180
|
+
userSelect: "none",
|
|
181
|
+
...isCircle ? {
|
|
182
|
+
width: `${effectiveSize}px`,
|
|
183
|
+
minWidth: `${effectiveSize}px`,
|
|
184
|
+
borderRadius: "9999px",
|
|
185
|
+
justifyContent: "center",
|
|
186
|
+
padding: 0
|
|
187
|
+
} : {
|
|
188
|
+
width: "auto",
|
|
189
|
+
minWidth: `${effectiveSize}px`,
|
|
190
|
+
borderRadius: "9999px",
|
|
191
|
+
flexDirection: "row",
|
|
192
|
+
justifyContent: "flex-start",
|
|
193
|
+
paddingLeft: `${Math.max(12, Math.round(effectiveSize * 0.28))}px`,
|
|
194
|
+
paddingRight: `${Math.max(12, Math.round(effectiveSize * 0.28))}px`,
|
|
195
|
+
gap: formatPx(effectiveItemGap)
|
|
196
|
+
},
|
|
197
|
+
...style
|
|
198
|
+
};
|
|
199
|
+
const combinedClassName = [
|
|
200
|
+
"bubble-group",
|
|
201
|
+
`bubble-group--${computedShape}`,
|
|
202
|
+
activity.isBusy && "bubble-group--busy",
|
|
203
|
+
className
|
|
204
|
+
].filter(Boolean).join(" ");
|
|
205
|
+
return /* @__PURE__ */ jsx(BubbleActivityContext.Provider, { value: activity, children: /* @__PURE__ */ jsx(
|
|
206
|
+
"div",
|
|
207
|
+
{
|
|
208
|
+
ref,
|
|
209
|
+
role: "group",
|
|
210
|
+
className: combinedClassName,
|
|
211
|
+
style: groupStyles,
|
|
212
|
+
"data-shape": computedShape,
|
|
213
|
+
"data-items-count": count,
|
|
214
|
+
...rest,
|
|
215
|
+
"aria-busy": activity.isBusy,
|
|
216
|
+
children: validChildren
|
|
217
|
+
}
|
|
218
|
+
) });
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
BubbleGroup.displayName = "BubbleGroup";
|
|
222
|
+
|
|
223
|
+
// src/BubbleToolbar.tsx
|
|
224
|
+
import { forwardRef as forwardRef2, useMemo as useMemo2 } from "react";
|
|
225
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
226
|
+
var BubbleToolbar = forwardRef2(
|
|
227
|
+
({
|
|
228
|
+
groups,
|
|
229
|
+
children,
|
|
230
|
+
position = "bottom",
|
|
231
|
+
theme = "glass",
|
|
232
|
+
size = "md",
|
|
233
|
+
blurred = true,
|
|
234
|
+
blurAmount = 16,
|
|
235
|
+
groupGap = 8,
|
|
236
|
+
itemGap = 8,
|
|
237
|
+
bordered = true,
|
|
238
|
+
shadow = true,
|
|
239
|
+
busy = false,
|
|
240
|
+
activityColors,
|
|
241
|
+
activityDuration,
|
|
242
|
+
className = "",
|
|
243
|
+
style,
|
|
244
|
+
ariaLabel = "Toolbar",
|
|
245
|
+
...rest
|
|
246
|
+
}, ref) => {
|
|
247
|
+
const contextValue = useMemo2(
|
|
248
|
+
() => ({
|
|
249
|
+
size,
|
|
250
|
+
theme,
|
|
251
|
+
blurred,
|
|
252
|
+
blurAmount,
|
|
253
|
+
itemGap,
|
|
254
|
+
bordered,
|
|
255
|
+
shadow,
|
|
256
|
+
busy,
|
|
257
|
+
activityColors,
|
|
258
|
+
activityDuration
|
|
259
|
+
}),
|
|
260
|
+
[
|
|
261
|
+
size,
|
|
262
|
+
theme,
|
|
263
|
+
blurred,
|
|
264
|
+
blurAmount,
|
|
265
|
+
itemGap,
|
|
266
|
+
bordered,
|
|
267
|
+
shadow,
|
|
268
|
+
busy,
|
|
269
|
+
activityColors,
|
|
270
|
+
activityDuration
|
|
271
|
+
]
|
|
272
|
+
);
|
|
273
|
+
const getPositionStyles = () => {
|
|
274
|
+
switch (position) {
|
|
275
|
+
case "bottom":
|
|
276
|
+
return {
|
|
277
|
+
position: "fixed",
|
|
278
|
+
bottom: "24px",
|
|
279
|
+
left: "50%",
|
|
280
|
+
transform: "translateX(-50%)",
|
|
281
|
+
zIndex: 1e3
|
|
282
|
+
};
|
|
283
|
+
case "top":
|
|
284
|
+
return {
|
|
285
|
+
position: "fixed",
|
|
286
|
+
top: "24px",
|
|
287
|
+
left: "50%",
|
|
288
|
+
transform: "translateX(-50%)",
|
|
289
|
+
zIndex: 1e3
|
|
290
|
+
};
|
|
291
|
+
case "static":
|
|
292
|
+
return {
|
|
293
|
+
position: "relative"
|
|
294
|
+
};
|
|
295
|
+
default:
|
|
296
|
+
return {};
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
const containerStyles = {
|
|
300
|
+
...getPositionStyles(),
|
|
301
|
+
display: "inline-flex",
|
|
302
|
+
alignItems: "center",
|
|
303
|
+
gap: formatPx(groupGap),
|
|
304
|
+
maxWidth: "calc(100vw - 32px)",
|
|
305
|
+
overflowX: "auto",
|
|
306
|
+
overflowY: "hidden",
|
|
307
|
+
padding: "4px",
|
|
308
|
+
boxSizing: "border-box",
|
|
309
|
+
scrollbarWidth: "none",
|
|
310
|
+
// Firefox
|
|
311
|
+
msOverflowStyle: "none",
|
|
312
|
+
// IE/Edge
|
|
313
|
+
WebkitOverflowScrolling: "touch",
|
|
314
|
+
pointerEvents: "auto",
|
|
315
|
+
...style
|
|
316
|
+
};
|
|
317
|
+
const combinedClassName = [
|
|
318
|
+
"bubble-toolbar",
|
|
319
|
+
`bubble-toolbar--${position}`,
|
|
320
|
+
`bubble-toolbar--${theme}`,
|
|
321
|
+
className
|
|
322
|
+
].filter(Boolean).join(" ");
|
|
323
|
+
return /* @__PURE__ */ jsx2(BubbleToolbarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
|
|
324
|
+
"div",
|
|
325
|
+
{
|
|
326
|
+
ref,
|
|
327
|
+
role: "toolbar",
|
|
328
|
+
"aria-label": ariaLabel,
|
|
329
|
+
className: combinedClassName,
|
|
330
|
+
style: containerStyles,
|
|
331
|
+
...rest,
|
|
332
|
+
children: [
|
|
333
|
+
groups && groups.length > 0 ? groups.map((groupItems, index) => (
|
|
334
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: The groups array API identifies groups by position; use compound children for keyed groups.
|
|
335
|
+
/* @__PURE__ */ jsx2(BubbleGroup, { children: groupItems }, index)
|
|
336
|
+
)) : null,
|
|
337
|
+
children
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
) });
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
BubbleToolbar.displayName = "BubbleToolbar";
|
|
344
|
+
BubbleToolbar.Group = BubbleGroup;
|
|
345
|
+
|
|
346
|
+
// src/components/BubbleArea.tsx
|
|
347
|
+
import { forwardRef as forwardRef3 } from "react";
|
|
348
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
349
|
+
var BubbleArea = forwardRef3(
|
|
350
|
+
({ children, minWidth = 120, maxWidth, className = "", style, ...rest }, ref) => {
|
|
351
|
+
const areaStyles = {
|
|
352
|
+
display: "inline-flex",
|
|
353
|
+
alignItems: "center",
|
|
354
|
+
minWidth: formatPx(minWidth),
|
|
355
|
+
maxWidth: maxWidth ? formatPx(maxWidth) : void 0,
|
|
356
|
+
flex: "1 1 auto",
|
|
357
|
+
fontSize: "14px",
|
|
358
|
+
color: "inherit",
|
|
359
|
+
...style
|
|
360
|
+
};
|
|
361
|
+
return /* @__PURE__ */ jsx3("div", { ref, className: `bubble-area ${className}`.trim(), style: areaStyles, ...rest, children });
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
BubbleArea.displayName = "BubbleArea";
|
|
365
|
+
|
|
366
|
+
// src/components/BubbleIconButton.tsx
|
|
367
|
+
import { forwardRef as forwardRef4, useState as useState2 } from "react";
|
|
368
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
369
|
+
var ICONS = {
|
|
370
|
+
search: /* @__PURE__ */ jsxs2(
|
|
371
|
+
"svg",
|
|
372
|
+
{
|
|
373
|
+
"aria-hidden": "true",
|
|
374
|
+
focusable: "false",
|
|
375
|
+
width: "18",
|
|
376
|
+
height: "18",
|
|
377
|
+
viewBox: "0 0 24 24",
|
|
378
|
+
fill: "none",
|
|
379
|
+
stroke: "currentColor",
|
|
380
|
+
strokeWidth: "2",
|
|
381
|
+
strokeLinecap: "round",
|
|
382
|
+
strokeLinejoin: "round",
|
|
383
|
+
children: [
|
|
384
|
+
/* @__PURE__ */ jsx4("circle", { cx: "11", cy: "11", r: "8" }),
|
|
385
|
+
/* @__PURE__ */ jsx4("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
theme: /* @__PURE__ */ jsxs2(
|
|
390
|
+
"svg",
|
|
391
|
+
{
|
|
392
|
+
"aria-hidden": "true",
|
|
393
|
+
focusable: "false",
|
|
394
|
+
width: "18",
|
|
395
|
+
height: "18",
|
|
396
|
+
viewBox: "0 0 24 24",
|
|
397
|
+
fill: "none",
|
|
398
|
+
stroke: "currentColor",
|
|
399
|
+
strokeWidth: "2",
|
|
400
|
+
strokeLinecap: "round",
|
|
401
|
+
strokeLinejoin: "round",
|
|
402
|
+
children: [
|
|
403
|
+
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "5" }),
|
|
404
|
+
/* @__PURE__ */ jsx4("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
|
|
405
|
+
/* @__PURE__ */ jsx4("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
|
|
406
|
+
/* @__PURE__ */ jsx4("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }),
|
|
407
|
+
/* @__PURE__ */ jsx4("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }),
|
|
408
|
+
/* @__PURE__ */ jsx4("line", { x1: "1", y1: "12", x2: "3", y2: "12" }),
|
|
409
|
+
/* @__PURE__ */ jsx4("line", { x1: "21", y1: "12", x2: "23", y2: "12" }),
|
|
410
|
+
/* @__PURE__ */ jsx4("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }),
|
|
411
|
+
/* @__PURE__ */ jsx4("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
),
|
|
415
|
+
chat: /* @__PURE__ */ jsx4(
|
|
416
|
+
"svg",
|
|
417
|
+
{
|
|
418
|
+
"aria-hidden": "true",
|
|
419
|
+
focusable: "false",
|
|
420
|
+
width: "18",
|
|
421
|
+
height: "18",
|
|
422
|
+
viewBox: "0 0 24 24",
|
|
423
|
+
fill: "none",
|
|
424
|
+
stroke: "currentColor",
|
|
425
|
+
strokeWidth: "2",
|
|
426
|
+
strokeLinecap: "round",
|
|
427
|
+
strokeLinejoin: "round",
|
|
428
|
+
children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
notifications: /* @__PURE__ */ jsxs2(
|
|
432
|
+
"svg",
|
|
433
|
+
{
|
|
434
|
+
"aria-hidden": "true",
|
|
435
|
+
focusable: "false",
|
|
436
|
+
width: "18",
|
|
437
|
+
height: "18",
|
|
438
|
+
viewBox: "0 0 24 24",
|
|
439
|
+
fill: "none",
|
|
440
|
+
stroke: "currentColor",
|
|
441
|
+
strokeWidth: "2",
|
|
442
|
+
strokeLinecap: "round",
|
|
443
|
+
strokeLinejoin: "round",
|
|
444
|
+
children: [
|
|
445
|
+
/* @__PURE__ */ jsx4("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
446
|
+
/* @__PURE__ */ jsx4("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
447
|
+
]
|
|
448
|
+
}
|
|
449
|
+
),
|
|
450
|
+
logo: /* @__PURE__ */ jsxs2(
|
|
451
|
+
"svg",
|
|
452
|
+
{
|
|
453
|
+
"aria-hidden": "true",
|
|
454
|
+
focusable: "false",
|
|
455
|
+
width: "20",
|
|
456
|
+
height: "20",
|
|
457
|
+
viewBox: "0 0 24 24",
|
|
458
|
+
fill: "none",
|
|
459
|
+
stroke: "currentColor",
|
|
460
|
+
strokeWidth: "2",
|
|
461
|
+
strokeLinecap: "round",
|
|
462
|
+
strokeLinejoin: "round",
|
|
463
|
+
children: [
|
|
464
|
+
/* @__PURE__ */ jsx4("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
465
|
+
/* @__PURE__ */ jsx4("polyline", { points: "2 17 12 22 22 17" }),
|
|
466
|
+
/* @__PURE__ */ jsx4("polyline", { points: "2 12 12 17 22 12" })
|
|
467
|
+
]
|
|
468
|
+
}
|
|
469
|
+
),
|
|
470
|
+
close: /* @__PURE__ */ jsxs2(
|
|
471
|
+
"svg",
|
|
472
|
+
{
|
|
473
|
+
"aria-hidden": "true",
|
|
474
|
+
focusable: "false",
|
|
475
|
+
width: "18",
|
|
476
|
+
height: "18",
|
|
477
|
+
viewBox: "0 0 24 24",
|
|
478
|
+
fill: "none",
|
|
479
|
+
stroke: "currentColor",
|
|
480
|
+
strokeWidth: "2",
|
|
481
|
+
strokeLinecap: "round",
|
|
482
|
+
strokeLinejoin: "round",
|
|
483
|
+
children: [
|
|
484
|
+
/* @__PURE__ */ jsx4("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
485
|
+
/* @__PURE__ */ jsx4("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
486
|
+
]
|
|
487
|
+
}
|
|
488
|
+
)
|
|
489
|
+
};
|
|
490
|
+
var BubbleIconButton = forwardRef4(
|
|
491
|
+
({
|
|
492
|
+
name,
|
|
493
|
+
icon,
|
|
494
|
+
active = false,
|
|
495
|
+
badge,
|
|
496
|
+
tooltip,
|
|
497
|
+
children,
|
|
498
|
+
className = "",
|
|
499
|
+
style,
|
|
500
|
+
onMouseEnter,
|
|
501
|
+
onMouseLeave,
|
|
502
|
+
ariaLabel,
|
|
503
|
+
...rest
|
|
504
|
+
}, ref) => {
|
|
505
|
+
const [isHovered, setIsHovered] = useState2(false);
|
|
506
|
+
const iconContent = icon || (name ? ICONS[name] : null) || children;
|
|
507
|
+
const computedAriaLabel = ariaLabel || tooltip || (name ? `${name} button` : "button");
|
|
508
|
+
const buttonStyles = {
|
|
509
|
+
position: "relative",
|
|
510
|
+
display: "inline-flex",
|
|
511
|
+
alignItems: "center",
|
|
512
|
+
justifyContent: "center",
|
|
513
|
+
width: "36px",
|
|
514
|
+
height: "36px",
|
|
515
|
+
borderRadius: "50%",
|
|
516
|
+
border: "none",
|
|
517
|
+
background: active ? "rgba(0, 0, 0, 0.08)" : isHovered ? "rgba(0, 0, 0, 0.05)" : "transparent",
|
|
518
|
+
color: "inherit",
|
|
519
|
+
cursor: "pointer",
|
|
520
|
+
padding: 0,
|
|
521
|
+
margin: 0,
|
|
522
|
+
outline: "none",
|
|
523
|
+
transition: "background-color 0.15s ease, transform 0.15s ease",
|
|
524
|
+
transform: isHovered ? "scale(1.06)" : "scale(1)",
|
|
525
|
+
flexShrink: 0,
|
|
526
|
+
...style
|
|
527
|
+
};
|
|
528
|
+
const badgeStyles = {
|
|
529
|
+
position: "absolute",
|
|
530
|
+
top: "4px",
|
|
531
|
+
right: "4px",
|
|
532
|
+
minWidth: "7px",
|
|
533
|
+
height: "7px",
|
|
534
|
+
padding: typeof badge === "number" || typeof badge === "string" ? "1px 3px" : 0,
|
|
535
|
+
borderRadius: "9999px",
|
|
536
|
+
backgroundColor: "#ef4444",
|
|
537
|
+
color: "#ffffff",
|
|
538
|
+
fontSize: "9px",
|
|
539
|
+
fontWeight: "bold",
|
|
540
|
+
lineHeight: "1",
|
|
541
|
+
display: "flex",
|
|
542
|
+
alignItems: "center",
|
|
543
|
+
justifyContent: "center",
|
|
544
|
+
boxShadow: "0 0 0 1.5px rgba(255, 255, 255, 0.9)"
|
|
545
|
+
};
|
|
546
|
+
return /* @__PURE__ */ jsxs2(
|
|
547
|
+
"button",
|
|
548
|
+
{
|
|
549
|
+
ref,
|
|
550
|
+
type: "button",
|
|
551
|
+
title: tooltip,
|
|
552
|
+
"aria-label": computedAriaLabel,
|
|
553
|
+
className: `bubble-icon-button ${active ? "bubble-icon-button--active" : ""} ${className}`.trim(),
|
|
554
|
+
style: buttonStyles,
|
|
555
|
+
onMouseEnter: (e) => {
|
|
556
|
+
setIsHovered(true);
|
|
557
|
+
onMouseEnter?.(e);
|
|
558
|
+
},
|
|
559
|
+
onMouseLeave: (e) => {
|
|
560
|
+
setIsHovered(false);
|
|
561
|
+
onMouseLeave?.(e);
|
|
562
|
+
},
|
|
563
|
+
...rest,
|
|
564
|
+
children: [
|
|
565
|
+
iconContent,
|
|
566
|
+
badge ? /* @__PURE__ */ jsx4("span", { className: "bubble-icon-button__badge", style: badgeStyles, children: typeof badge !== "boolean" ? badge : null }) : null
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
);
|
|
572
|
+
BubbleIconButton.displayName = "BubbleIconButton";
|
|
573
|
+
export {
|
|
574
|
+
BubbleArea,
|
|
575
|
+
BubbleGroup,
|
|
576
|
+
BubbleIconButton,
|
|
577
|
+
BubbleToolbar,
|
|
578
|
+
BubbleToolbarContext,
|
|
579
|
+
formatPx,
|
|
580
|
+
getGlassStyles,
|
|
581
|
+
getValidChildren,
|
|
582
|
+
resolveSize,
|
|
583
|
+
useBubbleActivity,
|
|
584
|
+
useBubbleToolbar
|
|
585
|
+
};
|
|
586
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/activity.ts","../src/BubbleGroup.tsx","../src/context.ts","../src/utils/children.ts","../src/utils/styles.ts","../src/BubbleToolbar.tsx","../src/components/BubbleArea.tsx","../src/components/BubbleIconButton.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nexport interface BubbleActivityValue {\n isBusy: boolean;\n run: <T>(task: () => Promise<T>) => Promise<T>;\n}\n\nexport const BubbleActivityContext = createContext<BubbleActivityValue | null>(null);\n\nexport const useBubbleActivity = (): BubbleActivityValue => {\n const activity = useContext(BubbleActivityContext);\n if (!activity) {\n throw new Error('useBubbleActivity must be used inside a BubbleGroup or BubbleToolbar.Group.');\n }\n return activity;\n};\n\nexport const useGroupActivity = (externalBusy: boolean): BubbleActivityValue => {\n const [pending, setPending] = useState(0);\n const mounted = useRef(true);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n const run = useCallback(async <T>(task: () => Promise<T>): Promise<T> => {\n if (mounted.current) {\n setPending((count) => count + 1);\n }\n try {\n return await task();\n } finally {\n if (mounted.current) {\n setPending((count) => count - 1);\n }\n }\n }, []);\n\n const isBusy = externalBusy || pending > 0;\n return useMemo(() => ({ isBusy, run }), [isBusy, run]);\n};\n","import type { CSSProperties } from 'react';\nimport { forwardRef } from 'react';\nimport { BubbleActivityContext, useGroupActivity } from './activity';\nimport { useBubbleToolbar } from './context';\nimport type { BubbleGroupProps, BubbleShape } from './types';\nimport { getValidChildren } from './utils/children';\nimport { formatPx, getGlassStyles, resolveSize } from './utils/styles';\n\nexport const BubbleGroup = forwardRef<HTMLDivElement, BubbleGroupProps>(\n (\n {\n children,\n shape: explicitShape,\n size: explicitSize,\n itemGap: explicitItemGap,\n busy = false,\n activityColors,\n activityDuration,\n className = '',\n style,\n ...rest\n },\n ref,\n ) => {\n const context = useBubbleToolbar();\n const activity = useGroupActivity(Boolean(context.busy || busy));\n const colors = activityColors ?? context.activityColors ?? ['#22d3ee', '#8b5cf6', '#ec4899'];\n const duration = activityDuration ?? context.activityDuration ?? 2.4;\n\n const validChildren = getValidChildren(children);\n const count = validChildren.length;\n\n // Morphological logic:\n // 1 node => circle\n // > 1 node => pill / rounded rectangle\n const computedShape: BubbleShape = explicitShape || (count <= 1 ? 'circle' : 'pill');\n\n const effectiveSize = resolveSize(explicitSize || context.size);\n const effectiveItemGap = explicitItemGap !== undefined ? explicitItemGap : context.itemGap;\n\n const glassStyles = getGlassStyles(\n context.theme,\n context.blurred,\n context.blurAmount,\n context.bordered,\n context.shadow,\n );\n\n const isCircle = computedShape === 'circle';\n\n const groupStyles: CSSProperties & Record<`--bubble-activity-${string}`, string> = {\n '--bubble-activity-color-1': colors[0],\n '--bubble-activity-color-2': colors[1],\n '--bubble-activity-color-3': colors[2],\n '--bubble-activity-duration': `${Number.isFinite(duration) && duration > 0 ? duration : 2.4}s`,\n ...glassStyles,\n height: `${effectiveSize}px`,\n boxSizing: 'border-box',\n display: 'inline-flex',\n alignItems: 'center',\n flexShrink: 0,\n userSelect: 'none',\n ...(isCircle\n ? {\n width: `${effectiveSize}px`,\n minWidth: `${effectiveSize}px`,\n borderRadius: '9999px',\n justifyContent: 'center',\n padding: 0,\n }\n : {\n width: 'auto',\n minWidth: `${effectiveSize}px`,\n borderRadius: '9999px',\n flexDirection: 'row',\n justifyContent: 'flex-start',\n paddingLeft: `${Math.max(12, Math.round(effectiveSize * 0.28))}px`,\n paddingRight: `${Math.max(12, Math.round(effectiveSize * 0.28))}px`,\n gap: formatPx(effectiveItemGap),\n }),\n ...style,\n };\n\n const combinedClassName = [\n 'bubble-group',\n `bubble-group--${computedShape}`,\n activity.isBusy && 'bubble-group--busy',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <BubbleActivityContext.Provider value={activity}>\n {/* biome-ignore lint/a11y/useSemanticElements: This toolbar group is not a form fieldset and exposes an HTMLDivElement ref. */}\n <div\n ref={ref}\n role=\"group\"\n className={combinedClassName}\n style={groupStyles}\n data-shape={computedShape}\n data-items-count={count}\n {...rest}\n aria-busy={activity.isBusy}\n >\n {validChildren}\n </div>\n </BubbleActivityContext.Provider>\n );\n },\n);\n\nBubbleGroup.displayName = 'BubbleGroup';\n","import { createContext, useContext } from 'react';\nimport type { BubbleActivityProps, BubbleToolbarSize, BubbleToolbarTheme } from './types';\n\nexport interface BubbleToolbarContextValue extends BubbleActivityProps {\n size: BubbleToolbarSize;\n theme: BubbleToolbarTheme;\n blurred: boolean;\n blurAmount: number | string;\n itemGap: number | string;\n bordered: boolean;\n shadow: boolean | string;\n}\n\nexport const defaultContextValue: BubbleToolbarContextValue = {\n size: 'md',\n theme: 'glass',\n blurred: true,\n blurAmount: 16,\n itemGap: 8,\n bordered: true,\n shadow: true,\n};\n\nexport const BubbleToolbarContext = createContext<BubbleToolbarContextValue>(defaultContextValue);\n\nexport const useBubbleToolbar = (): BubbleToolbarContextValue => {\n return useContext(BubbleToolbarContext);\n};\n","import type { ReactNode } from 'react';\nimport { Children, Fragment, isValidElement } from 'react';\n\n/**\n * Returns an array of non-null, non-undefined, non-boolean child elements.\n * Unpacks Fragment if encountered at the top level.\n */\nexport function getValidChildren(children: ReactNode): ReactNode[] {\n const result: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (child === null || child === undefined || typeof child === 'boolean') {\n return;\n }\n\n if (isValidElement(child) && child.type === Fragment) {\n const fragmentChildren = getValidChildren((child.props as { children?: ReactNode }).children);\n result.push(...fragmentChildren);\n } else {\n result.push(child);\n }\n });\n\n return result;\n}\n","import type { CSSProperties } from 'react';\nimport type { BubbleToolbarSize, BubbleToolbarTheme } from '../types';\n\nexport function resolveSize(size: BubbleToolbarSize): number {\n if (typeof size === 'number') {\n return size;\n }\n switch (size) {\n case 'sm':\n return 40;\n case 'lg':\n return 56;\n default:\n return 48;\n }\n}\n\nexport function formatPx(val: number | string): string {\n return typeof val === 'number' ? `${val}px` : val;\n}\n\nexport function getGlassStyles(\n theme: BubbleToolbarTheme,\n blurred: boolean,\n blurAmount: number | string,\n bordered: boolean,\n shadow: boolean | string,\n): CSSProperties {\n const blurVal = formatPx(blurAmount);\n\n // Background and border tint based on theme\n let background: string;\n let borderColor: string;\n let color: string;\n\n switch (theme) {\n case 'dark':\n background = blurred ? 'rgba(24, 24, 27, 0.72)' : 'rgba(24, 24, 27, 0.95)';\n borderColor = 'rgba(255, 255, 255, 0.12)';\n color = '#f4f4f5';\n break;\n case 'light':\n background = blurred ? 'rgba(255, 255, 255, 0.75)' : 'rgba(255, 255, 255, 0.95)';\n borderColor = 'rgba(0, 0, 0, 0.08)';\n color = '#18181b';\n break;\n case 'auto':\n background = 'var(--bubble-bg, rgba(255, 255, 255, 0.75))';\n borderColor = 'var(--bubble-border, rgba(0, 0, 0, 0.08))';\n color = 'var(--bubble-fg, #18181b)';\n break;\n default:\n // Neutral luminous frosted glass\n background = blurred ? 'rgba(255, 255, 255, 0.65)' : 'rgba(255, 255, 255, 0.92)';\n borderColor = 'rgba(255, 255, 255, 0.4)';\n color = '#09090b';\n break;\n }\n\n const boxShadow =\n typeof shadow === 'string'\n ? shadow\n : shadow\n ? '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.06)'\n : 'none';\n\n return {\n backgroundColor: background,\n backdropFilter: blurred ? `blur(${blurVal}) saturate(180%)` : undefined,\n WebkitBackdropFilter: blurred ? `blur(${blurVal}) saturate(180%)` : undefined,\n border: bordered ? `1px solid ${borderColor}` : 'none',\n boxShadow,\n color,\n transition: 'all 0.25s cubic-bezier(0.16, 1, 0.3, 1)',\n };\n}\n","import type { CSSProperties, ForwardRefExoticComponent, RefAttributes } from 'react';\nimport { forwardRef, useMemo } from 'react';\nimport { BubbleGroup } from './BubbleGroup';\nimport type { BubbleToolbarContextValue } from './context';\nimport { BubbleToolbarContext } from './context';\nimport type { BubbleToolbarProps } from './types';\nimport { formatPx } from './utils/styles';\n\nexport interface BubbleToolbarComponent\n extends ForwardRefExoticComponent<BubbleToolbarProps & RefAttributes<HTMLDivElement>> {\n Group: typeof BubbleGroup;\n}\n\nexport const BubbleToolbar = forwardRef<HTMLDivElement, BubbleToolbarProps>(\n (\n {\n groups,\n children,\n position = 'bottom',\n theme = 'glass',\n size = 'md',\n blurred = true,\n blurAmount = 16,\n groupGap = 8,\n itemGap = 8,\n bordered = true,\n shadow = true,\n busy = false,\n activityColors,\n activityDuration,\n className = '',\n style,\n ariaLabel = 'Toolbar',\n ...rest\n },\n ref,\n ) => {\n const contextValue = useMemo<BubbleToolbarContextValue>(\n () => ({\n size,\n theme,\n blurred,\n blurAmount,\n itemGap,\n bordered,\n shadow,\n busy,\n activityColors,\n activityDuration,\n }),\n [\n size,\n theme,\n blurred,\n blurAmount,\n itemGap,\n bordered,\n shadow,\n busy,\n activityColors,\n activityDuration,\n ],\n );\n\n // Compute positioning styles\n const getPositionStyles = (): CSSProperties => {\n switch (position) {\n case 'bottom':\n return {\n position: 'fixed',\n bottom: '24px',\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 1000,\n };\n case 'top':\n return {\n position: 'fixed',\n top: '24px',\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: 1000,\n };\n case 'static':\n return {\n position: 'relative',\n };\n default:\n return {};\n }\n };\n\n const containerStyles: CSSProperties = {\n ...getPositionStyles(),\n display: 'inline-flex',\n alignItems: 'center',\n gap: formatPx(groupGap),\n maxWidth: 'calc(100vw - 32px)',\n overflowX: 'auto',\n overflowY: 'hidden',\n padding: '4px',\n boxSizing: 'border-box',\n scrollbarWidth: 'none', // Firefox\n msOverflowStyle: 'none', // IE/Edge\n WebkitOverflowScrolling: 'touch',\n pointerEvents: 'auto',\n ...style,\n };\n\n const combinedClassName = [\n 'bubble-toolbar',\n `bubble-toolbar--${position}`,\n `bubble-toolbar--${theme}`,\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <BubbleToolbarContext.Provider value={contextValue}>\n <div\n ref={ref}\n role=\"toolbar\"\n aria-label={ariaLabel}\n className={combinedClassName}\n style={containerStyles}\n {...rest}\n >\n {groups && groups.length > 0\n ? groups.map((groupItems, index) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: The groups array API identifies groups by position; use compound children for keyed groups.\n <BubbleGroup key={index}>{groupItems}</BubbleGroup>\n ))\n : null}\n {children}\n </div>\n </BubbleToolbarContext.Provider>\n );\n },\n) as BubbleToolbarComponent;\n\nBubbleToolbar.displayName = 'BubbleToolbar';\nBubbleToolbar.Group = BubbleGroup;\n","import type { CSSProperties } from 'react';\nimport { forwardRef } from 'react';\nimport type { BubbleAreaProps } from '../types';\nimport { formatPx } from '../utils/styles';\n\nexport const BubbleArea = forwardRef<HTMLDivElement, BubbleAreaProps>(\n ({ children, minWidth = 120, maxWidth, className = '', style, ...rest }, ref) => {\n const areaStyles: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n minWidth: formatPx(minWidth),\n maxWidth: maxWidth ? formatPx(maxWidth) : undefined,\n flex: '1 1 auto',\n fontSize: '14px',\n color: 'inherit',\n ...style,\n };\n\n return (\n <div ref={ref} className={`bubble-area ${className}`.trim()} style={areaStyles} {...rest}>\n {children}\n </div>\n );\n },\n);\n\nBubbleArea.displayName = 'BubbleArea';\n","import type { CSSProperties, ReactNode } from 'react';\nimport { forwardRef, useState } from 'react';\nimport type { BubbleIconButtonProps } from '../types';\n\n/**\n * Standard inline SVG icons for quick prototyping out-of-the-box\n */\nconst ICONS: Record<string, ReactNode> = {\n search: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n ),\n theme: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"5\" />\n <line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\" />\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\" />\n <line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\" />\n <line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\" />\n <line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\" />\n <line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\" />\n <line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\" />\n <line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\" />\n </svg>\n ),\n chat: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n ),\n notifications: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\" />\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\" />\n </svg>\n ),\n logo: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polygon points=\"12 2 2 7 12 12 22 7 12 2\" />\n <polyline points=\"2 17 12 22 22 17\" />\n <polyline points=\"2 12 12 17 22 12\" />\n </svg>\n ),\n close: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n ),\n};\n\nexport const BubbleIconButton = forwardRef<HTMLButtonElement, BubbleIconButtonProps>(\n (\n {\n name,\n icon,\n active = false,\n badge,\n tooltip,\n children,\n className = '',\n style,\n onMouseEnter,\n onMouseLeave,\n ariaLabel,\n ...rest\n },\n ref,\n ) => {\n const [isHovered, setIsHovered] = useState(false);\n\n const iconContent = icon || (name ? ICONS[name] : null) || children;\n const computedAriaLabel = ariaLabel || tooltip || (name ? `${name} button` : 'button');\n\n const buttonStyles: CSSProperties = {\n position: 'relative',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '36px',\n height: '36px',\n borderRadius: '50%',\n border: 'none',\n background: active\n ? 'rgba(0, 0, 0, 0.08)'\n : isHovered\n ? 'rgba(0, 0, 0, 0.05)'\n : 'transparent',\n color: 'inherit',\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n transition: 'background-color 0.15s ease, transform 0.15s ease',\n transform: isHovered ? 'scale(1.06)' : 'scale(1)',\n flexShrink: 0,\n ...style,\n };\n\n const badgeStyles: CSSProperties = {\n position: 'absolute',\n top: '4px',\n right: '4px',\n minWidth: '7px',\n height: '7px',\n padding: typeof badge === 'number' || typeof badge === 'string' ? '1px 3px' : 0,\n borderRadius: '9999px',\n backgroundColor: '#ef4444',\n color: '#ffffff',\n fontSize: '9px',\n fontWeight: 'bold',\n lineHeight: '1',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 0 0 1.5px rgba(255, 255, 255, 0.9)',\n };\n\n return (\n <button\n ref={ref}\n type=\"button\"\n title={tooltip}\n aria-label={computedAriaLabel}\n className={`bubble-icon-button ${active ? 'bubble-icon-button--active' : ''} ${className}`.trim()}\n style={buttonStyles}\n onMouseEnter={(e) => {\n setIsHovered(true);\n onMouseEnter?.(e);\n }}\n onMouseLeave={(e) => {\n setIsHovered(false);\n onMouseLeave?.(e);\n }}\n {...rest}\n >\n {iconContent}\n {badge ? (\n <span className=\"bubble-icon-button__badge\" style={badgeStyles}>\n {typeof badge !== 'boolean' ? badge : null}\n </span>\n ) : null}\n </button>\n );\n },\n);\n\nBubbleIconButton.displayName = 'BubbleIconButton';\n"],"mappings":"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","names":["createContext","useContext","forwardRef","useMemo","jsx","forwardRef","useMemo","forwardRef","jsx","forwardRef","forwardRef","useState","jsx","jsxs"]}
|