@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/AGENTS.md ADDED
@@ -0,0 +1,110 @@
1
+ # AGENTS GUIDE
2
+
3
+ This guide summarizes how to work in the `permafrost` repo (published as `@indico-data/design-system`) and the conventions every agent must follow when making changes.
4
+
5
+ Permafrost is the code implementation of Indico's Figma design system. When behavior or styling is unclear, align with approved design-system specs before introducing new patterns.
6
+
7
+ ## Quick Reference
8
+
9
+ | Task | Command |
10
+ | -------------------- | ---------------------------------- |
11
+ | Start Storybook | `yarn dev` → http://localhost:6006 |
12
+ | Build library | `yarn build` |
13
+ | Run tests | `yarn test` |
14
+ | Run Storybook tests | `yarn test-storybook` |
15
+ | Lint | `yarn lint` |
16
+ | Check latest release | `yarn latest-release` |
17
+ | Check all releases | `yarn all-releases` |
18
+
19
+ ## Project Structure
20
+
21
+ ```
22
+ permafrost/
23
+ ├── src/
24
+ │ ├── index.ts # Public package API (`@indico-data/design-system`)
25
+ │ ├── components/ # All component directories
26
+ │ │ ├── index.ts # Internal convenience barrel (`@/components`) for docs/stories/dev
27
+ │ │ └── <component>/
28
+ │ │ ├── index.ts # Barrel export
29
+ │ │ ├── Component.tsx # Implementation
30
+ │ │ ├── types.ts # Props interface with JSDoc
31
+ │ │ ├── styles/ # Component styles (SCSS-first)
32
+ │ │ │ └── _tokens.scss # Component-level design tokens
33
+ │ │ ├── __tests__/ # Jest + Testing Library tests
34
+ │ │ ├── Component.stories.tsx # Storybook stories
35
+ │ │ └── Component.mdx # Storybook docs
36
+ │ ├── styles/
37
+ │ │ ├── primitives/ # Base tokens: colors, spacing, typography, borders
38
+ │ │ └── tokens/ # Semantic tokens (light/dark via data-theme)
39
+ │ ├── setup/ # Icon registration, test setup
40
+ ├── lib/ # Build output (CJS + ESM + CSS + .d.ts)
41
+ └── .storybook/ # Storybook configuration
42
+ ```
43
+
44
+ ## Editing Instructions
45
+
46
+ ### Adding or Modifying Components
47
+
48
+ 1. **Follow the component directory pattern**: each component lives in `src/components/<name>/` with an `index.ts` barrel, implementation file, `types.ts` for props, and co-located styles/tests/stories. (Not all legacy components fully conform yet — new components should follow this pattern.)
49
+ 2. **Props interfaces must have JSDoc** on every public prop — this feeds into Storybook's `react-docgen-typescript` for auto-generated docs.
50
+ 3. **Every component must have a Storybook story** (`.stories.tsx`) demonstrating its variants, and an MDX doc file showing usage.
51
+ 4. **Every component must have tests** using Jest + `@testing-library/react`. Tests live in `__tests__/` or as co-located `.test.tsx` files.
52
+ 5. **Export new components from `src/index.ts`** — this is the public API. If it's not exported here, consumers can't use it.
53
+ 6. **Treat `src/components/index.ts` as internal-only** — it is for repo-local imports (for example `@/components` in stories/docs). Do not treat it as consumer API, and keep naming/exports in `src/index.ts` authoritative.
54
+
55
+ ### Design Tokens and Styling
56
+
57
+ - **Semantic tokens first** (`src/styles/tokens/_semantic-tokens.scss`): these are the default tokens for component styling and should be used in most cases.
58
+ - **Primitives** (`src/styles/primitives/`): base values (`--pf-*-color-*`, spacing, typography, borders, shadows, breakpoints) that feed semantic tokens. Use directly only for limited foundation-level needs.
59
+ - **Component tokens** (`src/components/*/styles/_tokens.scss`): exception, not the rule. Add only when there are component specific (non-semantic) colors used in designs.
60
+ - Token names follow the pattern: `--pf-<layer>-<category>-<variant>` (e.g. `--pf-semantic-bg-primary`, `--pf-blue-color-500`).
61
+ - When adding tokens, follow the existing hierarchy: primitives → semantic → component. Do not hardcode color values in components.
62
+
63
+ ### Styling Conventions
64
+
65
+ - Use **SCSS** for new styling work.
66
+ - Do not introduce new **styled-components** in new components. If touching legacy code that already uses styled-components, keep changes localized unless refactoring is explicitly in scope.
67
+ - Use CSS custom properties (design tokens) for all colors, spacing, typography, and borders.
68
+
69
+ ### i18n
70
+
71
+ - ESLint enforces `i18next/no-literal-string` and `@sanity/i18n/no-attribute-string-literals` for user-facing text in `label`, `placeholder`, `title`, `alt`, `aria-label`, and `tooltip` attributes.
72
+ - These rules are relaxed for test files, stories, examples, docs, and mock data.
73
+ - Components should accept user-facing text via a `text` prop object pattern to support i18n in consumer apps.
74
+
75
+ ## Release Conventions
76
+
77
+ Releases are fully automated via [Semantic Release](https://github.com/semantic-release/semantic-release). The **PR title** controls versioning:
78
+
79
+ | PR Title Tag | Release Type | Example |
80
+ | ------------ | ------------ | ----------------------------------------- |
81
+ | `Fix` | Patch | `Fix: button hover state on dark theme` |
82
+ | `Update` | Patch | `Update: button color adjustment` |
83
+ | `New` | Minor | `New: [SNC-222] add dark mode` |
84
+ | `Breaking` | Major | `Breaking: remove deprecated Table props` |
85
+ | `Docs` | No release | `Docs: update Button MDX` |
86
+ | `Build` | No release | `Build: upgrade rollup` |
87
+ | `Upgrade` | No release | `Upgrade: bump react-aria` |
88
+ | `Chore` | No release | `Chore: clean up test fixtures` |
89
+
90
+ **Critical rules:**
91
+
92
+ - PR title **must** follow `<Tag>: <Short description>` format or merging is blocked.
93
+ - Do **not** manually update `version` in `package.json` — it stays at `0.0.0-semantically-released`.
94
+ - Do **not** manually publish to npm.
95
+
96
+ ## Review Guidelines
97
+
98
+ - Every component change must include a Storybook story demonstrating the change.
99
+ - Props interfaces must have JSDoc documentation.
100
+ - New components must have tests.
101
+ - Design tokens must follow the primitives → semantic → component hierarchy.
102
+ - Verify `yarn lint` and `yarn test` pass before submitting.
103
+
104
+ ## Validation
105
+
106
+ After any significant change, run:
107
+
108
+ ```bash
109
+ yarn lint && yarn test && yarn build
110
+ ```
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -0,0 +1,2 @@
1
+ import { type AlertProps } from './types';
2
+ export declare const Alert: ({ type, variant, size, tinted, title, children, actionText, onAction, onClose, closeAriaLabel, className, ...rest }: AlertProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { type Meta, type StoryObj } from '@storybook/react';
2
+ import { Alert } from './Alert';
3
+ declare const meta: Meta<typeof Alert>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Alert>;
6
+ export declare const Default: Story;
7
+ export declare const Types: Story;
8
+ export declare const Variants: Story;
9
+ export declare const WithTitle: Story;
10
+ export declare const WithAction: Story;
11
+ export declare const Closeable: Story;
12
+ export declare const Combined: Story;
13
+ export declare const SmallBordered: Story;
14
+ export declare const SmallBorderedTinted: Story;
15
+ export declare const SmallTintedWithClose: Story;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { Alert } from './Alert';
2
+ export type { AlertProps, AlertType, AlertVariant, AlertSize } from './types';
@@ -0,0 +1,26 @@
1
+ import type React from 'react';
2
+ export type AlertType = 'warning' | 'info' | 'success' | 'error';
3
+ export type AlertVariant = 'soft' | 'bordered';
4
+ export type AlertSize = 'small' | 'large';
5
+ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
6
+ /** Semantic type — controls the icon and accent color */
7
+ type: AlertType;
8
+ /** Visual style: soft (subtle bg) or bordered (colored border) */
9
+ variant?: AlertVariant;
10
+ /** Size: large (banner) or small (compact inline) */
11
+ size?: AlertSize;
12
+ /** When true, the bordered variant uses a type-specific tinted background instead of surface-secondary */
13
+ tinted?: boolean;
14
+ /** Optional title — when provided, renders above the message */
15
+ title?: string;
16
+ /** Alert body / message content */
17
+ children: React.ReactNode;
18
+ /** Optional action button label */
19
+ actionText?: string;
20
+ /** Called when the action button is clicked */
21
+ onAction?: () => void;
22
+ /** Called when the close button is clicked — omit to hide the close button */
23
+ onClose?: () => void;
24
+ /** Accessible label for the close button (for i18n) */
25
+ closeAriaLabel?: string;
26
+ }
@@ -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';
@@ -1,2 +1,2 @@
1
1
  import { type PillProps } from './types';
2
- export declare const Pill: ({ children, color, size, variant, type, iconLeft, iconRight, dot, onClose, closeAriaLabel, className, ...rest }: PillProps) => import("react/jsx-runtime").JSX.Element;
2
+ export declare const Pill: ({ children, color, size, variant, type, iconLeft, iconRight, dot, shade, shadeCount, onClose, closeAriaLabel, className, style, ...rest }: PillProps) => import("react/jsx-runtime").JSX.Element;
@@ -16,4 +16,7 @@ export declare const Closeable: Story;
16
16
  export declare const Combined: Story;
17
17
  export declare const FullMatrix: Story;
18
18
  export declare const CloseableMatrix: Story;
19
+ export declare const Shaded: Story;
20
+ export declare const ShadedSpectrum: Story;
21
+ export declare const ShadedDynamicCount: Story;
19
22
  export declare const FigmaMatrix: Story;
@@ -22,6 +22,10 @@ export interface PillProps extends React.HTMLAttributes<HTMLDivElement> {
22
22
  iconRight?: IconName;
23
23
  /** When true, renders a small colored dot indicator before the content */
24
24
  dot?: boolean;
25
+ /** 1-based shade index within a group. Used with shadeCount to vary background lightness via color-mix(). */
26
+ shade?: number;
27
+ /** Total shades in the group. Background blends lighter (white) below midpoint, darker (black) above. */
28
+ shadeCount?: number;
25
29
  /** When provided, renders a close button that calls this handler */
26
30
  onClose?: () => void;
27
31
  /** Accessible label for the close button (for i18n) */
package/lib/index.css CHANGED
@@ -6562,7 +6562,7 @@ body div[class*=select__single-value] {
6562
6562
  padding: var(--pf-spacing-xs) var(--pf-spacing-sm) var(--pf-spacing-xs) var(--pf-spacing-lg);
6563
6563
  }
6564
6564
  .pill--solid-red {
6565
- background-color: var(--pf-pill-solid-red-bg);
6565
+ background-color: color-mix(in srgb, var(--pf-pill-solid-red-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6566
6566
  color: var(--pf-pill-solid-red-text);
6567
6567
  }
6568
6568
  .pill--solid-red > .icon {
@@ -6579,7 +6579,7 @@ body div[class*=select__single-value] {
6579
6579
  background-color: var(--pf-pill-solid-red-close-hover-bg);
6580
6580
  }
6581
6581
  .pill--solid-purple {
6582
- background-color: var(--pf-pill-solid-purple-bg);
6582
+ background-color: color-mix(in srgb, var(--pf-pill-solid-purple-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6583
6583
  color: var(--pf-pill-solid-purple-text);
6584
6584
  }
6585
6585
  .pill--solid-purple > .icon {
@@ -6596,7 +6596,7 @@ body div[class*=select__single-value] {
6596
6596
  background-color: var(--pf-pill-solid-purple-close-hover-bg);
6597
6597
  }
6598
6598
  .pill--solid-yellow {
6599
- background-color: var(--pf-pill-solid-yellow-bg);
6599
+ background-color: color-mix(in srgb, var(--pf-pill-solid-yellow-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6600
6600
  color: var(--pf-pill-solid-yellow-text);
6601
6601
  }
6602
6602
  .pill--solid-yellow > .icon {
@@ -6613,7 +6613,7 @@ body div[class*=select__single-value] {
6613
6613
  background-color: var(--pf-pill-solid-yellow-close-hover-bg);
6614
6614
  }
6615
6615
  .pill--solid-blue {
6616
- background-color: var(--pf-pill-solid-blue-bg);
6616
+ background-color: color-mix(in srgb, var(--pf-pill-solid-blue-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6617
6617
  color: var(--pf-pill-solid-blue-text);
6618
6618
  }
6619
6619
  .pill--solid-blue > .icon {
@@ -6630,7 +6630,7 @@ body div[class*=select__single-value] {
6630
6630
  background-color: var(--pf-pill-solid-blue-close-hover-bg);
6631
6631
  }
6632
6632
  .pill--solid-green {
6633
- background-color: var(--pf-pill-solid-green-bg);
6633
+ background-color: color-mix(in srgb, var(--pf-pill-solid-green-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6634
6634
  color: var(--pf-pill-solid-green-text);
6635
6635
  }
6636
6636
  .pill--solid-green > .icon {
@@ -6647,7 +6647,7 @@ body div[class*=select__single-value] {
6647
6647
  background-color: var(--pf-pill-solid-green-close-hover-bg);
6648
6648
  }
6649
6649
  .pill--solid-gray {
6650
- background-color: var(--pf-pill-solid-gray-bg);
6650
+ background-color: color-mix(in srgb, var(--pf-pill-solid-gray-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6651
6651
  color: var(--pf-pill-solid-gray-text);
6652
6652
  }
6653
6653
  .pill--solid-gray > .icon {
@@ -6664,7 +6664,7 @@ body div[class*=select__single-value] {
6664
6664
  background-color: var(--pf-pill-solid-gray-close-hover-bg);
6665
6665
  }
6666
6666
  .pill--solid-pink {
6667
- background-color: var(--pf-pill-solid-pink-bg);
6667
+ background-color: color-mix(in srgb, var(--pf-pill-solid-pink-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6668
6668
  color: var(--pf-pill-solid-pink-text);
6669
6669
  }
6670
6670
  .pill--solid-pink > .icon {
@@ -6681,7 +6681,7 @@ body div[class*=select__single-value] {
6681
6681
  background-color: var(--pf-pill-solid-pink-close-hover-bg);
6682
6682
  }
6683
6683
  .pill--solid-orange {
6684
- background-color: var(--pf-pill-solid-orange-bg);
6684
+ background-color: color-mix(in srgb, var(--pf-pill-solid-orange-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6685
6685
  color: var(--pf-pill-solid-orange-text);
6686
6686
  }
6687
6687
  .pill--solid-orange > .icon {
@@ -6698,7 +6698,7 @@ body div[class*=select__single-value] {
6698
6698
  background-color: var(--pf-pill-solid-orange-close-hover-bg);
6699
6699
  }
6700
6700
  .pill--solid-teal {
6701
- background-color: var(--pf-pill-solid-teal-bg);
6701
+ background-color: color-mix(in srgb, var(--pf-pill-solid-teal-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6702
6702
  color: var(--pf-pill-solid-teal-text);
6703
6703
  }
6704
6704
  .pill--solid-teal > .icon {
@@ -6715,7 +6715,7 @@ body div[class*=select__single-value] {
6715
6715
  background-color: var(--pf-pill-solid-teal-close-hover-bg);
6716
6716
  }
6717
6717
  .pill--solid-soft {
6718
- background-color: var(--pf-pill-solid-soft-bg);
6718
+ background-color: color-mix(in srgb, var(--pf-pill-solid-soft-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6719
6719
  color: var(--pf-pill-solid-soft-text);
6720
6720
  }
6721
6721
  .pill--solid-soft > .icon {
@@ -6732,9 +6732,9 @@ body div[class*=select__single-value] {
6732
6732
  background-color: var(--pf-pill-solid-soft-close-hover-bg);
6733
6733
  }
6734
6734
  .pill--outline-red {
6735
- background-color: var(--pf-pill-outline-red-bg);
6735
+ background-color: color-mix(in srgb, var(--pf-pill-outline-red-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6736
6736
  color: var(--pf-pill-outline-red-text);
6737
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-red-border);
6737
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-red-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6738
6738
  }
6739
6739
  .pill--outline-red > .icon {
6740
6740
  color: var(--pf-pill-outline-red-icon);
@@ -6750,9 +6750,9 @@ body div[class*=select__single-value] {
6750
6750
  background-color: var(--pf-pill-outline-red-close-hover-bg);
6751
6751
  }
6752
6752
  .pill--outline-purple {
6753
- background-color: var(--pf-pill-outline-purple-bg);
6753
+ background-color: color-mix(in srgb, var(--pf-pill-outline-purple-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6754
6754
  color: var(--pf-pill-outline-purple-text);
6755
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-purple-border);
6755
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-purple-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6756
6756
  }
6757
6757
  .pill--outline-purple > .icon {
6758
6758
  color: var(--pf-pill-outline-purple-icon);
@@ -6768,9 +6768,9 @@ body div[class*=select__single-value] {
6768
6768
  background-color: var(--pf-pill-outline-purple-close-hover-bg);
6769
6769
  }
6770
6770
  .pill--outline-yellow {
6771
- background-color: var(--pf-pill-outline-yellow-bg);
6771
+ background-color: color-mix(in srgb, var(--pf-pill-outline-yellow-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6772
6772
  color: var(--pf-pill-outline-yellow-text);
6773
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-yellow-border);
6773
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-yellow-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6774
6774
  }
6775
6775
  .pill--outline-yellow > .icon {
6776
6776
  color: var(--pf-pill-outline-yellow-icon);
@@ -6786,9 +6786,9 @@ body div[class*=select__single-value] {
6786
6786
  background-color: var(--pf-pill-outline-yellow-close-hover-bg);
6787
6787
  }
6788
6788
  .pill--outline-blue {
6789
- background-color: var(--pf-pill-outline-blue-bg);
6789
+ background-color: color-mix(in srgb, var(--pf-pill-outline-blue-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6790
6790
  color: var(--pf-pill-outline-blue-text);
6791
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-blue-border);
6791
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-blue-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6792
6792
  }
6793
6793
  .pill--outline-blue > .icon {
6794
6794
  color: var(--pf-pill-outline-blue-icon);
@@ -6804,9 +6804,9 @@ body div[class*=select__single-value] {
6804
6804
  background-color: var(--pf-pill-outline-blue-close-hover-bg);
6805
6805
  }
6806
6806
  .pill--outline-green {
6807
- background-color: var(--pf-pill-outline-green-bg);
6807
+ background-color: color-mix(in srgb, var(--pf-pill-outline-green-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6808
6808
  color: var(--pf-pill-outline-green-text);
6809
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-green-border);
6809
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-green-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6810
6810
  }
6811
6811
  .pill--outline-green > .icon {
6812
6812
  color: var(--pf-pill-outline-green-icon);
@@ -6822,9 +6822,9 @@ body div[class*=select__single-value] {
6822
6822
  background-color: var(--pf-pill-outline-green-close-hover-bg);
6823
6823
  }
6824
6824
  .pill--outline-gray {
6825
- background-color: var(--pf-pill-outline-gray-bg);
6825
+ background-color: color-mix(in srgb, var(--pf-pill-outline-gray-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6826
6826
  color: var(--pf-pill-outline-gray-text);
6827
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-gray-border);
6827
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-gray-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6828
6828
  }
6829
6829
  .pill--outline-gray > .icon {
6830
6830
  color: var(--pf-pill-outline-gray-icon);
@@ -6840,9 +6840,9 @@ body div[class*=select__single-value] {
6840
6840
  background-color: var(--pf-pill-outline-gray-close-hover-bg);
6841
6841
  }
6842
6842
  .pill--outline-pink {
6843
- background-color: var(--pf-pill-outline-pink-bg);
6843
+ background-color: color-mix(in srgb, var(--pf-pill-outline-pink-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6844
6844
  color: var(--pf-pill-outline-pink-text);
6845
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-pink-border);
6845
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-pink-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6846
6846
  }
6847
6847
  .pill--outline-pink > .icon {
6848
6848
  color: var(--pf-pill-outline-pink-icon);
@@ -6858,9 +6858,9 @@ body div[class*=select__single-value] {
6858
6858
  background-color: var(--pf-pill-outline-pink-close-hover-bg);
6859
6859
  }
6860
6860
  .pill--outline-orange {
6861
- background-color: var(--pf-pill-outline-orange-bg);
6861
+ background-color: color-mix(in srgb, var(--pf-pill-outline-orange-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6862
6862
  color: var(--pf-pill-outline-orange-text);
6863
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-orange-border);
6863
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-orange-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6864
6864
  }
6865
6865
  .pill--outline-orange > .icon {
6866
6866
  color: var(--pf-pill-outline-orange-icon);
@@ -6876,9 +6876,9 @@ body div[class*=select__single-value] {
6876
6876
  background-color: var(--pf-pill-outline-orange-close-hover-bg);
6877
6877
  }
6878
6878
  .pill--outline-teal {
6879
- background-color: var(--pf-pill-outline-teal-bg);
6879
+ background-color: color-mix(in srgb, var(--pf-pill-outline-teal-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6880
6880
  color: var(--pf-pill-outline-teal-text);
6881
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-teal-border);
6881
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-teal-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6882
6882
  }
6883
6883
  .pill--outline-teal > .icon {
6884
6884
  color: var(--pf-pill-outline-teal-icon);
@@ -6894,9 +6894,9 @@ body div[class*=select__single-value] {
6894
6894
  background-color: var(--pf-pill-outline-teal-close-hover-bg);
6895
6895
  }
6896
6896
  .pill--outline-soft {
6897
- background-color: var(--pf-pill-outline-soft-bg);
6897
+ background-color: color-mix(in srgb, var(--pf-pill-outline-soft-bg) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6898
6898
  color: var(--pf-pill-outline-soft-text);
6899
- box-shadow: inset 0 0 0 1px var(--pf-pill-outline-soft-border);
6899
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-pill-outline-soft-border) var(--pill-shade-mix, 100%), var(--pill-shade-target, white));
6900
6900
  }
6901
6901
  .pill--outline-soft > .icon {
6902
6902
  color: var(--pf-pill-outline-soft-icon);
@@ -6932,6 +6932,190 @@ body div[class*=select__single-value] {
6932
6932
  transition: color 0.15s ease, background-color 0.15s ease;
6933
6933
  }
6934
6934
 
6935
+ :root,
6936
+ :root [data-theme=light] {
6937
+ --pf-alert-bordered-warning-bg: var(--pf-yellow-color-150);
6938
+ --pf-alert-bordered-warning-border: var(--pf-yellow-color-400);
6939
+ --pf-alert-bordered-warning-text: var(--pf-yellow-color-600);
6940
+ --pf-alert-bordered-warning-icon: var(--pf-yellow-color-400);
6941
+ --pf-alert-bordered-info-bg: var(--pf-blue-color-150);
6942
+ --pf-alert-bordered-info-border: var(--pf-secondary-color-400);
6943
+ --pf-alert-bordered-info-text: var(--pf-secondary-color-500);
6944
+ --pf-alert-bordered-info-icon: var(--pf-secondary-color-400);
6945
+ --pf-alert-bordered-success-bg: var(--pf-green-color-150);
6946
+ --pf-alert-bordered-success-border: var(--pf-green-color-450);
6947
+ --pf-alert-bordered-success-text: var(--pf-green-color-600);
6948
+ --pf-alert-bordered-success-icon: var(--pf-green-color-500);
6949
+ --pf-alert-bordered-error-bg: var(--pf-red-color-150);
6950
+ --pf-alert-bordered-error-border: var(--pf-red-color-250);
6951
+ --pf-alert-bordered-error-text: var(--pf-red-color-500);
6952
+ --pf-alert-bordered-error-icon: var(--pf-red-color-450);
6953
+ }
6954
+
6955
+ :root [data-theme=dark] {
6956
+ --pf-alert-bordered-warning-bg: var(--pf-yellow-color-800);
6957
+ --pf-alert-bordered-warning-border: var(--pf-yellow-color-500);
6958
+ --pf-alert-bordered-warning-text: var(--pf-yellow-color-300);
6959
+ --pf-alert-bordered-warning-icon: var(--pf-yellow-color-300);
6960
+ --pf-alert-bordered-info-bg: var(--pf-blue-color-700);
6961
+ --pf-alert-bordered-info-border: var(--pf-secondary-color-500);
6962
+ --pf-alert-bordered-info-text: var(--pf-secondary-color-250);
6963
+ --pf-alert-bordered-info-icon: var(--pf-secondary-color-250);
6964
+ --pf-alert-bordered-success-bg: var(--pf-green-color-800);
6965
+ --pf-alert-bordered-success-border: var(--pf-green-color-600);
6966
+ --pf-alert-bordered-success-text: var(--pf-green-color-300);
6967
+ --pf-alert-bordered-success-icon: var(--pf-green-color-300);
6968
+ --pf-alert-bordered-error-bg: var(--pf-red-color-700);
6969
+ --pf-alert-bordered-error-border: var(--pf-red-color-500);
6970
+ --pf-alert-bordered-error-text: var(--pf-red-color-300);
6971
+ --pf-alert-bordered-error-icon: var(--pf-red-color-300);
6972
+ }
6973
+
6974
+ .alert {
6975
+ display: flex;
6976
+ align-items: flex-start;
6977
+ gap: var(--pf-spacing-md);
6978
+ padding: var(--pf-spacing-2xl);
6979
+ border-radius: var(--pf-border-radius-md);
6980
+ background-color: var(--pf-semantic-background-secondary);
6981
+ font-family: var(--pf-font-family);
6982
+ box-shadow: 0 4px 6px -4px var(--pf-semantic-elevation-1), 0 10px 15px -3px var(--pf-semantic-elevation-1);
6983
+ }
6984
+ .alert--small {
6985
+ padding: var(--pf-spacing-sm);
6986
+ align-items: center;
6987
+ box-shadow: none;
6988
+ }
6989
+ .alert--bordered {
6990
+ border: 1px solid var(--alert-border-color);
6991
+ }
6992
+ .alert--soft-warning > .icon {
6993
+ color: var(--pf-semantic-utility-warning-default);
6994
+ }
6995
+ .alert--soft-info > .icon {
6996
+ color: var(--pf-semantic-utility-info-default);
6997
+ }
6998
+ .alert--soft-success > .icon {
6999
+ color: var(--pf-semantic-utility-success-default);
7000
+ }
7001
+ .alert--soft-error > .icon {
7002
+ color: var(--pf-semantic-utility-error-default);
7003
+ }
7004
+ .alert--bordered-warning {
7005
+ --alert-border-color: var(--pf-alert-bordered-warning-border);
7006
+ }
7007
+ .alert--bordered-warning > .icon {
7008
+ color: var(--pf-alert-bordered-warning-icon);
7009
+ }
7010
+ .alert--bordered-warning .alert__title {
7011
+ color: var(--pf-alert-bordered-warning-text);
7012
+ }
7013
+ .alert--tinted.alert--bordered-warning {
7014
+ background-color: var(--pf-alert-bordered-warning-bg);
7015
+ }
7016
+ .alert--bordered-info {
7017
+ --alert-border-color: var(--pf-alert-bordered-info-border);
7018
+ }
7019
+ .alert--bordered-info > .icon {
7020
+ color: var(--pf-alert-bordered-info-icon);
7021
+ }
7022
+ .alert--bordered-info .alert__title {
7023
+ color: var(--pf-alert-bordered-info-text);
7024
+ }
7025
+ .alert--tinted.alert--bordered-info {
7026
+ background-color: var(--pf-alert-bordered-info-bg);
7027
+ }
7028
+ .alert--bordered-success {
7029
+ --alert-border-color: var(--pf-alert-bordered-success-border);
7030
+ }
7031
+ .alert--bordered-success > .icon {
7032
+ color: var(--pf-alert-bordered-success-icon);
7033
+ }
7034
+ .alert--bordered-success .alert__title {
7035
+ color: var(--pf-alert-bordered-success-text);
7036
+ }
7037
+ .alert--tinted.alert--bordered-success {
7038
+ background-color: var(--pf-alert-bordered-success-bg);
7039
+ }
7040
+ .alert--bordered-error {
7041
+ --alert-border-color: var(--pf-alert-bordered-error-border);
7042
+ }
7043
+ .alert--bordered-error > .icon {
7044
+ color: var(--pf-alert-bordered-error-icon);
7045
+ }
7046
+ .alert--bordered-error .alert__title {
7047
+ color: var(--pf-alert-bordered-error-text);
7048
+ }
7049
+ .alert--tinted.alert--bordered-error {
7050
+ background-color: var(--pf-alert-bordered-error-bg);
7051
+ }
7052
+ .alert > .icon {
7053
+ flex-shrink: 0;
7054
+ }
7055
+ .alert__body {
7056
+ flex: 1;
7057
+ min-width: 0;
7058
+ }
7059
+ .alert__title {
7060
+ font-size: var(--pf-font-size-md);
7061
+ font-weight: var(--pf-font-weight-semibold);
7062
+ line-height: 20px;
7063
+ color: var(--pf-semantic-font-regular);
7064
+ margin-bottom: var(--pf-spacing-xxs);
7065
+ }
7066
+ .alert__message {
7067
+ font-size: var(--pf-font-size-md);
7068
+ font-weight: var(--pf-font-weight-regular);
7069
+ line-height: 20px;
7070
+ color: var(--pf-semantic-font-regular);
7071
+ }
7072
+ .alert__message a {
7073
+ color: var(--pf-semantic-font-link);
7074
+ text-decoration: underline;
7075
+ }
7076
+ .alert--has-title .alert__message {
7077
+ color: var(--pf-semantic-font-soft);
7078
+ }
7079
+ .alert__actions {
7080
+ display: flex;
7081
+ align-items: center;
7082
+ gap: var(--pf-spacing-sm);
7083
+ flex-shrink: 0;
7084
+ margin-left: auto;
7085
+ }
7086
+ .alert__action {
7087
+ background: none;
7088
+ border: none;
7089
+ cursor: pointer;
7090
+ font-family: var(--pf-font-family);
7091
+ font-size: var(--pf-font-size-md);
7092
+ font-weight: var(--pf-font-weight-medium);
7093
+ line-height: 20px;
7094
+ color: var(--pf-semantic-font-link);
7095
+ padding: 0;
7096
+ white-space: nowrap;
7097
+ }
7098
+ .alert__action:hover {
7099
+ text-decoration: underline;
7100
+ }
7101
+ .alert__close {
7102
+ display: inline-flex;
7103
+ align-items: center;
7104
+ justify-content: center;
7105
+ flex-shrink: 0;
7106
+ cursor: pointer;
7107
+ border: none;
7108
+ background: transparent;
7109
+ padding: var(--pf-spacing-xxs);
7110
+ border-radius: var(--pf-border-radius-xs);
7111
+ color: var(--pf-semantic-font-soft);
7112
+ line-height: 1;
7113
+ transition: color 0.15s ease, background-color 0.15s ease;
7114
+ }
7115
+ .alert__close:hover {
7116
+ color: var(--pf-semantic-font-regular);
7117
+ }
7118
+
6935
7119
  @keyframes moveBg {
6936
7120
  0% {
6937
7121
  transform: translateX(0);
package/lib/index.d.ts CHANGED
@@ -22,6 +22,32 @@ declare const Row: ({ ref: _ref, ...rest }: RowProps) => react_jsx_runtime.JSX.E
22
22
 
23
23
  declare const Col: ({ ref: _ref, ...rest }: ColProps) => react_jsx_runtime.JSX.Element;
24
24
 
25
+ type AlertType = 'warning' | 'info' | 'success' | 'error';
26
+ type AlertVariant = 'soft' | 'bordered';
27
+ type AlertSize = 'small' | 'large';
28
+ interface AlertProps extends React$1.HTMLAttributes<HTMLDivElement> {
29
+ /** Semantic type — controls the icon and accent color */
30
+ type: AlertType;
31
+ /** Visual style: soft (subtle bg) or bordered (colored border) */
32
+ variant?: AlertVariant;
33
+ /** Size: large (banner) or small (compact inline) */
34
+ size?: AlertSize;
35
+ /** When true, the bordered variant uses a type-specific tinted background instead of surface-secondary */
36
+ tinted?: boolean;
37
+ /** Optional title — when provided, renders above the message */
38
+ title?: string;
39
+ /** Alert body / message content */
40
+ children: React$1.ReactNode;
41
+ /** Optional action button label */
42
+ actionText?: string;
43
+ /** Called when the action button is clicked */
44
+ onAction?: () => void;
45
+ /** Called when the close button is clicked — omit to hide the close button */
46
+ onClose?: () => void;
47
+ /** Accessible label for the close button (for i18n) */
48
+ closeAriaLabel?: string;
49
+ }
50
+
25
51
  /** Customizable text for form Label. */
26
52
  interface FormLabelText {
27
53
  /** Text appended to aria-label for required fields. Default: "(required)" */
@@ -249,6 +275,10 @@ interface PillProps extends React$1.HTMLAttributes<HTMLDivElement> {
249
275
  iconRight?: IconName;
250
276
  /** When true, renders a small colored dot indicator before the content */
251
277
  dot?: boolean;
278
+ /** 1-based shade index within a group. Used with shadeCount to vary background lightness via color-mix(). */
279
+ shade?: number;
280
+ /** Total shades in the group. Background blends lighter (white) below midpoint, darker (black) above. */
281
+ shadeCount?: number;
252
282
  /** When provided, renders a close button that calls this handler */
253
283
  onClose?: () => void;
254
284
  /** Accessible label for the close button (for i18n) */
@@ -852,7 +882,9 @@ type MenuProps = {
852
882
  };
853
883
  declare function Menu({ children, className, ...rest }: MenuProps): react_jsx_runtime.JSX.Element;
854
884
 
855
- declare const Pill: ({ children, color, size, variant, type, iconLeft, iconRight, dot, onClose, closeAriaLabel, className, ...rest }: PillProps) => react_jsx_runtime.JSX.Element;
885
+ declare const Pill: ({ children, color, size, variant, type, iconLeft, iconRight, dot, shade, shadeCount, onClose, closeAriaLabel, className, style, ...rest }: PillProps) => react_jsx_runtime.JSX.Element;
886
+
887
+ declare const Alert: ({ type, variant, size, tinted, title, children, actionText, onAction, onClose, closeAriaLabel, className, ...rest }: AlertProps) => react_jsx_runtime.JSX.Element;
856
888
 
857
889
  type BadgeSizes = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
858
890
  interface BadgeProps {
@@ -1159,4 +1191,4 @@ interface TruncateProps {
1159
1191
 
1160
1192
  declare const Truncate: ({ numLines, tooltipOptions, children, ...rest }: TruncateProps) => react_jsx_runtime.JSX.Element;
1161
1193
 
1162
- export { Badge, BarSpinner, Button, Card, Checkbox, CirclePulse, Col, ConfirmationModal, Container, DatePicker, FloatUI, Form, Icon, IconTriggerDatePicker, LabeledInput as Input, InputDateRangePicker, Menu, Modal, Pagination, LabeledPasswordInput as PasswordInput, Pill, Radio as RadioInput, Row, LabeledSelect as SelectInput, type SelectOption, type SelectText, SingleInputDatePicker, SingleInputDateTimePicker, Skeleton, Stepper, Table, TanstackTable, LabeledTextarea as Textarea, TimePicker, Toggle as ToggleInput, Tooltip, Truncate, registerFontAwesomeIcons };
1194
+ export { Alert, Badge, BarSpinner, Button, Card, Checkbox, CirclePulse, Col, ConfirmationModal, Container, DatePicker, FloatUI, Form, Icon, IconTriggerDatePicker, LabeledInput as Input, InputDateRangePicker, Menu, Modal, Pagination, LabeledPasswordInput as PasswordInput, Pill, Radio as RadioInput, Row, LabeledSelect as SelectInput, type SelectOption, type SelectText, SingleInputDatePicker, SingleInputDateTimePicker, Skeleton, Stepper, Table, TanstackTable, LabeledTextarea as Textarea, TimePicker, Toggle as ToggleInput, Tooltip, Truncate, registerFontAwesomeIcons };