@camtomlabs/malix-design-system 0.1.2 → 0.1.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.
Files changed (58) hide show
  1. package/LICENSE +19 -5
  2. package/README.md +141 -10
  3. package/dist/index.cjs +2456 -0
  4. package/dist/index.d.cts +562 -0
  5. package/dist/index.d.ts +562 -0
  6. package/dist/index.js +2367 -0
  7. package/package.json +21 -8
  8. package/src/styles.css +186 -0
  9. package/src/components/Accordion.tsx +0 -52
  10. package/src/components/Avatar.tsx +0 -18
  11. package/src/components/Badge.tsx +0 -27
  12. package/src/components/Banner.tsx +0 -75
  13. package/src/components/Breadcrumb.tsx +0 -58
  14. package/src/components/Button.tsx +0 -47
  15. package/src/components/Card.tsx +0 -34
  16. package/src/components/ChatInput.tsx +0 -53
  17. package/src/components/Checkbox.tsx +0 -85
  18. package/src/components/CreditsIndicator.tsx +0 -41
  19. package/src/components/DataTable.tsx +0 -75
  20. package/src/components/DateInput.tsx +0 -57
  21. package/src/components/Divider.tsx +0 -12
  22. package/src/components/Dropzone.tsx +0 -94
  23. package/src/components/EmptyState.tsx +0 -65
  24. package/src/components/FileCard.tsx +0 -78
  25. package/src/components/FilterTabs.tsx +0 -49
  26. package/src/components/FlyoutMenu.tsx +0 -36
  27. package/src/components/GlassPopover.tsx +0 -38
  28. package/src/components/Header.tsx +0 -22
  29. package/src/components/Input.tsx +0 -18
  30. package/src/components/InputGroup.tsx +0 -37
  31. package/src/components/LanguageSelector.tsx +0 -81
  32. package/src/components/Modal.tsx +0 -104
  33. package/src/components/OnboardingPopover.tsx +0 -61
  34. package/src/components/OperationStatus.tsx +0 -73
  35. package/src/components/Overlay.tsx +0 -66
  36. package/src/components/Pagination.tsx +0 -89
  37. package/src/components/Pill.tsx +0 -19
  38. package/src/components/PricingCard.tsx +0 -74
  39. package/src/components/ProgressBar.tsx +0 -47
  40. package/src/components/Radio.tsx +0 -56
  41. package/src/components/SectionHeader.tsx +0 -32
  42. package/src/components/SegmentedControl.tsx +0 -42
  43. package/src/components/Select.tsx +0 -62
  44. package/src/components/SelectGroup.tsx +0 -32
  45. package/src/components/SelectionCard.tsx +0 -47
  46. package/src/components/SidebarItem.tsx +0 -27
  47. package/src/components/SidebarPanel.tsx +0 -84
  48. package/src/components/SplitPane.tsx +0 -85
  49. package/src/components/StatCard.tsx +0 -64
  50. package/src/components/StatusDot.tsx +0 -26
  51. package/src/components/Stepper.tsx +0 -40
  52. package/src/components/TabBar.tsx +0 -45
  53. package/src/components/Textarea.tsx +0 -43
  54. package/src/components/Toggle.tsx +0 -50
  55. package/src/components/Tooltip.tsx +0 -33
  56. package/src/components/UserProfilePopover.tsx +0 -100
  57. package/src/components/ValidationAlert.tsx +0 -72
  58. package/src/index.ts +0 -177
