@oscarrf2/goo-ds 0.1.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/README.md +163 -0
- package/package.json +60 -0
- package/src/components/Button/Button.css +107 -0
- package/src/components/Button/Button.tsx +82 -0
- package/src/components/Button/Button.types.ts +62 -0
- package/src/components/Button/index.ts +3 -0
- package/src/components/Cell/Cell.css +64 -0
- package/src/components/Cell/Cell.tsx +42 -0
- package/src/components/Cell/Cell.types.ts +42 -0
- package/src/components/Cell/index.ts +3 -0
- package/src/components/Codeblock/Codeblock.css +90 -0
- package/src/components/Codeblock/Codeblock.tsx +88 -0
- package/src/components/Codeblock/Codeblock.types.ts +42 -0
- package/src/components/Codeblock/index.ts +3 -0
- package/src/components/CoreText/CoreText.tsx +43 -0
- package/src/components/CoreText/CoreText.types.ts +56 -0
- package/src/components/CoreText/index.ts +2 -0
- package/src/components/Divider/Divider.css +38 -0
- package/src/components/Divider/Divider.tsx +35 -0
- package/src/components/Divider/Divider.types.ts +19 -0
- package/src/components/Divider/index.ts +3 -0
- package/src/components/InputImage/InputImage.css +212 -0
- package/src/components/InputImage/InputImage.tsx +314 -0
- package/src/components/InputImage/InputImage.types.ts +86 -0
- package/src/components/InputImage/index.ts +2 -0
- package/src/components/Sidebar/Sidebar.css +35 -0
- package/src/components/Sidebar/Sidebar.tsx +42 -0
- package/src/components/Sidebar/Sidebar.types.ts +24 -0
- package/src/components/Sidebar/index.ts +3 -0
- package/src/components/SidebarItem/SidebarItem.css +70 -0
- package/src/components/SidebarItem/SidebarItem.tsx +55 -0
- package/src/components/SidebarItem/SidebarItem.types.ts +39 -0
- package/src/components/SidebarItem/index.ts +3 -0
- package/src/components/Skeleton/Skeleton.css +25 -0
- package/src/components/Skeleton/Skeleton.tsx +41 -0
- package/src/components/Skeleton/Skeleton.types.ts +65 -0
- package/src/components/Skeleton/index.ts +5 -0
- package/src/components/Spacer/Spacer.tsx +31 -0
- package/src/components/Spacer/Spacer.types.ts +58 -0
- package/src/components/Spacer/index.ts +3 -0
- package/src/components/TabItem/TabItem.css +67 -0
- package/src/components/TabItem/TabItem.tsx +45 -0
- package/src/components/TabItem/TabItem.types.ts +35 -0
- package/src/components/TabItem/index.ts +3 -0
- package/src/components/Table/Table.css +16 -0
- package/src/components/Table/Table.tsx +39 -0
- package/src/components/Table/Table.types.ts +18 -0
- package/src/components/Table/index.ts +3 -0
- package/src/components/TableRow/TableRow.css +53 -0
- package/src/components/TableRow/TableRow.tsx +53 -0
- package/src/components/TableRow/TableRow.types.ts +41 -0
- package/src/components/TableRow/index.ts +3 -0
- package/src/components/Tabs/Tabs.css +11 -0
- package/src/components/Tabs/Tabs.tsx +37 -0
- package/src/components/Tabs/Tabs.types.ts +18 -0
- package/src/components/Tabs/index.ts +3 -0
- package/src/components/index.ts +15 -0
- package/src/compositions/index.ts +3 -0
- package/src/index.css +68 -0
- package/src/index.ts +4 -0
- package/src/styles/component-tokens.css +270 -0
- package/src/styles/component-tokens.current.css +3 -0
- package/src/styles/fonts.css +11 -0
- package/src/styles/global-tokens.css +257 -0
- package/src/styles/index.css +20 -0
- package/src/styles/number-tokens.css +72 -0
- package/src/styles/semantic-tokens.css +84 -0
- package/src/styles/style-tokens.css +219 -0
- package/src/styles/typography-tokens.css +50 -0
- package/src/styles.css +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @oscarrf2/goo-ds
|
|
2
|
+
|
|
3
|
+
A token-first React component library built with TypeScript and design tokens exported from Figma.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @oscarrf2/goo-ds
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @oscarrf2/goo-ds
|
|
11
|
+
# or
|
|
12
|
+
yarn add @oscarrf2/goo-ds
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### 1. Import Styles
|
|
18
|
+
|
|
19
|
+
Import the design system styles once in your app root:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
// In Next.js app/layout.tsx
|
|
23
|
+
import '@oscarrf2/goo-ds/styles.css';
|
|
24
|
+
|
|
25
|
+
// In Vite/React src/main.tsx
|
|
26
|
+
import '@oscarrf2/goo-ds/styles.css';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Use Components
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Button, CoreText, Spacer } from '@oscarrf2/goo-ds';
|
|
33
|
+
|
|
34
|
+
function App() {
|
|
35
|
+
return (
|
|
36
|
+
<div>
|
|
37
|
+
<CoreText variant="heading-lg-bold">Hello World</CoreText>
|
|
38
|
+
<Spacer size="24" />
|
|
39
|
+
<Button variant="primary" size="medium" onClick={() => alert('Clicked!')}>
|
|
40
|
+
Click Me
|
|
41
|
+
</Button>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Available Components
|
|
48
|
+
|
|
49
|
+
- **Button** - Versatile button with variants (primary, secondary, tertiary, ghost) and sizes
|
|
50
|
+
- **CoreText** - Typography component with text styles from design tokens
|
|
51
|
+
- **Spacer** - Layout spacing component
|
|
52
|
+
- **Divider** - Horizontal/vertical divider
|
|
53
|
+
- **Sidebar** / **SidebarItem** - Navigation sidebar components
|
|
54
|
+
- **Skeleton** - Loading skeleton with animation
|
|
55
|
+
- **Table** / **TableRow** / **Cell** - Table components
|
|
56
|
+
- **Tabs** / **TabItem** - Tab navigation
|
|
57
|
+
- **Codeblock** - Code display with syntax highlighting
|
|
58
|
+
- **InputImage** - Image input with drag-and-drop and comparison slider
|
|
59
|
+
|
|
60
|
+
## Token-First Architecture
|
|
61
|
+
|
|
62
|
+
All visual styling comes from design tokens:
|
|
63
|
+
|
|
64
|
+
- **Global tokens** - Base color and size values
|
|
65
|
+
- **Semantic tokens** - Contextual aliases (e.g., `--color-text-primary`)
|
|
66
|
+
- **Number tokens** - Spacing and sizing scales
|
|
67
|
+
- **Typography tokens** - Font families, sizes, line heights
|
|
68
|
+
- **Component tokens** - Component-specific styling
|
|
69
|
+
- **Style tokens** - Text styles, gradients, effects
|
|
70
|
+
|
|
71
|
+
### Custom Theming
|
|
72
|
+
|
|
73
|
+
To create a custom theme, copy the component tokens file and modify values:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Copy default tokens
|
|
77
|
+
cp node_modules/@oscarrf2/goo-ds/src/styles/component-tokens.css ./src/styles/my-theme.css
|
|
78
|
+
|
|
79
|
+
# Edit my-theme.css with your brand colors
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then import your custom tokens instead of the default:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// Import individual token layers + your custom component tokens
|
|
86
|
+
import '@oscarrf2/goo-ds/styles/fonts.css';
|
|
87
|
+
import '@oscarrf2/goo-ds/styles/global-tokens.css';
|
|
88
|
+
import '@oscarrf2/goo-ds/styles/semantic-tokens.css';
|
|
89
|
+
import '@oscarrf2/goo-ds/styles/number-tokens.css';
|
|
90
|
+
import '@oscarrf2/goo-ds/styles/typography-tokens.css';
|
|
91
|
+
import '@oscarrf2/goo-ds/styles/style-tokens.css';
|
|
92
|
+
import './styles/my-theme.css'; // Your custom component tokens
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
All component token files must define the same CSS variable names - only values should differ.
|
|
96
|
+
|
|
97
|
+
## TypeScript Support
|
|
98
|
+
|
|
99
|
+
Full TypeScript definitions are included. All components are fully typed with prop interfaces.
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import type { ButtonProps } from '@oscarrf2/goo-ds';
|
|
103
|
+
|
|
104
|
+
const MyButton: React.FC<ButtonProps> = (props) => {
|
|
105
|
+
return <Button {...props} />;
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Requirements
|
|
110
|
+
|
|
111
|
+
- **React**: 19.0.0 or higher
|
|
112
|
+
- **React DOM**: 19.0.0 or higher
|
|
113
|
+
|
|
114
|
+
## Browser Support
|
|
115
|
+
|
|
116
|
+
Modern browsers with CSS custom properties support:
|
|
117
|
+
- Chrome (latest)
|
|
118
|
+
- Firefox (latest)
|
|
119
|
+
- Safari (latest)
|
|
120
|
+
- Edge (latest)
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
Full documentation with interactive examples (coming soon).
|
|
125
|
+
|
|
126
|
+
## Component Extension
|
|
127
|
+
|
|
128
|
+
All components support standard React patterns for extension:
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// Event handler extension
|
|
132
|
+
<Button onClick={() => trackEvent('click')}>Click Me</Button>
|
|
133
|
+
|
|
134
|
+
// Wrapper components
|
|
135
|
+
function AnalyticsButton({ analyticsId, ...props }) {
|
|
136
|
+
const handleClick = (e) => {
|
|
137
|
+
trackButtonClick(analyticsId);
|
|
138
|
+
props.onClick?.(e);
|
|
139
|
+
};
|
|
140
|
+
return <Button {...props} onClick={handleClick} />;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Composition
|
|
144
|
+
function FormActions({ onSave, onCancel }) {
|
|
145
|
+
return (
|
|
146
|
+
<>
|
|
147
|
+
<Button variant="secondary" onClick={onCancel}>Cancel</Button>
|
|
148
|
+
<Spacer size="md" />
|
|
149
|
+
<Button variant="primary" onClick={onSave}>Save</Button>
|
|
150
|
+
</>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
|
158
|
+
|
|
159
|
+
## Version
|
|
160
|
+
|
|
161
|
+
0.1.0 - Pre-1.0 Release
|
|
162
|
+
|
|
163
|
+
This is an early release. APIs may change in future versions. The package is functional but some features are still being refined.
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oscarrf2/goo-ds",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts",
|
|
9
|
+
"./styles.css": "./src/styles.css"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src/**/*.ts",
|
|
13
|
+
"src/**/*.tsx",
|
|
14
|
+
"src/**/*.css",
|
|
15
|
+
"!src/**/*.test.ts",
|
|
16
|
+
"!src/**/*.test.tsx",
|
|
17
|
+
"!src/App.tsx",
|
|
18
|
+
"!src/App.css",
|
|
19
|
+
"!src/main.tsx",
|
|
20
|
+
"!src/assets",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"react": "^19.2.0",
|
|
25
|
+
"react-dom": "^19.2.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@eslint/js": "^9.39.1",
|
|
29
|
+
"@playwright/test": "^1.57.0",
|
|
30
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
31
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
32
|
+
"@testing-library/react": "^16.3.1",
|
|
33
|
+
"@testing-library/user-event": "^14.6.1",
|
|
34
|
+
"@types/node": "^24.10.1",
|
|
35
|
+
"@types/react": "^19.2.5",
|
|
36
|
+
"@types/react-dom": "^19.2.3",
|
|
37
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
38
|
+
"@vitest/ui": "^4.0.17",
|
|
39
|
+
"eslint": "^9.39.1",
|
|
40
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
41
|
+
"eslint-plugin-react-refresh": "^0.4.24",
|
|
42
|
+
"globals": "^16.5.0",
|
|
43
|
+
"identity-obj-proxy": "^3.0.0",
|
|
44
|
+
"jsdom": "^26.1.0",
|
|
45
|
+
"playwright": "^1.57.0",
|
|
46
|
+
"tailwindcss": "^4.1.18",
|
|
47
|
+
"typescript": "~5.9.3",
|
|
48
|
+
"typescript-eslint": "^8.46.4",
|
|
49
|
+
"vite": "^7.2.4",
|
|
50
|
+
"vitest": "^4.0.17"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"dev": "vite",
|
|
54
|
+
"build": "tsc -b && vite build",
|
|
55
|
+
"lint": "eslint .",
|
|
56
|
+
"preview": "vite preview",
|
|
57
|
+
"test": "vitest",
|
|
58
|
+
"test:e2e": "playwright test"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button component styles
|
|
3
|
+
* Token-driven button styling for the goo-ds design system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.gds-button {
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
gap: var(--btn-gap);
|
|
11
|
+
padding: var(--btn-padding-v) var(--btn-padding-h);
|
|
12
|
+
min-height: var(--btn-min-height);
|
|
13
|
+
border-radius: var(--btn-radius);
|
|
14
|
+
border: var(--btn-stroke-width) solid var(--btn-stroke);
|
|
15
|
+
background-color: var(--btn-background);
|
|
16
|
+
color: var(--btn-text);
|
|
17
|
+
font-family: var(--coreText-family-primary);
|
|
18
|
+
font-size: var(--btn-font-size);
|
|
19
|
+
font-weight: var(--font-weight-medium);
|
|
20
|
+
line-height: var(--btn-line-height);
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
transition: all 0.2s ease;
|
|
23
|
+
user-select: none;
|
|
24
|
+
text-decoration: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.gds-button-icon-only {
|
|
28
|
+
min-width: var(--btn-min-width);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.gds-button:hover:not(:disabled) {
|
|
32
|
+
background-color: var(--btn-background-hover);
|
|
33
|
+
border-color: var(--btn-stroke-hover);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.gds-button:active:not(:disabled) {
|
|
37
|
+
background-color: var(--btn-background-pressed);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.gds-button:disabled {
|
|
41
|
+
background-color: var(--btn-background-disabled);
|
|
42
|
+
border-color: var(--btn-stroke-disabled);
|
|
43
|
+
color: var(--btn-text-disabled);
|
|
44
|
+
cursor: not-allowed;
|
|
45
|
+
opacity: 0.6;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.gds-button:disabled .gds-button-icon {
|
|
49
|
+
color: var(--btn-icon-disabled);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.gds-button:focus-visible {
|
|
53
|
+
outline: 2px solid var(--color-stroke-focus);
|
|
54
|
+
outline-offset: 2px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.gds-button-text {
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.gds-button-icon {
|
|
62
|
+
display: inline-flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
color: var(--btn-icon);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Link variant special styling */
|
|
70
|
+
.gds-button-link {
|
|
71
|
+
background-color: transparent;
|
|
72
|
+
border-color: transparent;
|
|
73
|
+
padding-left: 0;
|
|
74
|
+
padding-right: 0;
|
|
75
|
+
text-decoration: underline;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.gds-button-link:hover:not(:disabled) {
|
|
79
|
+
background-color: transparent;
|
|
80
|
+
border-color: transparent;
|
|
81
|
+
text-decoration: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Ghost variant special styling */
|
|
85
|
+
.gds-button-ghost {
|
|
86
|
+
background-color: transparent;
|
|
87
|
+
border-color: transparent;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.gds-button-ghost:hover:not(:disabled) {
|
|
91
|
+
border-color: transparent;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.gds-button-ghost:active:not(:disabled) {
|
|
95
|
+
border-color: transparent;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.gds-button-ghost:disabled {
|
|
99
|
+
border-color: transparent;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Respect user's motion preferences */
|
|
103
|
+
@media (prefers-reduced-motion: reduce) {
|
|
104
|
+
.gds-button {
|
|
105
|
+
transition: none;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ButtonProps } from "./Button.types";
|
|
2
|
+
import "./Button.css";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Button - Interactive button component for the goo-ds design system
|
|
6
|
+
*
|
|
7
|
+
* Provides consistent button styles with multiple variants, sizes, and states.
|
|
8
|
+
* Supports icons, disabled state, and all standard button interactions.
|
|
9
|
+
* Token-first per Constitution (no hardcoded values).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Button>Click me</Button>
|
|
14
|
+
* <Button variant="secondary" size="small">Small button</Button>
|
|
15
|
+
* <Button variant="destructive" disabled>Disabled</Button>
|
|
16
|
+
* <Button iconLeft={<PlusIcon />}>With icon</Button>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function Button({
|
|
20
|
+
variant = "primary",
|
|
21
|
+
size = "medium",
|
|
22
|
+
iconLeft,
|
|
23
|
+
iconRight,
|
|
24
|
+
disabled = false,
|
|
25
|
+
children,
|
|
26
|
+
className = "",
|
|
27
|
+
type = "button",
|
|
28
|
+
...props
|
|
29
|
+
}: ButtonProps) {
|
|
30
|
+
const hasIcons = iconLeft || iconRight;
|
|
31
|
+
const isIconOnly = hasIcons && !children;
|
|
32
|
+
|
|
33
|
+
// Build CSS custom properties for the button variant
|
|
34
|
+
const buttonVars = {
|
|
35
|
+
"--btn-background": `var(--button-${variant}-background-default)`,
|
|
36
|
+
"--btn-background-hover": `var(--button-${variant}-background-hover, var(--button-${variant}-background-default))`,
|
|
37
|
+
"--btn-background-pressed": `var(--button-${variant}-background-pressed, var(--button-${variant}-background-default))`,
|
|
38
|
+
"--btn-background-disabled": `var(--button-${variant}-background-disabled, var(--button-${variant}-background-default))`,
|
|
39
|
+
"--btn-text": `var(--button-${variant}-text-default)`,
|
|
40
|
+
"--btn-text-disabled": `var(--button-${variant}-text-disabled, var(--button-${variant}-text-default))`,
|
|
41
|
+
"--btn-icon": `var(--button-${variant}-icon-default)`,
|
|
42
|
+
"--btn-icon-disabled": `var(--button-${variant}-icon-disabled, var(--button-${variant}-icon-default))`,
|
|
43
|
+
"--btn-stroke": `var(--button-${variant}-stroke-default, transparent)`,
|
|
44
|
+
"--btn-stroke-hover": `var(--button-${variant}-stroke-hover, var(--button-${variant}-stroke-default, transparent))`,
|
|
45
|
+
"--btn-stroke-disabled": `var(--button-${variant}-stroke-disabled, var(--button-${variant}-stroke-default, transparent))`,
|
|
46
|
+
} as React.CSSProperties;
|
|
47
|
+
|
|
48
|
+
// Size-dependent layout tokens
|
|
49
|
+
const buttonType = isIconOnly ? "icon" : "cta";
|
|
50
|
+
const sizeKey = size === "extraSmall" ? "extraSmall" : size;
|
|
51
|
+
|
|
52
|
+
const layoutVars = {
|
|
53
|
+
"--btn-gap": `var(--button-${sizeKey}-${buttonType}-gap)`,
|
|
54
|
+
"--btn-padding-v": `var(--button-${sizeKey}-${buttonType}-paddingVertical)`,
|
|
55
|
+
"--btn-padding-h": `var(--button-${sizeKey}-${buttonType}-paddingHorizontal)`,
|
|
56
|
+
"--btn-min-height": `var(--button-${sizeKey}-${buttonType}-minHeight)`,
|
|
57
|
+
"--btn-radius": `var(--button-${sizeKey}-${buttonType}-radius)`,
|
|
58
|
+
"--btn-stroke-width": `var(--button-${sizeKey}-${buttonType}-strokeWidth)`,
|
|
59
|
+
"--btn-min-width": isIconOnly ? `var(--button-${sizeKey}-${buttonType}-minWidth)` : "auto",
|
|
60
|
+
"--btn-font-size": `var(--font-size-${size === "large" ? "md" : size === "medium" ? "sm" : "xs"})`,
|
|
61
|
+
"--btn-line-height": `var(--font-lineHeight-${size === "large" ? "md" : size === "medium" ? "sm" : "xs"})`,
|
|
62
|
+
} as React.CSSProperties;
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<button
|
|
66
|
+
type={type}
|
|
67
|
+
disabled={disabled}
|
|
68
|
+
className={`gds-button gds-button-${variant} gds-button-${size} ${isIconOnly ? "gds-button-icon-only" : ""} ${className}`.trim()}
|
|
69
|
+
style={{ ...buttonVars, ...layoutVars }}
|
|
70
|
+
data-component="Button"
|
|
71
|
+
data-variant={variant}
|
|
72
|
+
data-size={size}
|
|
73
|
+
{...props}
|
|
74
|
+
>
|
|
75
|
+
{iconLeft && <span className="gds-button-icon gds-button-icon-left">{iconLeft}</span>}
|
|
76
|
+
{children && <span className="gds-button-text">{children}</span>}
|
|
77
|
+
{iconRight && <span className="gds-button-icon gds-button-icon-right">{iconRight}</span>}
|
|
78
|
+
</button>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default Button;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Button component props
|
|
5
|
+
* Provides interactive buttons using design system tokens
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type ButtonVariant =
|
|
9
|
+
| "primary"
|
|
10
|
+
| "secondary"
|
|
11
|
+
| "destructive"
|
|
12
|
+
| "outline"
|
|
13
|
+
| "ghost"
|
|
14
|
+
| "link";
|
|
15
|
+
|
|
16
|
+
export type ButtonSize = "extraSmall" | "small" | "medium" | "large";
|
|
17
|
+
|
|
18
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
19
|
+
/**
|
|
20
|
+
* The visual style variant of the button
|
|
21
|
+
* @default "primary"
|
|
22
|
+
*/
|
|
23
|
+
variant?: ButtonVariant;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The size of the button
|
|
27
|
+
* @default "medium"
|
|
28
|
+
*/
|
|
29
|
+
size?: ButtonSize;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Icon to display before the text
|
|
33
|
+
*/
|
|
34
|
+
iconLeft?: ReactNode;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Icon to display after the text
|
|
38
|
+
*/
|
|
39
|
+
iconRight?: ReactNode;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Whether the button is disabled
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Button content (text or other elements)
|
|
49
|
+
*/
|
|
50
|
+
children?: ReactNode;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Additional CSS class names
|
|
54
|
+
*/
|
|
55
|
+
className?: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Button type attribute
|
|
59
|
+
* @default "button"
|
|
60
|
+
*/
|
|
61
|
+
type?: "button" | "submit" | "reset";
|
|
62
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cell component styles
|
|
3
|
+
* Token-driven table cell styling for the goo-ds design system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.gds-cell {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
padding: var(--table-cell-paddingVertical) var(--table-cell-paddingHorizontal);
|
|
9
|
+
vertical-align: top;
|
|
10
|
+
|
|
11
|
+
/* Typography - body-sm-regular */
|
|
12
|
+
font-family: var(--coreText-family-primary);
|
|
13
|
+
font-size: var(--font-size-sm);
|
|
14
|
+
font-weight: var(--font-weight-regular);
|
|
15
|
+
line-height: var(--font-lineHeight-sm);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Header cell - secondary color */
|
|
19
|
+
.gds-cell-header {
|
|
20
|
+
color: var(--coreText-text-secondary-default);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Body cell - primary color */
|
|
24
|
+
.gds-cell-body {
|
|
25
|
+
color: var(--coreText-text-primary-default);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Alignment */
|
|
29
|
+
.gds-cell-align-left {
|
|
30
|
+
text-align: left;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.gds-cell-align-center {
|
|
34
|
+
text-align: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.gds-cell-align-right {
|
|
38
|
+
text-align: right;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Width presets */
|
|
42
|
+
.gds-cell-width-xs {
|
|
43
|
+
width: var(--table-cell-width-xs);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.gds-cell-width-sm {
|
|
47
|
+
width: var(--table-cell-width-sm);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.gds-cell-width-md {
|
|
51
|
+
width: var(--table-cell-width-md);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.gds-cell-width-lg {
|
|
55
|
+
width: var(--table-cell-width-lg);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.gds-cell-width-xl {
|
|
59
|
+
width: var(--table-cell-width-xl);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.gds-cell-width-fill {
|
|
63
|
+
width: auto;
|
|
64
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CellProps } from "./Cell.types";
|
|
2
|
+
import "./Cell.css";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cell - Table cell component for the goo-ds design system
|
|
6
|
+
*
|
|
7
|
+
* Provides consistent table cell layout with alignment and width presets.
|
|
8
|
+
* Designed to be used within table structures.
|
|
9
|
+
* Token-first per Constitution (no hardcoded values).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Cell type="header">Name</Cell>
|
|
14
|
+
* <Cell>John Doe</Cell>
|
|
15
|
+
* <Cell alignment="right" width="sm">$100</Cell>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function Cell({
|
|
19
|
+
type = "body",
|
|
20
|
+
alignment = "left",
|
|
21
|
+
width = "md",
|
|
22
|
+
children,
|
|
23
|
+
className = "",
|
|
24
|
+
...props
|
|
25
|
+
}: CellProps) {
|
|
26
|
+
const Tag = type === "header" ? "th" : "td";
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Tag
|
|
30
|
+
className={`gds-cell gds-cell-${type} gds-cell-align-${alignment} gds-cell-width-${width} ${className}`.trim()}
|
|
31
|
+
data-component="Cell"
|
|
32
|
+
data-type={type}
|
|
33
|
+
data-alignment={alignment}
|
|
34
|
+
data-width={width}
|
|
35
|
+
{...props}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</Tag>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default Cell;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cell component props
|
|
5
|
+
* Provides table cell layout using design system tokens
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type CellType = "header" | "body";
|
|
9
|
+
|
|
10
|
+
export type CellAlignment = "left" | "center" | "right";
|
|
11
|
+
|
|
12
|
+
export type CellWidth = "xs" | "sm" | "md" | "lg" | "xl" | "fill";
|
|
13
|
+
|
|
14
|
+
export interface CellProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
15
|
+
/**
|
|
16
|
+
* The type of cell (header or body)
|
|
17
|
+
* @default "body"
|
|
18
|
+
*/
|
|
19
|
+
type?: CellType;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Horizontal alignment of cell content
|
|
23
|
+
* @default "left"
|
|
24
|
+
*/
|
|
25
|
+
alignment?: CellAlignment;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Width preset for the cell
|
|
29
|
+
* @default "md"
|
|
30
|
+
*/
|
|
31
|
+
width?: CellWidth;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Cell content
|
|
35
|
+
*/
|
|
36
|
+
children?: ReactNode;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Additional CSS class names
|
|
40
|
+
*/
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|