@7onic-ui/react 0.2.2 → 0.2.4

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.js CHANGED
@@ -72,6 +72,15 @@ __export(ui_exports, {
72
72
  CardHeader: () => CardHeader,
73
73
  CardImage: () => CardImage,
74
74
  CardTitle: () => CardTitle,
75
+ ChatInput: () => ChatInput,
76
+ ChatInputField: () => ChatInputField,
77
+ ChatInputRoot: () => ChatInputRoot,
78
+ ChatInputSubmit: () => ChatInputSubmit,
79
+ ChatMessage: () => ChatMessage,
80
+ ChatMessageAvatar: () => ChatMessageAvatar,
81
+ ChatMessageContent: () => ChatMessageContent,
82
+ ChatMessageFooter: () => ChatMessageFooter,
83
+ ChatMessageRoot: () => ChatMessageRoot,
75
84
  Checkbox: () => Checkbox,
76
85
  Divider: () => Divider,
77
86
  Drawer: () => Drawer,
@@ -152,6 +161,9 @@ __export(ui_exports, {
152
161
  PopoverRoot: () => PopoverRoot,
153
162
  PopoverTrigger: () => PopoverTrigger,
154
163
  Progress: () => Progress,
164
+ QuickReply: () => QuickReply,
165
+ QuickReplyItem: () => QuickReplyItem,
166
+ QuickReplyRoot: () => QuickReplyRoot,
155
167
  RadioGroup: () => RadioGroup,
156
168
  RadioGroupItem: () => RadioGroupItem,
157
169
  Segmented: () => Segmented,
@@ -192,6 +204,7 @@ __export(ui_exports, {
192
204
  TooltipProvider: () => TooltipProvider,
193
205
  TooltipRoot: () => TooltipRoot,
194
206
  TooltipTrigger: () => TooltipTrigger,
207
+ TypingIndicator: () => TypingIndicator,
195
208
  accordionTriggerVariants: () => accordionTriggerVariants,
196
209
  accordionVariants: () => accordionVariants,
197
210
  alertModalContentVariants: () => alertModalContentVariants,
@@ -202,6 +215,7 @@ __export(ui_exports, {
202
215
  breadcrumbSizeMap: () => breadcrumbSizeMap,
203
216
  buttonVariants: () => buttonVariants,
204
217
  cardVariants: () => cardVariants,
218
+ chatInputVariants: () => chatInputVariants,
205
219
  checkboxVariants: () => checkboxVariants,
206
220
  dividerVariants: () => dividerVariants,
207
221
  drawerSizeHorizontal: () => drawerSizeHorizontal,
@@ -217,6 +231,8 @@ __export(ui_exports, {
217
231
  paginationItemVariants: () => paginationItemVariants,
218
232
  paginationSizeMap: () => paginationSizeMap,
219
233
  popoverContentVariants: () => popoverContentVariants,
234
+ quickReplyItemVariants: () => quickReplyItemVariants,
235
+ quickReplyRootVariants: () => quickReplyRootVariants,
220
236
  radioGroupVariants: () => radioGroupVariants,
221
237
  radioItemVariants: () => radioItemVariants,
222
238
  segmentedItemVariants: () => segmentedItemVariants,
@@ -234,6 +250,7 @@ __export(ui_exports, {
234
250
  toggleGroupVariants: () => toggleGroupVariants,
235
251
  toggleVariants: () => toggleVariants,
236
252
  tooltipContentVariants: () => tooltipContentVariants,
253
+ typingIndicatorVariants: () => typingIndicatorVariants,
237
254
  useButtonGroup: () => useButtonGroup,
238
255
  useFieldContext: () => useFieldContext,
239
256
  usePagination: () => usePagination
@@ -3784,7 +3801,7 @@ var CardTitle = React22.forwardRef(
3784
3801
  {
3785
3802
  ref,
3786
3803
  className: cn(
3787
- "font-semibold text-foreground leading-none tracking-tight",
3804
+ "text-base font-semibold text-foreground tracking-tight",
3788
3805
  icon && "flex items-center gap-2",
3789
3806
  className
3790
3807
  ),
@@ -4902,10 +4919,9 @@ var PaginationRoot = React26.forwardRef(
4902
4919
  color = "default",
4903
4920
  radius = "md",
4904
4921
  disabled = false,
4905
- withControls = true,
4906
- // eslint-disable-line @typescript-eslint/no-unused-vars
4907
- withEdges = false,
4908
- // eslint-disable-line @typescript-eslint/no-unused-vars
4922
+ // Pre-declared API; conditional auto-rendering is tracked in COMPONENT-IMPROVEMENTS.md.
4923
+ withControls: _withControls = true,
4924
+ withEdges: _withEdges = false,
4909
4925
  loop = false,
4910
4926
  children,
4911
4927
  ...props
@@ -5871,9 +5887,9 @@ var alertVariants = (0, import_class_variance_authority26.cva)(
5871
5887
  {
5872
5888
  variants: {
5873
5889
  size: {
5874
- sm: "gap-2 p-3 text-sm",
5875
- default: "gap-2.5 p-4 text-md",
5876
- lg: "gap-3 p-5 text-md"
5890
+ sm: "gap-2 p-2.5 text-sm",
5891
+ default: "gap-2.5 p-3.5 text-md",
5892
+ lg: "gap-3 p-4 text-md"
5877
5893
  },
5878
5894
  radius: {
5879
5895
  none: "rounded-none",
@@ -5901,15 +5917,20 @@ var ICON_SIZE_MAP = {
5901
5917
  lg: "icon-md"
5902
5918
  // 20px
5903
5919
  };
5920
+ var ICON_LINE_MAP = {
5921
+ sm: "text-sm",
5922
+ default: "text-md",
5923
+ lg: "text-base"
5924
+ };
5904
5925
  var TITLE_SIZE_MAP = {
5905
- sm: "text-sm font-semibold leading-4 tracking-tight",
5906
- default: "font-semibold leading-[18px] tracking-tight",
5907
- lg: "text-base font-semibold leading-5 tracking-tight"
5926
+ sm: "text-sm font-semibold tracking-tight",
5927
+ default: "text-md font-semibold tracking-tight",
5928
+ lg: "text-base font-semibold tracking-tight"
5908
5929
  };
5909
5930
  var DESC_SIZE_MAP = {
5910
5931
  sm: "text-xs mt-0.5",
5911
- default: "text-sm mt-1",
5912
- lg: "text-md mt-1.5"
5932
+ default: "text-sm mt-0.5",
5933
+ lg: "text-md mt-0.5"
5913
5934
  };
5914
5935
  var AlertContext = React31.createContext({
5915
5936
  variant: "default",
@@ -5949,7 +5970,7 @@ var AlertRoot = React31.forwardRef(
5949
5970
  ),
5950
5971
  ...props
5951
5972
  },
5952
- !hideIcon && /* @__PURE__ */ React31.createElement("span", { className: "shrink-0" }, icon || /* @__PURE__ */ React31.createElement(StatusIcon, { className: ICON_SIZE_MAP[size] })),
5973
+ !hideIcon && /* @__PURE__ */ React31.createElement("span", { className: cn("shrink-0 flex items-center min-h-[1lh]", ICON_LINE_MAP[size]) }, icon || /* @__PURE__ */ React31.createElement(StatusIcon, { className: ICON_SIZE_MAP[size] })),
5953
5974
  /* @__PURE__ */ React31.createElement("div", { className: "flex-1 min-w-0" }, children),
5954
5975
  closable && /* @__PURE__ */ React31.createElement(
5955
5976
  "button",
@@ -6200,7 +6221,6 @@ var ToastItem = React32.memo(function ToastItem2({
6200
6221
  }) {
6201
6222
  const [isExiting, setIsExiting] = React32.useState(false);
6202
6223
  const [isEntered, setIsEntered] = React32.useState(false);
6203
- const [isPaused, setIsPaused] = React32.useState(false);
6204
6224
  const timerRef = React32.useRef(null);
6205
6225
  const remainingRef = React32.useRef(0);
6206
6226
  const startTimeRef = React32.useRef(0);
@@ -6239,7 +6259,6 @@ var ToastItem = React32.memo(function ToastItem2({
6239
6259
  }, [duration, handleAutoClose]);
6240
6260
  const handleMouseEnter = React32.useCallback(() => {
6241
6261
  if (duration <= 0) return;
6242
- setIsPaused(true);
6243
6262
  if (timerRef.current) {
6244
6263
  clearTimeout(timerRef.current);
6245
6264
  remainingRef.current -= Date.now() - startTimeRef.current;
@@ -6247,7 +6266,6 @@ var ToastItem = React32.memo(function ToastItem2({
6247
6266
  }, [duration]);
6248
6267
  const handleMouseLeave = React32.useCallback(() => {
6249
6268
  if (duration <= 0) return;
6250
- setIsPaused(false);
6251
6269
  startTimeRef.current = Date.now();
6252
6270
  timerRef.current = setTimeout(handleAutoClose, Math.max(remainingRef.current, TOAST_MIN_RESUME_MS));
6253
6271
  }, [duration, handleAutoClose]);
@@ -7080,6 +7098,862 @@ var Skeleton = React35.forwardRef(
7080
7098
  }
7081
7099
  );
7082
7100
  Skeleton.displayName = "Skeleton";
7101
+
7102
+ // src/components/ui/typing-indicator.tsx
7103
+ var React36 = __toESM(require("react"));
7104
+ var import_class_variance_authority31 = require("class-variance-authority");
7105
+ var DOT_SIZES2 = { sm: 4, default: 6, lg: 8 };
7106
+ var DOT_GAP2 = { sm: 3, default: 4, lg: 5 };
7107
+ var SPEED_MS2 = { slow: 1600, default: 1100, fast: 700 };
7108
+ var DOT_COUNT2 = 3;
7109
+ var bgColorMap2 = {
7110
+ default: "bg-foreground",
7111
+ primary: "bg-primary",
7112
+ muted: "bg-text-subtle"
7113
+ };
7114
+ var typingIndicatorVariants = (0, import_class_variance_authority31.cva)(
7115
+ "inline-flex items-center",
7116
+ {
7117
+ variants: {
7118
+ size: {
7119
+ sm: "gap-1.5 text-xs",
7120
+ default: "gap-2 text-sm",
7121
+ lg: "gap-2.5 text-base"
7122
+ }
7123
+ },
7124
+ defaultVariants: {
7125
+ size: "default"
7126
+ }
7127
+ }
7128
+ );
7129
+ var TypingIndicator = React36.forwardRef(
7130
+ ({
7131
+ className,
7132
+ variant = "dots",
7133
+ size,
7134
+ color = "muted",
7135
+ speed = "default",
7136
+ label = "Typing",
7137
+ showLabel = false,
7138
+ ...props
7139
+ }, ref) => {
7140
+ const resolvedSize = size ?? "default";
7141
+ return /* @__PURE__ */ React36.createElement(
7142
+ "div",
7143
+ {
7144
+ ref,
7145
+ role: "status",
7146
+ "aria-live": "polite",
7147
+ "aria-label": label,
7148
+ className: cn(typingIndicatorVariants({ size }), className),
7149
+ ...props
7150
+ },
7151
+ variant === "dots" && /* @__PURE__ */ React36.createElement(DotsIndicator, { size: resolvedSize, color, speed }),
7152
+ variant === "cursor" && /* @__PURE__ */ React36.createElement(CursorIndicator, { size: resolvedSize, color }),
7153
+ showLabel && /* @__PURE__ */ React36.createElement("span", { className: "text-text-muted select-none" }, label)
7154
+ );
7155
+ }
7156
+ );
7157
+ TypingIndicator.displayName = "TypingIndicator";
7158
+ function DotsIndicator({
7159
+ size,
7160
+ color,
7161
+ speed
7162
+ }) {
7163
+ const dotSize = DOT_SIZES2[size];
7164
+ const gap = DOT_GAP2[size];
7165
+ const duration = SPEED_MS2[speed];
7166
+ return /* @__PURE__ */ React36.createElement("div", { className: "inline-flex items-center", style: { gap } }, Array.from({ length: DOT_COUNT2 }, (_, i) => /* @__PURE__ */ React36.createElement(
7167
+ "div",
7168
+ {
7169
+ key: i,
7170
+ className: cn(
7171
+ "rounded-full animate-spinner-dot motion-reduce:animate-none motion-reduce:opacity-60",
7172
+ bgColorMap2[color]
7173
+ ),
7174
+ style: {
7175
+ width: dotSize,
7176
+ height: dotSize,
7177
+ animationDuration: `${duration}ms`,
7178
+ animationDelay: `${i * (duration / DOT_COUNT2 / 1.5)}ms`
7179
+ }
7180
+ }
7181
+ )));
7182
+ }
7183
+ var CURSOR_SIZE = {
7184
+ sm: { width: 2, height: 14 },
7185
+ default: { width: 2.5, height: 20 },
7186
+ lg: { width: 3, height: 26 }
7187
+ };
7188
+ function CursorIndicator({
7189
+ size,
7190
+ color
7191
+ }) {
7192
+ const { width, height } = CURSOR_SIZE[size];
7193
+ return /* @__PURE__ */ React36.createElement(
7194
+ "div",
7195
+ {
7196
+ "aria-hidden": "true",
7197
+ className: cn(
7198
+ "rounded-full animate-typing-cursor motion-reduce:animate-none motion-reduce:opacity-60",
7199
+ bgColorMap2[color]
7200
+ ),
7201
+ style: { width, height, animationDuration: "1200ms" }
7202
+ }
7203
+ );
7204
+ }
7205
+
7206
+ // src/components/ui/quick-reply.tsx
7207
+ var React37 = __toESM(require("react"));
7208
+ var import_react_slot7 = require("@radix-ui/react-slot");
7209
+ var import_class_variance_authority32 = require("class-variance-authority");
7210
+ var colorMap5 = {
7211
+ default: {
7212
+ outline: "border border-border text-foreground bg-background hover:bg-background-muted",
7213
+ filled: "bg-background-muted text-foreground hover:bg-background-elevated",
7214
+ ghost: "text-foreground hover:bg-background-muted"
7215
+ },
7216
+ primary: {
7217
+ outline: "border border-primary text-text-primary bg-background hover:bg-primary-tint",
7218
+ filled: "bg-primary-tint text-text-primary hover:bg-primary/20",
7219
+ ghost: "text-text-primary hover:bg-primary-tint"
7220
+ }
7221
+ };
7222
+ var QuickReplyContext = React37.createContext({
7223
+ size: "default",
7224
+ variant: "outline",
7225
+ color: "default",
7226
+ radius: "full"
7227
+ });
7228
+ var quickReplyRootVariants = (0, import_class_variance_authority32.cva)(
7229
+ "flex items-center",
7230
+ {
7231
+ variants: {
7232
+ layout: {
7233
+ scroll: "overflow-x-auto",
7234
+ wrap: "flex-wrap"
7235
+ },
7236
+ gap: {
7237
+ sm: "gap-1.5",
7238
+ default: "gap-2",
7239
+ lg: "gap-2.5"
7240
+ }
7241
+ },
7242
+ defaultVariants: {
7243
+ layout: "scroll",
7244
+ gap: "default"
7245
+ }
7246
+ }
7247
+ );
7248
+ var quickReplyItemVariants = (0, import_class_variance_authority32.cva)(
7249
+ [
7250
+ "inline-flex items-center justify-center",
7251
+ "whitespace-nowrap font-semibold shrink-0",
7252
+ "transition-colors duration-fast cursor-pointer",
7253
+ "focus-visible:outline-none focus-visible:focus-ring",
7254
+ "disabled:pointer-events-none disabled:opacity-50",
7255
+ "select-none"
7256
+ ].join(" "),
7257
+ {
7258
+ variants: {
7259
+ size: {
7260
+ sm: "h-7 px-2.5 text-xs gap-1.5",
7261
+ // 28px
7262
+ default: "h-8 px-3 text-sm gap-1.5",
7263
+ // 32px
7264
+ lg: "h-9 px-3.5 text-md gap-1.5"
7265
+ // 36px
7266
+ },
7267
+ radius: {
7268
+ md: "rounded-md",
7269
+ // 6px
7270
+ lg: "rounded-lg",
7271
+ // 8px
7272
+ full: "rounded-full"
7273
+ // 9999px
7274
+ }
7275
+ },
7276
+ defaultVariants: {
7277
+ size: "default",
7278
+ radius: "full"
7279
+ }
7280
+ }
7281
+ );
7282
+ var iconSizeMap = {
7283
+ sm: "icon-xs",
7284
+ // 14px
7285
+ default: "icon-xs",
7286
+ // 14px
7287
+ lg: "icon-sm"
7288
+ // 16px
7289
+ };
7290
+ var QuickReplyRoot = React37.forwardRef(
7291
+ ({
7292
+ className,
7293
+ layout = "scroll",
7294
+ gap = "default",
7295
+ variant = "outline",
7296
+ color = "default",
7297
+ size = "default",
7298
+ radius = "full",
7299
+ role = "group",
7300
+ children,
7301
+ ...props
7302
+ }, ref) => {
7303
+ const contextValue = React37.useMemo(
7304
+ () => ({ size, variant, color, radius }),
7305
+ [size, variant, color, radius]
7306
+ );
7307
+ return /* @__PURE__ */ React37.createElement(QuickReplyContext.Provider, { value: contextValue }, /* @__PURE__ */ React37.createElement(
7308
+ "div",
7309
+ {
7310
+ ref,
7311
+ role,
7312
+ className: cn(quickReplyRootVariants({ layout, gap }), className),
7313
+ ...props
7314
+ },
7315
+ children
7316
+ ));
7317
+ }
7318
+ );
7319
+ QuickReplyRoot.displayName = "QuickReply";
7320
+ var QuickReplyItem = React37.forwardRef(
7321
+ ({ className, icon, asChild = false, children, ...props }, ref) => {
7322
+ const { size, variant, color, radius } = React37.useContext(QuickReplyContext);
7323
+ const Comp = asChild ? import_react_slot7.Slot : "button";
7324
+ const colorClasses = colorMap5[color][variant];
7325
+ return /* @__PURE__ */ React37.createElement(
7326
+ Comp,
7327
+ {
7328
+ ref,
7329
+ type: !asChild ? "button" : void 0,
7330
+ ...props,
7331
+ className: cn(
7332
+ quickReplyItemVariants({ size, radius }),
7333
+ colorClasses,
7334
+ className
7335
+ )
7336
+ },
7337
+ icon && /* @__PURE__ */ React37.createElement(
7338
+ "span",
7339
+ {
7340
+ className: cn("shrink-0 [&>svg]:w-full [&>svg]:h-full", iconSizeMap[size]),
7341
+ "aria-hidden": "true"
7342
+ },
7343
+ icon
7344
+ ),
7345
+ children
7346
+ );
7347
+ }
7348
+ );
7349
+ QuickReplyItem.displayName = "QuickReply.Item";
7350
+ var QuickReply = Object.assign(QuickReplyRoot, {
7351
+ Item: QuickReplyItem
7352
+ });
7353
+
7354
+ // src/components/ui/chat-input.tsx
7355
+ var React38 = __toESM(require("react"));
7356
+ var import_class_variance_authority33 = require("class-variance-authority");
7357
+ var fieldPaddingMap = {
7358
+ sm: "pt-2.5 px-3 text-md",
7359
+ default: "pt-3 px-4 text-md",
7360
+ lg: "pt-4 px-5 text-base"
7361
+ };
7362
+ var submitWrapperMap = {
7363
+ sm: "px-2.5 pb-2.5",
7364
+ default: "px-3 pb-3",
7365
+ lg: "px-4 pb-4"
7366
+ };
7367
+ var submitSizeMap = {
7368
+ sm: "h-7 w-7",
7369
+ default: "h-8 w-8",
7370
+ lg: "h-9 w-9"
7371
+ };
7372
+ var submitRadiusMap = {
7373
+ sm: "rounded-md",
7374
+ md: "rounded-md",
7375
+ lg: "rounded-md",
7376
+ xl: "rounded-lg",
7377
+ "2xl": "rounded-xl",
7378
+ full: "rounded-full"
7379
+ };
7380
+ var buttonRadiusClassMap = {
7381
+ sm: "rounded-sm",
7382
+ md: "rounded-md",
7383
+ lg: "rounded-lg",
7384
+ xl: "rounded-xl",
7385
+ "2xl": "rounded-2xl",
7386
+ full: "rounded-full"
7387
+ };
7388
+ var submitIconSizeMap = {
7389
+ sm: "icon-xs",
7390
+ default: "icon-xs",
7391
+ lg: "icon-sm"
7392
+ };
7393
+ var countStyleMap = {
7394
+ sm: "text-xs",
7395
+ default: "text-xs",
7396
+ lg: "text-sm"
7397
+ };
7398
+ var lineHeightMap = {
7399
+ sm: 20,
7400
+ default: 22,
7401
+ lg: 24
7402
+ };
7403
+ var inlineFieldPaddingMap = {
7404
+ sm: "px-3 text-md",
7405
+ default: "px-4 text-md",
7406
+ lg: "px-5 text-base"
7407
+ };
7408
+ var submitWrapperInlineMap = {
7409
+ sm: "px-2.5 py-2.5",
7410
+ default: "px-3 py-3",
7411
+ lg: "px-4 py-4"
7412
+ };
7413
+ var chatInputVariants = (0, import_class_variance_authority33.cva)(
7414
+ [
7415
+ "flex flex-col w-full overflow-hidden cursor-text",
7416
+ "transition-colors duration-micro"
7417
+ ].join(" "),
7418
+ {
7419
+ variants: {
7420
+ variant: {
7421
+ outline: [
7422
+ "border border-border bg-background",
7423
+ "hover:border-border-strong",
7424
+ "focus-within:border-border-strong focus-within:hover:border-border-strong"
7425
+ ].join(" "),
7426
+ filled: [
7427
+ "border border-transparent bg-background-muted",
7428
+ "focus-within:border-border"
7429
+ ].join(" ")
7430
+ },
7431
+ radius: {
7432
+ sm: "rounded-sm",
7433
+ md: "rounded-md",
7434
+ lg: "rounded-lg",
7435
+ xl: "rounded-xl",
7436
+ "2xl": "rounded-2xl",
7437
+ full: "rounded-full"
7438
+ }
7439
+ },
7440
+ defaultVariants: {
7441
+ variant: "outline",
7442
+ radius: "xl"
7443
+ }
7444
+ }
7445
+ );
7446
+ var ChatInputContext = React38.createContext({
7447
+ size: "default",
7448
+ color: "default",
7449
+ layout: "default",
7450
+ radius: "xl",
7451
+ disabled: false,
7452
+ isEmpty: true,
7453
+ charCount: 0,
7454
+ showCount: false,
7455
+ maxLength: void 0,
7456
+ _setIsEmpty: () => {
7457
+ },
7458
+ _setCharCount: () => {
7459
+ },
7460
+ _setShowCount: () => {
7461
+ },
7462
+ _setMaxLength: () => {
7463
+ },
7464
+ _fieldRef: { current: null },
7465
+ _handleSubmit: () => {
7466
+ }
7467
+ });
7468
+ var ChatInputRoot = React38.forwardRef(
7469
+ ({
7470
+ className,
7471
+ variant = "outline",
7472
+ radius = "xl",
7473
+ size = "default",
7474
+ color = "default",
7475
+ layout = "default",
7476
+ disabled = false,
7477
+ onSubmit,
7478
+ children,
7479
+ ...props
7480
+ }, ref) => {
7481
+ const [isEmpty, setIsEmpty] = React38.useState(true);
7482
+ const [charCount, setCharCount] = React38.useState(0);
7483
+ const [showCount, setShowCount] = React38.useState(false);
7484
+ const [maxLength, setMaxLength] = React38.useState(void 0);
7485
+ const fieldRef = React38.useRef(null);
7486
+ const handleSubmit = React38.useCallback(() => {
7487
+ const el = fieldRef.current;
7488
+ if (!el || disabled) return;
7489
+ const value = el.value.trim();
7490
+ if (!value) return;
7491
+ onSubmit?.(value);
7492
+ el.value = "";
7493
+ el.style.height = "auto";
7494
+ setIsEmpty(true);
7495
+ setCharCount(0);
7496
+ }, [disabled, onSubmit]);
7497
+ const contextValue = React38.useMemo(
7498
+ () => ({
7499
+ size,
7500
+ color,
7501
+ layout,
7502
+ radius,
7503
+ disabled,
7504
+ isEmpty,
7505
+ charCount,
7506
+ showCount,
7507
+ maxLength,
7508
+ _setIsEmpty: setIsEmpty,
7509
+ _setCharCount: setCharCount,
7510
+ _setShowCount: setShowCount,
7511
+ _setMaxLength: setMaxLength,
7512
+ _fieldRef: fieldRef,
7513
+ _handleSubmit: handleSubmit
7514
+ }),
7515
+ [size, color, layout, radius, disabled, isEmpty, charCount, showCount, maxLength, handleSubmit]
7516
+ );
7517
+ const handleContainerClick = React38.useCallback(
7518
+ (e) => {
7519
+ if (!disabled && !e.target.closest("button")) {
7520
+ fieldRef.current?.focus();
7521
+ }
7522
+ },
7523
+ [disabled]
7524
+ );
7525
+ return /* @__PURE__ */ React38.createElement(ChatInputContext.Provider, { value: contextValue }, /* @__PURE__ */ React38.createElement(
7526
+ "div",
7527
+ {
7528
+ ref,
7529
+ "data-disabled": disabled || void 0,
7530
+ onClick: handleContainerClick,
7531
+ className: cn(
7532
+ chatInputVariants({ variant, radius }),
7533
+ layout === "inline" && "flex-row",
7534
+ disabled && "opacity-50 pointer-events-none",
7535
+ className
7536
+ ),
7537
+ ...props
7538
+ },
7539
+ children
7540
+ ));
7541
+ }
7542
+ );
7543
+ ChatInputRoot.displayName = "ChatInput";
7544
+ var ChatInputField = React38.forwardRef(
7545
+ ({
7546
+ className,
7547
+ maxRows = 8,
7548
+ showCount = false,
7549
+ maxLength,
7550
+ placeholder,
7551
+ onChange,
7552
+ onKeyDown,
7553
+ disabled,
7554
+ ...props
7555
+ }, forwardedRef) => {
7556
+ const ctx = React38.useContext(ChatInputContext);
7557
+ const internalRef = React38.useRef(null);
7558
+ const isDisabled = disabled ?? ctx.disabled;
7559
+ React38.useEffect(() => {
7560
+ ctx._setShowCount(showCount);
7561
+ ctx._setMaxLength(maxLength);
7562
+ }, [showCount, maxLength]);
7563
+ const setRef = React38.useCallback(
7564
+ (el) => {
7565
+ internalRef.current = el;
7566
+ ctx._fieldRef.current = el;
7567
+ if (typeof forwardedRef === "function") {
7568
+ forwardedRef(el);
7569
+ } else if (forwardedRef) {
7570
+ forwardedRef.current = el;
7571
+ }
7572
+ },
7573
+ // eslint-disable-next-line react-hooks/exhaustive-deps
7574
+ [forwardedRef]
7575
+ );
7576
+ const autoResize = React38.useCallback(() => {
7577
+ const el = internalRef.current;
7578
+ if (!el) return;
7579
+ el.style.height = "auto";
7580
+ const maxHeight = maxRows * lineHeightMap[ctx.size];
7581
+ const newHeight = Math.min(el.scrollHeight, maxHeight);
7582
+ el.style.height = `${newHeight}px`;
7583
+ el.style.overflowY = el.scrollHeight > maxHeight ? "auto" : "hidden";
7584
+ }, [ctx.size, maxRows]);
7585
+ const handleChange = React38.useCallback(
7586
+ (e) => {
7587
+ const val = e.target.value;
7588
+ ctx._setIsEmpty(val.trim() === "");
7589
+ ctx._setCharCount(val.length);
7590
+ autoResize();
7591
+ onChange?.(e);
7592
+ },
7593
+ [ctx, autoResize, onChange]
7594
+ );
7595
+ const handleKeyDown = React38.useCallback(
7596
+ (e) => {
7597
+ if (e.key === "Enter" && !e.shiftKey) {
7598
+ e.preventDefault();
7599
+ ctx._handleSubmit();
7600
+ }
7601
+ onKeyDown?.(e);
7602
+ },
7603
+ [ctx, onKeyDown]
7604
+ );
7605
+ return /* @__PURE__ */ React38.createElement("div", { className: cn("flex-1 min-w-0", ctx.layout === "inline" && "flex items-center self-stretch") }, /* @__PURE__ */ React38.createElement(
7606
+ "textarea",
7607
+ {
7608
+ ref: setRef,
7609
+ rows: 1,
7610
+ placeholder,
7611
+ maxLength,
7612
+ disabled: isDisabled,
7613
+ className: cn(
7614
+ "w-full bg-transparent text-foreground placeholder:text-foreground/30",
7615
+ "resize-none outline-none focus:outline-none",
7616
+ "disabled:cursor-not-allowed",
7617
+ "overflow-hidden",
7618
+ ctx.layout === "inline" ? inlineFieldPaddingMap[ctx.size] : fieldPaddingMap[ctx.size],
7619
+ className
7620
+ ),
7621
+ onChange: handleChange,
7622
+ onKeyDown: handleKeyDown,
7623
+ ...props
7624
+ }
7625
+ ));
7626
+ }
7627
+ );
7628
+ ChatInputField.displayName = "ChatInput.Field";
7629
+ var ChatInputSubmit = React38.forwardRef(
7630
+ ({
7631
+ className,
7632
+ loading = false,
7633
+ onStop,
7634
+ children,
7635
+ disabled,
7636
+ onClick,
7637
+ buttonRadius,
7638
+ ...props
7639
+ }, ref) => {
7640
+ const ctx = React38.useContext(ChatInputContext);
7641
+ const isDisabled = (disabled ?? ctx.disabled) || !loading && ctx.isEmpty;
7642
+ const handleClick = React38.useCallback(
7643
+ (e) => {
7644
+ if (loading) {
7645
+ onStop?.();
7646
+ } else if (!isDisabled) {
7647
+ ctx._handleSubmit();
7648
+ }
7649
+ onClick?.(e);
7650
+ },
7651
+ [ctx, isDisabled, loading, onStop, onClick]
7652
+ );
7653
+ return /* @__PURE__ */ React38.createElement("div", { className: cn("flex items-center justify-end gap-2 shrink-0 cursor-default", ctx.layout === "inline" ? submitWrapperInlineMap[ctx.size] : submitWrapperMap[ctx.size]) }, ctx.showCount && ctx.maxLength != null && /* @__PURE__ */ React38.createElement("span", { className: cn("text-text-subtle select-none", countStyleMap[ctx.size]) }, ctx.charCount, " / ", ctx.maxLength), /* @__PURE__ */ React38.createElement(
7654
+ "button",
7655
+ {
7656
+ ref,
7657
+ type: "button",
7658
+ disabled: isDisabled && !loading,
7659
+ "aria-label": loading ? "Stop generating" : "Send message",
7660
+ className: cn(
7661
+ "inline-flex items-center justify-center shrink-0",
7662
+ buttonRadius ? buttonRadiusClassMap[buttonRadius] : submitRadiusMap[ctx.radius],
7663
+ "transition-all duration-fast",
7664
+ "focus-visible:outline-none focus-visible:focus-ring",
7665
+ submitSizeMap[ctx.size],
7666
+ // Loading state — enabled, pulsing
7667
+ loading && ctx.color === "default" && "bg-foreground text-background animate-pulse cursor-pointer",
7668
+ loading && ctx.color === "primary" && "bg-primary text-primary-foreground animate-pulse cursor-pointer",
7669
+ // Enabled state
7670
+ !loading && !isDisabled && ctx.color === "default" && [
7671
+ "bg-foreground text-background",
7672
+ "hover:bg-foreground/90 active:bg-foreground/80 active:scale-pressed cursor-pointer"
7673
+ ],
7674
+ !loading && !isDisabled && ctx.color === "primary" && [
7675
+ "bg-primary text-primary-foreground",
7676
+ "hover:bg-primary-hover active:scale-pressed cursor-pointer"
7677
+ ],
7678
+ // Disabled state
7679
+ !loading && isDisabled && "bg-background-muted text-text-subtle pointer-events-none",
7680
+ className
7681
+ ),
7682
+ onClick: handleClick,
7683
+ ...props
7684
+ },
7685
+ /* @__PURE__ */ React38.createElement(
7686
+ "span",
7687
+ {
7688
+ "aria-hidden": "true",
7689
+ className: cn("flex items-center justify-center", submitIconSizeMap[ctx.size])
7690
+ },
7691
+ children ?? (loading ? /* @__PURE__ */ React38.createElement(StopIcon, null) : /* @__PURE__ */ React38.createElement(SendIcon, null))
7692
+ )
7693
+ ));
7694
+ }
7695
+ );
7696
+ ChatInputSubmit.displayName = "ChatInput.Submit";
7697
+ function SendIcon() {
7698
+ return /* @__PURE__ */ React38.createElement(
7699
+ "svg",
7700
+ {
7701
+ viewBox: "0 0 24 24",
7702
+ fill: "none",
7703
+ stroke: "currentColor",
7704
+ strokeWidth: 2.5,
7705
+ strokeLinecap: "round",
7706
+ strokeLinejoin: "round",
7707
+ className: "w-full h-full"
7708
+ },
7709
+ /* @__PURE__ */ React38.createElement("path", { d: "M22 2 11 13" }),
7710
+ /* @__PURE__ */ React38.createElement("path", { d: "M22 2 15 22 11 13 2 9l20-7Z" })
7711
+ );
7712
+ }
7713
+ function StopIcon() {
7714
+ return /* @__PURE__ */ React38.createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "w-full h-full" }, /* @__PURE__ */ React38.createElement("rect", { x: "5", y: "5", width: "14", height: "14", rx: "2" }));
7715
+ }
7716
+ var ChatInput = Object.assign(ChatInputRoot, {
7717
+ Field: ChatInputField,
7718
+ Submit: ChatInputSubmit
7719
+ });
7720
+
7721
+ // src/components/ui/chat-message.tsx
7722
+ var React39 = __toESM(require("react"));
7723
+ var ChatMessageContext = React39.createContext({
7724
+ role: "assistant",
7725
+ variant: "bubble",
7726
+ color: "default",
7727
+ size: "default",
7728
+ radius: "2xl",
7729
+ tail: true,
7730
+ typing: false,
7731
+ actions: void 0
7732
+ });
7733
+ var bubblePaddingMap = {
7734
+ sm: "px-3 py-1.5",
7735
+ default: "px-3.5 py-2",
7736
+ lg: "px-4 py-2.5"
7737
+ };
7738
+ var bubbleTextMap = {
7739
+ sm: "text-sm",
7740
+ default: "text-md",
7741
+ lg: "text-base"
7742
+ };
7743
+ var footerTextMap = {
7744
+ sm: "text-2xs",
7745
+ default: "text-2xs",
7746
+ lg: "text-xs"
7747
+ };
7748
+ var rowGapMap = {
7749
+ sm: "gap-2",
7750
+ default: "gap-2.5",
7751
+ lg: "gap-3"
7752
+ };
7753
+ var avatarGapMap = {
7754
+ sm: "gap-1.5",
7755
+ md: "gap-2.5",
7756
+ lg: "gap-3"
7757
+ };
7758
+ var chatAvatarSizeMap = {
7759
+ sm: "w-6 h-6",
7760
+ // 24px
7761
+ md: "w-7 h-7",
7762
+ // 28px
7763
+ lg: "w-8 h-8"
7764
+ // 32px
7765
+ };
7766
+ var chatAvatarFontMap = {
7767
+ sm: "text-2xs",
7768
+ md: "text-2xs",
7769
+ lg: "text-xs"
7770
+ };
7771
+ var bubbleRadiusTailMap = {
7772
+ md: { assistant: "rounded-tl-md rounded-tr-md rounded-br-md rounded-bl-none", user: "rounded-tl-md rounded-tr-md rounded-br-none rounded-bl-md" },
7773
+ lg: { assistant: "rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-none", user: "rounded-tl-lg rounded-tr-lg rounded-br-none rounded-bl-lg" },
7774
+ xl: { assistant: "rounded-tl-xl rounded-tr-xl rounded-br-xl rounded-bl-none", user: "rounded-tl-xl rounded-tr-xl rounded-br-none rounded-bl-xl" },
7775
+ "2xl": { assistant: "rounded-tl-2xl rounded-tr-2xl rounded-br-2xl rounded-bl-none", user: "rounded-tl-2xl rounded-tr-2xl rounded-br-none rounded-bl-2xl" }
7776
+ };
7777
+ var bubbleRadiusSymMap = {
7778
+ md: "rounded-md",
7779
+ lg: "rounded-lg",
7780
+ xl: "rounded-xl",
7781
+ "2xl": "rounded-2xl"
7782
+ };
7783
+ function getBubbleColors(color, variant) {
7784
+ if (variant === "flat") {
7785
+ return color === "muted" ? "bg-background-muted" : "";
7786
+ }
7787
+ switch (color) {
7788
+ case "default":
7789
+ return "bg-background-paper border border-border text-foreground";
7790
+ case "muted":
7791
+ return "bg-background-muted text-foreground";
7792
+ case "primary":
7793
+ return "bg-primary text-primary-foreground";
7794
+ case "dark":
7795
+ return "bg-foreground text-background";
7796
+ }
7797
+ }
7798
+ var builtInStatusLabels = {
7799
+ sending: { label: "Sending...", className: "text-text-subtle" },
7800
+ sent: { label: "Sent", className: "text-text-subtle" },
7801
+ read: { label: "Read", className: "text-text-subtle" },
7802
+ error: { label: "Failed", className: "text-error" }
7803
+ };
7804
+ var typingSizeMap = {
7805
+ sm: "sm",
7806
+ default: "sm",
7807
+ lg: "default"
7808
+ };
7809
+ var typingMinWidthMap = {
7810
+ sm: "min-w-12",
7811
+ default: "min-w-12",
7812
+ lg: "min-w-16"
7813
+ };
7814
+ var ChatMessageRoot = React39.forwardRef(
7815
+ ({
7816
+ className,
7817
+ role = "assistant",
7818
+ variant = "bubble",
7819
+ color = "default",
7820
+ size = "default",
7821
+ radius = "2xl",
7822
+ tail = true,
7823
+ typing = false,
7824
+ avatarSize,
7825
+ actions,
7826
+ children,
7827
+ ...props
7828
+ }, ref) => {
7829
+ const ctx = React39.useMemo(
7830
+ () => ({ role, variant, color, size, radius, tail, typing, actions }),
7831
+ [role, variant, color, size, radius, tail, typing, actions]
7832
+ );
7833
+ const gapClass = avatarSize ? avatarGapMap[avatarSize] : rowGapMap[size];
7834
+ return /* @__PURE__ */ React39.createElement(ChatMessageContext.Provider, { value: ctx }, /* @__PURE__ */ React39.createElement(
7835
+ "div",
7836
+ {
7837
+ ref,
7838
+ className: cn(
7839
+ "group/message flex items-end",
7840
+ gapClass,
7841
+ role === "user" && variant !== "flat" ? "flex-row-reverse" : "flex-row",
7842
+ className
7843
+ ),
7844
+ ...props
7845
+ },
7846
+ children
7847
+ ));
7848
+ }
7849
+ );
7850
+ ChatMessageRoot.displayName = "ChatMessage";
7851
+ function DefaultAiIcon() {
7852
+ return /* @__PURE__ */ React39.createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "w-3/5 h-3/5", "aria-hidden": "true" }, /* @__PURE__ */ React39.createElement("path", { d: "M12 3l1.8 5.4 5.4 1.8-5.4 1.8L12 17.4l-1.8-5.4L4.8 10.2l5.4-1.8z" }), /* @__PURE__ */ React39.createElement("path", { d: "M19.5 3.5l.8 2.4 2.4.8-2.4.8L19.5 10l-.8-2.5-2.4-.8 2.4-.8z", opacity: ".6" }), /* @__PURE__ */ React39.createElement("path", { d: "M4.5 14.5l.7 2 2 .7-2 .7L4.5 20l-.7-2-2-.7 2-.7z", opacity: ".4" }));
7853
+ }
7854
+ var ChatMessageAvatar = React39.forwardRef(
7855
+ ({ className, size: avatarSize = "md", src, alt = "Avatar", initials, icon }, ref) => /* @__PURE__ */ React39.createElement(
7856
+ Avatar,
7857
+ {
7858
+ ref,
7859
+ "aria-hidden": "true",
7860
+ className: cn(chatAvatarSizeMap[avatarSize], "shrink-0", className)
7861
+ },
7862
+ src && /* @__PURE__ */ React39.createElement(AvatarImage, { src, alt }),
7863
+ /* @__PURE__ */ React39.createElement(AvatarFallback, { className: cn("font-semibold", chatAvatarFontMap[avatarSize]) }, icon ?? (initials || /* @__PURE__ */ React39.createElement(DefaultAiIcon, null)))
7864
+ )
7865
+ );
7866
+ ChatMessageAvatar.displayName = "ChatMessage.Avatar";
7867
+ var ChatMessageContent = React39.forwardRef(
7868
+ ({ className, children, ...props }, ref) => {
7869
+ const { role, variant, color, size, radius, tail, typing, actions } = React39.useContext(ChatMessageContext);
7870
+ const isTyping = !!typing;
7871
+ const typingProps = typeof typing === "object" ? typing : {};
7872
+ const isDarkBg = color === "primary" || color === "dark";
7873
+ const invertDots = variant === "bubble" && isDarkBg;
7874
+ const effectiveTail = variant === "flat" ? false : tail;
7875
+ const radiusClasses2 = effectiveTail ? bubbleRadiusTailMap[radius][role] : bubbleRadiusSymMap[radius];
7876
+ const bubble = /* @__PURE__ */ React39.createElement(
7877
+ "div",
7878
+ {
7879
+ ref,
7880
+ className: cn(
7881
+ bubbleTextMap[size],
7882
+ variant === "bubble" && "max-w-[75%]",
7883
+ isTyping && [typingMinWidthMap[size], "text-center"],
7884
+ getBubbleColors(color, variant),
7885
+ (variant === "bubble" || variant === "flat") && bubblePaddingMap[size],
7886
+ (variant === "bubble" || variant === "flat" && color === "muted") && radiusClasses2,
7887
+ className
7888
+ ),
7889
+ ...props
7890
+ },
7891
+ isTyping ? /* @__PURE__ */ React39.createElement(
7892
+ TypingIndicator,
7893
+ {
7894
+ size: typingSizeMap[size],
7895
+ color: "muted",
7896
+ ...typingProps,
7897
+ className: cn("align-middle", invertDots && "[&>div>div]:bg-current")
7898
+ }
7899
+ ) : children
7900
+ );
7901
+ if (!actions) return bubble;
7902
+ return /* @__PURE__ */ React39.createElement("div", { className: cn("flex items-end gap-1.5", role === "user" && variant !== "flat" ? "flex-row-reverse" : "flex-row") }, bubble, /* @__PURE__ */ React39.createElement("div", { className: cn(
7903
+ "shrink-0 flex items-center gap-1 pb-0.5",
7904
+ "opacity-0 group-hover/message:opacity-100",
7905
+ "transition-opacity duration-normal"
7906
+ ) }, actions));
7907
+ }
7908
+ );
7909
+ ChatMessageContent.displayName = "ChatMessage.Content";
7910
+ var ChatMessageFooter = React39.forwardRef(
7911
+ ({
7912
+ className,
7913
+ timestamp,
7914
+ status,
7915
+ role: roleProp,
7916
+ size: sizeProp,
7917
+ children,
7918
+ ...props
7919
+ }, ref) => {
7920
+ const ctx = React39.useContext(ChatMessageContext);
7921
+ const role = roleProp ?? ctx.role;
7922
+ const size = sizeProp ?? ctx.size;
7923
+ const variant = ctx.variant;
7924
+ const statusContent = React39.useMemo(() => {
7925
+ if (status == null) return null;
7926
+ if (typeof status === "string" && status in builtInStatusLabels) {
7927
+ const { label, className: cls } = builtInStatusLabels[status];
7928
+ return /* @__PURE__ */ React39.createElement("span", { className: cls }, label);
7929
+ }
7930
+ return status;
7931
+ }, [status]);
7932
+ return /* @__PURE__ */ React39.createElement(
7933
+ "div",
7934
+ {
7935
+ ref,
7936
+ className: cn(
7937
+ "flex items-center gap-1 select-none",
7938
+ footerTextMap[size],
7939
+ "text-text-subtle",
7940
+ role === "user" && variant !== "flat" ? "justify-end" : "justify-start",
7941
+ className
7942
+ ),
7943
+ ...props
7944
+ },
7945
+ children,
7946
+ statusContent,
7947
+ timestamp && /* @__PURE__ */ React39.createElement("span", null, timestamp)
7948
+ );
7949
+ }
7950
+ );
7951
+ ChatMessageFooter.displayName = "ChatMessage.Footer";
7952
+ var ChatMessage = Object.assign(ChatMessageRoot, {
7953
+ Avatar: ChatMessageAvatar,
7954
+ Content: ChatMessageContent,
7955
+ Footer: ChatMessageFooter
7956
+ });
7083
7957
  // Annotate the CommonJS export names for ESM import in node:
7084
7958
  0 && (module.exports = {
7085
7959
  Accordion,
@@ -7124,6 +7998,15 @@ Skeleton.displayName = "Skeleton";
7124
7998
  CardHeader,
7125
7999
  CardImage,
7126
8000
  CardTitle,
8001
+ ChatInput,
8002
+ ChatInputField,
8003
+ ChatInputRoot,
8004
+ ChatInputSubmit,
8005
+ ChatMessage,
8006
+ ChatMessageAvatar,
8007
+ ChatMessageContent,
8008
+ ChatMessageFooter,
8009
+ ChatMessageRoot,
7127
8010
  Checkbox,
7128
8011
  Divider,
7129
8012
  Drawer,
@@ -7204,6 +8087,9 @@ Skeleton.displayName = "Skeleton";
7204
8087
  PopoverRoot,
7205
8088
  PopoverTrigger,
7206
8089
  Progress,
8090
+ QuickReply,
8091
+ QuickReplyItem,
8092
+ QuickReplyRoot,
7207
8093
  RadioGroup,
7208
8094
  RadioGroupItem,
7209
8095
  Segmented,
@@ -7244,6 +8130,7 @@ Skeleton.displayName = "Skeleton";
7244
8130
  TooltipProvider,
7245
8131
  TooltipRoot,
7246
8132
  TooltipTrigger,
8133
+ TypingIndicator,
7247
8134
  accordionTriggerVariants,
7248
8135
  accordionVariants,
7249
8136
  alertModalContentVariants,
@@ -7254,6 +8141,7 @@ Skeleton.displayName = "Skeleton";
7254
8141
  breadcrumbSizeMap,
7255
8142
  buttonVariants,
7256
8143
  cardVariants,
8144
+ chatInputVariants,
7257
8145
  checkboxVariants,
7258
8146
  dividerVariants,
7259
8147
  drawerSizeHorizontal,
@@ -7269,6 +8157,8 @@ Skeleton.displayName = "Skeleton";
7269
8157
  paginationItemVariants,
7270
8158
  paginationSizeMap,
7271
8159
  popoverContentVariants,
8160
+ quickReplyItemVariants,
8161
+ quickReplyRootVariants,
7272
8162
  radioGroupVariants,
7273
8163
  radioItemVariants,
7274
8164
  segmentedItemVariants,
@@ -7286,6 +8176,7 @@ Skeleton.displayName = "Skeleton";
7286
8176
  toggleGroupVariants,
7287
8177
  toggleVariants,
7288
8178
  tooltipContentVariants,
8179
+ typingIndicatorVariants,
7289
8180
  useButtonGroup,
7290
8181
  useFieldContext,
7291
8182
  usePagination