package/package.json CHANGED
@@ -1,16 +1,20 @@
1
1
  {
2
2
  "name": "@camtomlabs/malix-design-system",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Malix Design System combined package with components, tokens, and bundled styles.",
5
5
  "type": "module",
6
- "main": "src/index.ts",
7
- "types": "src/index.ts",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
8
9
  "sideEffects": [
9
10
  "./src/styles.css",
10
11
  "./src/tokens.css"
11
12
  ],
12
13
  "files": [
13
- "src"
14
+ "dist",
15
+ "src/styles.css",
16
+ "src/tokens.css",
17
+ "src/tokens.registry.json"
14
18
  ],
15
19
  "repository": {
16
20
  "type": "git",
@@ -28,9 +32,13 @@
28
32
  "components",
29
33
  "tokens"
30
34
  ],
31
- "license": "UNLICENSED",
35
+ "license": "MIT",
32
36
  "exports": {
33
- ".": "./src/index.ts",
37
+ ".": {
38
+ "types": "./dist/index.d.ts",
39
+ "import": "./dist/index.js",
40
+ "require": "./dist/index.cjs"
41
+ },
34
42
  "./styles.css": "./src/styles.css",
35
43
  "./tokens.css": "./src/tokens.css",
36
44
  "./tokens.registry.json": "./src/tokens.registry.json"
@@ -43,7 +51,12 @@
43
51
  "access": "public"
44
52
  },
45
53
  "scripts": {
46
- "lint": "eslint src",
47
- "build": "node -e \"console.log('malix build: source package ready')\""
54
+ "build": "tsup",
55
+ "lint": "eslint src"
56
+ },
57
+ "devDependencies": {
58
+ "@types/react": "^19.0.0",
59
+ "@types/react-dom": "^19.0.0",
60
+ "tsup": "^8.5.1"
48
61
  }
49
62
  }
package/src/styles.css CHANGED
@@ -3235,3 +3235,189 @@ a.malix-breadcrumb__label:hover {
3235
3235
  height: 16px;
3236
3236
  flex-shrink: 0;
3237
3237
  }
