diff --git a/.changeset/small-apricots-judge.md b/.changeset/small-apricots-judge.md new file mode 100644 index 000000000..610784fdb --- /dev/null +++ b/.changeset/small-apricots-judge.md @@ -0,0 +1,20 @@ +--- +'@primer/react-brand': patch +--- + +Added `x` variant to `UnorderedList`, and `leadingVisual`, `variant`, `leadingVisualAriaLabel` and `leadingVisualFill` props to list items. + +Example: + +```jsx + + + Check icon override in green + + X icon in orange + X icon in red + X icon in blue + X icon in purple{' '} + Muted text color + +``` diff --git a/apps/docs/content/components/UnorderedList/react.mdx b/apps/docs/content/components/UnorderedList/react.mdx index eba5649ba..e90b2fc99 100644 --- a/apps/docs/content/components/UnorderedList/react.mdx +++ b/apps/docs/content/components/UnorderedList/react.mdx @@ -48,6 +48,44 @@ import {UnorderedList} from '@primer/react-brand' ``` +### `x` variant + +```jsx live + + + Automatic security and version updates + + GitHub Security Advisories + Code and secret scanning + Dependency review + + Automated authentication and identity management + + +``` + +### Custom colors + +```jsx live + + + Automatic security and version updates + + + GitHub Security Advisories + + + Code and secret scanning + + + Dependency review + + + Automated authentication and identity management + + +``` + ## Component props ### UnorderedList @@ -55,12 +93,17 @@ import {UnorderedList} from '@primer/react-brand' | Name | Type | Default | Description | | :---------- | :------------------------------------- | :-------: | :--------------------------------------------------------- | | `className` | `string` | | Sets a custom class on the root element | -| `variant` | `default`, `checked` | `default` | Specify alternative leading visual for list items | +| `variant` | `default`, `checked` , `x` | `default` | Specify alternative leading visual for list items | | `children` | `React.ReactNode`, `React.ReactNode[]` | | Content to be displayed within the UnorderedList component | ### UnorderedList.Item -| Name | Type | Default | Description | -| :---------- | :------------------------------------- | :-------: | :------------------------------------------------------- | -| `className` | `string` | | Sets a custom class on the root element | -| `children` | `React.ReactNode`, `React.ReactNode[]` | `default` | Content to be displayed within the OrderedList component | +| Name | Type | Default | Description | +| :----------------------- | :------------------------------------- | :---------: | :-------------------------------------------------------------------------------------------------- | +| `className` | `string` | | Sets a custom class on the root element | +| `children` | `React.ReactNode`, `React.ReactNode[]` | `default` | Content to be displayed within the OrderedList component | +| `leadingVisual` | `Icon` | `undefined` | Sets a custom leading visual ([Octicon](https://primer.style/foundations/icons/)) for the list item | +| `leadingVisualFill` | `string` | `undefined` | Sets a custom color value for the leading visual | +| `leadingVisualAriaLabel` | `string` | `undefined` | Sets `aria-label` on the leading visual icon | + +Also forwards the `variant` prop from the [Text component](/components/Text). diff --git a/apps/docs/scripts/components-with-animation.js b/apps/docs/scripts/components-with-animation.js index c5b3eb9f5..76dc2947c 100644 --- a/apps/docs/scripts/components-with-animation.js +++ b/apps/docs/scripts/components-with-animation.js @@ -1,19 +1,19 @@ /* This file is generated by a script. Do not modify. */ export const supportedComponents = [ - 'Button', 'Box', + 'Button', 'ComparisonTable', 'FAQ', 'Heading', 'Image', 'Label', 'Pillar', - 'SectionIntro', 'Stack', 'Testimonial', 'Text', 'Timeline', + 'SectionIntro', 'Animate', 'River', 'RiverBreakout', diff --git a/package-lock.json b/package-lock.json index 3d59c488f..46ae4cca5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ }, "apps/storybook": { "name": "@primer/brand-storybook", - "version": "0.30.0", + "version": "0.30.1", "license": "MIT", "devDependencies": { "@babel/preset-env": "^7.22.0", @@ -27353,7 +27353,7 @@ }, "packages/design-tokens": { "name": "@primer/brand-primitives", - "version": "0.30.0", + "version": "0.30.1", "license": "MIT", "devDependencies": { "@primer/primitives": "^7.15.0", @@ -27504,7 +27504,7 @@ }, "packages/e2e": { "name": "@primer/brand-e2e", - "version": "0.30.0", + "version": "0.30.1", "license": "MIT", "devDependencies": { "@github/axe-github": "^0.5.0", @@ -27518,7 +27518,7 @@ }, "packages/fonts": { "name": "@primer/brand-fonts", - "version": "0.30.0", + "version": "0.30.1", "license": "MIT", "engines": { "node": ">=16.0.0", @@ -27527,7 +27527,7 @@ }, "packages/react": { "name": "@primer/react-brand", - "version": "0.30.0", + "version": "0.30.1", "license": "MIT", "dependencies": { "@primer/behaviors": "^1.3.4", @@ -27575,7 +27575,7 @@ }, "packages/repo-configs": { "name": "@primer/brand-config", - "version": "0.30.0", + "version": "0.30.1", "license": "MIT" } }, diff --git a/packages/react/src/Avatar/Avatar.visual.spec.ts-snapshots/Visual-Comparison-Avatar-Avatar-Default-1-linux.png b/packages/react/src/Avatar/Avatar.visual.spec.ts-snapshots/Visual-Comparison-Avatar-Avatar-Default-1-linux.png new file mode 100644 index 000000000..f4825909a Binary files /dev/null and b/packages/react/src/Avatar/Avatar.visual.spec.ts-snapshots/Visual-Comparison-Avatar-Avatar-Default-1-linux.png differ diff --git a/packages/react/src/list/ListItem/ListItem.module.css b/packages/react/src/list/ListItem/ListItem.module.css index 44ce7d900..3d8fa6b6c 100644 --- a/packages/react/src/list/ListItem/ListItem.module.css +++ b/packages/react/src/list/ListItem/ListItem.module.css @@ -4,11 +4,22 @@ gap: var(--base-size-12); } +.ListItem--default { + color: var(--brand-color-text-default); +} + +.ListItem--muted { + color: var(--brand-color-text-muted); +} + .ListItem__leading-visual { - fill: var(--brand-color-text-muted); margin: var(--base-size-4) 0; } +.ListItem__leading-visual--muted { + fill: var(--brand-color-text-muted); +} + .OrderedList__item::before { content: counter(li) '.'; counter-increment: li; diff --git a/packages/react/src/list/ListItem/ListItem.module.css.d.ts b/packages/react/src/list/ListItem/ListItem.module.css.d.ts index cbf529ecc..2df20fa94 100644 --- a/packages/react/src/list/ListItem/ListItem.module.css.d.ts +++ b/packages/react/src/list/ListItem/ListItem.module.css.d.ts @@ -1,6 +1,9 @@ declare const styles: { readonly "ListItem": string; + readonly "ListItem--default": string; + readonly "ListItem--muted": string; readonly "ListItem__leading-visual": string; + readonly "ListItem__leading-visual--muted": string; readonly "OrderedList__item": string; }; export = styles; diff --git a/packages/react/src/list/ListItem/ListItem.tsx b/packages/react/src/list/ListItem/ListItem.tsx index 572340f69..191a8d988 100644 --- a/packages/react/src/list/ListItem/ListItem.tsx +++ b/packages/react/src/list/ListItem/ListItem.tsx @@ -1,7 +1,7 @@ import React, {type Ref, useContext} from 'react' import clsx from 'clsx' -import {CheckIcon, DashIcon} from '@primer/octicons-react' -import {Text} from '../../Text' +import {CheckIcon, DashIcon, Icon, IconProps, XIcon} from '@primer/octicons-react' +import {Text, TextProps} from '../../Text' import type {BaseProps} from '../../component-helpers' import {ListContext} from '../listContext' @@ -16,26 +16,92 @@ export type ListItemProps = BaseProps & { * The ref object to be attached to the list item. */ ref?: Ref -} + /* + * Custom icon to be used as leading visual + */ + leadingVisual?: Icon + /* + * Color of leading icon + */ + leadingVisualFill?: IconProps['fill'] + /* + * Aria label for the leading visual + */ + leadingVisualAriaLabel?: string +} & Pick -function Root({className, children, ...props}: ListItemProps) { +function Root({ + className, + children, + leadingVisualFill, + leadingVisual: LeadingVisual, + leadingVisualAriaLabel, + variant: textVariant = 'default', + ...props +}: ListItemProps) { const {variant} = useContext(ListContext) - const leadingVisual = () => { + const _leadingVisual = () => { + const iconProps = {fill: leadingVisualFill, 'aria-label': leadingVisualAriaLabel} + + if (LeadingVisual) { + return ( + + ) + } + switch (variant) { case 'checked': - return + return ( + + ) + case 'x': + return ( + + ) case 'default': - return + return ( + + ) default: return null } } + return (
  • - {leadingVisual()} - {children} + {_leadingVisual()} + + {children} +
  • ) } diff --git a/packages/react/src/list/UnorderedList/UnorderedList.features.stories.tsx b/packages/react/src/list/UnorderedList/UnorderedList.features.stories.tsx index 05140d07a..487fd20a6 100644 --- a/packages/react/src/list/UnorderedList/UnorderedList.features.stories.tsx +++ b/packages/react/src/list/UnorderedList/UnorderedList.features.stories.tsx @@ -2,6 +2,7 @@ import React from 'react' import {Meta} from '@storybook/react' import {UnorderedList} from '.' +import {XIcon} from '@primer/octicons-react' export default { title: 'Components/UnorderedList/Features', @@ -17,3 +18,56 @@ export const CheckList = () => ( Automated authentication and identity management ) + +export const XList = () => ( + + Automatic security and version updates + GitHub Security Advisories + Code and secret scanning + Dependency review + Automated authentication and identity management + +) + +export const customColor = () => ( + + Automatic security and version updates + GitHub Security Advisories + Code and secret scanning + Dependency review + Automated authentication and identity management + +) + +export const customIcon = () => ( + + + Automatic security and version updates + + + GitHub Security Advisories + + Code and secret scanning + + Dependency review + + + Automated authentication and identity management + + +) + +export const textVariant = () => ( + + Default + Muted + +) diff --git a/packages/react/src/list/UnorderedList/UnorderedList.stories.tsx b/packages/react/src/list/UnorderedList/UnorderedList.stories.tsx index 2c5401cb5..e9bb4d7c0 100644 --- a/packages/react/src/list/UnorderedList/UnorderedList.stories.tsx +++ b/packages/react/src/list/UnorderedList/UnorderedList.stories.tsx @@ -20,7 +20,7 @@ export default { description: 'Specify alternative leading visuals for list items', control: { type: 'radio', - options: ['default', 'checked'], + options: ['default', 'checked', 'x'], }, }, data: { diff --git a/packages/react/src/list/UnorderedList/UnorderedList.tsx b/packages/react/src/list/UnorderedList/UnorderedList.tsx index 303820f9a..0a1d19a4c 100644 --- a/packages/react/src/list/UnorderedList/UnorderedList.tsx +++ b/packages/react/src/list/UnorderedList/UnorderedList.tsx @@ -10,7 +10,7 @@ export type UnorderedListProps = PropsWithChildren> /** * The semantic structure of list that is presented visually setting 'ol' vs 'ul' based on the style the style of the list. */ - variant?: 'default' | 'checked' + variant?: 'default' | 'checked' | 'x' } function Root({variant = 'default', children, ...props}: UnorderedListProps) { diff --git a/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts index 564004613..af29dc4c0 100644 --- a/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts +++ b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts @@ -16,6 +16,42 @@ test.describe('Visual Comparison: UnorderedList', () => { expect(await page.screenshot()).toMatchSnapshot() }) + test('UnorderedList / X List', async ({page}) => { + await page.goto( + 'http://localhost:6006/iframe.html?args=&id=components-unorderedlist-features--x-list&viewMode=story', + ) + + await page.waitForTimeout(500) + expect(await page.screenshot()).toMatchSnapshot() + }) + + test('UnorderedList / Custom Color', async ({page}) => { + await page.goto( + 'http://localhost:6006/iframe.html?args=&id=components-unorderedlist-features--custom-color&viewMode=story', + ) + + await page.waitForTimeout(500) + expect(await page.screenshot()).toMatchSnapshot() + }) + + test('UnorderedList / Custom Icon', async ({page}) => { + await page.goto( + 'http://localhost:6006/iframe.html?args=&id=components-unorderedlist-features--custom-icon&viewMode=story', + ) + + await page.waitForTimeout(500) + expect(await page.screenshot()).toMatchSnapshot() + }) + + test('UnorderedList / Text Variant', async ({page}) => { + await page.goto( + 'http://localhost:6006/iframe.html?args=&id=components-unorderedlist-features--text-variant&viewMode=story', + ) + + await page.waitForTimeout(500) + expect(await page.screenshot()).toMatchSnapshot() + }) + test('UnorderedList / Default', async ({page}) => { await page.goto('http://localhost:6006/iframe.html?args=&id=components-unorderedlist--default&viewMode=story') diff --git a/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Custom-Color-1-linux.png b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Custom-Color-1-linux.png new file mode 100644 index 000000000..436b104a0 Binary files /dev/null and b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Custom-Color-1-linux.png differ diff --git a/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Custom-Icon-1-linux.png b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Custom-Icon-1-linux.png new file mode 100644 index 000000000..39dc2e3dc Binary files /dev/null and b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Custom-Icon-1-linux.png differ diff --git a/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Text-Variant-1-linux.png b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Text-Variant-1-linux.png new file mode 100644 index 000000000..b05815327 Binary files /dev/null and b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-Text-Variant-1-linux.png differ diff --git a/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-X-List-1-linux.png b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-X-List-1-linux.png new file mode 100644 index 000000000..635aad409 Binary files /dev/null and b/packages/react/src/list/UnorderedList/UnorderedList.visual.spec.ts-snapshots/Visual-Comparison-UnorderedList-UnorderedList-X-List-1-linux.png differ