@indico-data/design-system 3.22.1 → 3.23.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 (39) hide show
  1. package/AGENTS.md +110 -0
  2. package/CLAUDE.md +1 -0
  3. package/lib/components/alert/Alert.d.ts +2 -0
  4. package/lib/components/alert/Alert.stories.d.ts +15 -0
  5. package/lib/components/alert/__tests__/Alert.test.d.ts +1 -0
  6. package/lib/components/alert/index.d.ts +2 -0
  7. package/lib/components/alert/types.d.ts +26 -0
  8. package/lib/components/index.d.ts +1 -0
  9. package/lib/components/pill/Pill.d.ts +1 -1
  10. package/lib/components/pill/Pill.stories.d.ts +3 -0
  11. package/lib/components/pill/types.d.ts +4 -0
  12. package/lib/index.css +214 -30
  13. package/lib/index.d.ts +34 -2
  14. package/lib/index.esm.css +214 -30
  15. package/lib/index.esm.js +41 -5
  16. package/lib/index.esm.js.map +1 -1
  17. package/lib/index.js +40 -3
  18. package/lib/index.js.map +1 -1
  19. package/lib/types.d.ts +2 -0
  20. package/package.json +1 -1
  21. package/src/components/alert/Alert.mdx +65 -0
  22. package/src/components/alert/Alert.stories.tsx +162 -0
  23. package/src/components/alert/Alert.tsx +68 -0
  24. package/src/components/alert/__tests__/Alert.test.tsx +52 -0
  25. package/src/components/alert/index.ts +2 -0
  26. package/src/components/alert/styles/Alert.scss +139 -0
  27. package/src/components/alert/styles/_tokens.scss +71 -0
  28. package/src/components/alert/types.ts +28 -0
  29. package/src/components/index.ts +1 -0
  30. package/src/components/pill/Pill.mdx +27 -0
  31. package/src/components/pill/Pill.stories.tsx +87 -0
  32. package/src/components/pill/Pill.tsx +36 -0
  33. package/src/components/pill/__tests__/Pill.test.tsx +93 -0
  34. package/src/components/pill/styles/Pill.scss +15 -2
  35. package/src/components/pill/types.ts +4 -0
  36. package/src/index.ts +1 -0
  37. package/src/setup/setupIcons.ts +8 -0
  38. package/src/styles/index.scss +2 -1
  39. package/src/types.ts +2 -0
package/lib/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type AlertType, type AlertSize, type AlertVariant } from './components/alert/types';
1
2
  import { type SelectOption } from './components/forms/select/types';
2
3
  import { type IconSizes, type IconName } from './components/icons/types';
3
4
  import { type PillColor, type PillSize, type PillVariant, type PillType } from './components/pill/types';
@@ -15,3 +16,4 @@ export type SemanticColor = 'neutral' | 'info' | 'warning' | 'error' | 'success'
15
16
  export type { SelectOption };
16
17
  export type { TableProps, TableColumn, Direction, Alignment };
17
18
  export type { PillColor, PillSize, PillVariant, PillType };
