@versini/ui-bubble 6.2.0 → 6.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,98 +1,99 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
-
3
- declare const BUBBLE_CLASSNAME = "av-bubble";
4
-
5
- type BubbleProps = {
6
- /**
7
- * The text to render in the bubble.
8
- */
9
- children: React.ReactNode;
10
- /**
11
- * CSS class(es) to add to the main component wrapper.
12
- * Bubble is made of a wrapper, a main content, and a footer. This prop
13
- * allows you to add classes to the main component wrapper.
14
- */
15
- className?: string;
16
- /**
17
- * CSS class(es) to add to the content wrapper.
18
- * Bubble is made of a wrapper, a main content, and a footer. This prop
19
- * allows you to add classes to the content wrapper.
20
- */
21
- contentClassName?: string;
22
- /**
23
- * Whether or not to show a "copy/paste" icon next to the Bubble.
24
- * - If a function is passed, it will be called with the text to copy.
25
- * - If a string is passed, that string will be copied.
26
- * - If a boolean is passed, the children will be copied, but only if they
27
- * are of type string.
28
- */
29
- copyToClipboard?: boolean | string | ((text: any) => void);
30
- /**
31
- * The type of focus for the Copy Button. This will change the color
32
- * of the focus ring around the Button.
33
- */
34
- copyToClipboardFocusMode?: "dark" | "light" | "system" | "alt-system";
35
- /**
36
- * The mode of Copy Button. This will change the color of the Button.
37
- */
38
- copyToClipboardMode?: "dark" | "light" | "system" | "alt-system";
39
- /**
40
- * Object depicting the extra rows for the Bubble.
41
- * @example
42
- * ```tsx
43
- * <Bubble
44
- * footer={{
45
- * "Sent": "12:00 PM",
46
- * "Delivered": "12:01 PM",
47
- * "Verified": Bubble.FOOTER_EMPTY,
48
- * "Read": "12:02 PM",
49
- * }}
50
- * >Hello World</Bubble>
51
- * ```
52
- * This will create a footer with 4 rows, with the row before last being
53
- * empty but taking the full height of a normal row.
54
- *
55
- */
56
- footer?: {
57
- [key: string]: string | number | undefined | null;
58
- };
59
- /**
60
- * The type of Bubble. This will change the color of the Bubble
61
- * as well as the chevron location.
62
- */
63
- kind?: "left" | "right";
64
- /**
65
- * Same as "footer" but accepts raw JSX.
66
- */
67
- rawFooter?: React.ReactNode;
68
- /**
69
- * Whether or not the Bubble should have a default max-width.
70
- * By default, bubble width will be responsive to the viewport,
71
- * but in some cases, it may be useful to disable this behavior
72
- * and allow the Bubble to grow to its content.
73
- * You can also provide your own container class to control the width,
74
- * based on the container's width.
75
- * @see https://css-tricks.com/css-container-queries/#aa-container-length-units
76
- *
77
- * @example
78
- * ```tsx
79
- * <div> // this div should be declared as a container
80
- * <Bubble kind="left" noMaxWidth className="max-w-[95qcw]">
81
- * Hello World
82
- * </Bubble>
83
- * </div>
84
- * ```
85
- * @default false
86
- */
87
- noMaxWidth?: boolean;
88
- /**
89
- * Whether or not the Bubble should have a tail.
90
- * @default false
91
- */
92
- tail?: boolean;
93
- };
94
-
95
- declare const BUBBLE_FOOTER_EMPTY = "FOOTER_EMPTY";
96
- declare const Bubble: ({ children, kind, className, contentClassName, footer, rawFooter, copyToClipboard, copyToClipboardFocusMode, copyToClipboardMode, noMaxWidth, tail, }: BubbleProps) => react_jsx_runtime.JSX.Element;
97
-
98
- export { BUBBLE_CLASSNAME, BUBBLE_FOOTER_EMPTY, Bubble, type BubbleProps };
1
+ import { JSX } from 'react/jsx-runtime';
2
+
3
+ export declare const Bubble: ({ children, kind, className, contentClassName, footer, rawFooter, copyToClipboard, copyToClipboardFocusMode, copyToClipboardMode, noMaxWidth, tail, }: BubbleProps) => JSX.Element;
4
+
5
+ export declare const BUBBLE_CLASSNAME = "av-bubble";
6
+
7
+ export declare const BUBBLE_FOOTER_EMPTY = "FOOTER_EMPTY";
8
+
9
+ export declare type BubbleProps = {
10
+ /**
11
+ * The text to render in the bubble.
12
+ */
13
+ children: React.ReactNode;
14
+ /**
15
+ * CSS class(es) to add to the main component wrapper.
16
+ * Bubble is made of a wrapper, a main content, and a footer. This prop
17
+ * allows you to add classes to the main component wrapper.
18
+ */
19
+ className?: string;
20
+ /**
21
+ * CSS class(es) to add to the content wrapper.
22
+ * Bubble is made of a wrapper, a main content, and a footer. This prop
23
+ * allows you to add classes to the content wrapper.
24
+ */
25
+ contentClassName?: string;
26
+ /**
27
+ * Whether or not to show a "copy/paste" icon next to the Bubble.
28
+ * - If a function is passed, it will be called with the text to copy.
29
+ * - If a string is passed, that string will be copied.
30
+ * - If a boolean is passed, the children will be copied, but only if they
31
+ * are of type string.
32
+ */
33
+ copyToClipboard?: boolean | string | ((text: any) => void);
34
+ /**
35
+ * The type of focus for the Copy Button. This will change the color
36
+ * of the focus ring around the Button.
37
+ */
38
+ copyToClipboardFocusMode?: "dark" | "light" | "system" | "alt-system";
39
+ /**
40
+ * The mode of Copy Button. This will change the color of the Button.
41
+ */
42
+ copyToClipboardMode?: "dark" | "light" | "system" | "alt-system";
43
+ /**
44
+ * Object depicting the extra rows for the Bubble.
45
+ * @example
46
+ * ```tsx
47
+ * <Bubble
48
+ * footer={{
49
+ * "Sent": "12:00 PM",
50
+ * "Delivered": "12:01 PM",
51
+ * "Verified": Bubble.FOOTER_EMPTY,
52
+ * "Read": "12:02 PM",
53
+ * }}
54
+ * >Hello World</Bubble>
55
+ * ```
56
+ * This will create a footer with 4 rows, with the row before last being
57
+ * empty but taking the full height of a normal row.
58
+ *
59
+ */
60
+ footer?: {
61
+ [key: string]: string | number | undefined | null;
62
+ };
63
+ /**
64
+ * The type of Bubble. This will change the color of the Bubble
65
+ * as well as the chevron location.
66
+ */
67
+ kind?: "left" | "right";
68
+ /**
69
+ * Same as "footer" but accepts raw JSX.
70
+ */
71
+ rawFooter?: React.ReactNode;
72
+ /**
73
+ * Whether or not the Bubble should have a default max-width.
74
+ * By default, bubble width will be responsive to the viewport,
75
+ * but in some cases, it may be useful to disable this behavior
76
+ * and allow the Bubble to grow to its content.
77
+ * You can also provide your own container class to control the width,
78
+ * based on the container's width.
79
+ * @see https://css-tricks.com/css-container-queries/#aa-container-length-units
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * <div> // this div should be declared as a container
84
+ * <Bubble kind="left" noMaxWidth className="max-w-[95qcw]">
85
+ * Hello World
86
+ * </Bubble>
87
+ * </div>
88
+ * ```
89
+ * @default false
90
+ */
91
+ noMaxWidth?: boolean;
92
+ /**
93
+ * Whether or not the Bubble should have a tail.
94
+ * @default false
95
+ */
96
+ tail?: boolean;
97
+ };
98
+
99
+ export { }
package/dist/index.js CHANGED
@@ -1,19 +1,211 @@
1
- import { BUBBLE_CLASSNAME as i, BUBBLE_FOOTER_EMPTY as o, Bubble as E } from "./components/Bubble/Bubble.js";
2
1
  /*!
3
- @versini/ui-bubble v6.2.0
2
+ @versini/ui-bubble v6.3.1
4
3
  © 2025 gizmette.com
5
4
  */
