Skip to content

Commit 5282c40

Browse files
committed
feat: ✨ Implement Button 2.0 component
1 parent b5f886d commit 5282c40

12 files changed

Lines changed: 1781 additions & 52 deletions

File tree

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { Primary, Canvas, Controls, Meta } from '@storybook/addon-docs/blocks'
2+
import * as ComponentStories from './Button.stories'
3+
4+
<Meta of={ComponentStories} />
5+
6+
# Button
7+
8+
Button component for triggering actions.
9+
10+
**⚠️ Beta Component** - This component is under active development and may have breaking changes.
11+
12+
```bash
13+
npm install @equinor/eds-core-react@beta
14+
```
15+
16+
<Primary />
17+
<Controls />
18+
19+
## Usage
20+
21+
```tsx
22+
import { Button } from '@equinor/eds-core-react/next'
23+
import { Icon } from '@equinor/eds-core-react/next'
24+
import { add, chevron_right } from '@equinor/eds-icons'
25+
26+
// Text only
27+
<Button variant="primary" tone="accent">
28+
Submit
29+
</Button>
30+
31+
// Icon before label
32+
<Button variant="secondary">
33+
<Icon data={add} aria-hidden />
34+
Add item
35+
</Button>
36+
37+
// Icon after label
38+
<Button>
39+
Next
40+
<Icon data={chevron_right} aria-hidden />
41+
</Button>
42+
43+
// Icon-only button (requires aria-label)
44+
<Button icon aria-label="Add item">
45+
<Icon data={add} aria-hidden />
46+
</Button>
47+
48+
// Circular icon-only button
49+
<Button icon round aria-label="Add item">
50+
<Icon data={add} aria-hidden />
51+
</Button>
52+
```
53+
54+
## Examples
55+
56+
### Sizes
57+
58+
Three sizes are available: `small` (24px spacious / 20px comfortable), `default` (36px spacious / 24px comfortable), and `large` (44px spacious / 36px comfortable).
59+
60+
<Canvas of={ComponentStories.Sizes} />
61+
62+
### Tones
63+
64+
The `tone` prop controls the color scheme using `data-color-appearance`.
65+
66+
<Canvas of={ComponentStories.Tones} />
67+
68+
### With Icons
69+
70+
Place an Icon before or after the text as a child.
71+
72+
<Canvas of={ComponentStories.WithIconBefore} />
73+
<Canvas of={ComponentStories.WithIconAfter} />
74+
75+
### Disabled States
76+
77+
All variants support the disabled state.
78+
79+
<Canvas of={ComponentStories.DisabledVariants} />
80+
81+
### Danger Actions
82+
83+
Use `tone="danger"` for destructive actions.
84+
85+
<Canvas of={ComponentStories.DangerAction} />
86+
87+
### Icon-Only Buttons
88+
89+
Use the `icon` prop for icon-only buttons. They are square with uniform padding. Always provide `aria-label` for accessibility.
90+
91+
<Canvas of={ComponentStories.IconOnly} />
92+
<Canvas of={ComponentStories.IconOnlyVariants} />
93+
94+
### Circular Icon-Only Buttons
95+
96+
Use `round` on icon-only buttons to create circular buttons.
97+
98+
<Canvas of={ComponentStories.CircularIconOnly} />
99+
100+
### Density Modes
101+
102+
Comparison of all button sizes across density modes. Use `data-density` on a parent container to control density.
103+
104+
<Canvas of={ComponentStories.DensityComparison} />
105+
106+
### All Variants
107+
108+
Complete overview of all variants, sizes, and color appearances.
109+
110+
<Canvas of={ComponentStories.AllVariants} />
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import figma from '@figma/code-connect'
2+
import { Button } from './Button'
3+
4+
/**
5+
* Code Connect mapping for Button component.
6+
*
7+
* Maps Figma design variants to React component props.
8+
* Run `npx figma connect publish` from packages/eds-core-react/ to publish.
9+
*
10+
* Figma component structure:
11+
* - Button [EDS] (18:1193) → .Geometry Options → ⌘ Button
12+
* - Icon Button [EDS] (18:1373) → .Geometry Options → ⌘ Icon Button
13+
*/
14+
15+
// ============================================
16+
// Connection 1: Button [EDS] (18:1193)
17+
// Top-level wrapper with Tone + nested geometry + nested button
18+
// ============================================
19+
20+
figma.connect(
21+
Button,
22+
'https://www.figma.com/design/dz0XQdc5j7AAtjXr1gTfVR/EDS-Core-Components?node-id=18-1193',
23+
{
24+
props: {
25+
tone: figma.enum('Tone', {
26+
Accent: 'accent',
27+
Neutral: 'neutral',
28+
Danger: 'danger',
29+
}),
30+
geometry: figma.nestedProps('.Geometry Options', {
31+
size: figma.enum('Size', {
32+
Large: 'large',
33+
Default: 'default',
34+
Small: 'small',
35+
}),
36+
}),
37+
inner: figma.nestedProps('⌘ Button', {
38+
variant: figma.enum('Variant', {
39+
Primary: 'primary',
40+
Outline: 'secondary',
41+
Ghost: 'ghost',
42+
}),
43+
disabled: figma.enum('State', {
44+
Disabled: true,
45+
}),
46+
leadingIcon: figma.boolean('Show Leading Icon', {
47+
true: figma.instance('Leading Icon Item'),
48+
false: undefined,
49+
}),
50+
trailingIcon: figma.boolean('Show Trailing Icon', {
51+
true: figma.instance('Trailing Icon Item'),
52+
false: undefined,
53+
}),
54+
label: figma.string('Label'),
55+
}),
56+
},
57+
example: ({ tone, geometry, inner }) => (
58+
<Button
59+
variant={inner.variant}
60+
size={geometry.size}
61+
tone={tone}
62+
disabled={inner.disabled}
63+
>
64+
{/* TODO: Replace with actual icon components, when Icon component is
65+
available in Code Connect */}
66+
{inner.leadingIcon}
67+
{inner.label}
68+
{inner.trailingIcon}
69+
</Button>
70+
),
71+
},
72+
)
73+
74+
// ============================================
75+
// Connection 2: Icon Button [EDS] (18:1373)
76+
// Top-level wrapper with Tone + nested geometry (includes Round) + nested icon button
77+
// ============================================
78+
79+
figma.connect(
80+
Button,
81+
'https://www.figma.com/design/dz0XQdc5j7AAtjXr1gTfVR/EDS-Core-Components?node-id=18-1373',
82+
{
83+
props: {
84+
tone: figma.enum('Tone', {
85+
Accent: 'accent',
86+
Neutral: 'neutral',
87+
Danger: 'danger',
88+
}),
89+
geometry: figma.nestedProps('.Geometry Options', {
90+
size: figma.enum('Size', {
91+
Large: 'large',
92+
Default: 'default',
93+
Small: 'small',
94+
}),
95+
round: figma.boolean('Round'),
96+
}),
97+
// @ts-expect-error - Code Connect's ConnectedComponent type doesn't match ReactElement
98+
inner: figma.nestedProps('⌘ Icon Button', {
99+
variant: figma.enum('Variant', {
100+
Primary: 'primary',
101+
Outline: 'secondary',
102+
Ghost: 'ghost',
103+
}),
104+
disabled: figma.enum('State', {
105+
Disabled: true,
106+
}),
107+
iconContent: figma.instance('icon'),
108+
}),
109+
},
110+
example: ({ tone, geometry, inner }) => (
111+
<Button
112+
icon
113+
variant={inner.variant}
114+
size={geometry.size}
115+
tone={tone}
116+
round={geometry.round}
117+
disabled={inner.disabled}
118+
/* Remember to describe the action of the icon button for accessibility */
119+
aria-label="[Describe action]"
120+
>
121+
{inner.iconContent}
122+
</Button>
123+
),
124+
},
125+
)

0 commit comments

Comments
 (0)