@codecademy/styleguide 78.5.5-alpha.86d3e6.0 → 78.5.5-alpha.cb4c1d.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/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
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
- ### [78.5.5-alpha.86d3e6.0](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@78.5.4...@codecademy/styleguide@78.5.5-alpha.86d3e6.0) (2026-01-06)
6
+ ### [78.5.5-alpha.cb4c1d.0](https://github.com/Codecademy/gamut/compare/@codecademy/styleguide@78.5.4...@codecademy/styleguide@78.5.5-alpha.cb4c1d.0) (2026-01-07)
7
7
 
8
8
  **Note:** Version bump only for package @codecademy/styleguide
9
9
 
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": "78.5.5-alpha.86d3e6.0",
4
+ "version": "78.5.5-alpha.cb4c1d.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": "2988ef3b1571897c2359c9031389d08356b819be"
11
+ "gitHead": "8f9681525aad2b306aff70b92f65739463850b5a"
12
12
  }
@@ -94,12 +94,6 @@ Using `popoverProps`, you can customize the look of the rendered popover. For ex
94
94
 
95
95
  <Canvas of={CoachmarkStories.Customized} />
96
96
 
97
- ### Z-Index
98
-
99
- You can customize the `zIndex` of the Coachmark's popover by passing `zIndex` through `popoverProps`. This is useful when the popover needs to appear above other positioned elements.
100
-
101
- <Canvas of={CoachmarkStories.ZIndex} />
102
-
103
97
  ## Playground
104
98
 
105
99
  <Canvas sourceState="shown" of={CoachmarkStories.Default} />
@@ -1,4 +1,4 @@
1
- import { Box, Coachmark, FillButton, FlexBox, Text } from '@codecademy/gamut';
1
+ import { Coachmark, FillButton, FlexBox, Text } from '@codecademy/gamut';
2
2
  import * as patterns from '@codecademy/gamut-patterns';
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
4
  import { ComponentProps, useEffect, useState } from 'react';
@@ -197,39 +197,3 @@ export const Customized: Story = {
197
197
  );
198
198
  },
199
199
  };
200
-
201
- export const ZIndex: Story = {
202
- args: {
203
- popoverProps: {
204
- position: 'below',
205
- zIndex: 5,
206
- },
207
- },
208
- render: function ZIndexExample(args) {
209
- const [shouldShow, setShouldShow] = useState(true);
210
-
211
- return (
212
- <FlexBox flexDirection="column" gap={16}>
213
- <Box bg="paleBlue" p={16} zIndex={3} position="relative">
214
- Element with z-index: 3
215
- </Box>
216
- <Coachmark
217
- {...args}
218
- renderPopover={() => (
219
- <FlexBox alignItems="flex-start" flexDirection="column" p={16}>
220
- <Text mb={8}>This coachmark has z-index: 5 via popoverProps</Text>
221
- <FillButton size="small" onClick={() => setShouldShow(false)}>
222
- Got it
223
- </FillButton>
224
- </FlexBox>
225
- )}
226
- shouldShow={shouldShow}
227
- >
228
- <FillButton onClick={() => setShouldShow(true)}>
229
- Show Coachmark
230
- </FillButton>
231
- </Coachmark>
232
- </FlexBox>
233
- );
234
- },
235
- };
@@ -89,16 +89,6 @@ A Modal can be made scrollable by including large content inside.
89
89
 
90
90
  <Canvas of={ModalStories.Scrollable} />
91
91
 
92
- ## Z-Index
93
-
94
- Modal accepts a `zIndex` prop (defaults to `3`) that controls the stacking order of its underlying Overlay. Use this when the modal needs to appear above other positioned elements like sticky headers or custom floating UI.
95
-
96
- ```tsx
97
- <Modal zIndex={10} isOpen={isOpen} onRequestClose={handleClose}>
98
- Content that needs to appear above other positioned elements
99
- </Modal>
100
- ```
101
-
102
92
  ## Focus management
103
93
 
104
94
  The `containerFocusRef` prop allows you to programmatically control focus on the Modal container. This is useful for advanced focus management scenarios where you need to override the default focus behavior (the Modal has `data-autofocus` by default).
@@ -32,12 +32,6 @@ Unlike the legacy `Modal` implementations in the monolith, this:
32
32
 
