@codecademy/styleguide 79.2.0-alpha.f66feb.0 → 79.2.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/.storybook/components/Scales/ColorScale.tsx +1 -1
- package/.storybook/preview.ts +5 -4
- package/.storybook/theming/GamutThemeProvider.tsx +4 -4
- package/CHANGELOG.md +20 -3
- package/package.json +2 -2
- package/src/lib/Foundations/Layout.mdx +1 -1
- package/src/lib/Foundations/System/Props/Layout.mdx +23 -2
- package/src/lib/Foundations/System/Props/Layout.stories.tsx +85 -0
- package/src/lib/Foundations/System/Props/Positioning.mdx +7 -2
- package/src/lib/Foundations/System/Props/Positioning.stories.tsx +32 -0
- package/src/lib/Meta/Installation.mdx +14 -2
- package/src/lib/Meta/Logical and physical CSS properties.mdx +24 -8
- package/src/lib/Molecules/Popover/Popover.stories.tsx +6 -0
- package/src/lib/Molecules/Tips/InfoTip/InfoTip.stories.tsx +2 -2
- package/src/lib/Typography/Text/Text.stories.tsx +4 -4
- package/src/lib/Typography/Text/tables.tsx +2 -2
- package/src/lib/UX Writing/Component guidelines/Alerts.mdx +1 -1
- package/src/lib/UX Writing/Component guidelines/Confirmation dialogs.mdx +44 -26
- package/src/static/ux writing/clear_chat.png +0 -0
- package/src/static/ux writing/delete_study_plan.png +0 -0
- package/src/static/ux writing/delete_this_course.png +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { themed } from '@codecademy/gamut-styles';
|
|
3
3
|
import styled from '@emotion/styled';
|
|
4
|
-
import { Box, GridBox } from '@codecademy/gamut';
|
|
4
|
+
import { Box, GridBox } from '@codecademy/gamut/src';
|
|
5
5
|
|
|
6
6
|
const HexCode = styled.span`
|
|
7
7
|
font-family: ${themed('fontFamily.monospace')};
|
package/.storybook/preview.ts
CHANGED
|
@@ -175,20 +175,21 @@ export const globalTypes = {
|
|
|
175
175
|
toolbar: {
|
|
176
176
|
icon: 'transfer',
|
|
177
177
|
items: [
|
|
178
|
-
{ value: 'true', title: 'Logical' },
|
|
179
178
|
{ value: 'false', title: 'Physical' },
|
|
179
|
+
{ value: 'true', title: 'Logical' },
|
|
180
180
|
],
|
|
181
181
|
showName: true,
|
|
182
182
|
},
|
|
183
183
|
},
|
|
184
184
|
direction: {
|
|
185
185
|
name: 'Direction',
|
|
186
|
-
description: 'Text direction
|
|
186
|
+
description: 'Text direction (LTR or RTL)',
|
|
187
187
|
defaultValue: 'ltr',
|
|
188
188
|
toolbar: {
|
|
189
|
+
icon: 'arrowright',
|
|
189
190
|
items: [
|
|
190
|
-
{ value: 'ltr',
|
|
191
|
-
{ value: 'rtl',
|
|
191
|
+
{ value: 'ltr', title: 'Left-to-Right (LTR)', icon: 'arrowright' },
|
|
192
|
+
{ value: 'rtl', title: 'Right-to-Left (RTL)', icon: 'arrowleft' },
|
|
192
193
|
],
|
|
193
194
|
showName: true,
|
|
194
195
|
},
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
} from '@codecademy/gamut-styles/src';
|
|
13
13
|
import { Theme } from '@emotion/react';
|
|
14
14
|
|
|
15
|
+
const STORYBOOK_CSP_NONCE = 'storybook-csp-nonce';
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
18
|
* Story functions must be called as a regular function to avoid full-remounts
|
|
17
19
|
* See: https://github.com/storybookjs/storybook/issues/12255
|
|
@@ -68,9 +70,8 @@ export const withEmotion = (Story: any, context: GlobalsContext) => {
|
|
|
68
70
|
alwaysSetVariables
|
|
69
71
|
bg={themeBackground[colorMode]}
|
|
70
72
|
ref={storyRef}
|
|
71
|
-
dir={direction}
|
|
72
73
|
>
|
|
73
|
-
{Story()}
|
|
74
|
+
<div dir={direction}>{Story()}</div>
|
|
74
75
|
</Background>
|
|
75
76
|
</GamutProvider>
|
|
76
77
|
);
|
|
@@ -86,9 +87,8 @@ export const withEmotion = (Story: any, context: GlobalsContext) => {
|
|
|
86
87
|
alwaysSetVariables
|
|
87
88
|
bg={themeBackground[colorMode]}
|
|
88
89
|
ref={storyRef}
|
|
89
|
-
dir={direction}
|
|
90
90
|
>
|
|
91
|
-
{Story()}
|
|
91
|
+
<div dir={direction}>{Story()}</div>
|
|
92
92
|
</Background>
|
|
93
93
|
</GamutProvider>
|
|
94
94
|
);
|
package/CHANGELOG.md
CHANGED
|
@@ -3,12 +3,29 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
## [79.2.0
|
|
6
|
+
## [79.2.0](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@79.1.4...@codecademy/styleguide@79.2.0) (2026-03-12)
|
|
7
7
|
|
|
8
8
|
### Features
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
|
|
10
|
+
- Logical properties ([4c340c3](https://github.com/Codecademy/gamut/commit/4c340c3949bad30fce4f9ffabb2018763df5c4ba))
|
|
11
|
+
|
|
12
|
+
### [79.1.4](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@79.1.3...@codecademy/styleguide@79.1.4) (2026-03-09)
|
|
13
|
+
|
|
14
|
+
**Note:** Version bump only for package @codecademy/styleguide
|
|
15
|
+
|
|
16
|
+
### [79.1.3](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@79.1.2...@codecademy/styleguide@79.1.3) (2026-03-02)
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- **GamutProvider:** CSP improvements ([1026353](https://github.com/Codecademy/gamut/commit/10263537c190aff0e5686872da2be2a30b1d9201)), closes [/github.com/adobe/react-spectrum/issues/8273#issuecomment-3897820426](https://github.com/Codecademy//github.com/adobe/react-spectrum/issues/8273/issues/issuecomment-3897820426)
|
|
21
|
+
|
|
22
|
+
### [79.1.2](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@79.1.1...@codecademy/styleguide@79.1.2) (2026-02-12)
|
|
23
|
+
|
|
24
|
+
**Note:** Version bump only for package @codecademy/styleguide
|
|
25
|
+
|
|
26
|
+
### [79.1.1](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@79.1.0...@codecademy/styleguide@79.1.1) (2026-02-11)
|
|
27
|
+
|
|
28
|
+
**Note:** Version bump only for package @codecademy/styleguide
|
|
12
29
|
|
|
13
30
|
## [79.1.0](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@79.0.0...@codecademy/styleguide@79.1.0) (2026-02-09)
|
|
14
31
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codecademy/styleguide",
|
|
3
3
|
"description": "Styleguide & Component library for codecademy.com",
|
|
4
|
-
"version": "79.2.0
|
|
4
|
+
"version": "79.2.0",
|
|
5
5
|
"author": "Codecademy Engineering",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
10
10
|
"repository": "git@github.com:Codecademy/gamut.git",
|
|
11
|
-
"gitHead": "
|
|
11
|
+
"gitHead": "4f0b229a70b7b652b7ac2589ede7cd947b301014"
|
|
12
12
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Meta } from '@storybook/blocks';
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
2
|
|
|
3
3
|
import { AboutHeader, TokenTable } from '~styleguide/blocks';
|
|
4
4
|
|
|
5
5
|
import { defaultColumns, getPropRows } from '../../shared/elements';
|
|
6
|
+
import * as LayoutStories from './Layout.stories';
|
|
6
7
|
|
|
7
8
|
export const parameters = {
|
|
8
9
|
title: 'Layout',
|
|
@@ -11,12 +12,22 @@ export const parameters = {
|
|
|
11
12
|
status: 'updating',
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
<Meta title="Foundations/System/Props/Layout" />
|
|
15
|
+
<Meta title="Foundations/System/Props/Layout" of={LayoutStories} />
|
|
15
16
|
|
|
16
17
|
<AboutHeader {...parameters} />
|
|
17
18
|
|
|
18
19
|
Layout props control the visual structure and dimensions of elements. These properties determine how components take up space, their display behavior, and how they align within their containers. Use these props to set widths, heights, overflow behavior, and container types for responsive layouts.
|
|
19
20
|
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
### Overflow X
|
|
24
|
+
|
|
25
|
+
<Canvas of={LayoutStories.OverflowXExample} />
|
|
26
|
+
|
|
27
|
+
### Overflow Y
|
|
28
|
+
|
|
29
|
+
<Canvas of={LayoutStories.OverflowYExample} />
|
|
30
|
+
|
|
20
31
|
```tsx
|
|
21
32
|
import styled from '@emotion/styled';
|
|
22
33
|
import { system } from '@codecademy/gamut-styles';
|
|
@@ -31,4 +42,14 @@ const LayoutExample = styled.div(system.layout);
|
|
|
31
42
|
/>;
|
|
32
43
|
```
|
|
33
44
|
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
### Width
|
|
48
|
+
|
|
49
|
+
<Canvas of={LayoutStories.WidthExample} />
|
|
50
|
+
|
|
51
|
+
### Direction
|
|
52
|
+
|
|
53
|
+
<Canvas of={LayoutStories.DirectionExample} />
|
|
54
|
+
|
|
34
55
|
<TokenTable rows={getPropRows('layout')} columns={defaultColumns} />
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Box, Markdown } from '@codecademy/gamut';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Box> = {
|
|
5
|
+
title: 'Foundations/System/Props/Layout',
|
|
6
|
+
component: Box,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof Box>;
|
|
11
|
+
|
|
12
|
+
export const OverflowXExample: Story = {
|
|
13
|
+
render: () => (
|
|
14
|
+
<Box
|
|
15
|
+
bg="background-selected"
|
|
16
|
+
overflowX="scroll"
|
|
17
|
+
p={16}
|
|
18
|
+
whiteSpace="nowrap"
|
|
19
|
+
width="200px"
|
|
20
|
+
>
|
|
21
|
+
<Box
|
|
22
|
+
bg="primary"
|
|
23
|
+
color="background-contrast"
|
|
24
|
+
display="inline-block"
|
|
25
|
+
p={8}
|
|
26
|
+
>
|
|
27
|
+
This content is wider than its container and has{' '}
|
|
28
|
+
<Markdown text="`overflowX='scroll'`." /> Inspect the example to see
|
|
29
|
+
what CSS properties are rendered.
|
|
30
|
+
</Box>
|
|
31
|
+
</Box>
|
|
32
|
+
),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const OverflowYExample: Story = {
|
|
36
|
+
render: () => (
|
|
37
|
+
<Box bg="background-selected" height="100px" overflowY="scroll" p={16}>
|
|
38
|
+
<Box bg="primary" color="background-contrast" p={8}>
|
|
39
|
+
This content is taller than its container and has{' '}
|
|
40
|
+
<Markdown text="`overflowY='scroll'`." /> Inspect the example to see
|
|
41
|
+
what CSS properties are rendered.
|
|
42
|
+
<Box mt={16}>Line 2</Box>
|
|
43
|
+
<Box mt={16}>Line 3</Box>
|
|
44
|
+
<Box mt={16}>Line 4</Box>
|
|
45
|
+
<Box mt={16}>Line 5</Box>
|
|
46
|
+
</Box>
|
|
47
|
+
</Box>
|
|
48
|
+
),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const WidthExample: Story = {
|
|
52
|
+
render: () => (
|
|
53
|
+
<Box bg="background-selected" p={16}>
|
|
54
|
+
<Box
|
|
55
|
+
bg="primary"
|
|
56
|
+
color="background-contrast"
|
|
57
|
+
height="300px"
|
|
58
|
+
p={16}
|
|
59
|
+
width="50%"
|
|
60
|
+
>
|
|
61
|
+
This box has <Markdown text="`width='50%' and height='300px'`." />{' '}
|
|
62
|
+
Inspect the box to see the rendered CSS property.
|
|
63
|
+
</Box>
|
|
64
|
+
</Box>
|
|
65
|
+
),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const DirectionExample: Story = {
|
|
69
|
+
render: () => (
|
|
70
|
+
<Box display="flex" flexDirection="row" gap={16}>
|
|
71
|
+
<Box bg="background-selected" p={16} width="50%">
|
|
72
|
+
<Box bg="primary" color="background-contrast" direction="ltr" p={16}>
|
|
73
|
+
<Markdown text="`direction='ltr'`." /> Left-to-right text direction
|
|
74
|
+
(default for English).
|
|
75
|
+
</Box>
|
|
76
|
+
</Box>
|
|
77
|
+
<Box bg="background-selected" p={16} width="50%">
|
|
78
|
+
<Box bg="primary" color="background-contrast" direction="rtl" p={16}>
|
|
79
|
+
<Markdown text="`direction='rtl'`." /> Right-to-left text direction
|
|
80
|
+
(used for Arabic, Hebrew, etc.).
|
|
81
|
+
</Box>
|
|
82
|
+
</Box>
|
|
83
|
+
</Box>
|
|
84
|
+
),
|
|
85
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Meta } from '@storybook/blocks';
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
2
|
|
|
3
3
|
import { AboutHeader, TokenTable } from '~styleguide/blocks';
|
|
4
4
|
|
|
5
5
|
import { defaultColumns, getPropRows } from '../../shared/elements';
|
|
6
|
+
import * as PositioningStories from './Positioning.stories';
|
|
6
7
|
|
|
7
8
|
export const parameters = {
|
|
8
9
|
title: 'Positioning',
|
|
@@ -11,7 +12,7 @@ export const parameters = {
|
|
|
11
12
|
status: 'updating',
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
<Meta title="Foundations/System/Props/Positioning" />
|
|
15
|
+
<Meta title="Foundations/System/Props/Positioning" of={PositioningStories} />
|
|
15
16
|
|
|
16
17
|
<AboutHeader {...parameters} />
|
|
17
18
|
|
|
@@ -26,4 +27,8 @@ const PositioningExample = styled.div(system.positioning);
|
|
|
26
27
|
<PositioningExample position="absolute" zIndex={2} top="0" left="0" />;
|
|
27
28
|
```
|
|
28
29
|
|
|
30
|
+
These positioning props support both physical and logical CSS properties and will render the appropriate properties based on `useLogicalProperties`'s value passed into the `<GamutProvider>` at the root of your application.
|
|
31
|
+
|
|
32
|
+
<Canvas of={PositioningStories.PositionExample} />
|
|
33
|
+
|
|
29
34
|
<TokenTable rows={getPropRows('positioning')} columns={defaultColumns} />
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Box, Markdown } from '@codecademy/gamut';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Box> = {
|
|
5
|
+
title: 'Foundations/System/Props/Positioning',
|
|
6
|
+
component: Box,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof Box>;
|
|
11
|
+
|
|
12
|
+
export const PositionExample: Story = {
|
|
13
|
+
render: () => (
|
|
14
|
+
<Box bg="background-selected" height="250px" position="relative">
|
|
15
|
+
<Box
|
|
16
|
+
bg="primary"
|
|
17
|
+
color="background-contrast"
|
|
18
|
+
left={16}
|
|
19
|
+
p={16}
|
|
20
|
+
position="absolute"
|
|
21
|
+
top={16}
|
|
22
|
+
>
|
|
23
|
+
This box has{' '}
|
|
24
|
+
<Markdown text="`position='absolute'`, `top={16}`, and `left={16}`." />{' '}
|
|
25
|
+
Inspect the example to see what CSS properties are rendered. You can
|
|
26
|
+
also change the value of{' '}
|
|
27
|
+
<Markdown text="`useLogicalProperties` and `direction`" /> in the
|
|
28
|
+
toolbar to see how the box renders differently.
|
|
29
|
+
</Box>
|
|
30
|
+
</Box>
|
|
31
|
+
),
|
|
32
|
+
};
|
|
@@ -68,7 +68,7 @@ GamutProvider handles a few critical tasks that need to happen in order for comp
|
|
|
68
68
|
- **Next** `_app.tsx`
|
|
69
69
|
- **Gatsby** `gatsby-ssr.js` `gatsby-browser.js` and use `wrapRootElement` in each.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
5. Add required types for your theme, which will determine what props Gamut components allow.
|
|
72
72
|
|
|
73
73
|
```tsx
|
|
74
74
|
// theme.d.ts
|
|
@@ -84,7 +84,7 @@ declare module '@emotion/react' {
|
|
|
84
84
|
|
|
85
85
|
For more information this declaration please checkout the [official emotion documentation](https://emotion.sh/docs/typescript#define-a-theme)!
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
6. Start Building!
|
|
88
88
|
|
|
89
89
|
```tsx
|
|
90
90
|
import { Background } from '@codecademy/gamut-styles';
|
|
@@ -96,3 +96,15 @@ export const App = () => (
|
|
|
96
96
|
</Background>
|
|
97
97
|
);
|
|
98
98
|
```
|
|
99
|
+
|
|
100
|
+
### Content Security Policy (CSP)
|
|
101
|
+
|
|
102
|
+
If your app uses a strict Content-Security-Policy (e.g. `style-src` without `'unsafe-inline'`), pass a nonce to `GamutProvider` so Emotion and other Gamut-managed style tags are allowed:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<GamutProvider nonce={yourCspNonce}>
|
|
106
|
+
<App />
|
|
107
|
+
</GamutProvider>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Your nonce should be the same value you use in your CSP header (e.g. `style-src 'self' 'nonce-{value}'`).
|
|
@@ -22,7 +22,7 @@ export const parameters = {
|
|
|
22
22
|
|
|
23
23
|
## What are CSS logical properties?
|
|
24
24
|
|
|
25
|
-
CSS logical properties are a modern approach to styling that adapts to the writing mode and text direction of your content, rather than being tied to physical screen directions. More information can be found on[MDN: CSS Logical Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values)
|
|
25
|
+
CSS logical properties are a modern approach to styling that adapts to the writing mode and text direction of your content, rather than being tied to physical screen directions. More information can be found on [MDN: CSS Logical Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values)
|
|
26
26
|
|
|
27
27
|
### Physical Properties (Traditional)
|
|
28
28
|
|
|
@@ -46,7 +46,9 @@ Gamut supports both physical and logical CSS properties through the `useLogicalP
|
|
|
46
46
|
|
|
47
47
|
### Affected Props
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
When `useLogicalProperties` is enabled, Gamut replaces physical CSS properties with their logical equivalents. This applies to both **base properties** (like `marginLeft`, `width`) and **shorthand props** (like `mx`, `py`).
|
|
50
|
+
|
|
51
|
+
The table below shows a few examples — this is not a comprehensive list.
|
|
50
52
|
|
|
51
53
|
<TokenTable
|
|
52
54
|
idKey="prop"
|
|
@@ -59,7 +61,7 @@ Here are some examples of how physical and logical properties are affected by th
|
|
|
59
61
|
},
|
|
60
62
|
{
|
|
61
63
|
key: 'physical',
|
|
62
|
-
name: 'Physical',
|
|
64
|
+
name: 'Physical CSS',
|
|
63
65
|
size: 'xl',
|
|
64
66
|
render: ({ physical }) =>
|
|
65
67
|
physical.map((p) => (
|
|
@@ -70,7 +72,7 @@ Here are some examples of how physical and logical properties are affected by th
|
|
|
70
72
|
},
|
|
71
73
|
{
|
|
72
74
|
key: 'logical',
|
|
73
|
-
name: 'Logical',
|
|
75
|
+
name: 'Logical CSS',
|
|
74
76
|
size: 'xl',
|
|
75
77
|
render: ({ logical }) =>
|
|
76
78
|
logical.map((l) => (
|
|
@@ -81,21 +83,35 @@ Here are some examples of how physical and logical properties are affected by th
|
|
|
81
83
|
},
|
|
82
84
|
]}
|
|
83
85
|
rows={[
|
|
86
|
+
{
|
|
87
|
+
prop: 'marginLeft',
|
|
88
|
+
physical: ['margin-left'],
|
|
89
|
+
logical: ['margin-inline-start'],
|
|
90
|
+
},
|
|
84
91
|
{
|
|
85
92
|
prop: 'mx',
|
|
86
93
|
physical: ['margin-left', 'margin-right'],
|
|
87
94
|
logical: ['margin-inline-start', 'margin-inline-end'],
|
|
88
95
|
},
|
|
89
|
-
{
|
|
96
|
+
{
|
|
97
|
+
prop: 'paddingTop',
|
|
98
|
+
physical: ['padding-top'],
|
|
99
|
+
logical: ['padding-block-start'],
|
|
100
|
+
},
|
|
90
101
|
{
|
|
91
102
|
prop: 'py',
|
|
92
103
|
physical: ['padding-top', 'padding-bottom'],
|
|
93
104
|
logical: ['padding-block-start', 'padding-block-end'],
|
|
94
105
|
},
|
|
95
106
|
{
|
|
96
|
-
prop: '
|
|
97
|
-
physical: ['
|
|
98
|
-
logical: ['
|
|
107
|
+
prop: 'width',
|
|
108
|
+
physical: ['width'],
|
|
109
|
+
logical: ['inline-size'],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
prop: 'height',
|
|
113
|
+
physical: ['height'],
|
|
114
|
+
logical: ['block-size'],
|
|
99
115
|
},
|
|
100
116
|
]}
|
|
101
117
|
/>
|
|
@@ -80,6 +80,7 @@ export const Above: Story = {
|
|
|
80
80
|
export const Below: Story = {
|
|
81
81
|
render: (args) => <PopoverExample {...args} beak="center" position="below" />,
|
|
82
82
|
};
|
|
83
|
+
|
|
83
84
|
export const CenterLeft: Story = {
|
|
84
85
|
render: (args) => (
|
|
85
86
|
<PopoverExample
|
|
@@ -113,6 +114,7 @@ export const PopoverCheckerDense: Story = {
|
|
|
113
114
|
/>
|
|
114
115
|
),
|
|
115
116
|
};
|
|
117
|
+
|
|
116
118
|
export const PopoverCheckerLoose: Story = {
|
|
117
119
|
render: (args) => (
|
|
118
120
|
<PopoverExample
|
|
@@ -122,6 +124,7 @@ export const PopoverCheckerLoose: Story = {
|
|
|
122
124
|
/>
|
|
123
125
|
),
|
|
124
126
|
};
|
|
127
|
+
|
|
125
128
|
export const PopoverCheckerRegular: Story = {
|
|
126
129
|
render: (args) => (
|
|
127
130
|
<PopoverExample
|
|
@@ -131,6 +134,7 @@ export const PopoverCheckerRegular: Story = {
|
|
|
131
134
|
/>
|
|
132
135
|
),
|
|
133
136
|
};
|
|
137
|
+
|
|
134
138
|
export const PopoverDiagonalADense: Story = {
|
|
135
139
|
render: (args) => (
|
|
136
140
|
<PopoverExample
|
|
@@ -140,6 +144,7 @@ export const PopoverDiagonalADense: Story = {
|
|
|
140
144
|
/>
|
|
141
145
|
),
|
|
142
146
|
};
|
|
147
|
+
|
|
143
148
|
export const PopoverDiagonalALoose: Story = {
|
|
144
149
|
render: (args) => (
|
|
145
150
|
<PopoverExample
|
|
@@ -149,6 +154,7 @@ export const PopoverDiagonalALoose: Story = {
|
|
|
149
154
|
/>
|
|
150
155
|
),
|
|
151
156
|
};
|
|
157
|
+
|
|
152
158
|
export const PopoverDiagonalARegular: Story = {
|
|
153
159
|
render: (args) => (
|
|
154
160
|
<PopoverExample
|
|
@@ -296,14 +296,14 @@ export const ZIndex: Story = {
|
|
|
296
296
|
},
|
|
297
297
|
render: (args) => (
|
|
298
298
|
<FlexBox center flexDirection="column" m={24} py={64}>
|
|
299
|
-
<Box bg="
|
|
299
|
+
<Box bg="background-primary" zIndex={3}>
|
|
300
300
|
I will not be behind the infotip, sad + unreadable
|
|
301
301
|
</Box>
|
|
302
302
|
<InfoTip
|
|
303
303
|
ariaLabel="z-index example without override"
|
|
304
304
|
info="I am inline, cool"
|
|
305
305
|
/>
|
|
306
|
-
<Box bg="
|
|
306
|
+
<Box bg="background-primary" zIndex={3}>
|
|
307
307
|
I will be behind the infotip, nice + great
|
|
308
308
|
</Box>
|
|
309
309
|
<InfoTip {...args} ariaLabel="z-index example with override" />
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Box, Column, LayoutGrid, Text } from '@codecademy/gamut';
|
|
2
|
-
|
|
3
|
-
import { Fragment } from 'react';
|
|
4
|
-
|
|
2
|
+
// eslint-disable-next-line gamut/import-paths
|
|
5
3
|
import {
|
|
6
4
|
typographyElementVariants,
|
|
7
5
|
typographyStyleVariants,
|
|
8
6
|
typographyUtilities,
|
|
9
|
-
} from '
|
|
7
|
+
} from '@codecademy/gamut/src/Typography/variants';
|
|
8
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
9
|
+
import { Fragment } from 'react';
|
|
10
10
|
|
|
11
11
|
const meta: Meta<typeof Text> = {
|
|
12
12
|
component: Text,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Column, LayoutGrid, Text } from '@codecademy/gamut';
|
|
2
|
+
// eslint-disable-next-line gamut/import-paths
|
|
3
|
+
import { typographyElementVariants } from '@codecademy/gamut/src/Typography/variants';
|
|
2
4
|
import { Fragment } from 'react';
|
|
3
5
|
|
|
4
|
-
import { typographyElementVariants } from '../../../../../gamut/src/Typography/variants';
|
|
5
|
-
|
|
6
6
|
export const Elements: React.FC = () => (
|
|
7
7
|
<LayoutGrid gap={32} my={48}>
|
|
8
8
|
{Object.keys(typographyElementVariants).map((tag) => (
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Meta } from '@storybook/blocks';
|
|
2
2
|
|
|
3
|
-
import { AboutHeader, LinkTo } from '~styleguide/blocks';
|
|
3
|
+
import { AboutHeader, ImageWrapper, LinkTo } from '~styleguide/blocks';
|
|
4
4
|
|
|
5
5
|
export const parameters = {
|
|
6
6
|
title: 'Confirmation dialogs',
|
|
7
7
|
subtitle:
|
|
8
|
-
'
|
|
8
|
+
'Use the same verb from the triggering button, heading, to action confirmation button; clearly communicate the consequences; and keep the copy decision-focused.',
|
|
9
9
|
status: 'static',
|
|
10
10
|
design: {
|
|
11
11
|
type: 'figma',
|
|
@@ -17,39 +17,57 @@ export const parameters = {
|
|
|
17
17
|
|
|
18
18
|
<AboutHeader {...parameters} />
|
|
19
19
|
|
|
20
|
-
Confirmation
|
|
20
|
+
Confirmation dialogs use the <LinkTo id="Molecules/Modals/Dialog">Dialog component in Gamut</LinkTo> to create intentional friction to verify that a learner wants to take a high-impact action, such as:
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
- Irreversible actions (e.g., submitting payment)
|
|
23
|
+
- Loss of data, time, or work (e.g., deleting a course)
|
|
24
|
+
- Unexpected consequences (e.g., losing learning history on an existing prototype when when generating a new prototype)
|
|
25
|
+
|
|
26
|
+
Adding friction for these purposes helps improve trust and avoid unintentional actions by making sure learners clearly understand the consequences before continuing. It also lets us offer alternatives or undo options when needed.
|
|
23
27
|
|
|
24
28
|
## Best practices
|
|
25
29
|
|
|
26
|
-
###
|
|
30
|
+
### Heading
|
|
31
|
+
|
|
32
|
+
- **Ask or inform about one main action**, mirroring the button that triggered the confirmation dialog.
|
|
33
|
+
- **Frame your headline as a binary question**, when possible, with 2 unambiguous answers.
|
|
34
|
+
- **Avoid generic “Are you sure?” headings and body text.** This phrasing takes up space, increases cognitive load, and may undermine users' confidence or be interpreted as patronizing.
|
|
35
|
+
|
|
36
|
+
### Body (optional)
|
|
37
|
+
|
|
38
|
+
- **Add essential information about the contextual consequences.** State what will happen, what will be lost/changed, and any critical conditions.
|
|
39
|
+
- **Avoid redundancy.** If the heading is already self-explanatory, the body is not needed.
|
|
40
|
+
- **Keep to 1–2 lines, unless more is required to get all the information across.**
|
|
41
|
+
|
|
42
|
+
### Buttons (CTA1 and CTA2)
|
|
27
43
|
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
44
|
+
- **Avoid using “Yes” or “No,”** as they can be misinterpreted in global English and internationalization contexts.
|
|
45
|
+
- **CTA1 matches the verb from the heading** to confirm the action.
|
|
46
|
+
- **CTA2 clarifies the alternative or undo** path.
|
|
47
|
+
- Whenever possible, be specific about the alternative. However, when space is limited, 'Cancel' can be used.
|
|
31
48
|
|
|
32
|
-
###
|
|
49
|
+
### Examples — putting it all together
|
|
33
50
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
<ImageWrapper
|
|
52
|
+
src="./ux writing/delete_this_course.png"
|
|
53
|
+
alt="Delete this course confirmation dialog"
|
|
54
|
+
/>
|
|
38
55
|
|
|
39
|
-
|
|
56
|
+
<ImageWrapper
|
|
57
|
+
src="./ux writing/delete_study_plan.png"
|
|
58
|
+
alt="Delete study plan confirmation dialog"
|
|
59
|
+
/>
|
|
40
60
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
61
|
+
<ImageWrapper
|
|
62
|
+
src="./ux writing/clear_chat.png"
|
|
63
|
+
alt="Clear chat confirmation dialog"
|
|
64
|
+
/>
|
|
44
65
|
|
|
45
66
|
## Checklist
|
|
46
67
|
|
|
47
|
-
- Is the
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
- Does the
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
- Do the buttons include context to reaffirm the action?
|
|
54
|
-
- Is your copy at a reading level of grade 7 or below? Test with [Hemingway App](https://hemingwayapp.com).
|
|
55
|
-
- Have you asked someone unrelated to the project to read the message and did they understand it?
|
|
68
|
+
- Is the action irreversible, destructive, or has unexpected consequences? If not, consider using a different pattern.
|
|
69
|
+
- Is the same verb used from the action triggering the confirmation dialog, to the heading, to CTA1?
|
|
70
|
+
- Did you avoid filler language such as “Are you sure you want to...?”
|
|
71
|
+
- Does the body front-load the critical consequence in 1–3 lines?
|
|
72
|
+
- Are the buttons mutually exclusive (and avoid using “Yes/No”)?
|
|
73
|
+
- Is there a safer alternative or undo to mention? (If available, offer the option as CTA2.)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|