@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.
- package/LICENSE +19 -5
- package/README.md +141 -10
- package/dist/index.cjs +2456 -0
- package/dist/index.d.cts +562 -0
- package/dist/index.d.ts +562 -0
- package/dist/index.js +2367 -0
- package/package.json +21 -8
- package/src/styles.css +186 -0
- package/src/components/Accordion.tsx +0 -52
- package/src/components/Avatar.tsx +0 -18
- package/src/components/Badge.tsx +0 -27
- package/src/components/Banner.tsx +0 -75
- package/src/components/Breadcrumb.tsx +0 -58
- package/src/components/Button.tsx +0 -47
- package/src/components/Card.tsx +0 -34
- package/src/components/ChatInput.tsx +0 -53
- package/src/components/Checkbox.tsx +0 -85
- package/src/components/CreditsIndicator.tsx +0 -41
- package/src/components/DataTable.tsx +0 -75
- package/src/components/DateInput.tsx +0 -57
- package/src/components/Divider.tsx +0 -12
- package/src/components/Dropzone.tsx +0 -94
- package/src/components/EmptyState.tsx +0 -65
- package/src/components/FileCard.tsx +0 -78
- package/src/components/FilterTabs.tsx +0 -49
- package/src/components/FlyoutMenu.tsx +0 -36
- package/src/components/GlassPopover.tsx +0 -38
- package/src/components/Header.tsx +0 -22
- package/src/components/Input.tsx +0 -18
- package/src/components/InputGroup.tsx +0 -37
- package/src/components/LanguageSelector.tsx +0 -81
- package/src/components/Modal.tsx +0 -104
- package/src/components/OnboardingPopover.tsx +0 -61
- package/src/components/OperationStatus.tsx +0 -73
- package/src/components/Overlay.tsx +0 -66
- package/src/components/Pagination.tsx +0 -89
- package/src/components/Pill.tsx +0 -19
- package/src/components/PricingCard.tsx +0 -74
- package/src/components/ProgressBar.tsx +0 -47
- package/src/components/Radio.tsx +0 -56
- package/src/components/SectionHeader.tsx +0 -32
- package/src/components/SegmentedControl.tsx +0 -42
- package/src/components/Select.tsx +0 -62
- package/src/components/SelectGroup.tsx +0 -32
- package/src/components/SelectionCard.tsx +0 -47
- package/src/components/SidebarItem.tsx +0 -27
- package/src/components/SidebarPanel.tsx +0 -84
- package/src/components/SplitPane.tsx +0 -85
- package/src/components/StatCard.tsx +0 -64
- package/src/components/StatusDot.tsx +0 -26
- package/src/components/Stepper.tsx +0 -40
- package/src/components/TabBar.tsx +0 -45
- package/src/components/Textarea.tsx +0 -43
- package/src/components/Toggle.tsx +0 -50
- package/src/components/Tooltip.tsx +0 -33
- package/src/components/UserProfilePopover.tsx +0 -100
- package/src/components/ValidationAlert.tsx +0 -72
- 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.
|
|
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": "
|
|
7
|
-
"
|
|
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
|
-
"
|
|
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": "
|
|
35
|
+
"license": "MIT",
|
|
32
36
|
"exports": {
|
|
33
|
-
".":
|
|
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
|
-
"
|
|
47
|
-
"
|
|
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
|
-
}
|
package/src/components/Badge.tsx
DELETED
|
@@ -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
|
-
}
|
package/src/components/Card.tsx
DELETED
|
@@ -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
|
-
}
|