@neoptocom/neopto-ui 0.11.0 → 0.12.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/dist/index.cjs +32 -9
- package/dist/index.d.cts +21 -3
- package/dist/index.d.ts +21 -3
- package/dist/index.js +32 -10
- package/dist/styles.css +0 -2
- package/package.json +1 -1
- package/src/components/Button.tsx +1 -1
- package/src/components/Input.tsx +14 -7
- package/src/components/MessageBubble.tsx +43 -0
- package/src/components/Typo.tsx +0 -3
- package/src/index.ts +3 -1
- package/src/stories/Input.stories.tsx +11 -0
- package/src/stories/MessageBubble.stories.tsx +135 -0
- package/src/stories/Modal.stories.tsx +2 -2
- package/src/styles/library.css +4 -0
- package/src/styles/tailwind.css +3 -0
- package/src/styles/tokens.css +0 -2
package/dist/index.cjs
CHANGED
|
@@ -230,20 +230,23 @@ function Card({
|
|
|
230
230
|
);
|
|
231
231
|
}
|
|
232
232
|
var Input = React2__namespace.forwardRef(
|
|
233
|
-
({ className, disabled, ...props }, ref) => {
|
|
233
|
+
({ className, disabled, variant = "default", ...props }, ref) => {
|
|
234
|
+
const isBorderless = variant === "borderless";
|
|
234
235
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
235
236
|
"input",
|
|
236
237
|
{
|
|
237
238
|
ref,
|
|
238
239
|
disabled,
|
|
239
240
|
className: [
|
|
240
|
-
"w-full h-12 px-4 rounded-full
|
|
241
|
+
"w-full h-12 px-4 rounded-full bg-transparent outline-none transition-colors",
|
|
241
242
|
"text-sm placeholder:text-[var(--muted-fg)]",
|
|
242
|
-
|
|
243
|
+
!isBorderless && "border",
|
|
244
|
+
disabled ? "text-[#3F424F] cursor-not-allowed" + (isBorderless ? "" : " border-[#3F424F]") : [
|
|
243
245
|
"text-[var(--muted-fg)]",
|
|
244
|
-
"border-[var(--muted-fg)]",
|
|
245
|
-
"hover:border-[var(--border)]",
|
|
246
|
-
"focus:
|
|
246
|
+
isBorderless ? "" : "border-[var(--muted-fg)]",
|
|
247
|
+
isBorderless ? "" : "hover:border-[var(--border)]",
|
|
248
|
+
"focus:text-[var(--fg)]",
|
|
249
|
+
isBorderless ? "" : "focus:border-[var(--color-brand)]"
|
|
247
250
|
].join(" "),
|
|
248
251
|
className
|
|
249
252
|
].join(" "),
|
|
@@ -343,7 +346,6 @@ var typoStyles = {
|
|
|
343
346
|
"button": { fontSize: "16px", lineHeight: "24px", letterSpacing: "0" }
|
|
344
347
|
};
|
|
345
348
|
function getTypoClasses(weight = "normal", muted, className) {
|
|
346
|
-
const base = "text-current";
|
|
347
349
|
const weights = {
|
|
348
350
|
normal: "font-normal",
|
|
349
351
|
medium: "font-medium",
|
|
@@ -351,7 +353,6 @@ function getTypoClasses(weight = "normal", muted, className) {
|
|
|
351
353
|
bold: "font-bold"
|
|
352
354
|
};
|
|
353
355
|
return [
|
|
354
|
-
base,
|
|
355
356
|
weights[weight],
|
|
356
357
|
muted ? "text-[var(--muted-fg)]" : "",
|
|
357
358
|
className
|
|
@@ -988,7 +989,7 @@ function Search({
|
|
|
988
989
|
);
|
|
989
990
|
}
|
|
990
991
|
function getButtonClasses(variant = "primary", size = "md", fullWidth, className) {
|
|
991
|
-
const base = "cursor-pointer inline-flex items-center justify-center gap-2 rounded-[
|
|
992
|
+
const base = "cursor-pointer inline-flex items-center justify-center gap-2 rounded-[1.875rem] transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-cyan-500/40 disabled:cursor-not-allowed disabled:opacity-50";
|
|
992
993
|
const variants = {
|
|
993
994
|
primary: "bg-cyan-500 text-white hover:bg-cyan-400 active:bg-cyan-600 disabled:bg-neutral-400",
|
|
994
995
|
secondary: "border border-cyan-500 text-cyan-500 bg-transparent hover:bg-cyan-50 active:bg-cyan-100 disabled:border-neutral-400 disabled:text-neutral-400",
|
|
@@ -1290,6 +1291,27 @@ var AgentButton = ({
|
|
|
1290
1291
|
);
|
|
1291
1292
|
};
|
|
1292
1293
|
var AgentButton_default = AgentButton;
|
|
1294
|
+
var MessageBubble = React2__namespace.forwardRef(
|
|
1295
|
+
({ direction, color, children, className, ...props }, ref) => {
|
|
1296
|
+
const borderRadiusClass = direction === "left" ? "[border-radius:16px_16px_16px_2px]" : direction === "right" ? "[border-radius:16px_16px_2px_16px]" : "rounded-2xl";
|
|
1297
|
+
const backgroundColor = color || "var(--muted)";
|
|
1298
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1299
|
+
"div",
|
|
1300
|
+
{
|
|
1301
|
+
ref,
|
|
1302
|
+
className: [
|
|
1303
|
+
"px-4 py-2 inline-block",
|
|
1304
|
+
borderRadiusClass,
|
|
1305
|
+
className
|
|
1306
|
+
].filter(Boolean).join(" "),
|
|
1307
|
+
style: { backgroundColor },
|
|
1308
|
+
...props,
|
|
1309
|
+
children
|
|
1310
|
+
}
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
);
|
|
1314
|
+
MessageBubble.displayName = "MessageBubble";
|
|
1293
1315
|
|
|
1294
1316
|
exports.AgentButton = AgentButton_default;
|
|
1295
1317
|
exports.AnimatedBgCircle = AnimatedBgCircle_default;
|
|
@@ -1306,6 +1328,7 @@ exports.Counter = Counter;
|
|
|
1306
1328
|
exports.Icon = Icon;
|
|
1307
1329
|
exports.IconButton = IconButton;
|
|
1308
1330
|
exports.Input = Input;
|
|
1331
|
+
exports.MessageBubble = MessageBubble;
|
|
1309
1332
|
exports.Modal = Modal;
|
|
1310
1333
|
exports.Search = Search;
|
|
1311
1334
|
exports.Skeleton = Skeleton;
|
package/dist/index.d.cts
CHANGED
|
@@ -50,8 +50,14 @@ type CardProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
50
50
|
};
|
|
51
51
|
declare function Card({ children, className, style, showDecorations, ...props }: CardProps): react_jsx_runtime.JSX.Element;
|
|
52
52
|
|
|
53
|
-
type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'
|
|
54
|
-
|
|
53
|
+
type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & {
|
|
54
|
+
/** Input visual variant */
|
|
55
|
+
variant?: "default" | "borderless";
|
|
56
|
+
};
|
|
57
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
58
|
+
/** Input visual variant */
|
|
59
|
+
variant?: "default" | "borderless";
|
|
60
|
+
} & React.RefAttributes<HTMLInputElement>>;
|
|
55
61
|
|
|
56
62
|
type ModalProps = {
|
|
57
63
|
/** Whether the modal is open */
|
|
@@ -291,4 +297,16 @@ interface AnimatedBgRectangleProps {
|
|
|
291
297
|
}
|
|
292
298
|
declare const AnimatedBgRectangle: ({ colors, delay }: AnimatedBgRectangleProps) => react_jsx_runtime.JSX.Element;
|
|
293
299
|
|
|
294
|
-
|
|
300
|
+
type MessageBubbleProps = {
|
|
301
|
+
/** Direction of the message bubble, affects border radius */
|
|
302
|
+
direction?: "left" | "right";
|
|
303
|
+
/** Custom background color (CSS color value) */
|
|
304
|
+
color?: string;
|
|
305
|
+
/** Content to display inside the bubble */
|
|
306
|
+
children: React.ReactNode;
|
|
307
|
+
/** Additional CSS classes */
|
|
308
|
+
className?: string;
|
|
309
|
+
};
|
|
310
|
+
declare const MessageBubble: React.ForwardRefExoticComponent<MessageBubbleProps & React.RefAttributes<HTMLDivElement>>;
|
|
311
|
+
|
|
312
|
+
export { AgentButton, type AgentButtonProps, AnimatedBgCircle, AnimatedBgRectangle, AppBackground, type AppBackgroundProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BackgroundBlur, type BackgroundBlurProps, Button, type ButtonProps, Card, type CardProps, Chip, type ChipProps, Counter, type CounterProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, MessageBubble, type MessageBubbleProps, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Skeleton, type SkeletonProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
|
package/dist/index.d.ts
CHANGED
|
@@ -50,8 +50,14 @@ type CardProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
50
50
|
};
|
|
51
51
|
declare function Card({ children, className, style, showDecorations, ...props }: CardProps): react_jsx_runtime.JSX.Element;
|
|
52
52
|
|
|
53
|
-
type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'
|
|
54
|
-
|
|
53
|
+
type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & {
|
|
54
|
+
/** Input visual variant */
|
|
55
|
+
variant?: "default" | "borderless";
|
|
56
|
+
};
|
|
57
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
|
|
58
|
+
/** Input visual variant */
|
|
59
|
+
variant?: "default" | "borderless";
|
|
60
|
+
} & React.RefAttributes<HTMLInputElement>>;
|
|
55
61
|
|
|
56
62
|
type ModalProps = {
|
|
57
63
|
/** Whether the modal is open */
|
|
@@ -291,4 +297,16 @@ interface AnimatedBgRectangleProps {
|
|
|
291
297
|
}
|
|
292
298
|
declare const AnimatedBgRectangle: ({ colors, delay }: AnimatedBgRectangleProps) => react_jsx_runtime.JSX.Element;
|
|
293
299
|
|
|
294
|
-
|
|
300
|
+
type MessageBubbleProps = {
|
|
301
|
+
/** Direction of the message bubble, affects border radius */
|
|
302
|
+
direction?: "left" | "right";
|
|
303
|
+
/** Custom background color (CSS color value) */
|
|
304
|
+
color?: string;
|
|
305
|
+
/** Content to display inside the bubble */
|
|
306
|
+
children: React.ReactNode;
|
|
307
|
+
/** Additional CSS classes */
|
|
308
|
+
className?: string;
|
|
309
|
+
};
|
|
310
|
+
declare const MessageBubble: React.ForwardRefExoticComponent<MessageBubbleProps & React.RefAttributes<HTMLDivElement>>;
|
|
311
|
+
|
|
312
|
+
export { AgentButton, type AgentButtonProps, AnimatedBgCircle, AnimatedBgRectangle, AppBackground, type AppBackgroundProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BackgroundBlur, type BackgroundBlurProps, Button, type ButtonProps, Card, type CardProps, Chip, type ChipProps, Counter, type CounterProps, Icon, IconButton, type IconButtonProps, type IconProps, Input, type InputProps, MessageBubble, type MessageBubbleProps, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Skeleton, type SkeletonProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
|
package/dist/index.js
CHANGED
|
@@ -209,20 +209,23 @@ function Card({
|
|
|
209
209
|
);
|
|
210
210
|
}
|
|
211
211
|
var Input = React2.forwardRef(
|
|
212
|
-
({ className, disabled, ...props }, ref) => {
|
|
212
|
+
({ className, disabled, variant = "default", ...props }, ref) => {
|
|
213
|
+
const isBorderless = variant === "borderless";
|
|
213
214
|
return /* @__PURE__ */ jsx(
|
|
214
215
|
"input",
|
|
215
216
|
{
|
|
216
217
|
ref,
|
|
217
218
|
disabled,
|
|
218
219
|
className: [
|
|
219
|
-
"w-full h-12 px-4 rounded-full
|
|
220
|
+
"w-full h-12 px-4 rounded-full bg-transparent outline-none transition-colors",
|
|
220
221
|
"text-sm placeholder:text-[var(--muted-fg)]",
|
|
221
|
-
|
|
222
|
+
!isBorderless && "border",
|
|
223
|
+
disabled ? "text-[#3F424F] cursor-not-allowed" + (isBorderless ? "" : " border-[#3F424F]") : [
|
|
222
224
|
"text-[var(--muted-fg)]",
|
|
223
|
-
"border-[var(--muted-fg)]",
|
|
224
|
-
"hover:border-[var(--border)]",
|
|
225
|
-
"focus:
|
|
225
|
+
isBorderless ? "" : "border-[var(--muted-fg)]",
|
|
226
|
+
isBorderless ? "" : "hover:border-[var(--border)]",
|
|
227
|
+
"focus:text-[var(--fg)]",
|
|
228
|
+
isBorderless ? "" : "focus:border-[var(--color-brand)]"
|
|
226
229
|
].join(" "),
|
|
227
230
|
className
|
|
228
231
|
].join(" "),
|
|
@@ -322,7 +325,6 @@ var typoStyles = {
|
|
|
322
325
|
"button": { fontSize: "16px", lineHeight: "24px", letterSpacing: "0" }
|
|
323
326
|
};
|
|
324
327
|
function getTypoClasses(weight = "normal", muted, className) {
|
|
325
|
-
const base = "text-current";
|
|
326
328
|
const weights = {
|
|
327
329
|
normal: "font-normal",
|
|
328
330
|
medium: "font-medium",
|
|
@@ -330,7 +332,6 @@ function getTypoClasses(weight = "normal", muted, className) {
|
|
|
330
332
|
bold: "font-bold"
|
|
331
333
|
};
|
|
332
334
|
return [
|
|
333
|
-
base,
|
|
334
335
|
weights[weight],
|
|
335
336
|
muted ? "text-[var(--muted-fg)]" : "",
|
|
336
337
|
className
|
|
@@ -967,7 +968,7 @@ function Search({
|
|
|
967
968
|
);
|
|
968
969
|
}
|
|
969
970
|
function getButtonClasses(variant = "primary", size = "md", fullWidth, className) {
|
|
970
|
-
const base = "cursor-pointer inline-flex items-center justify-center gap-2 rounded-[
|
|
971
|
+
const base = "cursor-pointer inline-flex items-center justify-center gap-2 rounded-[1.875rem] transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-cyan-500/40 disabled:cursor-not-allowed disabled:opacity-50";
|
|
971
972
|
const variants = {
|
|
972
973
|
primary: "bg-cyan-500 text-white hover:bg-cyan-400 active:bg-cyan-600 disabled:bg-neutral-400",
|
|
973
974
|
secondary: "border border-cyan-500 text-cyan-500 bg-transparent hover:bg-cyan-50 active:bg-cyan-100 disabled:border-neutral-400 disabled:text-neutral-400",
|
|
@@ -1269,5 +1270,26 @@ var AgentButton = ({
|
|
|
1269
1270
|
);
|
|
1270
1271
|
};
|
|
1271
1272
|
var AgentButton_default = AgentButton;
|
|
1273
|
+
var MessageBubble = React2.forwardRef(
|
|
1274
|
+
({ direction, color, children, className, ...props }, ref) => {
|
|
1275
|
+
const borderRadiusClass = direction === "left" ? "[border-radius:16px_16px_16px_2px]" : direction === "right" ? "[border-radius:16px_16px_2px_16px]" : "rounded-2xl";
|
|
1276
|
+
const backgroundColor = color || "var(--muted)";
|
|
1277
|
+
return /* @__PURE__ */ jsx(
|
|
1278
|
+
"div",
|
|
1279
|
+
{
|
|
1280
|
+
ref,
|
|
1281
|
+
className: [
|
|
1282
|
+
"px-4 py-2 inline-block",
|
|
1283
|
+
borderRadiusClass,
|
|
1284
|
+
className
|
|
1285
|
+
].filter(Boolean).join(" "),
|
|
1286
|
+
style: { backgroundColor },
|
|
1287
|
+
...props,
|
|
1288
|
+
children
|
|
1289
|
+
}
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
);
|
|
1293
|
+
MessageBubble.displayName = "MessageBubble";
|
|
1272
1294
|
|
|
1273
|
-
export { AgentButton_default as AgentButton, AnimatedBgCircle_default as AnimatedBgCircle, AnimatedBgRectangle_default as AnimatedBgRectangle, AppBackground, Autocomplete, Avatar, AvatarGroup, BackgroundBlur, Button, Card, Chip, Counter, Icon, IconButton, Input, Modal, Search, Skeleton, Typo, assets_exports as assets };
|
|
1295
|
+
export { AgentButton_default as AgentButton, AnimatedBgCircle_default as AnimatedBgCircle, AnimatedBgRectangle_default as AnimatedBgRectangle, AppBackground, Autocomplete, Avatar, AvatarGroup, BackgroundBlur, Button, Card, Chip, Counter, Icon, IconButton, Input, MessageBubble, Modal, Search, Skeleton, Typo, assets_exports as assets };
|
package/dist/styles.css
CHANGED
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
--radius-md: 0.375rem;
|
|
26
26
|
--radius-lg: 0.5rem;
|
|
27
27
|
--radius-xl: 0.75rem;
|
|
28
|
-
--radius-2xl: 1.875rem;
|
|
29
28
|
--bg: #F3F4F6;
|
|
30
29
|
--surface: #FFFFFF;
|
|
31
30
|
--fg: #242832;
|
|
@@ -47,7 +46,6 @@
|
|
|
47
46
|
--radius-md: 0.375rem;
|
|
48
47
|
--radius-lg: 0.5rem;
|
|
49
48
|
--radius-xl: 0.75rem;
|
|
50
|
-
--radius-2xl: 1.875rem;
|
|
51
49
|
--bg: #F3F4F6;
|
|
52
50
|
--surface: #FFFFFF;
|
|
53
51
|
--fg: #242832;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neoptocom/neopto-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A modern React component library built with Tailwind CSS v4 and TypeScript. Features dark mode, design tokens, and comprehensive Storybook documentation. Requires Tailwind v4+.",
|
|
6
6
|
"keywords": [
|
|
@@ -18,7 +18,7 @@ function getButtonClasses(
|
|
|
18
18
|
className?: string
|
|
19
19
|
): string {
|
|
20
20
|
const base =
|
|
21
|
-
"cursor-pointer inline-flex items-center justify-center gap-2 rounded-[
|
|
21
|
+
"cursor-pointer inline-flex items-center justify-center gap-2 rounded-[1.875rem] transition-colors " +
|
|
22
22
|
"focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-cyan-500/40 " +
|
|
23
23
|
"disabled:cursor-not-allowed disabled:opacity-50";
|
|
24
24
|
|
package/src/components/Input.tsx
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'
|
|
3
|
+
export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & {
|
|
4
|
+
/** Input visual variant */
|
|
5
|
+
variant?: "default" | "borderless";
|
|
6
|
+
};
|
|
4
7
|
|
|
5
8
|
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
6
|
-
({ className, disabled, ...props }, ref) => {
|
|
9
|
+
({ className, disabled, variant = "default", ...props }, ref) => {
|
|
10
|
+
const isBorderless = variant === "borderless";
|
|
11
|
+
|
|
7
12
|
return (
|
|
8
13
|
<input
|
|
9
14
|
ref={ref}
|
|
10
15
|
disabled={disabled}
|
|
11
16
|
className={[
|
|
12
|
-
"w-full h-12 px-4 rounded-full
|
|
17
|
+
"w-full h-12 px-4 rounded-full bg-transparent outline-none transition-colors",
|
|
13
18
|
"text-sm placeholder:text-[var(--muted-fg)]",
|
|
19
|
+
!isBorderless && "border",
|
|
14
20
|
disabled
|
|
15
|
-
? "
|
|
21
|
+
? "text-[#3F424F] cursor-not-allowed" + (isBorderless ? "" : " border-[#3F424F]")
|
|
16
22
|
: [
|
|
17
23
|
"text-[var(--muted-fg)]",
|
|
18
|
-
"border-[var(--muted-fg)]",
|
|
19
|
-
"hover:border-[var(--border)]",
|
|
20
|
-
"focus:
|
|
24
|
+
isBorderless ? "" : "border-[var(--muted-fg)]",
|
|
25
|
+
isBorderless ? "" : "hover:border-[var(--border)]",
|
|
26
|
+
"focus:text-[var(--fg)]",
|
|
27
|
+
isBorderless ? "" : "focus:border-[var(--color-brand)]"
|
|
21
28
|
].join(" "),
|
|
22
29
|
className
|
|
23
30
|
].join(" ")}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export type MessageBubbleProps = {
|
|
4
|
+
/** Direction of the message bubble, affects border radius */
|
|
5
|
+
direction?: "left" | "right";
|
|
6
|
+
/** Custom background color (CSS color value) */
|
|
7
|
+
color?: string;
|
|
8
|
+
/** Content to display inside the bubble */
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
/** Additional CSS classes */
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const MessageBubble = React.forwardRef<HTMLDivElement, MessageBubbleProps>(
|
|
15
|
+
({ direction, color, children, className, ...props }, ref) => {
|
|
16
|
+
const borderRadiusClass =
|
|
17
|
+
direction === "left"
|
|
18
|
+
? "[border-radius:16px_16px_16px_2px]"
|
|
19
|
+
: direction === "right"
|
|
20
|
+
? "[border-radius:16px_16px_2px_16px]"
|
|
21
|
+
: "rounded-2xl";
|
|
22
|
+
|
|
23
|
+
const backgroundColor = color || "var(--muted)";
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
ref={ref}
|
|
28
|
+
className={[
|
|
29
|
+
"px-4 py-2 inline-block",
|
|
30
|
+
borderRadiusClass,
|
|
31
|
+
className
|
|
32
|
+
].filter(Boolean).join(" ")}
|
|
33
|
+
style={{ backgroundColor }}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
MessageBubble.displayName = "MessageBubble";
|
|
43
|
+
|
package/src/components/Typo.tsx
CHANGED
|
@@ -41,8 +41,6 @@ function getTypoClasses(
|
|
|
41
41
|
muted?: boolean,
|
|
42
42
|
className?: string
|
|
43
43
|
): string {
|
|
44
|
-
const base = "text-current";
|
|
45
|
-
|
|
46
44
|
const weights: Record<TypoWeight, string> = {
|
|
47
45
|
normal: "font-normal",
|
|
48
46
|
medium: "font-medium",
|
|
@@ -51,7 +49,6 @@ function getTypoClasses(
|
|
|
51
49
|
};
|
|
52
50
|
|
|
53
51
|
return [
|
|
54
|
-
base,
|
|
55
52
|
weights[weight],
|
|
56
53
|
muted ? "text-[var(--muted-fg)]" : "",
|
|
57
54
|
className
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export { default as Icon } from "./components/Icon";
|
|
|
19
19
|
export { default as Chip } from "./components/Chip";
|
|
20
20
|
export { default as Counter } from "./components/Counter";
|
|
21
21
|
export * from "./components/Chat";
|
|
22
|
+
export * from "./components/MessageBubble";
|
|
22
23
|
|
|
23
24
|
// Types
|
|
24
25
|
export type { AppBackgroundProps } from "./components/AppBackground";
|
|
@@ -37,4 +38,5 @@ export type { IconButtonProps } from "./components/IconButton";
|
|
|
37
38
|
export type { IconProps } from "./components/Icon";
|
|
38
39
|
export type { ChipProps } from "./components/Chip";
|
|
39
40
|
export type { CounterProps } from "./components/Counter";
|
|
40
|
-
export type { AgentButtonProps } from "./components/Chat";
|
|
41
|
+
export type { AgentButtonProps } from "./components/Chat";
|
|
42
|
+
export type { MessageBubbleProps } from "./components/MessageBubble";
|
|
@@ -36,3 +36,14 @@ export const Types: Story = {
|
|
|
36
36
|
</div>
|
|
37
37
|
)
|
|
38
38
|
};
|
|
39
|
+
|
|
40
|
+
export const Borderless: Story = {
|
|
41
|
+
render: () => (
|
|
42
|
+
<div className="flex flex-col gap-4 w-96">
|
|
43
|
+
<Input variant="borderless" placeholder="Borderless input" type="text" />
|
|
44
|
+
<Input variant="borderless" placeholder="Borderless email" type="email" />
|
|
45
|
+
<Input variant="borderless" placeholder="Borderless search..." />
|
|
46
|
+
<Input variant="borderless" placeholder="Disabled borderless" disabled />
|
|
47
|
+
</div>
|
|
48
|
+
)
|
|
49
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { MessageBubble } from "../components/MessageBubble";
|
|
3
|
+
import Typo from "../components/Typo";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof MessageBubble> = {
|
|
6
|
+
title: "Components/MessageBubble",
|
|
7
|
+
component: MessageBubble
|
|
8
|
+
};
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof MessageBubble>;
|
|
11
|
+
|
|
12
|
+
export const Default: Story = {
|
|
13
|
+
render: () => (
|
|
14
|
+
<div className="flex flex-col gap-4 max-w-md p-4">
|
|
15
|
+
<MessageBubble>
|
|
16
|
+
<Typo variant="title-sm">Hello! This is a default message bubble with no direction.</Typo>
|
|
17
|
+
</MessageBubble>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const Directions: Story = {
|
|
23
|
+
render: () => (
|
|
24
|
+
<div className="flex flex-col gap-4 max-w-md p-4">
|
|
25
|
+
<div className="flex justify-start">
|
|
26
|
+
<MessageBubble direction="left">
|
|
27
|
+
<Typo variant="title-sm">This is a left-aligned message bubble.</Typo>
|
|
28
|
+
</MessageBubble>
|
|
29
|
+
</div>
|
|
30
|
+
<div className="flex justify-end">
|
|
31
|
+
<MessageBubble direction="right">
|
|
32
|
+
<Typo variant="title-sm">This is a right-aligned message bubble.</Typo>
|
|
33
|
+
</MessageBubble>
|
|
34
|
+
</div>
|
|
35
|
+
<div className="flex justify-start">
|
|
36
|
+
<MessageBubble direction="left">
|
|
37
|
+
<Typo variant="title-sm">Messages from the left typically have the small radius on bottom-left corner.</Typo>
|
|
38
|
+
</MessageBubble>
|
|
39
|
+
</div>
|
|
40
|
+
<div className="flex justify-end">
|
|
41
|
+
<MessageBubble direction="right">
|
|
42
|
+
<Typo variant="title-sm">Messages from the right have the small radius on bottom-right corner.</Typo>
|
|
43
|
+
</MessageBubble>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const CustomColors: Story = {
|
|
50
|
+
render: () => (
|
|
51
|
+
<div className="flex flex-col gap-4 max-w-md p-4">
|
|
52
|
+
<div className="flex justify-start">
|
|
53
|
+
<MessageBubble direction="left" color="#E3F2FD">
|
|
54
|
+
<Typo variant="title-sm" className="text-[#1565C0]">Light blue message</Typo>
|
|
55
|
+
</MessageBubble>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="flex justify-end">
|
|
58
|
+
<MessageBubble direction="right" color="#1976D2">
|
|
59
|
+
<Typo variant="title-sm" className="text-white">Blue message with white text</Typo>
|
|
60
|
+
</MessageBubble>
|
|
61
|
+
</div>
|
|
62
|
+
<div className="flex justify-start">
|
|
63
|
+
<MessageBubble direction="left" color="#F3E5F5">
|
|
64
|
+
<Typo variant="title-sm" className="text-[#7B1FA2]">Purple tinted message</Typo>
|
|
65
|
+
</MessageBubble>
|
|
66
|
+
</div>
|
|
67
|
+
<div className="flex justify-end">
|
|
68
|
+
<MessageBubble direction="right" color="#E8F5E9">
|
|
69
|
+
<Typo variant="title-sm" className="text-[#2E7D32]">Green message</Typo>
|
|
70
|
+
</MessageBubble>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const ChatConversation: Story = {
|
|
77
|
+
render: () => (
|
|
78
|
+
<div className="flex flex-col gap-3 max-w-2xl p-4">
|
|
79
|
+
<div className="flex justify-start">
|
|
80
|
+
<MessageBubble direction="left" color="#F5F5F5">
|
|
81
|
+
<Typo variant="title-sm" className="text-[#333]">Hey! How can I help you today?</Typo>
|
|
82
|
+
</MessageBubble>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="flex justify-end">
|
|
85
|
+
<MessageBubble direction="right" color="var(--color-brand)">
|
|
86
|
+
<Typo variant="title-sm" className="text-white">I need help with my account settings.</Typo>
|
|
87
|
+
</MessageBubble>
|
|
88
|
+
</div>
|
|
89
|
+
<div className="flex justify-start">
|
|
90
|
+
<MessageBubble direction="left" color="#F5F5F5">
|
|
91
|
+
<Typo variant="title-sm" className="text-[#333]">
|
|
92
|
+
Sure! I can help you with that. What specific setting would you like to change?
|
|
93
|
+
</Typo>
|
|
94
|
+
</MessageBubble>
|
|
95
|
+
</div>
|
|
96
|
+
<div className="flex justify-end">
|
|
97
|
+
<MessageBubble direction="right" color="var(--color-brand)">
|
|
98
|
+
<Typo variant="title-sm" className="text-white">I want to update my email address.</Typo>
|
|
99
|
+
</MessageBubble>
|
|
100
|
+
</div>
|
|
101
|
+
<div className="flex justify-start">
|
|
102
|
+
<MessageBubble direction="left" color="#F5F5F5">
|
|
103
|
+
<Typo variant="title-sm" className="text-[#333]">
|
|
104
|
+
No problem! You can update your email in Account Settings → Profile → Email.
|
|
105
|
+
</Typo>
|
|
106
|
+
</MessageBubble>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
)
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const LongMessages: Story = {
|
|
113
|
+
render: () => (
|
|
114
|
+
<div className="flex flex-col gap-4 max-w-2xl p-4">
|
|
115
|
+
<div className="flex justify-start">
|
|
116
|
+
<MessageBubble direction="left">
|
|
117
|
+
<Typo variant="title-sm" className="text-[#333]">
|
|
118
|
+
This is a longer message to demonstrate how the bubble handles multiple lines of text.
|
|
119
|
+
The border radius should remain consistent regardless of the content length.
|
|
120
|
+
The bubble will grow to accommodate the text while maintaining its shape.
|
|
121
|
+
</Typo>
|
|
122
|
+
</MessageBubble>
|
|
123
|
+
</div>
|
|
124
|
+
<div className="flex justify-end">
|
|
125
|
+
<MessageBubble direction="right" color="var(--color-brand)">
|
|
126
|
+
<Typo variant="title-sm" className="text-white">
|
|
127
|
+
Great! The bubble handles long text really well. It maintains the proper border
|
|
128
|
+
radius and looks clean even with multiple lines of content.
|
|
129
|
+
</Typo>
|
|
130
|
+
</MessageBubble>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
)
|
|
134
|
+
};
|
|
135
|
+
|
|
@@ -74,11 +74,11 @@ export const CustomStyling: Story = {
|
|
|
74
74
|
This modal has custom styling with a larger max-width and more padding.
|
|
75
75
|
</Typo>
|
|
76
76
|
<div className="mt-6 grid grid-cols-2 gap-4">
|
|
77
|
-
<div className="p-4 bg-[var(--muted)]
|
|
77
|
+
<div className="p-4 bg-[var(--muted)] [border-radius:1.875rem]">
|
|
78
78
|
<Typo variant="label-lg" bold="semibold">Feature 1</Typo>
|
|
79
79
|
<Typo variant="body-sm" className="mt-2">Description here</Typo>
|
|
80
80
|
</div>
|
|
81
|
-
<div className="p-4 bg-[var(--muted)]
|
|
81
|
+
<div className="p-4 bg-[var(--muted)] [border-radius:1.875rem]">
|
|
82
82
|
<Typo variant="label-lg" bold="semibold">Feature 2</Typo>
|
|
83
83
|
<Typo variant="body-sm" className="mt-2">Description here</Typo>
|
|
84
84
|
</div>
|
package/src/styles/library.css
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/* Build-only CSS for publishing the lib (no Preflight/reset) */
|
|
2
|
+
|
|
3
|
+
/* Google Fonts */
|
|
4
|
+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap');
|
|
5
|
+
|
|
2
6
|
@import "tailwindcss/utilities";
|
|
3
7
|
@import "./tokens.css";
|
|
4
8
|
|
package/src/styles/tailwind.css
CHANGED
package/src/styles/tokens.css
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
--radius-md: 0.375rem;
|
|
10
10
|
--radius-lg: 0.5rem;
|
|
11
11
|
--radius-xl: 0.75rem;
|
|
12
|
-
--radius-2xl: 1.875rem;
|
|
13
12
|
--bg: #F3F4F6;
|
|
14
13
|
--surface: #FFFFFF;
|
|
15
14
|
--fg: #242832;
|
|
@@ -31,7 +30,6 @@
|
|
|
31
30
|
--radius-md: 0.375rem;
|
|
32
31
|
--radius-lg: 0.5rem;
|
|
33
32
|
--radius-xl: 0.75rem;
|
|
34
|
-
--radius-2xl: 1.875rem;
|
|
35
33
|
--bg: #F3F4F6;
|
|
36
34
|
--surface: #FFFFFF;
|
|
37
35
|
--fg: #242832;
|