beacon-ui 3.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/CHANGELOG.md +50 -0
- package/README.md +175 -0
- package/dist/components/Avatar.d.ts +20 -0
- package/dist/components/Avatar.d.ts.map +1 -0
- package/dist/components/Avatar.js +174 -0
- package/dist/components/Button.d.ts +21 -0
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/Button.js +227 -0
- package/dist/components/Card.d.ts +40 -0
- package/dist/components/Card.d.ts.map +1 -0
- package/dist/components/Card.js +517 -0
- package/dist/components/Checkbox.d.ts +12 -0
- package/dist/components/Checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox.js +64 -0
- package/dist/components/CheckboxPreview.d.ts +13 -0
- package/dist/components/CheckboxPreview.d.ts.map +1 -0
- package/dist/components/CheckboxPreview.js +155 -0
- package/dist/components/Chip.d.ts +15 -0
- package/dist/components/Chip.d.ts.map +1 -0
- package/dist/components/Chip.js +99 -0
- package/dist/components/Input.d.ts +24 -0
- package/dist/components/Input.d.ts.map +1 -0
- package/dist/components/Input.js +138 -0
- package/dist/components/Menu.d.ts +20 -0
- package/dist/components/Menu.d.ts.map +1 -0
- package/dist/components/Menu.js +252 -0
- package/dist/components/RadioButton.d.ts +13 -0
- package/dist/components/RadioButton.d.ts.map +1 -0
- package/dist/components/RadioButton.js +140 -0
- package/dist/components/Switch.d.ts +11 -0
- package/dist/components/Switch.d.ts.map +1 -0
- package/dist/components/Switch.js +64 -0
- package/dist/components/SwitchPreview.d.ts +14 -0
- package/dist/components/SwitchPreview.d.ts.map +1 -0
- package/dist/components/SwitchPreview.js +281 -0
- package/dist/icons/index.d.ts +97 -0
- package/dist/icons/index.d.ts.map +1 -0
- package/dist/icons/index.js +383 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/providers/ThemeProvider.d.ts +23 -0
- package/dist/providers/ThemeProvider.d.ts.map +1 -0
- package/dist/providers/ThemeProvider.js +79 -0
- package/dist/tokens/types.d.ts +14 -0
- package/dist/tokens/types.d.ts.map +1 -0
- package/dist/tokens/types.js +5 -0
- package/dist/utils/patternPaths.d.ts +28 -0
- package/dist/utils/patternPaths.d.ts.map +1 -0
- package/dist/utils/patternPaths.js +92 -0
- package/package.json +51 -0
- package/tokens/generated/brand-dark.css +86 -0
- package/tokens/generated/brand-light.css +86 -0
- package/tokens/generated/effects.css +10 -0
- package/tokens/generated/index.css +804 -0
- package/tokens/generated/primitives.css +116 -0
- package/tokens/generated/responsive.css +235 -0
- package/tokens/generated/semantic.css +138 -0
- package/tokens/generated/typography.css +124 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [3.1.4] - 2025-12-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial npm package release as `beacon-ui`
|
|
12
|
+
- README.md with installation and usage instructions
|
|
13
|
+
- CHANGELOG.md for version tracking
|
|
14
|
+
- Comprehensive documentation for all components
|
|
15
|
+
- TypeScript type exports for design tokens
|
|
16
|
+
- 9 production-ready components:
|
|
17
|
+
- Avatar
|
|
18
|
+
- Button
|
|
19
|
+
- Card
|
|
20
|
+
- Checkbox
|
|
21
|
+
- Chip
|
|
22
|
+
- Input
|
|
23
|
+
- Menu
|
|
24
|
+
- Radio Button
|
|
25
|
+
- Switch
|
|
26
|
+
- ThemeProvider for theme and hue management
|
|
27
|
+
- Complete design token system:
|
|
28
|
+
- Primitives (colors, spacing, typography)
|
|
29
|
+
- Semantic tokens (primary, success, warning, critical)
|
|
30
|
+
- Brand tokens (light/dark themes)
|
|
31
|
+
- Responsive tokens (desktop, tablet, mobile)
|
|
32
|
+
- Effect tokens (shadows)
|
|
33
|
+
- Typography tokens
|
|
34
|
+
- TypeScript support with full type definitions
|
|
35
|
+
- Icon component library
|
|
36
|
+
- Support for multiple themes (light/dark)
|
|
37
|
+
- Support for multiple hue variants (chromatic-prime, hue-sky, hue-indigo)
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
- Token-driven architecture
|
|
41
|
+
- WCAG 2.1 AA accessibility compliance
|
|
42
|
+
- Responsive design support
|
|
43
|
+
- Full TypeScript support
|
|
44
|
+
- React 18 and 19 compatibility
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Version History
|
|
49
|
+
|
|
50
|
+
- **3.1.4** - Initial release of `beacon-ui` package
|
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Beacon Design System
|
|
2
|
+
|
|
3
|
+
A comprehensive React design system with 9 production-ready components and design tokens. Built with TypeScript and token-driven architecture for consistency and scalability.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install beacon-ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Import Tokens CSS
|
|
14
|
+
|
|
15
|
+
Import the design tokens in your main CSS file or at the root of your application:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import 'beacon-ui/tokens';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or import specific token files:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import 'beacon-ui/tokens/primitives';
|
|
25
|
+
import 'beacon-ui/tokens/semantic';
|
|
26
|
+
import 'beacon-ui/tokens/brand-light';
|
|
27
|
+
import 'beacon-ui/tokens/brand-dark';
|
|
28
|
+
import 'beacon-ui/tokens/responsive';
|
|
29
|
+
import 'beacon-ui/tokens/effects';
|
|
30
|
+
import 'beacon-ui/tokens/typography';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Wrap Your App with ThemeProvider
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { ThemeProvider } from 'beacon-ui';
|
|
37
|
+
|
|
38
|
+
function App() {
|
|
39
|
+
return (
|
|
40
|
+
<ThemeProvider defaultTheme="dark" defaultHue="hue-sky">
|
|
41
|
+
{/* Your app content */}
|
|
42
|
+
</ThemeProvider>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Use Components
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { Button, Card, Checkbox, Switch, Input, Avatar, Chip, Menu, RadioButton } from 'beacon-ui';
|
|
51
|
+
|
|
52
|
+
function MyComponent() {
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<Button
|
|
56
|
+
variant="filled"
|
|
57
|
+
size="md"
|
|
58
|
+
cornerRadius={2}
|
|
59
|
+
hasStartIcon={false}
|
|
60
|
+
hasEndIcon={false}
|
|
61
|
+
fillContainer={false}
|
|
62
|
+
justifyContent="center"
|
|
63
|
+
state="default"
|
|
64
|
+
theme="dark"
|
|
65
|
+
hue="hue-sky"
|
|
66
|
+
/>
|
|
67
|
+
<Checkbox checked={true} onChange={(checked) => console.log(checked)} />
|
|
68
|
+
<Switch checked={false} onChange={(checked) => console.log(checked)} />
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Components
|
|
75
|
+
|
|
76
|
+
- **Avatar** - User avatars with icon, text, or image support
|
|
77
|
+
- **Button** - Multiple variants (filled, tonal, outline, link) with sizes and states
|
|
78
|
+
- **Card** - Flexible card components (product, experience, info, generic)
|
|
79
|
+
- **Checkbox** - Accessible checkbox with label support
|
|
80
|
+
- **Chip** - Compact labels and tags
|
|
81
|
+
- **Input** - Form inputs with icons, labels, and error states
|
|
82
|
+
- **Menu** - Navigation menus for desktop, tablet, and mobile
|
|
83
|
+
- **Radio Button** - Radio button groups with label support
|
|
84
|
+
- **Switch** - Toggle switches with optional icons
|
|
85
|
+
|
|
86
|
+
## Design Tokens
|
|
87
|
+
|
|
88
|
+
Beacon Design System uses a comprehensive token system:
|
|
89
|
+
|
|
90
|
+
- **Primitives** - Base color, spacing, and typography values
|
|
91
|
+
- **Semantic** - Context-aware tokens (primary, success, warning, critical)
|
|
92
|
+
- **Brand** - Theme-specific tokens (light/dark)
|
|
93
|
+
- **Responsive** - Breakpoint-aware tokens for desktop, tablet, and mobile
|
|
94
|
+
- **Effects** - Shadows and visual effects
|
|
95
|
+
- **Typography** - Font families, sizes, weights, and line heights
|
|
96
|
+
|
|
97
|
+
## Theme Support
|
|
98
|
+
|
|
99
|
+
Beacon supports multiple themes and hue variants:
|
|
100
|
+
|
|
101
|
+
### Themes
|
|
102
|
+
- `light` - Light theme
|
|
103
|
+
- `dark` - Dark theme (default)
|
|
104
|
+
|
|
105
|
+
### Hue Variants
|
|
106
|
+
- `chromatic-prime` - Default chromatic palette
|
|
107
|
+
- `hue-sky` - Sky blue variant
|
|
108
|
+
- `hue-indigo` - Indigo variant
|
|
109
|
+
|
|
110
|
+
### Using Theme Context
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { useTheme } from 'beacon-ui';
|
|
114
|
+
|
|
115
|
+
function ThemeToggle() {
|
|
116
|
+
const { theme, hue, setTheme, setHue, toggleTheme } = useTheme();
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<button onClick={toggleTheme}>
|
|
120
|
+
Current theme: {theme}
|
|
121
|
+
</button>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## TypeScript Support
|
|
127
|
+
|
|
128
|
+
Full TypeScript support with exported types:
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import type {
|
|
132
|
+
Theme,
|
|
133
|
+
HueVariant,
|
|
134
|
+
ColorPrimitive,
|
|
135
|
+
SemanticColor,
|
|
136
|
+
SpacingToken,
|
|
137
|
+
BackgroundToken,
|
|
138
|
+
ForegroundToken,
|
|
139
|
+
BorderToken
|
|
140
|
+
} from 'beacon-ui';
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Accessibility
|
|
144
|
+
|
|
145
|
+
All components are built with accessibility in mind:
|
|
146
|
+
- WCAG 2.1 AA compliant
|
|
147
|
+
- Proper ARIA attributes
|
|
148
|
+
- Keyboard navigation support
|
|
149
|
+
- Focus management
|
|
150
|
+
- Screen reader friendly
|
|
151
|
+
|
|
152
|
+
## Responsive Design
|
|
153
|
+
|
|
154
|
+
Components adapt seamlessly across breakpoints:
|
|
155
|
+
- Desktop (default)
|
|
156
|
+
- Tablet (max-width: 1024px)
|
|
157
|
+
- Mobile (max-width: 768px)
|
|
158
|
+
|
|
159
|
+
## Documentation
|
|
160
|
+
|
|
161
|
+
For detailed documentation, component APIs, and examples, visit:
|
|
162
|
+
https://beacon.uxraza.com/
|
|
163
|
+
|
|
164
|
+
## Version
|
|
165
|
+
|
|
166
|
+
Current version: **3.1.4**
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
171
|
+
|
|
172
|
+
## Repository
|
|
173
|
+
|
|
174
|
+
https://github.com/raza-ahmed/beacon
|
|
175
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Theme, HueVariant } from "../tokens/types";
|
|
2
|
+
type AvatarSize = "sm" | "md" | "lg" | "xl";
|
|
3
|
+
type AvatarType = "icon" | "text" | "image";
|
|
4
|
+
type AvatarColor = "primary" | "neutral" | "success" | "critical" | "warning";
|
|
5
|
+
type AvatarVariant = "solid" | "faded";
|
|
6
|
+
interface AvatarProps {
|
|
7
|
+
size: AvatarSize;
|
|
8
|
+
type: AvatarType;
|
|
9
|
+
color: AvatarColor;
|
|
10
|
+
variant: AvatarVariant;
|
|
11
|
+
isRound: boolean;
|
|
12
|
+
hasStroke: boolean;
|
|
13
|
+
theme: Theme;
|
|
14
|
+
hue: HueVariant;
|
|
15
|
+
initials?: string;
|
|
16
|
+
imageUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function Avatar({ size, type, color, variant, isRound, hasStroke, theme, hue, initials, imageUrl, }: AvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=Avatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/components/Avatar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGzD,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC5C,KAAK,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAC5C,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAC9E,KAAK,aAAa,GAAG,OAAO,GAAG,OAAO,CAAC;AAEvC,UAAU,WAAW;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAwBD,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,OAAO,EACP,SAAS,EACT,KAAK,EACL,GAAG,EACH,QAAe,EACf,QAAQ,GACT,EAAE,WAAW,2CA4Lb"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { UserPersonIcon } from "../icons";
|
|
5
|
+
// Avatar container sizes
|
|
6
|
+
const CONTAINER_SIZE_CONFIG = {
|
|
7
|
+
sm: { width: "32px", height: "32px" },
|
|
8
|
+
md: { width: "48px", height: "48px" },
|
|
9
|
+
lg: { width: "64px", height: "64px" },
|
|
10
|
+
xl: { width: "124px", height: "124px" },
|
|
11
|
+
};
|
|
12
|
+
// Icon sizes (no xl)
|
|
13
|
+
const ICON_SIZE_CONFIG = {
|
|
14
|
+
sm: { size: 16 },
|
|
15
|
+
md: { size: 24 },
|
|
16
|
+
lg: { size: 40 },
|
|
17
|
+
};
|
|
18
|
+
// Text sizes (no xl)
|
|
19
|
+
const TEXT_SIZE_CONFIG = {
|
|
20
|
+
sm: { fontSize: "var(--body-small-text-size)" },
|
|
21
|
+
md: { fontSize: "var(--body-regular-text-size)" },
|
|
22
|
+
lg: { fontSize: "var(--heading-h5-text-size)" },
|
|
23
|
+
};
|
|
24
|
+
export function Avatar({ size, type, color, variant, isRound, hasStroke, theme, hue, initials = "JD", imageUrl, }) {
|
|
25
|
+
const [imageError, setImageError] = useState(false);
|
|
26
|
+
const containerSize = CONTAINER_SIZE_CONFIG[size];
|
|
27
|
+
const avatarStyles = useMemo(() => {
|
|
28
|
+
// Determine border color for stroke based on variant and color
|
|
29
|
+
let borderColor = "";
|
|
30
|
+
if (hasStroke) {
|
|
31
|
+
if (variant === "solid") {
|
|
32
|
+
// Solid variants use tonal border colors (except warning which uses solid)
|
|
33
|
+
switch (color) {
|
|
34
|
+
case "primary":
|
|
35
|
+
borderColor = "var(--border-primary-tonal)";
|
|
36
|
+
break;
|
|
37
|
+
case "neutral":
|
|
38
|
+
borderColor = "var(--border-strong-100)";
|
|
39
|
+
break;
|
|
40
|
+
case "success":
|
|
41
|
+
borderColor = "var(--border-success-tonal)";
|
|
42
|
+
break;
|
|
43
|
+
case "critical":
|
|
44
|
+
borderColor = "var(--border-critical-tonal)";
|
|
45
|
+
break;
|
|
46
|
+
case "warning":
|
|
47
|
+
borderColor = "var(--border-warning)";
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Faded variants use solid border colors
|
|
53
|
+
switch (color) {
|
|
54
|
+
case "primary":
|
|
55
|
+
borderColor = "var(--border-primary)";
|
|
56
|
+
break;
|
|
57
|
+
case "neutral":
|
|
58
|
+
borderColor = "var(--border-strong-100)";
|
|
59
|
+
break;
|
|
60
|
+
case "success":
|
|
61
|
+
borderColor = "var(--border-success)";
|
|
62
|
+
break;
|
|
63
|
+
case "critical":
|
|
64
|
+
borderColor = "var(--border-critical)";
|
|
65
|
+
break;
|
|
66
|
+
case "warning":
|
|
67
|
+
borderColor = "var(--border-warning)";
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const baseStyles = {
|
|
73
|
+
width: containerSize.width,
|
|
74
|
+
height: containerSize.height,
|
|
75
|
+
display: "flex",
|
|
76
|
+
alignItems: "center",
|
|
77
|
+
justifyContent: "center",
|
|
78
|
+
flexShrink: 0,
|
|
79
|
+
overflow: "hidden",
|
|
80
|
+
position: "relative",
|
|
81
|
+
border: hasStroke ? `var(--border-width-50) solid ${borderColor}` : "none",
|
|
82
|
+
boxSizing: "border-box",
|
|
83
|
+
};
|
|
84
|
+
// Corner radius: default 8px, or full (50%) if isRound
|
|
85
|
+
if (isRound) {
|
|
86
|
+
baseStyles.borderRadius = "50%";
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
baseStyles.borderRadius = "8px"; // Default 8px corner radius
|
|
90
|
+
}
|
|
91
|
+
// Background color based on color and variant
|
|
92
|
+
let backgroundColor = "";
|
|
93
|
+
let textColor = "var(--fg-on-action)";
|
|
94
|
+
if (variant === "solid") {
|
|
95
|
+
switch (color) {
|
|
96
|
+
case "primary":
|
|
97
|
+
backgroundColor = "var(--bg-primary)";
|
|
98
|
+
break;
|
|
99
|
+
case "neutral":
|
|
100
|
+
backgroundColor = "var(--color-neutral-500)";
|
|
101
|
+
break;
|
|
102
|
+
case "success":
|
|
103
|
+
backgroundColor = "var(--bg-success)";
|
|
104
|
+
break;
|
|
105
|
+
case "critical":
|
|
106
|
+
backgroundColor = "var(--bg-critical)";
|
|
107
|
+
break;
|
|
108
|
+
case "warning":
|
|
109
|
+
backgroundColor = "var(--bg-warning)";
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// faded variant
|
|
115
|
+
switch (color) {
|
|
116
|
+
case "primary":
|
|
117
|
+
backgroundColor = "var(--bg-primary-tonal)";
|
|
118
|
+
textColor = "var(--fg-primary-on-tonal)";
|
|
119
|
+
break;
|
|
120
|
+
case "neutral":
|
|
121
|
+
backgroundColor = "var(--color-neutral-200)";
|
|
122
|
+
textColor = "var(--fg-neutral)";
|
|
123
|
+
break;
|
|
124
|
+
case "success":
|
|
125
|
+
backgroundColor = "var(--bg-success-tonal)";
|
|
126
|
+
textColor = "var(--fg-success-on-tonal)";
|
|
127
|
+
break;
|
|
128
|
+
case "critical":
|
|
129
|
+
backgroundColor = "var(--bg-critical-tonal)";
|
|
130
|
+
textColor = "var(--fg-critical-on-tonal)";
|
|
131
|
+
break;
|
|
132
|
+
case "warning":
|
|
133
|
+
backgroundColor = "var(--bg-warning-tonal)";
|
|
134
|
+
textColor = "var(--fg-warning-on-tonal)";
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
baseStyles.backgroundColor = backgroundColor;
|
|
139
|
+
baseStyles.color = textColor;
|
|
140
|
+
return baseStyles;
|
|
141
|
+
}, [containerSize, isRound, hasStroke, color, variant]);
|
|
142
|
+
const handleImageError = () => {
|
|
143
|
+
setImageError(true);
|
|
144
|
+
};
|
|
145
|
+
const renderContent = () => {
|
|
146
|
+
if (type === "image" && imageUrl && !imageError) {
|
|
147
|
+
return (_jsx("img", { src: imageUrl, alt: "Avatar", onError: handleImageError, style: {
|
|
148
|
+
width: "100%",
|
|
149
|
+
height: "100%",
|
|
150
|
+
objectFit: "cover",
|
|
151
|
+
} }));
|
|
152
|
+
}
|
|
153
|
+
if (type === "text" || (type === "image" && imageError)) {
|
|
154
|
+
// Text type: no xl size
|
|
155
|
+
const textSize = size === "xl" ? "lg" : size;
|
|
156
|
+
const textConfig = TEXT_SIZE_CONFIG[textSize];
|
|
157
|
+
return (_jsx("span", { style: {
|
|
158
|
+
fontSize: textConfig.fontSize,
|
|
159
|
+
fontWeight: "var(--font-weight-secondary-medium)",
|
|
160
|
+
lineHeight: "1",
|
|
161
|
+
userSelect: "none",
|
|
162
|
+
}, children: initials }));
|
|
163
|
+
}
|
|
164
|
+
// Icon type: no xl size
|
|
165
|
+
const iconSize = size === "xl" ? "lg" : size;
|
|
166
|
+
const iconConfig = ICON_SIZE_CONFIG[iconSize];
|
|
167
|
+
return (_jsx("div", { style: {
|
|
168
|
+
display: "flex",
|
|
169
|
+
alignItems: "center",
|
|
170
|
+
justifyContent: "center",
|
|
171
|
+
}, children: _jsx(UserPersonIcon, { size: iconConfig.size }) }));
|
|
172
|
+
};
|
|
173
|
+
return (_jsx("div", { className: "ds-avatar-preview-container", children: _jsx("div", { className: "ds-avatar-preview-canvas", children: _jsx("div", { className: "ds-avatar-preview-avatar", style: avatarStyles, children: renderContent() }) }) }));
|
|
174
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Theme, HueVariant } from "../tokens/types";
|
|
2
|
+
type ButtonVariant = "filled" | "tonal" | "outline" | "link";
|
|
3
|
+
type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
4
|
+
type CornerRadiusStep = 0 | 1 | 2 | 3 | 4 | 5;
|
|
5
|
+
type ButtonState = "default" | "hovered" | "focused" | "pressed" | "disabled" | "loading" | "success" | "critical" | "warning";
|
|
6
|
+
type JustifyContent = "center" | "space-between";
|
|
7
|
+
interface ButtonProps {
|
|
8
|
+
variant: ButtonVariant;
|
|
9
|
+
size: ButtonSize;
|
|
10
|
+
cornerRadius: CornerRadiusStep;
|
|
11
|
+
hasStartIcon: boolean;
|
|
12
|
+
hasEndIcon: boolean;
|
|
13
|
+
fillContainer: boolean;
|
|
14
|
+
justifyContent: JustifyContent;
|
|
15
|
+
state: ButtonState;
|
|
16
|
+
theme: Theme;
|
|
17
|
+
hue: HueVariant;
|
|
18
|
+
}
|
|
19
|
+
export declare function Button({ variant, size, cornerRadius, hasStartIcon, hasEndIcon, fillContainer, justifyContent, state, theme, hue, }: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGzD,KAAK,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAC7D,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACnD,KAAK,gBAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC9C,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAC/H,KAAK,cAAc,GAAG,QAAQ,GAAG,eAAe,CAAC;AAEjD,UAAU,WAAW;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;CACjB;AAkED,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,aAAa,EACb,cAAc,EACd,KAAK,EACL,KAAK,EACL,GAAG,GACJ,EAAE,WAAW,2CAmLb"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { SearchIcon, ChevronDownIcon, LoaderIcon } from "../icons";
|
|
5
|
+
const CORNER_RADIUS_MAP = {
|
|
6
|
+
0: "var(--corner-radius-none)",
|
|
7
|
+
1: "var(--corner-radius-100)",
|
|
8
|
+
2: "var(--corner-radius-200)",
|
|
9
|
+
3: "var(--corner-radius-300)",
|
|
10
|
+
4: "var(--corner-radius-400)",
|
|
11
|
+
5: "var(--corner-radius-full)",
|
|
12
|
+
};
|
|
13
|
+
const SIZE_CONFIG = {
|
|
14
|
+
xs: {
|
|
15
|
+
height: "28px",
|
|
16
|
+
paddingX: "var(--spacing-200)",
|
|
17
|
+
paddingY: "var(--spacing-50)",
|
|
18
|
+
fontSize: "var(--body-extra-small-text-size)",
|
|
19
|
+
iconSize: "xs",
|
|
20
|
+
},
|
|
21
|
+
sm: {
|
|
22
|
+
height: "36px",
|
|
23
|
+
paddingX: "var(--spacing-300)",
|
|
24
|
+
paddingY: "var(--spacing-100)",
|
|
25
|
+
fontSize: "var(--body-small-text-size)",
|
|
26
|
+
iconSize: "xs",
|
|
27
|
+
},
|
|
28
|
+
md: {
|
|
29
|
+
height: "44px",
|
|
30
|
+
paddingX: "var(--spacing-400)",
|
|
31
|
+
paddingY: "var(--spacing-200)",
|
|
32
|
+
fontSize: "var(--body-regular-text-size)",
|
|
33
|
+
iconSize: "xs",
|
|
34
|
+
},
|
|
35
|
+
lg: {
|
|
36
|
+
height: "56px",
|
|
37
|
+
paddingX: "var(--spacing-500)",
|
|
38
|
+
paddingY: "var(--spacing-300)",
|
|
39
|
+
fontSize: "var(--body-medium-text-size)",
|
|
40
|
+
iconSize: "sm",
|
|
41
|
+
},
|
|
42
|
+
xl: {
|
|
43
|
+
height: "68px",
|
|
44
|
+
paddingX: "var(--spacing-600)",
|
|
45
|
+
paddingY: "var(--spacing-400)",
|
|
46
|
+
fontSize: "var(--body-medium-text-size)",
|
|
47
|
+
iconSize: "sm",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const LOADER_ICON_SIZE_MAP = {
|
|
51
|
+
xs: 20,
|
|
52
|
+
sm: 24,
|
|
53
|
+
md: 24,
|
|
54
|
+
lg: 32,
|
|
55
|
+
xl: 40,
|
|
56
|
+
};
|
|
57
|
+
export function Button({ variant, size, cornerRadius, hasStartIcon, hasEndIcon, fillContainer, justifyContent, state, theme, hue, }) {
|
|
58
|
+
const sizeConfig = SIZE_CONFIG[size];
|
|
59
|
+
const borderRadius = CORNER_RADIUS_MAP[cornerRadius];
|
|
60
|
+
const buttonStyles = useMemo(() => {
|
|
61
|
+
const baseStyles = {
|
|
62
|
+
display: "inline-flex",
|
|
63
|
+
alignItems: "center",
|
|
64
|
+
justifyContent: justifyContent,
|
|
65
|
+
gap: "var(--spacing-100)",
|
|
66
|
+
fontFamily: "var(--font-secondary)",
|
|
67
|
+
fontSize: sizeConfig.fontSize,
|
|
68
|
+
lineHeight: "1",
|
|
69
|
+
fontWeight: "var(--font-weight-secondary-medium)",
|
|
70
|
+
borderWidth: "var(--border-width-25)",
|
|
71
|
+
borderStyle: "solid",
|
|
72
|
+
borderColor: "transparent",
|
|
73
|
+
borderRadius,
|
|
74
|
+
cursor: state === "disabled" ? "not-allowed" : "pointer",
|
|
75
|
+
transition: "background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease",
|
|
76
|
+
minHeight: sizeConfig.height,
|
|
77
|
+
paddingLeft: sizeConfig.paddingX,
|
|
78
|
+
paddingRight: sizeConfig.paddingX,
|
|
79
|
+
paddingTop: sizeConfig.paddingY,
|
|
80
|
+
paddingBottom: sizeConfig.paddingY,
|
|
81
|
+
width: fillContainer ? "100%" : "auto",
|
|
82
|
+
opacity: state === "disabled" ? 0.6 : 1,
|
|
83
|
+
};
|
|
84
|
+
// Get base variant styles
|
|
85
|
+
let variantStyles = {};
|
|
86
|
+
switch (variant) {
|
|
87
|
+
case "filled":
|
|
88
|
+
variantStyles = {
|
|
89
|
+
backgroundColor: "var(--bg-primary)",
|
|
90
|
+
color: "var(--fg-on-action)",
|
|
91
|
+
borderColor: "var(--bg-primary)",
|
|
92
|
+
};
|
|
93
|
+
break;
|
|
94
|
+
case "tonal":
|
|
95
|
+
variantStyles = {
|
|
96
|
+
backgroundColor: "var(--bg-primary-tonal)",
|
|
97
|
+
color: "var(--fg-primary-on-tonal)",
|
|
98
|
+
borderColor: "var(--border-primary-tonal)",
|
|
99
|
+
};
|
|
100
|
+
break;
|
|
101
|
+
case "outline":
|
|
102
|
+
variantStyles = {
|
|
103
|
+
backgroundColor: "transparent",
|
|
104
|
+
color: "var(--fg-primary)",
|
|
105
|
+
borderColor: "var(--border-primary)",
|
|
106
|
+
};
|
|
107
|
+
break;
|
|
108
|
+
case "link":
|
|
109
|
+
variantStyles = {
|
|
110
|
+
backgroundColor: "transparent",
|
|
111
|
+
color: "var(--fg-primary)",
|
|
112
|
+
borderWidth: 0,
|
|
113
|
+
borderStyle: "none",
|
|
114
|
+
borderColor: "transparent",
|
|
115
|
+
textDecoration: "underline",
|
|
116
|
+
textUnderlineOffset: "2px",
|
|
117
|
+
};
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
// Apply state-specific overrides
|
|
121
|
+
const stateStyles = {};
|
|
122
|
+
if (state === "disabled") {
|
|
123
|
+
if (variant === "filled") {
|
|
124
|
+
stateStyles.backgroundColor = "var(--bg-disabled)";
|
|
125
|
+
stateStyles.color = "var(--fg-on-disabled)";
|
|
126
|
+
stateStyles.borderColor = "var(--border-disabled)";
|
|
127
|
+
}
|
|
128
|
+
else if (variant === "tonal") {
|
|
129
|
+
stateStyles.backgroundColor = "var(--bg-disabled)";
|
|
130
|
+
stateStyles.color = "var(--fg-disabled)";
|
|
131
|
+
stateStyles.borderColor = "var(--border-disabled)";
|
|
132
|
+
}
|
|
133
|
+
else if (variant === "outline") {
|
|
134
|
+
stateStyles.color = "var(--fg-disabled)";
|
|
135
|
+
stateStyles.borderColor = "var(--border-disabled)";
|
|
136
|
+
}
|
|
137
|
+
else if (variant === "link") {
|
|
138
|
+
stateStyles.color = "var(--fg-disabled)";
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (state === "hovered") {
|
|
142
|
+
if (variant === "filled") {
|
|
143
|
+
stateStyles.backgroundColor = "var(--bg-primary-on-hover)";
|
|
144
|
+
stateStyles.borderColor = "var(--bg-primary-on-hover)";
|
|
145
|
+
}
|
|
146
|
+
else if (variant === "tonal") {
|
|
147
|
+
stateStyles.backgroundColor = "var(--bg-primary-tonal-on-hover)";
|
|
148
|
+
}
|
|
149
|
+
else if (variant === "outline") {
|
|
150
|
+
stateStyles.borderColor = "var(--border-primary-on-hover)";
|
|
151
|
+
}
|
|
152
|
+
else if (variant === "link") {
|
|
153
|
+
stateStyles.color = "var(--fg-primary-on-hover)";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (state === "pressed") {
|
|
157
|
+
if (variant === "filled") {
|
|
158
|
+
stateStyles.backgroundColor = "var(--bg-primary-pressed)";
|
|
159
|
+
stateStyles.borderColor = "var(--bg-primary-pressed)";
|
|
160
|
+
}
|
|
161
|
+
else if (variant === "tonal") {
|
|
162
|
+
stateStyles.backgroundColor = "var(--bg-primary-tonal-on-hover)";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (state === "focused") {
|
|
166
|
+
if (variant === "filled") {
|
|
167
|
+
stateStyles.backgroundColor = "var(--bg-primary-on-focused)";
|
|
168
|
+
stateStyles.borderColor = "var(--bg-primary-on-focused)";
|
|
169
|
+
}
|
|
170
|
+
else if (variant === "outline") {
|
|
171
|
+
stateStyles.borderColor = "var(--border-primary)";
|
|
172
|
+
}
|
|
173
|
+
stateStyles.outline = "2px solid var(--border-primary)";
|
|
174
|
+
stateStyles.outlineOffset = "2px";
|
|
175
|
+
}
|
|
176
|
+
else if (state === "success") {
|
|
177
|
+
if (variant === "filled") {
|
|
178
|
+
stateStyles.backgroundColor = "var(--bg-success)";
|
|
179
|
+
stateStyles.borderColor = "var(--border-success)";
|
|
180
|
+
}
|
|
181
|
+
else if (variant === "tonal") {
|
|
182
|
+
stateStyles.backgroundColor = "var(--bg-success-tonal)";
|
|
183
|
+
stateStyles.color = "var(--fg-success-on-tonal)";
|
|
184
|
+
stateStyles.borderColor = "var(--border-success-tonal)";
|
|
185
|
+
}
|
|
186
|
+
else if (variant === "outline") {
|
|
187
|
+
stateStyles.color = "var(--fg-success)";
|
|
188
|
+
stateStyles.borderColor = "var(--border-success)";
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else if (state === "critical") {
|
|
192
|
+
if (variant === "filled") {
|
|
193
|
+
stateStyles.backgroundColor = "var(--bg-critical)";
|
|
194
|
+
stateStyles.borderColor = "var(--border-critical)";
|
|
195
|
+
}
|
|
196
|
+
else if (variant === "tonal") {
|
|
197
|
+
stateStyles.backgroundColor = "var(--bg-critical-tonal)";
|
|
198
|
+
stateStyles.color = "var(--fg-critical-on-tonal)";
|
|
199
|
+
stateStyles.borderColor = "var(--border-critical-tonal)";
|
|
200
|
+
}
|
|
201
|
+
else if (variant === "outline") {
|
|
202
|
+
stateStyles.color = "var(--fg-critical)";
|
|
203
|
+
stateStyles.borderColor = "var(--border-critical)";
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else if (state === "warning") {
|
|
207
|
+
if (variant === "filled") {
|
|
208
|
+
stateStyles.backgroundColor = "var(--bg-warning)";
|
|
209
|
+
stateStyles.borderColor = "var(--border-warning)";
|
|
210
|
+
}
|
|
211
|
+
else if (variant === "tonal") {
|
|
212
|
+
stateStyles.backgroundColor = "var(--bg-warning-tonal)";
|
|
213
|
+
stateStyles.color = "var(--fg-warning-on-tonal)";
|
|
214
|
+
stateStyles.borderColor = "var(--border-warning-tonal)";
|
|
215
|
+
}
|
|
216
|
+
else if (variant === "outline") {
|
|
217
|
+
stateStyles.color = "var(--fg-warning)";
|
|
218
|
+
stateStyles.borderColor = "var(--border-warning)";
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return { ...baseStyles, ...variantStyles, ...stateStyles };
|
|
222
|
+
}, [variant, sizeConfig, borderRadius, fillContainer, justifyContent, state]);
|
|
223
|
+
const isLoading = state === "loading";
|
|
224
|
+
const showStartIcon = !isLoading && hasStartIcon;
|
|
225
|
+
const showEndIcon = !isLoading && hasEndIcon;
|
|
226
|
+
return (_jsx("div", { className: "ds-button-preview-container", children: _jsx("div", { className: "ds-button-preview-canvas", children: _jsx("button", { type: "button", className: "ds-button-preview-button", style: buttonStyles, disabled: state === "disabled", children: isLoading ? (_jsx(LoaderIcon, { size: LOADER_ICON_SIZE_MAP[size], className: "ds-button-loading-spinner" })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "ds-button-preview-start", children: [showStartIcon && _jsx(SearchIcon, { size: sizeConfig.iconSize }), _jsx("span", { children: "Button" })] }), showEndIcon && _jsx(ChevronDownIcon, { size: sizeConfig.iconSize })] })) }) }) }));
|
|
227
|
+
}
|