33
33
  - If you need styles such as a background behind content, see `Modal` for general modals and `Dialog` for confirmation flows.
34
34
 
35
- ## Z-Index
36
-
37
- The `zIndex` prop controls the stacking order of the overlay. It defaults to `3`, which places it above most common UI elements. Increase this value when the overlay needs to appear above other positioned elements like sticky headers or floating UI.
38
-
39
- <Canvas of={OverlayStories.ZIndex} />
40
-
41
35
  ## Playground
42
36
 
43
37
  <Canvas sourceState="shown" of={OverlayStories.Default} />
@@ -1,5 +1,5 @@
1
- import { Box, FillButton, FlexBox, Overlay, Text } from '@codecademy/gamut';
2
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import { FillButton, FlexBox, Overlay, Text } from '@codecademy/gamut';
2
+ import type { Meta } from '@storybook/react';
3
3
  import { useEffect, useState } from 'react';
4
4
 
5
5
  const meta: Meta<typeof Overlay> = {
@@ -8,7 +8,6 @@ const meta: Meta<typeof Overlay> = {
8
8
  };
9
9
 
10
10
  export default meta;
11
- type Story = StoryObj<typeof Overlay>;
12
11
 
13
12
  export const Default: React.FC<React.ComponentProps<typeof Overlay>> = (
14
13
  args
@@ -35,67 +34,3 @@ export const Default: React.FC<React.ComponentProps<typeof Overlay>> = (
35
34
  </>
36
35
  );
37
36
  };
38
-
39
- export const ZIndex: Story = {
40
- render: function ZIndexExample() {
41
- const [defaultOpen, setDefaultOpen] = useState(false);
42
- const [customOpen, setCustomOpen] = useState(false);
43
-
44
- return (
45
- <FlexBox flexDirection="column" gap={16}>
46
- <FlexBox gap={16}>
47
- <FillButton onClick={() => setDefaultOpen(true)}>
48
- Open Overlay (default z-index: 3)
49
- </FillButton>
50
- <FillButton onClick={() => setCustomOpen(true)}>
51
- Open Overlay (z-index: 10)
52
- </FillButton>
53
- </FlexBox>
54
-
55
- <Box position="relative" height="100px">
56
- <Box
57
- position="absolute"
58
- top={0}
59
- left={0}
60
- bg="paleYellow"
61
- p={16}
62
- zIndex={5}
63
- >
64
- <Text>Element with z-index: 5</Text>
65
- </Box>
66
- </Box>
67
-
68
- <Overlay
69
- isOpen={defaultOpen}
70
- onRequestClose={() => setDefaultOpen(false)}
71
- shroud
72
- >
73
- <FlexBox bg="white" p={24} borderRadius="md" flexDirection="column" gap={16}>
74
- <Text>
75
- This overlay uses the default z-index of 3.
76
- <br />
77
- It may appear behind elements with higher z-index values.
78
- </Text>
79
- <FillButton onClick={() => setDefaultOpen(false)}>Close</FillButton>
80
- </FlexBox>
81
- </Overlay>
82
-
83
- <Overlay
84
- isOpen={customOpen}
85
- onRequestClose={() => setCustomOpen(false)}
86
- shroud
87
- zIndex={10}
88
- >
89
- <FlexBox bg="white" p={24} borderRadius="md" flexDirection="column" gap={16}>
90
- <Text>
91
- This overlay uses z-index: 10.
92
- <br />
93
- It will appear above the yellow element with z-index: 5.
94
- </Text>
95
- <FillButton onClick={() => setCustomOpen(false)}>Close</FillButton>
96
- </FlexBox>
97
- </Overlay>
98
- </FlexBox>
99
- );
100
- },
101
- };
@@ -82,24 +82,9 @@ InfoTips have intelligent Escape key handling that works correctly both inside a
82
82
 
83
83
  <Canvas of={InfoTipStories.InfoTipInsideModal} />
84
84
 
85
- ## Custom Accessible Labeling
85
+ ## InfoTips and zIndex
86
86
 
87
- Provide either `ariaLabel` or `ariaLabelledby` to ensure screen reader users understand the purpose of the InfoTip button.
88
-
89
- The InfoTip button's accessible label can be customized using either prop:
90
-
91
- - **`ariaLabel`**: Directly sets the accessible label text. Useful when you want to provide a custom label without referencing another element.
92
- - **`ariaLabelledby`**: References the ID of another element to use as the label. Useful when you want the InfoTip button to be labeled by visible text elsewhere on the page. This is useful for when the `InfoTip` is beside text that contextualizes it.
93
-
94
- ### Custom Role Description
95
-
96
- The `InfoTipButton` uses [`aria-roledescription="More information button"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-roledescription) to provide additional context to screen reader users about the button's specific purpose.
97
-
98
- <Canvas of={InfoTipStories.AriaLabel} />
99
-
100
- ## Z-Index
101
-
102
- You can customize the `zIndex` of the InfoTip's portal with the `zIndex` prop. This works for both `inline` and `floating` placements, and is useful when the tip needs to appear above other positioned elements.
87
+ You can change the zIndex of your `InfoTip` with the zIndex property.
103
88
 
104
89
  <Canvas of={InfoTipStories.ZIndex} />
105
90
 
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  Anchor,
3
3
  Box,
4
- Coachmark,
5
4
  FillButton,
6
5
  FlexBox,
7
6
  GridBox,
@@ -196,7 +195,6 @@ export const InfoTipInsideModal: Story = {
196
195
  },
197
196
  render: function InfoTipInsideModal(args) {
198
197
  const [isModalOpen, setIsModalOpen] = useState(false);
199
- const [showCoachmark, setShowCoachmark] = useState(false);
200
198
 
201
199
  return (
202
200
  <FlexBox center flexDirection="column" gap={16} py={64}>
@@ -235,37 +233,6 @@ export const InfoTipInsideModal: Story = {
235
233
  closing the modal itself. Inline placement works correctly.
236
234
  </Text>
237
235
 
238
- <FlexBox alignItems="center" borderTop={1} gap={8} mt={8} pt={16}>
239
- <Text id="modal-coachmark-text">
240
- This modal also contains a Coachmark
241
- </Text>
242
- <Coachmark
243
- popoverProps={{ zIndex: 3 }}
244
- renderPopover={() => (
245
- <FlexBox
246
- alignItems="flex-start"
247
- flexDirection="column"
248
- p={16}
249
- >
250
- <Text mb={8}>
251
- This Coachmark is inside a Modal. Try pressing Escape!
252
- </Text>
253
- <FillButton
254
- size="small"
255
- onClick={() => setShowCoachmark(false)}
256
- >
257
- Got it
258
- </FillButton>
259
- </FlexBox>
260
- )}
261
- shouldShow={showCoachmark}
262
- >
263
- <FillButton size="small" onClick={() => setShowCoachmark(true)}>
264
- Show Coachmark
265
- </FillButton>
266
- </Coachmark>
267
- </FlexBox>
268
-
269
236
  <FillButton onClick={() => setIsModalOpen(false)}>
270
237
  Close Modal
271
238
  </FillButton>
@@ -278,49 +245,19 @@ export const InfoTipInsideModal: Story = {
278
245
 
279
246
  export const ZIndex: Story = {
280
247
  args: {
281
- info: 'I have a custom z-index',
248
+ info: 'I am inline, cool',
282
249
  zIndex: 5,
283
250
  },
284
251
  render: (args) => (
285
- <FlexBox center flexDirection="column" gap={16} m={24} py={64}>
286
- <Text variant="p-small">Inline placement:</Text>
287
- <FlexBox alignItems="center" gap={8}>
288
- <Box bg="paleBlue" p={8} zIndex={3} position="relative">
289
- z-index: 3
290
- </Box>
291
- <InfoTip ariaLabel="inline default" info="Default z-index (inline)" />
292
- <Box bg="paleBlue" p={8} zIndex={3} position="relative">
293
- z-index: 3
294
- </Box>
295
- <InfoTip
296
- {...args}
297
- ariaLabel="inline custom"
298
- info="z-index: 5 (inline)"
299
- />
300
- </FlexBox>
301
-
302
- <Text variant="p-small" mt={24}>
303
- Floating placement:
304
- </Text>
305
- <FlexBox alignItems="center" gap={8}>
306
- <Box bg="paleGreen" p={8} zIndex={3} position="relative">
307
- z-index: 3
308
- </Box>
309
- <InfoTip
310
- ariaLabel="floating default"
311
- info="Default z-index (floating)"
312
- placement="floating"
313
- />
314
- <Box bg="paleGreen" p={8} zIndex={3} position="relative">
315
- z-index: 3
316
- </Box>
317
- <InfoTip
318
- {...args}
319
- ariaLabel="floating custom"
320
- info="z-index: 5 (floating)"
321
- placement="floating"
322
- />
323
- </FlexBox>
252
+ <FlexBox center flexDirection="column" m={24} py={64}>
253
+ <Box bg="paleBlue" zIndex={3}>
254
+ I will not be behind the infotip, sad + unreadable
255
+ </Box>
256
+ <InfoTip info="I am inline, cool" />
257
+ <Box bg="paleBlue" zIndex={3}>
258
+ I will be behind the infotip, nice + great
259
+ </Box>
260
+ <InfoTip {...args} />
324
261
  </FlexBox>
325
262
  ),
326
263
  };
@@ -55,12 +55,6 @@ The `truncateLines` prop allows you to set the maximum number of lines that the
55
55
 
56
56
  <Canvas of={PreviewTipStories.Truncation} />
57
57
 
58
- ## Z-Index
59
-
60
- You can customize the `zIndex` of the PreviewTip's portal with the `zIndex` prop. This works for both `inline` and `floating` placements, and is useful when the tip needs to appear above other positioned elements.
61
-
62
- <Canvas of={PreviewTipStories.ZIndex} />
63
-
64
58
  ## Playground
65
59
 
66
60
  <Canvas sourceState="shown" of={PreviewTipStories.Default} />
@@ -1,4 +1,4 @@
1
- import { Box, FlexBox, PreviewTip, Text } from '@codecademy/gamut';
1
+ import { Box, FlexBox, PreviewTip } from '@codecademy/gamut';
2
2
  import { SmileyIndifferentIcon } from '@codecademy/gamut-icons';
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
4
  import { useState } from 'react';
@@ -110,70 +110,3 @@ const TruncationExample = (args: React.ComponentProps<typeof PreviewTip>) => {
110
110
  export const Truncation: Story = {
111
111
  render: (args) => <TruncationExample {...args} />,
112
112
  };
113
-
114
- export const ZIndex: Story = {
115
- args: {
116
- zIndex: 5,
117
- },
118
- render: (args) => (
119
- <FlexBox center flexDirection="column" gap={16} py={64}>
120
- <Text variant="p-small">Inline placement:</Text>
121
- <FlexBox alignItems="center" gap={16}>
122
- <Box bg="paleBlue" p={8} zIndex={3} position="relative">
123
- z-index: 3
124
- </Box>
125
- <PreviewTip
126
- {...args}
127
- alignment="bottom-right"
128
- href="#"
129
- linkDescription="Default z-index (inline)"
130
- >
131
- Default z-index
132
- </PreviewTip>
133
- <Box bg="paleBlue" p={8} zIndex={3} position="relative">
134
- z-index: 3
135
- </Box>
136
- <PreviewTip
137
- {...args}
138
- alignment="top-right"
139
- href="#"
140
- linkDescription="z-index: 5 (inline)"
141
- zIndex={5}
142
- >
143
- z-index: 5
144
- </PreviewTip>
145
- </FlexBox>
146
-
147
- <Text variant="p-small" mt={24}>
148
- Floating placement:
149
- </Text>
150
- <FlexBox alignItems="center" gap={16}>
151
- <Box bg="paleGreen" p={8} zIndex={3} position="relative">
152
- z-index: 3
153
- </Box>
154
- <PreviewTip
155
- {...args}
156
- alignment="bottom-right"
157
- href="#"
158
- linkDescription="Default z-index (floating)"
159
- placement="floating"
160
- >
161
- Default z-index
162
- </PreviewTip>
163
- <Box bg="paleGreen" p={8} zIndex={3} position="relative">
164
- z-index: 3
165
- </Box>
166
- <PreviewTip
167
- {...args}
168
- alignment="top-right"
169
- href="#"
170
- linkDescription="z-index: 5 (floating)"
171
- placement="floating"
172
- zIndex={5}
173
- >
174
- z-index: 5
175
- </PreviewTip>
176
- </FlexBox>
177
- </FlexBox>
178
- ),
179
- };
@@ -63,12 +63,6 @@ When a Button is disabled with a tooltip, you must use the `aria-disabled` prop
63
63
 
64
64
  <Canvas of={ToolTipStories.Disabled} />
65
65
 
66
- ## Z-Index
67
-
68
- You can customize the `zIndex` of the ToolTip's portal with the `zIndex` prop. This works for both `inline` and `floating` placements, and is useful when the tip needs to appear above other positioned elements.
69
-
70
- <Canvas of={ToolTipStories.ZIndex} />
71
-
72
66
  ## Playground
73
67
 
74
68
  <Canvas sourceState="shown" of={ToolTipStories.Default} />
@@ -1,10 +1,8 @@
1
1
  import {
2
- Box,
3
2
  FillButton,
4
3
  FlexBox,
5
4
  IconButton,
6
5
  StrokeButton,
7
- Text,
8
6
  ToolTip,
9
7
  } from '@codecademy/gamut';
10
8
  import {
@@ -135,60 +133,3 @@ export const Disabled: Story = {
135
133
  </FlexBox>
136
134
  ),
137
135
  };
138
-
139
- export const ZIndex: Story = {
140
- render: () => (
141
- <FlexBox center flexDirection="column" gap={16} m={24} py={64}>
142
- <Text variant="p-small">Inline placement:</Text>
143
- <FlexBox alignItems="center" gap={16}>
144
- <Box bg="paleBlue" p={8} zIndex={3} position="relative">
145
- z-index: 3
146
- </Box>
147
- <ToolTip id="zindex-inline-default" info="Default z-index (inline)">
148
- <FillButton aria-describedby="zindex-inline-default">
149
- Default
150
- </FillButton>
151
- </ToolTip>
152
- <Box bg="paleBlue" p={8} zIndex={3} position="relative">
153
- z-index: 3
154
- </Box>
155
- <ToolTip id="zindex-inline-custom" info="z-index: 5 (inline)" zIndex={5}>
156
- <FillButton aria-describedby="zindex-inline-custom">
157
- z-index: 5
158
- </FillButton>
159
- </ToolTip>
160
- </FlexBox>
161
-
162
- <Text variant="p-small" mt={24}>
163
- Floating placement:
164
- </Text>
165
- <FlexBox alignItems="center" gap={16}>
166
- <Box bg="paleGreen" p={8} zIndex={3} position="relative">
167
- z-index: 3
168
- </Box>
169
- <ToolTip
170
- id="zindex-floating-default"
171
- info="Default z-index (floating)"
172
- placement="floating"
173
- >
174
- <FillButton aria-describedby="zindex-floating-default">
175
- Default
176
- </FillButton>
177
- </ToolTip>
178
- <Box bg="paleGreen" p={8} zIndex={3} position="relative">
179
- z-index: 3
180
- </Box>
181
- <ToolTip
182
- id="zindex-floating-custom"
183
- info="z-index: 5 (floating)"
184
- placement="floating"
185
- zIndex={5}
186
- >
187
- <FillButton aria-describedby="zindex-floating-custom">
188
- z-index: 5
189
- </FillButton>
190
- </ToolTip>
191
- </FlexBox>
192
- </FlexBox>
193
- ),
194
- };
@@ -0,0 +1,92 @@
1
+ import { Canvas, Controls, Meta } from '@storybook/blocks';
2
+
3
+ import { ComponentHeader } from '~styleguide/blocks';
4
+
5
+ import * as BarChartStories from './BarChart.stories';
6
+
7
+ export const parameters = {
8
+ subtitle: `A horizontal bar chart for visualizing comparative data`,
9
+ design: {
10
+ type: 'figma',
11
+ url: 'https://www.figma.com/design/ReGfRNillGABAj5SlITalN/%F0%9F%93%90-Gamut?node-id=55123-4176',
12
+ },
13
+ status: 'current',
14
+ source: {
15
+ repo: 'gamut',
16
+ githubLink:
17
+ 'https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/BarChart',
18
+ },
19
+ };
20
+
21
+ <Meta of={BarChartStories} />;
22
+
23
+ <ComponentHeader {...parameters} />
24
+
25
+ ## Usage
26
+
27
+ Use BarChart to display comparative data across categories, such as skills progress, XP earned, or any quantitative metrics that benefit from visual comparison.
28
+
29
+ ### Best practices:
30
+
31
+ - Use consistent units across all bars in a chart
32
+ - Limit the number of bars to maintain readability (5-10 is optimal)
33
+ - Consider using the stacked variant to show progress toward a goal
34
+ - Sort bars by value (descending) when ranking is important
35
+
36
+ When NOT to use
37
+
38
+ - For showing trends over time - use a line chart instead
39
+ - For showing parts of a whole - use a pie or donut chart
40
+ - For very small datasets (1-2 items) - consider using ProgressBar
41
+
42
+ ## Variants
43
+
44
+ ### Simple (Non-stacked)
45
+
46
+ Use the simple variant when showing single values per category. Only `seriesOneValue` is provided.
47
+
48
+ <Canvas of={BarChartStories.Default} />
49
+
50
+ ### Stacked
51
+
52
+ Use the stacked variant when showing progress within a total. Provide both `seriesOneValue` (progress) and `seriesTwoValue` (total).
53
+
54
+ <Canvas of={BarChartStories.Stacked} />
55
+
56
+ ### With Icons
57
+
58
+ Add icons to labels for better visual identification of categories.
59
+
60
+ <Canvas of={BarChartStories.WithIcons} />
61
+
62
+ ### Animated
63
+
64
+ Enable entrance animations for a more engaging experience.
65
+
66
+ <Canvas of={BarChartStories.Animated} />
67
+
68
+ ### Interactive
69
+
70
+ Rows can be made interactive with `onClick` handlers or `href` links.
71
+
72
+ <Canvas of={BarChartStories.Interactive} />
73
+
74
+ ## Playground
75
+
76
+ <Canvas sourceState="shown" of={BarChartStories.Default} />
77
+
78
+ <Controls />
79
+
80
+ ## Accessibility considerations
81
+
82
+ - Always provide either `aria-label` or `aria-labelledby` to describe the chart
83
+ - Each row automatically generates an accessible label summarizing its values
84
+ - Interactive rows (with onClick/href) are properly announced as buttons/links
85
+ - Grid lines are marked as decorative and hidden from screen readers
86
+ - The scale header is hidden on small screens and marked as decorative
87
+
88
+ ## UX writing
89
+
90
+ - Keep y-axis labels concise (1-3 words)
91
+ - Use consistent unit labels (e.g., "XP", "hours", "points")
92
+ - Consider locale-aware number formatting for international audiences
@@ -0,0 +1,183 @@
1
+ import { BarChart, BarProps } from '@codecademy/gamut';
2
+ import {
3
+ BookFlipPageIcon,
4
+ CodeIcon,
5
+ DataScienceIcon,
6
+ GameControllerIcon,
7
+ TerminalIcon,
8
+ } from '@codecademy/gamut-icons';
9
+ import { action } from '@storybook/addon-actions';
10
+ import type { Meta, StoryObj } from '@storybook/react';
11
+
12
+ const meta: Meta<typeof BarChart> = {
13
+ component: BarChart,
14
+ args: {
15
+ 'aria-label': 'Skills experience chart',
16
+ minRange: 0,
17
+ maxRange: 2000,
18
+ unit: 'XP',
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+ type Story = StoryObj<typeof BarChart>;
24
+
25
+ // Sample data for non-stacked (simple) bars
26
+ const simpleBarData: BarProps[] = [
27
+ { yLabel: 'Python', seriesOneValue: 1500 },
28
+ { yLabel: 'JavaScript', seriesOneValue: 2000 },
29
+ { yLabel: 'HTML/CSS', seriesOneValue: 800 },
30
+ { yLabel: 'SQL', seriesOneValue: 600 },
31
+ { yLabel: 'React', seriesOneValue: 450 },
32
+ ];
33
+
34
+ // Sample data for stacked bars (with seriesTwoValue)
35
+ const stackedBarData: BarProps[] = [
36
+ { yLabel: 'Python', seriesOneValue: 200, seriesTwoValue: 1500 },
37
+ { yLabel: 'JavaScript', seriesOneValue: 1800, seriesTwoValue: 2000 },
38
+ { yLabel: 'HTML/CSS', seriesOneValue: 600, seriesTwoValue: 800 },
39
+ { yLabel: 'SQL', seriesOneValue: 550, seriesTwoValue: 600 },
40
+ { yLabel: 'React', seriesOneValue: 300, seriesTwoValue: 450 },
41
+ ];
42
+
43
+ // Sample data with icons
44
+ const barDataWithIcons: BarProps[] = [
45
+ {
46
+ yLabel: 'Python',
47
+ seriesOneValue: 200,
48
+ seriesTwoValue: 1500,
49
+ icon: CodeIcon,
50
+ },
51
+ {
52
+ yLabel: 'JavaScript',
53
+ seriesOneValue: 150,
54
+ seriesTwoValue: 2000,
55
+ icon: TerminalIcon,
56
+ },
57
+ {
58
+ yLabel: 'Data Science',
59
+ seriesOneValue: 100,
60
+ seriesTwoValue: 800,
61
+ icon: DataScienceIcon,
62
+ },
63
+ {
64
+ yLabel: 'Game Dev',
65
+ seriesOneValue: 50,
66
+ seriesTwoValue: 600,
67
+ icon: GameControllerIcon,
68
+ },
69
+ {
70
+ yLabel: 'Reading',
71
+ seriesOneValue: 75,
72
+ seriesTwoValue: 450,
73
+ icon: BookFlipPageIcon,
74
+ },
75
+ ];
76
+
77
+ /**
78
+ * Default non-stacked bar chart showing single values
79
+ */
80
+ export const Default: Story = {
81
+ args: {
82
+ barValues: simpleBarData,
83
+ },
84
+ };
85
+
86
+ /**
87
+ * Stacked bar chart showing progress (seriesOneValue) over total (seriesTwoValue)
88
+ */
89
+ export const Stacked: Story = {
90
+ args: {
91
+ barValues: stackedBarData,
92
+ },
93
+ };
94
+
95
+ /**
96
+ * Bar chart with icons next to labels
97
+ */
98
+ export const WithIcons: Story = {
99
+ args: {
100
+ barValues: barDataWithIcons,
101
+ },
102
+ };
103
+
104
+ /**
105
+ * Animated bar chart with staggered entrance
106
+ */
107
+ export const Animated: Story = {
108
+ args: {
109
+ barValues: stackedBarData,
110
+ animate: true,
111
+ },
112
+ };
113
+
114
+ /**
115
+ * Bar chart sorted by value in descending order
116
+ */
117
+ export const SortedByValue: Story = {
118
+ args: {
119
+ barValues: simpleBarData,
120
+ sortBy: 'value',
121
+ order: 'descending',
122
+ },
123
+ };
124
+
125
+ /**
126
+ * Bar chart sorted alphabetically by label
127
+ */
128
+ export const SortedByLabel: Story = {
129
+ args: {
130
+ barValues: simpleBarData,
131
+ sortBy: 'label',
132
+ order: 'ascending',
133
+ },
134
+ };
135
+
136
+ /**
137
+ * Interactive bar chart with clickable rows
138
+ */
139
+ export const Interactive: Story = {
140
+ args: {
141
+ barValues: simpleBarData.map((bar) => ({
142
+ ...bar,
143
+ onClick: action(`Clicked ${bar.yLabel}`),
144
+ })),
145
+ },
146
+ };
147
+
148
+ /**
149
+ * Interactive bar chart with linked rows
150
+ */
151
+ export const WithLinks: Story = {
152
+ args: {
153
+ barValues: simpleBarData.map((bar) => ({
154
+ ...bar,
155
+ href: `#${bar.yLabel.toLowerCase().replace(/\s+/g, '-')}`,
156
+ })),
157
+ },
158
+ };
159
+
160
+ /**
161
+ * Bar chart with custom styling
162
+ */
163
+ export const CustomStyles: Story = {
164
+ args: {
165
+ barValues: stackedBarData,
166
+ styleConfig: {
167
+ backgroundBarColor: 'paleGreen',
168
+ foregroundBarColor: 'feedback-success',
169
+ textColor: 'navy',
170
+ },
171
+ },
172
+ };
173
+
174
+ /**
175
+ * Bar chart with custom xScale interval
176
+ */
177
+ export const CustomScale: Story = {
178
+ args: {
179
+ barValues: simpleBarData,
180
+ maxRange: 2000,
181
+ xScale: 250,
182
+ },
183
+ };