@neoptocom/neopto-ui 0.11.1 → 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 CHANGED
@@ -346,7 +346,6 @@ var typoStyles = {
346
346
  "button": { fontSize: "16px", lineHeight: "24px", letterSpacing: "0" }
347
347
  };
348
348
  function getTypoClasses(weight = "normal", muted, className) {
349
- const base = "text-current";
350
349
  const weights = {
351
350
  normal: "font-normal",
352
351
  medium: "font-medium",
@@ -354,7 +353,6 @@ function getTypoClasses(weight = "normal", muted, className) {
354
353
  bold: "font-bold"
355
354
  };
356
355
  return [
357
- base,
358
356
  weights[weight],
359
357
  muted ? "text-[var(--muted-fg)]" : "",
360
358
  className
@@ -991,7 +989,7 @@ function Search({
991
989
  );
992
990
  }
993
991
  function getButtonClasses(variant = "primary", size = "md", fullWidth, className) {
994
- const base = "cursor-pointer inline-flex items-center justify-center gap-2 rounded-[var(--radius-2xl)] 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
+ 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";
995
993
  const variants = {
996
994
  primary: "bg-cyan-500 text-white hover:bg-cyan-400 active:bg-cyan-600 disabled:bg-neutral-400",
997
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",
@@ -1293,6 +1291,27 @@ var AgentButton = ({
1293
1291
  );
1294
1292
  };
1295
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";
1296
1315
 
1297
1316
  exports.AgentButton = AgentButton_default;
1298
1317
  exports.AnimatedBgCircle = AnimatedBgCircle_default;
@@ -1309,6 +1328,7 @@ exports.Counter = Counter;
1309
1328
  exports.Icon = Icon;
1310
1329
  exports.IconButton = IconButton;
1311
1330
  exports.Input = Input;
1331
+ exports.MessageBubble = MessageBubble;
1312
1332
  exports.Modal = Modal;
1313
1333
  exports.Search = Search;
1314
1334
  exports.Skeleton = Skeleton;
package/dist/index.d.cts CHANGED
@@ -297,4 +297,16 @@ interface AnimatedBgRectangleProps {
297
297
  }
298
298
  declare const AnimatedBgRectangle: ({ colors, delay }: AnimatedBgRectangleProps) => react_jsx_runtime.JSX.Element;
299
299
 
300
- 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, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Skeleton, type SkeletonProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
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
@@ -297,4 +297,16 @@ interface AnimatedBgRectangleProps {
297
297
  }
298
298
  declare const AnimatedBgRectangle: ({ colors, delay }: AnimatedBgRectangleProps) => react_jsx_runtime.JSX.Element;
299
299
 
300
- 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, Modal, type ModalProps, Search, type SearchOption, type SearchProps, Skeleton, type SkeletonProps, Typo, type TypoProps, type TypoVariant, type TypoWeight, index as assets };
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
@@ -325,7 +325,6 @@ var typoStyles = {
325
325
  "button": { fontSize: "16px", lineHeight: "24px", letterSpacing: "0" }
326
326
  };
327
327
  function getTypoClasses(weight = "normal", muted, className) {
328
- const base = "text-current";
329
328
  const weights = {
330
329
  normal: "font-normal",
331
330
  medium: "font-medium",
@@ -333,7 +332,6 @@ function getTypoClasses(weight = "normal", muted, className) {
333
332
  bold: "font-bold"
334
333
  };
335
334
  return [
336
- base,
337
335
  weights[weight],
338
336
  muted ? "text-[var(--muted-fg)]" : "",
339
337
  className
@@ -970,7 +968,7 @@ function Search({
970
968
  );
971
969
  }
972
970
  function getButtonClasses(variant = "primary", size = "md", fullWidth, className) {
973
- const base = "cursor-pointer inline-flex items-center justify-center gap-2 rounded-[var(--radius-2xl)] 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
+ 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";
974
972
  const variants = {
975
973
  primary: "bg-cyan-500 text-white hover:bg-cyan-400 active:bg-cyan-600 disabled:bg-neutral-400",
976
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",
@@ -1272,5 +1270,26 @@ var AgentButton = ({
1272
1270
  );
1273
1271
  };
1274
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";
1275
1294
 
1276
- 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.11.1",
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-[var(--radius-2xl)] transition-colors " +
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
 
@@ -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
+
@@ -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";
@@ -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)] rounded-2xl">
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)] rounded-2xl">
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>
@@ -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
 
@@ -1,3 +1,6 @@
1
+ /* Google Fonts */
2
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap');
3
+
1
4
  /* Tailwind v4+ core */
2
5
  @import "tailwindcss";
3
6
 
@@ -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;