6
5
  try {
7
- window.__VERSINI_UI_BUBBLE__ || (window.__VERSINI_UI_BUBBLE__ = {
8
- version: "6.2.0",
9
- buildTime: "11/03/2025 10:48 AM EST",
10
- homepage: "https://github.com/aversini/ui-components",
11
- license: "MIT"
12
- });
13
- } catch {
6
+ if (!window.__VERSINI_UI_BUBBLE__) {
7
+ window.__VERSINI_UI_BUBBLE__ = {
8
+ version: "6.3.1",
9
+ buildTime: "11/04/2025 10:26 AM EST",
10
+ homepage: "https://github.com/aversini/ui-components",
11
+ license: "MIT",
12
+ };
13
+ }
14
+ } catch (error) {
15
+ // nothing to declare officer
14
16
  }
15
- export {
16
- i as BUBBLE_CLASSNAME,
17
- o as BUBBLE_FOOTER_EMPTY,
18
- E as Bubble
17
+
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ import { ButtonIcon } from "@versini/ui-button";
20
+ import { IconCopied, IconCopy } from "@versini/ui-icons";
21
+ import { useEffect, useState } from "react";
22
+ import clsx from "clsx";
23
+
24
+ ;// CONCATENATED MODULE: ./src/common/constants.ts
25
+ const BUBBLE_CLASSNAME = "av-bubble";
26
+
27
+ ;// CONCATENATED MODULE: external "react/jsx-runtime"
28
+
29
+ ;// CONCATENATED MODULE: external "@versini/ui-button"
30
+
31
+ ;// CONCATENATED MODULE: external "@versini/ui-icons"
32
+
33
+ ;// CONCATENATED MODULE: external "react"
34
+
35
+ ;// CONCATENATED MODULE: external "clsx"
36
+
37
+ ;// CONCATENATED MODULE: ./src/components/Bubble/utilities.ts
38
+
39
+
40
+ const getBubbleSizesClasses = ({ kind, noMaxWidth })=>{
41
+ return clsx("px-4 py-2", {
42
+ "max-w-xs sm:max-w-md md:max-w-2xl": !noMaxWidth,
43
+ "lg:max-w-3xl": kind === "left" && !noMaxWidth
44
+ });
19
45
  };
46
+ const getBubbleColorClasses = ({ kind })=>{
47
+ return clsx({
48
+ "bg-surface-light dark:bg-surface-dark": kind === "left",
49
+ "bg-surface-accent": kind === "right"
50
+ });
51
+ };
52
+ const getBubbleTypographyClasses = ({ kind })=>{
53
+ return clsx("prose prose-dark dark:prose-lighter", "prose-blockquote:my-1", "prose-ol:my-1 prose-ul:my-1", {
54
+ "text-copy-lighter": kind === "right"
55
+ });
56
+ };
57
+ const getBubbleBorderClasses = ({ kind, tail })=>{
58
+ if (tail) {
59
+ return clsx(`${BUBBLE_CLASSNAME}-${kind}-tail`, "rounded-3xl", "relative", "before:content-['']", "before:w-3", "before:h-2", "before:absolute", "before:bottom-0", {
60
+ "last-bubble-right:before:right-[2px] last-bubble-right:before:border-l-[8px] last-bubble-right:before:border-l-surface-accent last-bubble-right:before:rounded-bl-[100%]": kind === "right",
61
+ "last-bubble-left:before:left-[2px] last-bubble-left:before:border-r-[8px] last-bubble-left:before:border-r-surface-light last-bubble-left:dark:before:border-r-surface-dark last-bubble-left:before:rounded-br-[100%]": kind === "left"
62
+ });
63
+ }
64
+ if (!tail) {
65
+ return clsx("rounded-b-xl", {
66
+ "rounded-tr-xl": kind === "left",
67
+ "rounded-tl-xl": kind === "right"
68
+ });
69
+ }
70
+ };
71
+ const getBubbleClasses = ({ kind, className, contentClassName, noMaxWidth, tail })=>{
72
+ const wrapper = clsx(BUBBLE_CLASSNAME, `${BUBBLE_CLASSNAME}-${kind}`, "flex items-start", {
73
+ "flex-row-reverse": kind === "right"
74
+ }, className);
75
+ const main = clsx(`${BUBBLE_CLASSNAME}-content`, "flex flex-col empty:hidden", getBubbleSizesClasses({
76
+ kind,
77
+ noMaxWidth
78
+ }), getBubbleTypographyClasses({
79
+ kind
80
+ }), getBubbleColorClasses({
81
+ kind
82
+ }), getBubbleBorderClasses({
83
+ kind,
84
+ tail
85
+ }), contentClassName);
86
+ const footer = "pr-2 pt-1 text-end text-xs text-copy-light";
87
+ const copyButton = clsx("flex flex-col-reverse sm:flex-row", {
88
+ "ml-2": kind === "left" && !tail,
89
+ "mr-2": kind === "right" && !tail,
90
+ "ml-1": kind === "left" && tail,
91
+ "mr-1": kind === "right" && tail
92
+ });
93
+ return {
94
+ wrapper,
95
+ main,
96
+ footer,
97
+ copyButton
98
+ };
99
+ };
100
+
101
+ ;// CONCATENATED MODULE: ./src/components/Bubble/Bubble.tsx
102
+
103
+
104
+
105
+
106
+
107
+ // Special symbol to represent an empty footer row that should maintain its height
108
+ const BUBBLE_FOOTER_EMPTY = "FOOTER_EMPTY";
109
+ const Bubble = ({ children, kind = "left", className, contentClassName, footer, rawFooter, copyToClipboard, copyToClipboardFocusMode = "system", copyToClipboardMode = "system", noMaxWidth = false, tail = false })=>{
110
+ const [copied, setCopied] = useState(false);
111
+ const bubbleClasses = getBubbleClasses({
112
+ kind,
113
+ className,
114
+ contentClassName,
115
+ noMaxWidth,
116
+ tail
117
+ });
118
+ const isCopyToClipboardEnabled = Boolean(copyToClipboard) && (typeof copyToClipboard === "function" || typeof copyToClipboard === "string" || typeof children === "string");
119
+ // copy to clipboard function
120
+ const handleCopyToClipboard = ()=>{
121
+ setCopied(true);
122
+ if (typeof copyToClipboard === "function") {
123
+ copyToClipboard(children);
124
+ } else if (typeof copyToClipboard === "string") {
125
+ navigator.clipboard.writeText(copyToClipboard);
126
+ } else if (typeof children === "string") {
127
+ navigator.clipboard.writeText(children);
128
+ }
129
+ };
130
+ // after 3 seconds, reset the copied state
131
+ useEffect(()=>{
132
+ let timeoutId;
133
+ if (copied) {
134
+ timeoutId = window.setTimeout(()=>{
135
+ setCopied(false);
136
+ }, 3000);
137
+ }
138
+ return ()=>{
139
+ clearTimeout(timeoutId);
140
+ };
141
+ }, [
142
+ copied
143
+ ]);
144
+ return /*#__PURE__*/ jsxs("div", {
145
+ className: bubbleClasses.wrapper,
146
+ children: [
147
+ /*#__PURE__*/ jsxs("div", {
148
+ children: [
149
+ /*#__PURE__*/ jsx("div", {
150
+ className: bubbleClasses.main,
151
+ children: children
152
+ }),
153
+ footer && Object.keys(footer).map((key, idx)=>{
154
+ const footerValue = footer[key];
155
+ // Handle the FOOTER_EMPTY case
156
+ if (footerValue === BUBBLE_FOOTER_EMPTY) {
157
+ return /*#__PURE__*/ jsx("div", {
158
+ className: "prose-p:m-0",
159
+ children: /*#__PURE__*/ jsx("p", {
160
+ className: bubbleClasses.footer,
161
+ "aria-hidden": "true",
162
+ children: /*#__PURE__*/ jsx("span", {
163
+ className: "invisible",
164
+ children: "\xa0"
165
+ })
166
+ })
167
+ }, `${key}-${idx}`);
168
+ }
169
+ // Handle normal footer values (only if they exist)
170
+ return footerValue ? /*#__PURE__*/ jsx("div", {
171
+ className: "prose-p:m-0",
172
+ children: /*#__PURE__*/ jsxs("p", {
173
+ className: bubbleClasses.footer,
174
+ children: [
175
+ key,
176
+ ": ",
177
+ footerValue
178
+ ]
179
+ })
180
+ }, `${key}-${idx}`) : null;
181
+ }),
182
+ rawFooter && rawFooter
183
+ ]
184
+ }),
185
+ isCopyToClipboardEnabled && /*#__PURE__*/ jsx("div", {
186
+ className: bubbleClasses.copyButton,
187
+ children: /*#__PURE__*/ jsx(ButtonIcon, {
188
+ noBorder: true,
189
+ noBackground: true,
190
+ size: "small",
191
+ mode: copyToClipboardMode,
192
+ focusMode: copyToClipboardFocusMode,
193
+ label: copied ? "Copied to clipboard" : "Copy to clipboard",
194
+ onClick: handleCopyToClipboard,
195
+ disabled: copied,
196
+ children: copied ? /*#__PURE__*/ jsx(IconCopied, {
197
+ size: "size-3"
198
+ }) : /*#__PURE__*/ jsx(IconCopy, {
199
+ size: "size-3"
200
+ })
201
+ })
202
+ })
203
+ ]
204
+ });
205
+ };
206
+
207
+ ;// CONCATENATED MODULE: ./src/components/index.ts
208
+
209
+
210
+
211
+ export { BUBBLE_CLASSNAME, BUBBLE_FOOTER_EMPTY, Bubble };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/ui-bubble",
3
- "version": "6.2.0",
3
+ "version": "6.3.1",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -20,13 +20,13 @@
20
20
  ],