19
+ export type { AlertType, AlertSize, AlertVariant };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indico-data/design-system",
3
- "version": "3.22.1",
3
+ "version": "3.23.0",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "main": "lib/index.js",
@@ -0,0 +1,65 @@
1
+ import { Canvas, Meta, Controls, Story } from '@storybook/blocks';
2
+ import * as Alert from './Alert.stories';
3
+
4
+ <Meta title="Components/Alert" name="Alert" of={Alert} />
5
+
6
+ # Alert
7
+
8
+ Inline alerts notify users of a status or action result. They appear at the top
9
+ of a content area or near the item that needs attention.
10
+
11
+ Use `type` to set the semantic meaning (warning, info, success, error) — the
12
+ icon and accent color are chosen automatically. `variant` controls the visual
13
+ style: **soft** (subtle background) or **bordered** (colored border).
14
+
15
+ `size` controls density: **large** (default, banner-style) or **small**
16
+ (compact inline). When `tinted` is true on a **bordered** alert, the background
17
+ swaps from neutral to a type-specific tinted color.
18
+
19
+ Pass `title` to add a heading above the message. Add `actionText` + `onAction`
20
+ for an inline action button, and `onClose` to make it dismissable.
21
+
22
+ <Canvas of={Alert.Default} />
23
+
24
+ <Controls of={Alert.Default} />
25
+
26
+ ## Types
27
+
28
+ <Canvas of={Alert.Types} />
29
+
30
+ ## Variants
31
+
32
+ <Canvas of={Alert.Variants} />
33
+
34
+ ## Small Bordered
35
+
36
+ Compact inline alerts without tinted backgrounds.
37
+
38
+ <Canvas of={Alert.SmallBordered} />
39
+
40
+ ## Small Bordered Tinted
41
+
42
+ Compact inline alerts with type-specific tinted backgrounds — useful when
43
+ alerts sit alongside content and need stronger visual distinction.
44
+
45
+ <Canvas of={Alert.SmallBorderedTinted} />
46
+
47
+ ## Small Tinted with Close
48
+
49
+ <Canvas of={Alert.SmallTintedWithClose} />
50
+
51
+ ## With Title
52
+
53
+ <Canvas of={Alert.WithTitle} />
54
+
55
+ ## With Action
56
+
57
+ <Canvas of={Alert.WithAction} />
58
+
59
+ ## Closeable
60
+
61
+ <Canvas of={Alert.Closeable} />
62
+
63
+ ## Combined
64
+
65
+ <Canvas of={Alert.Combined} />
@@ -0,0 +1,162 @@
1
+ import {
2
+ faTriangleExclamation,
3
+ faCircleInfo,
4
+ faCircleCheck,
5
+ faCircleExclamation,
6
+ faXmark,
7
+ } from '@fortawesome/free-solid-svg-icons';
8
+ import { type Meta, type StoryObj } from '@storybook/react';
9
+ import { fn } from '@storybook/test';
10
+
11
+ import { registerFontAwesomeIcons } from '@/setup/setupIcons';
12
+
13
+ import { Alert } from './Alert';
14
+ import { type AlertSize, type AlertType, type AlertVariant } from './types';
15
+
16
+ registerFontAwesomeIcons(
17
+ faTriangleExclamation,
18
+ faCircleInfo,
19
+ faCircleCheck,
20
+ faCircleExclamation,
21
+ faXmark,
22
+ );
23
+
24
+ const TYPES: AlertType[] = ['warning', 'info', 'success', 'error'];
25
+ const VARIANTS: AlertVariant[] = ['soft', 'bordered'];
26
+ const SIZES: AlertSize[] = ['large', 'small'];
27
+
28
+ const meta: Meta<typeof Alert> = {
29
+ title: 'Components/Alert',
30
+ component: Alert,
31
+ decorators: [
32
+ (Story) => (
33
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 700 }}>
34
+ <Story />
35
+ </div>
36
+ ),
37
+ ],
38
+ argTypes: {
39
+ type: { control: 'select', options: TYPES },
40
+ variant: { control: 'select', options: VARIANTS },
41
+ size: { control: 'select', options: SIZES },
42
+ tinted: { control: 'boolean' },
43
+ title: { control: 'text' },
44
+ actionText: { control: 'text' },
45
+ onAction: { control: false },
46
+ onClose: { control: false },
47
+ children: { control: 'text' },
48
+ },
49
+ };
50
+
51
+ export default meta;
52
+
53
+ type Story = StoryObj<typeof Alert>;
54
+
55
+ export const Default: Story = {
56
+ args: {
57
+ type: 'warning',
58
+ variant: 'soft',
59
+ children:
60
+ 'This preset may incur additional charges depending on your submission size and usage.',
61
+ },
62
+ };
63
+
64
+ export const Types: Story = {
65
+ render: () => (
66
+ <>
67
+ {TYPES.map((type) => (
68
+ <Alert key={type} type={type}>
69
+ This is a {type} alert.
70
+ </Alert>
71
+ ))}
72
+ </>
73
+ ),
74
+ };
75
+
76
+ export const Variants: Story = {
77
+ render: () => (
78
+ <>
79
+ {VARIANTS.map((variant) => (
80
+ <Alert key={variant} type="info" variant={variant}>
81
+ This is the {variant} variant.
82
+ </Alert>
83
+ ))}
84
+ </>
85
+ ),
86
+ };
87
+
88
+ export const WithTitle: Story = {
89
+ args: {
90
+ type: 'info',
91
+ title: 'Info Title',
92
+ children: (
93
+ <>
94
+ An amazing message giving more context. A <a href="#">link</a> can be used in this content.
95
+ </>
96
+ ),
97
+ },
98
+ };
99
+
100
+ export const WithAction: Story = {
101
+ args: {
102
+ type: 'warning',
103
+ actionText: 'Action',
104
+ onAction: fn(),
105
+ children: 'This preset may incur additional charges.',
106
+ },
107
+ };
108
+
109
+ export const Closeable: Story = {
110
+ args: {
111
+ type: 'success',
112
+ onClose: fn(),
113
+ children: 'Your changes have been saved.',
114
+ },
115
+ };
116
+
117
+ export const Combined: Story = {
118
+ args: {
119
+ type: 'error',
120
+ variant: 'bordered',
121
+ title: 'Upload Failed',
122
+ actionText: 'Retry',
123
+ onAction: fn(),
124
+ onClose: fn(),
125
+ children: 'The file could not be uploaded. Please check your connection and try again.',
126
+ },
127
+ };
128
+
129
+ export const SmallBordered: Story = {
130
+ render: () => (
131
+ <>
132
+ {TYPES.map((type) => (
133
+ <Alert key={type} type={type} variant="bordered" size="small">
134
+ This is a small bordered {type} alert.
135
+ </Alert>
136
+ ))}
137
+ </>
138
+ ),
139
+ };
140
+
141
+ export const SmallBorderedTinted: Story = {
142
+ render: () => (
143
+ <>
144
+ {TYPES.map((type) => (
145
+ <Alert key={type} type={type} variant="bordered" size="small" tinted>
146
+ This is a small bordered tinted {type} alert.
147
+ </Alert>
148
+ ))}
149
+ </>
150
+ ),
151
+ };
152
+
153
+ export const SmallTintedWithClose: Story = {
154
+ args: {
155
+ type: 'info',
156
+ variant: 'bordered',
157
+ size: 'small',
158
+ tinted: true,
159
+ onClose: fn(),
160
+ children: 'New correspondence has been added',
161
+ },
162
+ };
@@ -0,0 +1,68 @@
1
+ import classNames from 'classnames';
2
+
3
+ import { type AlertProps, type AlertType } from './types';
4
+ import { Icon } from '../icons/Icon';
5
+ import { type IconName } from '../icons/types';
6
+
7
+ const ALERT_ICON: Record<AlertType, IconName> = {
8
+ warning: 'fa-triangle-exclamation',
9
+ info: 'fa-circle-info',
10
+ success: 'fa-circle-check',
11
+ error: 'fa-circle-exclamation',
12
+ };
13
+
14
+ export const Alert = ({
15
+ type,
16
+ variant = 'soft',
17
+ size = 'large',
18
+ tinted = false,
19
+ title,
20
+ children,
21
+ actionText,
22
+ onAction,
23
+ onClose,
24
+ closeAriaLabel = 'Dismiss',
25
+ className,
26
+ ...rest
27
+ }: AlertProps) => {
28
+ return (
29
+ <div
30
+ role="alert"
31
+ className={classNames(
32
+ 'alert',
33
+ `alert--${variant}`,
34
+ `alert--${variant}-${type}`,
35
+ { 'alert--small': size === 'small', 'alert--tinted': tinted, 'alert--has-title': !!title },
36
+ className,
37
+ )}
38
+ {...rest}
39
+ >
40
+ <Icon name={ALERT_ICON[type]} size="sm" />
41
+
42
+ <div className="alert__body">
43
+ {title && <div className="alert__title">{title}</div>}
44
+ <div className="alert__message">{children}</div>
45
+ </div>
46
+
47
+ {((actionText && onAction) || onClose) && (
48
+ <div className="alert__actions">
49
+ {actionText && onAction && (
50
+ <button type="button" className="alert__action" onClick={onAction}>
51
+ {actionText}
52
+ </button>
53
+ )}
54
+ {onClose && (
55
+ <button
56
+ type="button"
57
+ className="alert__close"
58
+ onClick={onClose}
59
+ aria-label={closeAriaLabel}
60
+ >
61
+ <Icon name="fa-xmark" size="xs" />
62
+ </button>
63
+ )}
64
+ </div>
65
+ )}
66
+ </div>
67
+ );
68
+ };
@@ -0,0 +1,52 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+
4
+ import { Alert } from '@/components/alert/Alert';
5
+
6
+ describe('Alert', () => {
7
+ describe('action button', () => {
8
+ it('renders action button and calls onAction when clicked', async () => {
9
+ const user = userEvent.setup();
10
+ const handleAction = jest.fn();
11
+ render(
12
+ <Alert type="info" actionText="Retry" onAction={handleAction}>
13
+ Something failed
14
+ </Alert>,
15
+ );
16
+ await user.click(screen.getByRole('button', { name: 'Retry' }));
17
+ expect(handleAction).toHaveBeenCalledTimes(1);
18
+ });
19
+
20
+ it('does not render action button when actionText is provided without onAction', () => {
21
+ render(
22
+ <Alert type="info" actionText="Orphan">
23
+ msg
24
+ </Alert>,
25
+ );
26
+ expect(screen.queryByRole('button', { name: 'Orphan' })).not.toBeInTheDocument();
27
+ });
28
+ });
29
+
30
+ describe('close button', () => {
31
+ it('calls onClose when close button is clicked', async () => {
32
+ const user = userEvent.setup();
33
+ const handleClose = jest.fn();
34
+ render(
35
+ <Alert type="warning" onClose={handleClose}>
36
+ dismissable
37
+ </Alert>,
38
+ );
39
+ await user.click(screen.getByRole('button', { name: 'Dismiss' }));
40
+ expect(handleClose).toHaveBeenCalledTimes(1);
41
+ });
42
+
43
+ it('uses custom closeAriaLabel', () => {
44
+ render(
45
+ <Alert type="info" onClose={() => {}} closeAriaLabel="Fermer">
46
+ msg
47
+ </Alert>,
48
+ );
49
+ expect(screen.getByRole('button', { name: 'Fermer' })).toBeInTheDocument();
50
+ });
51
+ });
52
+ });
@@ -0,0 +1,2 @@
1
+ export { Alert } from './Alert';
2
+ export type { AlertProps, AlertType, AlertVariant, AlertSize } from './types';
@@ -0,0 +1,139 @@
1
+ $alert-types: 'warning', 'info', 'success', 'error';
2
+
3
+ .alert {
4
+ display: flex;
5
+ align-items: flex-start;
6
+ gap: var(--pf-spacing-md);
7
+ padding: var(--pf-spacing-2xl);
8
+ border-radius: var(--pf-border-radius-md);
9
+ background-color: var(--pf-semantic-background-secondary);
10
+ font-family: var(--pf-font-family);
11
+ box-shadow:
12
+ 0 4px 6px -4px var(--pf-semantic-elevation-1),
13
+ 0 10px 15px -3px var(--pf-semantic-elevation-1);
14
+
15
+ // ------- Size: small (compact inline) -------
16
+ &--small {
17
+ padding: var(--pf-spacing-sm);
18
+ align-items: center;
19
+ box-shadow: none;
20
+ }
21
+
22
+ // ------- Variant: bordered -------
23
+ &--bordered {
24
+ border: 1px solid var(--alert-border-color);
25
+ }
26
+
27
+ // ------- Type-specific icon colors (soft uses semantic utility tokens) -------
28
+ &--soft-warning > .icon {
29
+ color: var(--pf-semantic-utility-warning-default);
30
+ }
31
+ &--soft-info > .icon {
32
+ color: var(--pf-semantic-utility-info-default);
33
+ }
34
+ &--soft-success > .icon {
35
+ color: var(--pf-semantic-utility-success-default);
36
+ }
37
+ &--soft-error > .icon {
38
+ color: var(--pf-semantic-utility-error-default);
39
+ }
40
+
41
+ // ------- Type-specific bordered colors (from component tokens) -------
42
+ @each $type in $alert-types {
43
+ &--bordered-#{$type} {
44
+ --alert-border-color: var(--pf-alert-bordered-#{$type}-border);
45
+
46
+ > .icon {
47
+ color: var(--pf-alert-bordered-#{$type}-icon);
48
+ }
49
+
50
+ .alert__title {
51
+ color: var(--pf-alert-bordered-#{$type}-text);
52
+ }
53
+ }
54
+
55
+ &--tinted#{&}--bordered-#{$type} {
56
+ background-color: var(--pf-alert-bordered-#{$type}-bg);
57
+ }
58
+ }
59
+
60
+ // ------- Sub-elements -------
61
+ > .icon {
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ &__body {
66
+ flex: 1;
67
+ min-width: 0;
68
+ }
69
+
70
+ &__title {
71
+ font-size: var(--pf-font-size-md);
72
+ font-weight: var(--pf-font-weight-semibold);
73
+ line-height: 20px;
74
+ color: var(--pf-semantic-font-regular);
75
+ margin-bottom: var(--pf-spacing-xxs);
76
+ }
77
+
78
+ &__message {
79
+ font-size: var(--pf-font-size-md);
80
+ font-weight: var(--pf-font-weight-regular);
81
+ line-height: 20px;
82
+ color: var(--pf-semantic-font-regular);
83
+
84
+ a {
85
+ color: var(--pf-semantic-font-link);
86
+ text-decoration: underline;
87
+ }
88
+ }
89
+
90
+ &--has-title .alert__message {
91
+ color: var(--pf-semantic-font-soft);
92
+ }
93
+
94
+ &__actions {
95
+ display: flex;
96
+ align-items: center;
97
+ gap: var(--pf-spacing-sm);
98
+ flex-shrink: 0;
99
+ margin-left: auto;
100
+ }
101
+
102
+ &__action {
103
+ background: none;
104
+ border: none;
105
+ cursor: pointer;
106
+ font-family: var(--pf-font-family);
107
+ font-size: var(--pf-font-size-md);
108
+ font-weight: var(--pf-font-weight-medium);
109
+ line-height: 20px;
110
+ color: var(--pf-semantic-font-link);
111
+ padding: 0;
112
+ white-space: nowrap;
113
+
114
+ &:hover {
115
+ text-decoration: underline;
116
+ }
117
+ }
118
+
119
+ &__close {
120
+ display: inline-flex;
121
+ align-items: center;
122
+ justify-content: center;
123
+ flex-shrink: 0;
124
+ cursor: pointer;
125
+ border: none;
126
+ background: transparent;
127
+ padding: var(--pf-spacing-xxs);
128
+ border-radius: var(--pf-border-radius-xs);
129
+ color: var(--pf-semantic-font-soft);
130
+ line-height: 1;
131
+ transition:
132
+ color 0.15s ease,
133
+ background-color 0.15s ease;
134
+
135
+ &:hover {
136
+ color: var(--pf-semantic-font-regular);
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,71 @@
1
+ // ============================================================================
2
+ // ALERT COMPONENT TOKENS (internal)
3
+ // ============================================================================
4
+ // These CSS custom properties are implementation details of the Alert component.
5
+ // They provide light/dark theme values for the bordered variant's per-type
6
+ // accent colors (border, title text, icon). The soft variant uses semantic
7
+ // utility tokens directly and doesn't need component-level overrides.
8
+ //
9
+ // Consumers should style alerts through the component props, not by
10
+ // overriding these variables.
11
+ //
12
+ // Aligned with Figma's "Alert" variable group.
13
+
14
+ // ============================================================================
15
+ // Bordered variant - Light Theme
16
+ // ============================================================================
17
+ :root,
18
+ :root [data-theme='light'] {
19
+ // Bordered / Warning
20
+ --pf-alert-bordered-warning-bg: var(--pf-yellow-color-150);
21
+ --pf-alert-bordered-warning-border: var(--pf-yellow-color-400);
22
+ --pf-alert-bordered-warning-text: var(--pf-yellow-color-600);
23
+ --pf-alert-bordered-warning-icon: var(--pf-yellow-color-400);
24
+
25
+ // Bordered / Info
26
+ --pf-alert-bordered-info-bg: var(--pf-blue-color-150);
27
+ --pf-alert-bordered-info-border: var(--pf-secondary-color-400);
28
+ --pf-alert-bordered-info-text: var(--pf-secondary-color-500);
29
+ --pf-alert-bordered-info-icon: var(--pf-secondary-color-400);
30
+
31
+ // Bordered / Success
32
+ --pf-alert-bordered-success-bg: var(--pf-green-color-150);
33
+ --pf-alert-bordered-success-border: var(--pf-green-color-450);
34
+ --pf-alert-bordered-success-text: var(--pf-green-color-600);
35
+ --pf-alert-bordered-success-icon: var(--pf-green-color-500);
36
+
37
+ // Bordered / Error
38
+ --pf-alert-bordered-error-bg: var(--pf-red-color-150);
39
+ --pf-alert-bordered-error-border: var(--pf-red-color-250);
40
+ --pf-alert-bordered-error-text: var(--pf-red-color-500);
41
+ --pf-alert-bordered-error-icon: var(--pf-red-color-450);
42
+ }
43
+
44
+ // ============================================================================
45
+ // Bordered variant - Dark Theme
46
+ // ============================================================================
47
+ :root [data-theme='dark'] {
48
+ // Bordered / Warning
49
+ --pf-alert-bordered-warning-bg: var(--pf-yellow-color-800);
50
+ --pf-alert-bordered-warning-border: var(--pf-yellow-color-500);
51
+ --pf-alert-bordered-warning-text: var(--pf-yellow-color-300);
52
+ --pf-alert-bordered-warning-icon: var(--pf-yellow-color-300);
53
+
54
+ // Bordered / Info
55
+ --pf-alert-bordered-info-bg: var(--pf-blue-color-700);
56
+ --pf-alert-bordered-info-border: var(--pf-secondary-color-500);
57
+ --pf-alert-bordered-info-text: var(--pf-secondary-color-250);
58
+ --pf-alert-bordered-info-icon: var(--pf-secondary-color-250);
59
+
60
+ // Bordered / Success
61
+ --pf-alert-bordered-success-bg: var(--pf-green-color-800);
62
+ --pf-alert-bordered-success-border: var(--pf-green-color-600);
63
+ --pf-alert-bordered-success-text: var(--pf-green-color-300);
64
+ --pf-alert-bordered-success-icon: var(--pf-green-color-300);
65
+
66
+ // Bordered / Error
67
+ --pf-alert-bordered-error-bg: var(--pf-red-color-700);
68
+ --pf-alert-bordered-error-border: var(--pf-red-color-500);
69
+ --pf-alert-bordered-error-text: var(--pf-red-color-300);
70
+ --pf-alert-bordered-error-icon: var(--pf-red-color-300);
71
+ }
@@ -0,0 +1,28 @@
1
+ import type React from 'react';
2
+
3
+ export type AlertType = 'warning' | 'info' | 'success' | 'error';
4
+ export type AlertVariant = 'soft' | 'bordered';
5
+ export type AlertSize = 'small' | 'large';
6
+
7
+ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ /** Semantic type — controls the icon and accent color */
9
+ type: AlertType;
10
+ /** Visual style: soft (subtle bg) or bordered (colored border) */
11
+ variant?: AlertVariant;
12
+ /** Size: large (banner) or small (compact inline) */
13
+ size?: AlertSize;
14
+ /** When true, the bordered variant uses a type-specific tinted background instead of surface-secondary */
15
+ tinted?: boolean;
16
+ /** Optional title — when provided, renders above the message */
17
+ title?: string;
18
+ /** Alert body / message content */
19
+ children: React.ReactNode;
20
+ /** Optional action button label */
21
+ actionText?: string;
22
+ /** Called when the action button is clicked */
23
+ onAction?: () => void;
24
+ /** Called when the close button is clicked — omit to hide the close button */
25
+ onClose?: () => void;
26
+ /** Accessible label for the close button (for i18n) */
27
+ closeAriaLabel?: string;
28
+ }
@@ -21,6 +21,7 @@ export { InputDateRangePicker } from './forms/date/inputDateRangePicker';
21
21
  export { Modal, ConfirmationModal } from './modal';
22
22
  export { Badge } from './badge';
23
23
  export { Pill } from './pill';
24
+ export { Alert } from './alert';
24
25
  export { Pagination } from './pagination';
25
26
  export { TanstackTable } from './tanstackTable';
26
27
  export { Tooltip } from './tooltip';
@@ -68,6 +68,33 @@ Multiple features can be combined freely.
68
68
 
69
69
  <Canvas of={Pill.Combined} />
70
70
 
71
+ ## Shading
72
+
73
+ Use `shade` and `shadeCount` to visually differentiate pills within a single color.
74
+ The middle shade renders the base color; shades below the midpoint blend toward white
75
+ (up to 30% lighter), shades above blend toward black (up to 30% darker). Text and icons
76
+ stay at full strength throughout.
77
+
78
+ Pass both props together — `shade` is the 1-based index of this pill, `shadeCount` is
79
+ the total number of pills in the group. When either prop is omitted the pill renders
80
+ at full color as usual.
81
+
82
+ <Canvas of={Pill.Shaded} />
83
+
84
+ <Controls of={Pill.Shaded} />
85
+
86
+ ### Spectrum across colors
87
+
88
+ Every chromatic color works with shading, in both solid and outline variants.
89
+
90
+ <Canvas of={Pill.ShadedSpectrum} />
91
+
92
+ ### Dynamic shade counts
93
+
94
+ The distribution adapts to any group size — no fixed token set required.
95
+
96
+ <Canvas of={Pill.ShadedDynamicCount} />
97
+
71
98
  ## Full Color × Variant Matrix
72
99
 
73
100
  <Canvas of={Pill.FullMatrix} />