3238
+
3239
+ /* ═══════════════════════════════════════════════
3240
+ CHAT BUBBLE — Pencil: gNrQK, dqzNT
3241
+ AI: surface-secondary bg, foreground text
3242
+ User: cta-primary bg, primary-foreground text
3243
+ ═══════════════════════════════════════════════ */
3244
+
3245
+ .malix-chat-bubble-row {
3246
+ display: flex;
3247
+ align-items: flex-end;
3248
+ gap: var(--malix-space-sm);
3249
+ width: 100%;
3250
+ }
3251
+
3252
+ .malix-chat-bubble-row[data-variant="user"] {
3253
+ justify-content: flex-end;
3254
+ }
3255
+
3256
+ .malix-chat-bubble {
3257
+ padding: 10px 14px;
3258
+ font-family: var(--malix-font-body);
3259
+ font-size: var(--malix-text-sm);
3260
+ font-weight: var(--malix-weight-normal);
3261
+ line-height: 1.45;
3262
+ max-width: 280px;
3263
+ word-wrap: break-word;
3264
+ }
3265
+
3266
+ .malix-chat-bubble[data-variant="ai"] {
3267
+ background: var(--malix-surface-secondary);
3268
+ color: var(--malix-foreground);
3269
+ border-radius: 8px 8px 8px 2px;
3270
+ }
3271
+
3272
+ .malix-chat-bubble[data-variant="user"] {
3273
+ background: var(--malix-cta-primary-bg);
3274
+ color: var(--malix-primary-foreground);
3275
+ border-radius: 8px 8px 2px 8px;
3276
+ }
3277
+
3278
+ .malix-chat-bubble__avatar {
3279
+ display: inline-flex;
3280
+ align-items: center;
3281
+ justify-content: center;
3282
+ width: 28px;
3283
+ height: 28px;
3284
+ min-width: 28px;
3285
+ border-radius: 50%;
3286
+ background: var(--malix-background-main);
3287
+ border: 1px solid var(--malix-border);
3288
+ font-family: var(--malix-font-body);
3289
+ font-size: var(--malix-text-xs);
3290
+ font-weight: var(--malix-weight-semibold);
3291
+ color: var(--malix-foreground-secondary);
3292
+ }
3293
+
3294
+ /* ═══════════════════════════════════════════════
3295
+ AI ASSISTANT PANEL — Pencil: MtZxU
3296
+ 380×500 panel, border+radius-lg, vertical flex
3297
+ ═══════════════════════════════════════════════ */
3298
+
3299
+ .malix-ai-panel {
3300
+ display: flex;
3301
+ flex-direction: column;
3302
+ width: 380px;
3303
+ height: 500px;
3304
+ border-radius: var(--malix-radius-lg);
3305
+ background: var(--malix-background-main);
3306
+ border: 1px solid var(--malix-border);
3307
+ overflow: hidden;
3308
+ font-family: var(--malix-font-body);
3309
+ }
3310
+
3311
+ /* Header */
3312
+ .malix-ai-panel__header {
3313
+ display: flex;
3314
+ align-items: center;
3315
+ gap: 10px;
3316
+ padding: 14px 16px;
3317
+ border-bottom: 1px solid var(--malix-border);
3318
+ }
3319
+
3320
+ .malix-ai-panel__logo {
3321
+ display: inline-flex;
3322
+ align-items: center;
3323
+ justify-content: center;
3324
+ width: 28px;
3325
+ height: 28px;
3326
+ min-width: 28px;
3327
+ border-radius: var(--malix-radius-pill);
3328
+ background: var(--malix-cta-primary-bg);
3329
+ color: var(--malix-primary-foreground);
3330
+ }
3331
+
3332
+ .malix-ai-panel__title {
3333
+ font-size: var(--malix-text-base);
3334
+ font-weight: var(--malix-weight-semibold);
3335
+ color: var(--malix-foreground);
3336
+ flex: 1;
3337
+ }
3338
+
3339
+ .malix-ai-panel__close {
3340
+ display: inline-flex;
3341
+ align-items: center;
3342
+ justify-content: center;
3343
+ background: none;
3344
+ border: none;
3345
+ padding: 0;
3346
+ cursor: pointer;
3347
+ color: var(--malix-foreground-secondary);
3348
+ transition: color 120ms ease;
3349
+ }
3350
+
3351
+ .malix-ai-panel__close:hover {
3352
+ color: var(--malix-foreground);
3353
+ }
3354
+
3355
+ /* Body */
3356
+ .malix-ai-panel__body {
3357
+ flex: 1;
3358
+ overflow-y: auto;
3359
+ padding: 12px 16px;
3360
+ display: flex;
3361
+ flex-direction: column;
3362
+ gap: var(--malix-space-md);
3363
+ }
3364
+
3365
+ /* Footer */
3366
+ .malix-ai-panel__footer {
3367
+ padding: 12px 16px;
3368
+ border-top: 1px solid var(--malix-border);
3369
+ }
3370
+
3371
+ .malix-ai-panel__input-row {
3372
+ display: flex;
3373
+ align-items: center;
3374
+ gap: var(--malix-space-sm);
3375
+ padding: 10px 12px 10px 16px;
3376
+ border-radius: var(--malix-radius-lg);
3377
+ border: 1px solid var(--malix-border);
3378
+ background: var(--malix-background-main);
3379
+ transition: border-color 120ms ease;
3380
+ }
3381
+
3382
+ .malix-ai-panel__input-row:focus-within {
3383
+ border-color: var(--malix-border-focus);
3384
+ }
3385
+
3386
+ .malix-ai-panel__input {
3387
+ flex: 1;
3388
+ border: none;
3389
+ outline: none;
3390
+ background: transparent;
3391
+ font-family: var(--malix-font-body);
3392
+ font-size: var(--malix-text-base);
3393
+ color: var(--malix-foreground);
3394
+ padding: 0;
3395
+ }
3396
+
3397
+ .malix-ai-panel__input::placeholder {
3398
+ color: var(--malix-foreground-tertiary);
3399
+ }
3400
+
3401
+ .malix-ai-panel__send {
3402
+ display: inline-flex;
3403
+ align-items: center;
3404
+ justify-content: center;
3405
+ width: 32px;
3406
+ height: 32px;
3407
+ min-width: 32px;
3408
+ border-radius: var(--malix-radius-md);
3409
+ background: var(--malix-cta-primary-bg);
3410
+ color: var(--malix-primary-foreground);
3411
+ border: none;
3412
+ cursor: pointer;
3413
+ transition: background-color 120ms ease;
3414
+ }
3415
+
3416
+ .malix-ai-panel__send:hover:not(:disabled) {
3417
+ background: var(--malix-primary-hover);
3418
+ }
3419
+
3420
+ .malix-ai-panel__send:disabled {
3421
+ opacity: 0.5;
3422
+ cursor: not-allowed;
3423
+ }
@@ -1,52 +0,0 @@
1
- import React, { useState } from 'react';
2
-
3
- export type AccordionProps = React.HTMLAttributes<HTMLDivElement> & {
4
- title: string;
5
- children: React.ReactNode;
6
- defaultOpen?: boolean;
7
- icon?: React.ReactNode;
8
- };
9
-
10
- export function Accordion({
11
- title,
12
- children,
13
- defaultOpen = false,
14
- icon,
15
- className,
16
- ...props
17
- }: AccordionProps) {
18
- const [open, setOpen] = useState(defaultOpen);
19
-
20
- return (
21
- <div
22
- className={`malix-accordion${className ? ` ${className}` : ''}`}
23
- data-open={open}
24
- {...props}
25
- >
26
- <button
27
- type="button"
28
- className="malix-accordion__header"
29
- onClick={() => setOpen((prev) => !prev)}
30
- aria-expanded={open}
31
- >
32
- {icon ? <span className="malix-accordion__icon">{icon}</span> : null}
33
- <span className="malix-accordion__title">{title}</span>
34
- <svg
35
- className="malix-accordion__chevron"
36
- width="16"
37
- height="16"
38
- viewBox="0 0 24 24"
39
- fill="none"
40
- stroke="currentColor"
41
- strokeWidth="2"
42
- strokeLinecap="round"
43
- strokeLinejoin="round"
44
- aria-hidden="true"
45
- >
46
- <polyline points="6 9 12 15 18 9" />
47
- </svg>
48
- </button>
49
- <div className="malix-accordion__body">{children}</div>
50
- </div>
51
- );
52
- }
@@ -1,18 +0,0 @@
1
- import React from 'react';
2
-
3
- export type AvatarProps = React.HTMLAttributes<HTMLSpanElement> & {
4
- initials: string;
5
- size?: number;
6
- };
7
-
8
- export function Avatar({ initials, size = 40, className, style, ...props }: AvatarProps) {
9
- return (
10
- <span
11
- className={`malix-avatar${className ? ` ${className}` : ''}`}
12
- style={{ width: size, height: size, borderRadius: size * 0.35, ...style }}
13
- {...props}
14
- >
15
- <span className="malix-avatar__text">{initials}</span>
16
- </span>
17
- );
18
- }
@@ -1,27 +0,0 @@
1
- import React from 'react';
2
-
3
- export type BadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'error';
4
-
5
- export type BadgeProps = React.HTMLAttributes<HTMLSpanElement> & {
6
- variant?: BadgeVariant;
7
- dot?: boolean;
8
- };
9
-
10
- export function Badge({
11
- variant = 'default',
12
- dot = false,
13
- children,
14
- className,
15
- ...props
16
- }: BadgeProps) {
17
- return (
18
- <span
19
- className={`malix-badge${className ? ` ${className}` : ''}`}
20
- data-variant={variant}
21
- {...props}
22
- >
23
- {dot ? <span className="malix-badge__dot" /> : null}
24
- <span className="malix-badge__label">{children}</span>
25
- </span>
26
- );
27
- }
@@ -1,75 +0,0 @@
1
- import React from 'react';
2
-
3
- export type BannerVariant = 'info' | 'success' | 'warning' | 'error';
4
-
5
- export type BannerProps = React.HTMLAttributes<HTMLDivElement> & {
6
- variant?: BannerVariant;
7
- onClose?: () => void;
8
- icon?: React.ReactNode;
9
- };
10
-
11
- const defaultIcons: Record<BannerVariant, React.ReactNode> = {
12
- info: (
13
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
14
- <circle cx="12" cy="12" r="10" />
15
- <line x1="12" y1="16" x2="12" y2="12" />
16
- <line x1="12" y1="8" x2="12.01" y2="8" />
17
- </svg>
18
- ),
19
- success: (
20
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
21
- <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
22
- <polyline points="22 4 12 14.01 9 11.01" />
23
- </svg>
24
- ),
25
- warning: (
26
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
27
- <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
28
- <line x1="12" y1="9" x2="12" y2="13" />
29
- <line x1="12" y1="17" x2="12.01" y2="17" />
30
- </svg>
31
- ),
32
- error: (
33
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
34
- <circle cx="12" cy="12" r="10" />
35
- <line x1="15" y1="9" x2="9" y2="15" />
36
- <line x1="9" y1="9" x2="15" y2="15" />
37
- </svg>
38
- ),
39
- };
40
-
41
- export function Banner({
42
- variant = 'info',
43
- onClose,
44
- icon,
45
- children,
46
- className,
47
- ...props
48
- }: BannerProps) {
49
- return (
50
- <div
51
- className={`malix-banner${className ? ` ${className}` : ''}`}
52
- data-variant={variant}
53
- role="alert"
54
- {...props}
55
- >
56
- <span className="malix-banner__icon">
57
- {icon ?? defaultIcons[variant]}
58
- </span>
59
- <span className="malix-banner__content">{children}</span>
60
- {onClose ? (
61
- <button
62
- type="button"
63
- className="malix-banner__close"
64
- onClick={onClose}
65
- aria-label="Dismiss"
66
- >
67
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
68
- <line x1="18" y1="6" x2="6" y2="18" />
69
- <line x1="6" y1="6" x2="18" y2="18" />
70
- </svg>
71
- </button>
72
- ) : null}
73
- </div>
74
- );
75
- }
@@ -1,58 +0,0 @@
1
- import React from 'react';
2
-
3
- export type BreadcrumbItem = {
4
- label: string;
5
- href?: string;
6
- icon?: React.ReactNode;
7
- active?: boolean;
8
- };
9
-
10
- export type BreadcrumbProps = React.HTMLAttributes<HTMLElement> & {
11
- items: BreadcrumbItem[];
12
- separator?: React.ReactNode;
13
- };
14
-
15
- const DefaultSeparator = () => (
16
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
17
- <path d="M6 3L11 8L6 13" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
18
- </svg>
19
- );
20
-
21
- export function Breadcrumb({ items, separator, className, ...props }: BreadcrumbProps) {
22
- return (
23
- <nav
24
- className={`malix-breadcrumb${className ? ` ${className}` : ''}`}
25
- aria-label="Breadcrumb"
26
- {...props}
27
- >
28
- {items.map((item, index) => {
29
- const isLast = index === items.length - 1;
30
- const isActive = item.active ?? isLast;
31
-
32
- return (
33
- <React.Fragment key={index}>
34
- <span className="malix-breadcrumb__item" data-active={isActive || undefined}>
35
- {item.icon ? (
36
- <span className="malix-breadcrumb__icon">{item.icon}</span>
37
- ) : null}
38
- {isActive || !item.href ? (
39
- <span className="malix-breadcrumb__label" aria-current={isActive ? 'page' : undefined}>
40
- {item.label}
41
- </span>
42
- ) : (
43
- <a className="malix-breadcrumb__label" href={item.href}>
44
- {item.label}
45
- </a>
46
- )}
47
- </span>
48
- {!isLast ? (
49
- <span className="malix-breadcrumb__separator" aria-hidden="true">
50
- {separator ?? <DefaultSeparator />}
51
- </span>
52
- ) : null}
53
- </React.Fragment>
54
- );
55
- })}
56
- </nav>
57
- );
58
- }
@@ -1,47 +0,0 @@
1
- import React from 'react';
2
-
3
- export type ButtonHierarchy = 'primary' | 'secondary' | 'tertiary' | 'ghost';
4
- export type ButtonVariant = 'text' | 'leading-icon-text' | 'icon-only' | 'icon-badge';
5
-
6
- export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
7
- hierarchy?: ButtonHierarchy;
8
- variant?: ButtonVariant;
9
- icon?: React.ReactNode;
10
- badge?: React.ReactNode;
11
- loading?: boolean;
12
- label?: string;
13
- };
14
-
15
- export function Button({
16
- hierarchy = 'primary',
17
- variant = 'text',
18
- icon,
19
- badge,
20
- loading = false,
21
- disabled,
22
- children,
23
- label,
24
- ...props
25
- }: ButtonProps) {
26
- const isDisabled = disabled || loading;
27
- const isIconOnly = variant === 'icon-only';
28
-
29
- return (
30
- <button
31
- type="button"
32
- className="malix-button"
33
- data-hierarchy={hierarchy}
34
- data-variant={variant}
35
- data-loading={loading}
36
- disabled={isDisabled}
37
- aria-busy={loading || undefined}
38
- aria-label={isIconOnly ? label : props['aria-label']}
39
- {...props}
40
- >
41
- {icon ? <span className="malix-button__icon">{icon}</span> : null}
42
- {!isIconOnly ? <span>{loading ? 'Loading...' : children}</span> : null}
43
- {variant === 'icon-badge' && badge ? <span className="malix-button__badge">{badge}</span> : null}
44
- {isIconOnly && !icon ? <span>{loading ? '...' : label}</span> : null}
45
- </button>
46
- );
47
- }
@@ -1,34 +0,0 @@
1
- import React from 'react';
2
-
3
- export type CardLevel = 1 | 2 | 3;
4
-
5
- export type CardProps = React.HTMLAttributes<HTMLDivElement> & {
6
- level?: CardLevel;
7
- title?: string;
8
- description?: string;
9
- };
10
-
11
- export function Card({
12
- level = 1,
13
- title,
14
- description,
15
- children,
16
- className,
17
- ...props
18
- }: CardProps) {
19
- return (
20
- <div
21
- className={`malix-card${className ? ` ${className}` : ''}`}
22
- data-level={level}
23
- {...props}
24
- >
25
- {(title || description) ? (
26
- <div className="malix-card__header">
27
- {title ? <h3 className="malix-card__title">{title}</h3> : null}
28
- {description ? <p className="malix-card__desc">{description}</p> : null}
29
- </div>
30
- ) : null}
31
- {children ? <div className="malix-card__body">{children}</div> : null}
32
- </div>
33
- );
34
- }
@@ -1,53 +0,0 @@
1
- import React from 'react';
2
-
3
- export type ChatInputProps = {
4
- value: string;
5
- onChange: (value: string) => void;
6
- onSend: () => void;
7
- placeholder?: string;
8
- disabled?: boolean;
9
- className?: string;
10
- };
11
-
12
- export function ChatInput({
13
- value,
14
- onChange,
15
- onSend,
16
- placeholder = 'Type a message...',
17
- disabled,
18
- className,
19
- }: ChatInputProps) {
20
- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
21
- if (e.key === 'Enter' && !e.shiftKey && value.trim()) {
22
- e.preventDefault();
23
- onSend();
24
- }
25
- };
26
-
27
- return (
28
- <div className={`malix-chat-input${className ? ` ${className}` : ''}`}>
29
- <input
30
- type="text"
31
- className="malix-chat-input__field"
32
- value={value}
33
- onChange={(e) => onChange(e.target.value)}
34
- onKeyDown={handleKeyDown}
35
- placeholder={placeholder}
36
- disabled={disabled}
37
- aria-label={placeholder}
38
- />
39
- <button
40
- type="button"
41
- className="malix-chat-input__send-btn"
42
- onClick={onSend}
43
- disabled={disabled || !value.trim()}
44
- aria-label="Send message"
45
- >
46
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
47
- <path d="M12 19V5" />
48
- <path d="m5 12 7-7 7 7" />
49
- </svg>
50
- </button>
51
- </div>
52
- );
53
- }