@gadagi/design-system 1.0.0
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/package.json +38 -0
- package/src/components/Badge/Badge.tsx +37 -0
- package/src/components/Badge/index.ts +1 -0
- package/src/components/Button/Button.tsx +59 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Input/Input.tsx +55 -0
- package/src/components/Input/index.ts +1 -0
- package/src/index.ts +6 -0
- package/src/theme/ThemeProvider.tsx +27 -0
- package/src/theme/interfaces/theme.interface.ts +9 -0
- package/src/theme/useTheme.ts +1 -0
- package/src/tokens/colors.ts +77 -0
- package/src/tokens/index.ts +3 -0
- package/src/tokens/spacing.ts +13 -0
- package/src/tokens/typography.ts +21 -0
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gadagi/design-system",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Design system for gadagi micro-frontends",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"module": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"default": "./src/index.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["src"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc && echo 'export * from \"./src/index\";' > dist/adi-design-system/index.js",
|
|
17
|
+
"dev": "tsc --watch"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^19.0.0",
|
|
21
|
+
"react-dom": "^19.0.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@gadagi/types": "^1.0.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/react": "^19.0.0",
|
|
28
|
+
"@types/react-dom": "^19.0.0",
|
|
29
|
+
"css-loader": "^7.0.0",
|
|
30
|
+
"react": "^19.0.0",
|
|
31
|
+
"react-dom": "^19.0.0",
|
|
32
|
+
"style-loader": "^4.0.0",
|
|
33
|
+
"ts-loader": "^9.0.0",
|
|
34
|
+
"typescript": "^5.0.0",
|
|
35
|
+
"webpack": "^5.0.0",
|
|
36
|
+
"webpack-cli": "^5.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { colors, spacing, typography } from '../../tokens';
|
|
3
|
+
|
|
4
|
+
type BadgeVariant = 'default' | 'success' | 'warning' | 'danger' | 'info';
|
|
5
|
+
|
|
6
|
+
interface BadgeProps {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
variant?: BadgeVariant;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const badgeColors: Record<BadgeVariant, { bg: string; text: string }> = {
|
|
12
|
+
default: { bg: colors.neutral[100], text: colors.neutral[600] },
|
|
13
|
+
success: { bg: colors.success[100], text: '#15803d' },
|
|
14
|
+
warning: { bg: colors.warning[100], text: '#92400e' },
|
|
15
|
+
danger: { bg: colors.danger[100], text: '#b91c1c' },
|
|
16
|
+
info: { bg: colors.primary[100], text: colors.primary[700] },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Badge: React.FC<BadgeProps> = ({ children, variant = 'default' }) => {
|
|
20
|
+
const { bg, text } = badgeColors[variant];
|
|
21
|
+
return (
|
|
22
|
+
<span
|
|
23
|
+
style={{
|
|
24
|
+
display: 'inline-flex',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
padding: `${spacing[0]} ${spacing[2]}`,
|
|
27
|
+
borderRadius: '9999px',
|
|
28
|
+
fontSize: typography.fontSize.xs,
|
|
29
|
+
fontWeight: typography.fontWeight.medium,
|
|
30
|
+
background: bg,
|
|
31
|
+
color: text,
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</span>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Badge } from './Badge';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import { colors, spacing, typography } from '../../tokens';
|
|
3
|
+
|
|
4
|
+
type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'ghost';
|
|
5
|
+
type ButtonSize = 'sm' | 'md' | 'lg';
|
|
6
|
+
|
|
7
|
+
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
|
+
variant?: ButtonVariant;
|
|
9
|
+
size?: ButtonSize;
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
fullWidth?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const sizeStyles: Record<ButtonSize, React.CSSProperties> = {
|
|
15
|
+
sm: { padding: `${spacing[1]} ${spacing[3]}`, fontSize: typography.fontSize.sm },
|
|
16
|
+
md: { padding: `${spacing[2]} ${spacing[4]}`, fontSize: typography.fontSize.base },
|
|
17
|
+
lg: { padding: `${spacing[3]} ${spacing[6]}`, fontSize: typography.fontSize.lg },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const variantStyles: Record<ButtonVariant, React.CSSProperties> = {
|
|
21
|
+
primary: { background: colors.primary[600], color: '#fff', border: 'none' },
|
|
22
|
+
secondary: { background: 'transparent', color: colors.primary[600], border: `1px solid ${colors.primary[600]}` },
|
|
23
|
+
danger: { background: colors.danger[500], color: '#fff', border: 'none' },
|
|
24
|
+
ghost: { background: 'transparent', color: colors.neutral[600], border: 'none' },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Button: React.FC<ButtonProps> = ({
|
|
28
|
+
variant = 'primary',
|
|
29
|
+
size = 'md',
|
|
30
|
+
loading = false,
|
|
31
|
+
fullWidth = false,
|
|
32
|
+
children,
|
|
33
|
+
disabled,
|
|
34
|
+
style,
|
|
35
|
+
...rest
|
|
36
|
+
}) => {
|
|
37
|
+
const baseStyle: React.CSSProperties = {
|
|
38
|
+
display: 'inline-flex',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
justifyContent: 'center',
|
|
41
|
+
gap: spacing[2],
|
|
42
|
+
borderRadius: '6px',
|
|
43
|
+
fontWeight: typography.fontWeight.medium,
|
|
44
|
+
fontFamily: typography.fontFamily.sans,
|
|
45
|
+
cursor: disabled || loading ? 'not-allowed' : 'pointer',
|
|
46
|
+
opacity: disabled || loading ? 0.6 : 1,
|
|
47
|
+
width: fullWidth ? '100%' : undefined,
|
|
48
|
+
transition: 'opacity 0.15s, transform 0.1s',
|
|
49
|
+
...sizeStyles[size],
|
|
50
|
+
...variantStyles[variant],
|
|
51
|
+
...style,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<button style={baseStyle} disabled={disabled || loading} {...rest}>
|
|
56
|
+
{loading ? 'Loading...' : children}
|
|
57
|
+
</button>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, { InputHTMLAttributes } from 'react';
|
|
2
|
+
import { colors, spacing, typography } from '../../tokens';
|
|
3
|
+
|
|
4
|
+
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
5
|
+
label?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
hint?: string;
|
|
8
|
+
fullWidth?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Input: React.FC<InputProps> = ({
|
|
12
|
+
label,
|
|
13
|
+
error,
|
|
14
|
+
hint,
|
|
15
|
+
fullWidth = false,
|
|
16
|
+
id,
|
|
17
|
+
style,
|
|
18
|
+
...rest
|
|
19
|
+
}) => {
|
|
20
|
+
const inputId = id ?? label?.toLowerCase().replace(/\s+/g, '-');
|
|
21
|
+
|
|
22
|
+
const inputStyle: React.CSSProperties = {
|
|
23
|
+
display: 'block',
|
|
24
|
+
width: fullWidth ? '100%' : undefined,
|
|
25
|
+
padding: `${spacing[2]} ${spacing[3]}`,
|
|
26
|
+
fontSize: typography.fontSize.base,
|
|
27
|
+
fontFamily: typography.fontFamily.sans,
|
|
28
|
+
borderRadius: '6px',
|
|
29
|
+
border: `1px solid ${error ? colors.danger[500] : colors.neutral[200]}`,
|
|
30
|
+
outline: 'none',
|
|
31
|
+
background: '#fff',
|
|
32
|
+
color: colors.neutral[900],
|
|
33
|
+
...style,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: spacing[1] }}>
|
|
38
|
+
{label && (
|
|
39
|
+
<label
|
|
40
|
+
htmlFor={inputId}
|
|
41
|
+
style={{ fontSize: typography.fontSize.sm, fontWeight: typography.fontWeight.medium, color: colors.neutral[600] }}
|
|
42
|
+
>
|
|
43
|
+
{label}
|
|
44
|
+
</label>
|
|
45
|
+
)}
|
|
46
|
+
<input id={inputId} style={inputStyle} {...rest} />
|
|
47
|
+
{error && (
|
|
48
|
+
<span style={{ fontSize: typography.fontSize.xs, color: colors.danger[500] }}>{error}</span>
|
|
49
|
+
)}
|
|
50
|
+
{hint && !error && (
|
|
51
|
+
<span style={{ fontSize: typography.fontSize.xs, color: colors.neutral[400] }}>{hint}</span>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Input } from './Input';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Button } from './components/Button';
|
|
2
|
+
export { Input } from './components/Input';
|
|
3
|
+
export { Badge } from './components/Badge';
|
|
4
|
+
export { ThemeProvider } from './theme/ThemeProvider';
|
|
5
|
+
export { useTheme } from './theme/useTheme';
|
|
6
|
+
export * from './tokens';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
2
|
+
import { ThemeContextValue, Theme } from './interfaces/theme.interface'
|
|
3
|
+
|
|
4
|
+
const ThemeContext = createContext<ThemeContextValue>({
|
|
5
|
+
theme: 'system',
|
|
6
|
+
setTheme: () => {},
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
interface ThemeProviderProps {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
defaultTheme?: Theme;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ThemeProvider: React.FC<ThemeProviderProps> = ({
|
|
15
|
+
children,
|
|
16
|
+
defaultTheme = 'system',
|
|
17
|
+
}) => {
|
|
18
|
+
const [theme, setTheme] = useState<Theme>(defaultTheme);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
22
|
+
<div data-theme={theme}>{children}</div>
|
|
23
|
+
</ThemeContext.Provider>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const useTheme = (): ThemeContextValue => useContext(ThemeContext);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useTheme } from './ThemeProvider';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const colors = {
|
|
2
|
+
primary: {
|
|
3
|
+
50: '#f0f0ff',
|
|
4
|
+
100: '#e6e6ff',
|
|
5
|
+
500: '#4a3fb5', // WCAG compliant version of #5447c7
|
|
6
|
+
600: '#4235a3',
|
|
7
|
+
700: '#3a2c91',
|
|
8
|
+
900: '#2a1f5f',
|
|
9
|
+
},
|
|
10
|
+
neutral: {
|
|
11
|
+
50: '#f8fafc',
|
|
12
|
+
100: '#ebedef', // Your lightColor
|
|
13
|
+
200: '#e2e8f0',
|
|
14
|
+
400: '#94a3b8',
|
|
15
|
+
600: '#4b5463', // Your darkColor
|
|
16
|
+
800: '#1e293b',
|
|
17
|
+
900: '#0f172a',
|
|
18
|
+
},
|
|
19
|
+
success: {
|
|
20
|
+
500: '#2fb855', // WCAG compliant version of #36cd69
|
|
21
|
+
100: '#dcfce7',
|
|
22
|
+
},
|
|
23
|
+
warning: {
|
|
24
|
+
500: '#e6a110', // WCAG compliant version of #f9b115
|
|
25
|
+
100: '#fef3c7',
|
|
26
|
+
},
|
|
27
|
+
danger: {
|
|
28
|
+
500: '#dc4c4c', // WCAG compliant version of #e55353
|
|
29
|
+
100: '#fee2e2',
|
|
30
|
+
},
|
|
31
|
+
info: {
|
|
32
|
+
500: '#2d7fd8', // WCAG compliant version of #3090f1
|
|
33
|
+
100: '#dbeafe',
|
|
34
|
+
},
|
|
35
|
+
light: '#ebedef', // Your lightColor
|
|
36
|
+
dark: '#4b5463', // Your darkColor
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
// Dark Theme Tokens - High contrast versions for dark backgrounds
|
|
40
|
+
export const darkColors = {
|
|
41
|
+
primary: {
|
|
42
|
+
50: '#1a1a2e',
|
|
43
|
+
100: '#252542',
|
|
44
|
+
500: '#7c71e6', // Lighter purple for dark backgrounds
|
|
45
|
+
600: '#8b82eb',
|
|
46
|
+
700: '#9a93f0',
|
|
47
|
+
900: '#b8b3f5',
|
|
48
|
+
},
|
|
49
|
+
neutral: {
|
|
50
|
+
50: '#0f172a',
|
|
51
|
+
100: '#1e293b',
|
|
52
|
+
200: '#334155',
|
|
53
|
+
400: '#64748b',
|
|
54
|
+
600: '#cbd5e1', // Light gray for dark text
|
|
55
|
+
800: '#f1f5f9',
|
|
56
|
+
900: '#f8fafc',
|
|
57
|
+
},
|
|
58
|
+
success: {
|
|
59
|
+
500: '#4ade80', // Bright green for dark backgrounds
|
|
60
|
+
100: '#14532d',
|
|
61
|
+
},
|
|
62
|
+
warning: {
|
|
63
|
+
500: '#fbbf24', // Bright amber for dark backgrounds
|
|
64
|
+
100: '#713f12',
|
|
65
|
+
},
|
|
66
|
+
danger: {
|
|
67
|
+
500: '#f87171', // Bright red for dark backgrounds
|
|
68
|
+
100: '#7f1d1d',
|
|
69
|
+
},
|
|
70
|
+
info: {
|
|
71
|
+
500: '#60a5fa', // Bright blue for dark backgrounds
|
|
72
|
+
100: '#1e3a8a',
|
|
73
|
+
},
|
|
74
|
+
light: '#f8fafc', // Light text color for dark theme
|
|
75
|
+
dark: '#0f172a', // Dark background color
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const typography = {
|
|
2
|
+
fontFamily: {
|
|
3
|
+
sans: '"Inter", -apple-system, BlinkMacSystemFont, sans-serif',
|
|
4
|
+
mono: '"JetBrains Mono", "Fira Code", monospace',
|
|
5
|
+
},
|
|
6
|
+
fontSize: {
|
|
7
|
+
xs: '0.75rem',
|
|
8
|
+
sm: '0.875rem',
|
|
9
|
+
base: '1rem',
|
|
10
|
+
lg: '1.125rem',
|
|
11
|
+
xl: '1.25rem',
|
|
12
|
+
'2xl':'1.5rem',
|
|
13
|
+
'3xl':'1.875rem',
|
|
14
|
+
},
|
|
15
|
+
fontWeight: {
|
|
16
|
+
normal: 400,
|
|
17
|
+
medium: 500,
|
|
18
|
+
semibold:600,
|
|
19
|
+
bold: 700,
|
|
20
|
+
},
|
|
21
|
+
} as const;
|