21
21
  "scripts": {
22
22
  "build:check": "tsc",
23
- "build:js": "vite build",
24
- "build:types": "tsup",
25
- "build": "npm-run-all --serial clean build:check build:js build:types",
23
+ "build:js": "rslib build",
24
+ "build:types": "echo 'Types now built with rslib'",
25
+ "build": "npm-run-all --serial clean build:check build:js",
26
26
  "clean": "rimraf dist tmp",
27
- "dev:js": "vite build --watch --mode development",
28
- "dev:types": "tsup --watch src",
29
- "dev": "npm-run-all clean --parallel dev:js dev:types",
27
+ "dev:js": "rslib build --watch",
28
+ "dev:types": "echo 'Types now watched with rslib'",
29
+ "dev": "rslib build --watch",
30
30
  "lint": "biome lint src",
31
31
  "lint:fix": "biome check src --write --no-errors-on-unmatched",
32
32
  "prettier": "biome check --write --no-errors-on-unmatched",
@@ -42,13 +42,13 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@tailwindcss/typography": "0.5.19",
45
- "@versini/ui-button": "8.1.4",
46
- "@versini/ui-icons": "4.14.1",
45
+ "@versini/ui-button": "8.3.0",
46
+ "@versini/ui-icons": "4.15.1",
47
47
  "clsx": "2.1.1",
48
48
  "tailwindcss": "4.1.16"
49
49
  },
