@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.
Files changed (70) hide show
  1. package/README.md +163 -0
  2. package/package.json +60 -0
  3. package/src/components/Button/Button.css +107 -0
  4. package/src/components/Button/Button.tsx +82 -0
  5. package/src/components/Button/Button.types.ts +62 -0
  6. package/src/components/Button/index.ts +3 -0
  7. package/src/components/Cell/Cell.css +64 -0
  8. package/src/components/Cell/Cell.tsx +42 -0
  9. package/src/components/Cell/Cell.types.ts +42 -0
  10. package/src/components/Cell/index.ts +3 -0
  11. package/src/components/Codeblock/Codeblock.css +90 -0
  12. package/src/components/Codeblock/Codeblock.tsx +88 -0
  13. package/src/components/Codeblock/Codeblock.types.ts +42 -0
  14. package/src/components/Codeblock/index.ts +3 -0
  15. package/src/components/CoreText/CoreText.tsx +43 -0
  16. package/src/components/CoreText/CoreText.types.ts +56 -0
  17. package/src/components/CoreText/index.ts +2 -0
  18. package/src/components/Divider/Divider.css +38 -0
  19. package/src/components/Divider/Divider.tsx +35 -0
  20. package/src/components/Divider/Divider.types.ts +19 -0
  21. package/src/components/Divider/index.ts +3 -0
  22. package/src/components/InputImage/InputImage.css +212 -0
  23. package/src/components/InputImage/InputImage.tsx +314 -0
  24. package/src/components/InputImage/InputImage.types.ts +86 -0
  25. package/src/components/InputImage/index.ts +2 -0
  26. package/src/components/Sidebar/Sidebar.css +35 -0
  27. package/src/components/Sidebar/Sidebar.tsx +42 -0
  28. package/src/components/Sidebar/Sidebar.types.ts +24 -0
  29. package/src/components/Sidebar/index.ts +3 -0
  30. package/src/components/SidebarItem/SidebarItem.css +70 -0
  31. package/src/components/SidebarItem/SidebarItem.tsx +55 -0
  32. package/src/components/SidebarItem/SidebarItem.types.ts +39 -0
  33. package/src/components/SidebarItem/index.ts +3 -0
  34. package/src/components/Skeleton/Skeleton.css +25 -0
  35. package/src/components/Skeleton/Skeleton.tsx +41 -0
  36. package/src/components/Skeleton/Skeleton.types.ts +65 -0
  37. package/src/components/Skeleton/index.ts +5 -0
  38. package/src/components/Spacer/Spacer.tsx +31 -0
  39. package/src/components/Spacer/Spacer.types.ts +58 -0
  40. package/src/components/Spacer/index.ts +3 -0
  41. package/src/components/TabItem/TabItem.css +67 -0
  42. package/src/components/TabItem/TabItem.tsx +45 -0
  43. package/src/components/TabItem/TabItem.types.ts +35 -0
  44. package/src/components/TabItem/index.ts +3 -0
  45. package/src/components/Table/Table.css +16 -0
  46. package/src/components/Table/Table.tsx +39 -0
  47. package/src/components/Table/Table.types.ts +18 -0
  48. package/src/components/Table/index.ts +3 -0
  49. package/src/components/TableRow/TableRow.css +53 -0
  50. package/src/components/TableRow/TableRow.tsx +53 -0
  51. package/src/components/TableRow/TableRow.types.ts +41 -0
  52. package/src/components/TableRow/index.ts +3 -0
  53. package/src/components/Tabs/Tabs.css +11 -0
  54. package/src/components/Tabs/Tabs.tsx +37 -0
  55. package/src/components/Tabs/Tabs.types.ts +18 -0
  56. package/src/components/Tabs/index.ts +3 -0
  57. package/src/components/index.ts +15 -0
  58. package/src/compositions/index.ts +3 -0
  59. package/src/index.css +68 -0
  60. package/src/index.ts +4 -0
  61. package/src/styles/component-tokens.css +270 -0
  62. package/src/styles/component-tokens.current.css +3 -0
  63. package/src/styles/fonts.css +11 -0
  64. package/src/styles/global-tokens.css +257 -0
  65. package/src/styles/index.css +20 -0
  66. package/src/styles/number-tokens.css +72 -0
  67. package/src/styles/semantic-tokens.css +84 -0
  68. package/src/styles/style-tokens.css +219 -0
  69. package/src/styles/typography-tokens.css +50 -0
  70. 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,3 @@
1
+ export { Button } from "./Button";
2
+ export type { ButtonProps, ButtonVariant, ButtonSize } from "./Button.types";
3
+ export { default } from "./Button";
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export { Cell } from "./Cell";
2
+ export type { CellProps, CellType, CellAlignment, CellWidth } from "./Cell.types";
3
+ export { default } from "./Cell";