@7onic-ui/react 0.2.1 → 0.2.3

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