50
50
  "sideEffects": [
51
51
  "**/*.css"
52
52
  ],
53
- "gitHead": "6e772b53eddd144bb51e2345c545ff338832d668"
53
+ "gitHead": "2169d82d7a8199466642cad5b4cf01cc3b8a3128"
54
54
  }
@@ -1,236 +0,0 @@
1
- import { jsxs as d, jsx as r } from "react/jsx-runtime";
2
- import { ButtonIcon as I } from "@versini/ui-button";
3
- import { useState as y, useEffect as C } from "react";
4
- import c from "clsx";
5
- const p = "av-bubble", v = ({
6
- children: e,
7
- fill: t,
8
- viewBox: o,
9
- className: i,
10
- defaultViewBox: s,
11
- size: n,
12
- title: l,
13
- semantic: b = !1,
14
- ...f
15
- }) => {
16
- const h = c(n, i);
17
- return /* @__PURE__ */ d(
18
- "svg",
19
- {
20
- xmlns: "http://www.w3.org/2000/svg",
21
- className: h,
22
- viewBox: o || s,
23
- fill: t || "currentColor",
24
- role: "img",
25
- "aria-hidden": !b,
26
- focusable: !1,
27
- ...f,
28
- children: [
29
- l && b && /* @__PURE__ */ r("title", { children: l }),
30
- e
31
- ]
32
- }
33
- );
34
- };
35
- /*!
36
- @versini/ui-svgicon v4.2.2
37
- © 2025 gizmette.com
38
- */
39
- try {
40
- window.__VERSINI_UI_SVGICON__ || (window.__VERSINI_UI_SVGICON__ = {
41
- version: "4.2.2",
42
- buildTime: "10/24/2025 06:42 PM EDT",
43
- homepage: "https://github.com/aversini/ui-components",
44
- license: "MIT"
45
- });
46
- } catch {
47
- }
48
- const E = ({
49
- className: e,
50
- viewBox: t,
51
- title: o,
52
- monotone: i,
53
- ...s
54
- }) => /* @__PURE__ */ d(
55
- v,
56
- {
57
- defaultViewBox: "0 0 448 512",
58
- size: "size-5",
59
- viewBox: t,
60
- className: e,
61
- title: o || "Copied",
62
- ...s,
63
- children: [
64
- /* @__PURE__ */ r(
65
- "path",
66
- {
67
- d: "M0 96v320c0 35.3 28.7 64 64 64h320c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64C28.7 32 0 60.7 0 96m104 160c0-6.1 2.3-12.3 7-17 9.4-9.4 24.6-9.4 33.9 0l47 47 111-111c4.7-4.7 10.8-7 17-7s12.3 2.3 17 7c2.3 2.3 4.1 5 5.3 7.9.6 1.5 1 2.9 1.3 4.4.2 1.1.3 2.2.3 2.2.1 1.2.1 1.2.1 2.5-.1 1.5-.1 1.9-.1 2.3-.1.7-.2 1.5-.3 2.2-.3 1.5-.7 3-1.3 4.4-1.2 2.9-2.9 5.6-5.3 7.9l-128 128c-4.7 4.7-10.8 7-17 7s-12.3-2.3-17-7l-64-64c-4.7-4.7-7-10.8-7-17z",
68
- opacity: ".4"
69
- }
70
- ),
71
- /* @__PURE__ */ r("path", { d: "M337 175c9.4 9.4 9.4 24.6 0 33.9L209 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L303 175c9.4-9.4 24.6-9.4 33.9 0z" })
72
- ]
73
- }
74
- ), V = ({
75
- className: e,
76
- viewBox: t,
77
- title: o,
78
- monotone: i,
79
- ...s
80
- }) => /* @__PURE__ */ r(
81
- v,
82
- {
83
- defaultViewBox: "0 0 512 512",
84
- size: "size-5",
85
- viewBox: t,
86
- className: e,
87
- title: o || "Copy",
88
- ...s,
89
- children: /* @__PURE__ */ r("path", { d: "M64 464h224c8.8 0 16-7.2 16-16v-64h48v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V224c0-35.3 28.7-64 64-64h64v48H64c-8.8 0-16 7.2-16 16v224c0 8.8 7.2 16 16 16m160-160h224c8.8 0 16-7.2 16-16V64c0-8.8-7.2-16-16-16H224c-8.8 0-16 7.2-16 16v224c0 8.8 7.2 16 16 16m-64-16V64c0-35.3 28.7-64 64-64h224c35.3 0 64 28.7 64 64v224c0 35.3-28.7 64-64 64H224c-35.3 0-64-28.7-64-64" })
90
- }
91
- );
92
- /*!
93
- @versini/ui-icons v4.14.1
94
- © 2025 gizmette.com
95
- */
96
- try {
97
- window.__VERSINI_UI_ICONS__ || (window.__VERSINI_UI_ICONS__ = {
98
- version: "4.14.1",
99
- buildTime: "10/24/2025 06:42 PM EDT",
100
- homepage: "https://github.com/aversini/ui-components",
101
- license: "MIT"
102
- });
103
- } catch {
104
- }
105
- const z = ({ kind: e, noMaxWidth: t }) => c("px-4 py-2", {
106
- "max-w-xs sm:max-w-md md:max-w-2xl": !t,
107
- "lg:max-w-3xl": e === "left" && !t
108
- }), S = ({ kind: e }) => c({
109
- "bg-surface-light dark:bg-surface-dark": e === "left",
110
- "bg-surface-accent": e === "right"
111
- }), T = ({ kind: e }) => c(
112
- "prose prose-dark dark:prose-lighter",
113
- "prose-blockquote:my-1",
114
- "prose-ol:my-1 prose-ul:my-1",
115
- {
116
- "text-copy-lighter": e === "right"
117
- }
118
- ), M = ({ kind: e, tail: t }) => {
119
- if (t)
120
- return c(
121
- `${p}-${e}-tail`,
122
- "rounded-3xl",
123
- "relative",
124
- "before:content-['']",
125
- "before:w-3",
126
- "before:h-2",
127
- "before:absolute",
128
- "before:bottom-0",
129
- {
130
- "last-bubble-right:before:right-[2px] last-bubble-right:before:border-l-[8px] last-bubble-right:before:border-l-surface-accent last-bubble-right:before:rounded-bl-[100%]": e === "right",
131
- "last-bubble-left:before:left-[2px] last-bubble-left:before:border-r-[8px] last-bubble-left:before:border-r-surface-light last-bubble-left:dark:before:border-r-surface-dark last-bubble-left:before:rounded-br-[100%]": e === "left"
132
- }
133
- );
134
- if (!t)
135
- return c("rounded-b-xl", {
136
- "rounded-tr-xl": e === "left",
137
- "rounded-tl-xl": e === "right"
138
- });
139
- }, O = ({
140
- kind: e,
141
- className: t,
142
- contentClassName: o,
143
- noMaxWidth: i,
144
- tail: s
145
- }) => {
146
- const n = c(
147
- p,
148
- `${p}-${e}`,
149
- "flex items-start",
150
- {
151
- "flex-row-reverse": e === "right"
152
- },
153
- t
154
- ), l = c(
155
- `${p}-content`,
156
- "flex flex-col empty:hidden",
157
- z({ kind: e, noMaxWidth: i }),
158
- T({ kind: e }),
159
- S({ kind: e }),
160
- M({ kind: e, tail: s }),
161
- o
162
- ), b = "pr-2 pt-1 text-end text-xs text-copy-light", f = c("flex flex-col-reverse sm:flex-row", {
163
- "ml-2": e === "left" && !s,
164
- "mr-2": e === "right" && !s,
165
- "ml-1": e === "left" && s,
166
- "mr-1": e === "right" && s
167
- });
168
- return {
169
- wrapper: n,
170
- main: l,
171
- footer: b,
172
- copyButton: f
173
- };
174
- }, $ = "FOOTER_EMPTY", P = ({
175
- children: e,
176
- kind: t = "left",
177
- className: o,
178
- contentClassName: i,
179
- footer: s,
180
- rawFooter: n,
181
- copyToClipboard: l,
182
- copyToClipboardFocusMode: b = "system",
183
- copyToClipboardMode: f = "system",
184
- noMaxWidth: h = !1,
185
- tail: B = !1
186
- }) => {
187
- const [u, x] = y(!1), m = O({
188
- kind: t,
189
- className: o,
190
- contentClassName: i,
191
- noMaxWidth: h,
192
- tail: B
193
- }), _ = !!l && (typeof l == "function" || typeof l == "string" || typeof e == "string"), N = () => {
194
- x(!0), typeof l == "function" ? l(e) : typeof l == "string" ? navigator.clipboard.writeText(l) : typeof e == "string" && navigator.clipboard.writeText(e);
195
- };
196
- return C(() => {
197
- let a;
198
- return u && (a = window.setTimeout(() => {
199
- x(!1);
200
- }, 3e3)), () => {
201
- clearTimeout(a);
202
- };
203
- }, [u]), /* @__PURE__ */ d("div", { className: m.wrapper, children: [
204
- /* @__PURE__ */ d("div", { children: [
205
- /* @__PURE__ */ r("div", { className: m.main, children: e }),
206
- s && Object.keys(s).map((a, w) => {
207
- const g = s[a];
208
- return g === $ ? /* @__PURE__ */ r("div", { className: "prose-p:m-0", children: /* @__PURE__ */ r("p", { className: m.footer, "aria-hidden": "true", children: /* @__PURE__ */ r("span", { className: "invisible", children: " " }) }) }, `${a}-${w}`) : g ? /* @__PURE__ */ r("div", { className: "prose-p:m-0", children: /* @__PURE__ */ d("p", { className: m.footer, children: [
209
- a,
210
- ": ",
211
- g
212
- ] }) }, `${a}-${w}`) : null;
213
- }),
214
- n && n
215
- ] }),
216
- _ && /* @__PURE__ */ r("div", { className: m.copyButton, children: /* @__PURE__ */ r(
217
- I,
218
- {
219
- noBorder: !0,
220
- noBackground: !0,
221
- size: "small",
222
- mode: f,
223
- focusMode: b,
224
- label: u ? "Copied to clipboard" : "Copy to clipboard",
225
- onClick: N,
226
- disabled: u,
227
- children: u ? /* @__PURE__ */ r(E, { size: "size-3" }) : /* @__PURE__ */ r(V, { size: "size-3" })
228
- }
229
- ) })
230
- ] });
231
- };
232
- export {
233
- p as BUBBLE_CLASSNAME,
234
- $ as BUBBLE_FOOTER_EMPTY,
235
- P as Bubble
236
- };