diff --git a/docs/examples/icon/compactIcon.tsx b/docs/examples/icon/compactIcon.tsx new file mode 100644 index 0000000000..4963cc8a54 --- /dev/null +++ b/docs/examples/icon/compactIcon.tsx @@ -0,0 +1,26 @@ +import React, { useState } from 'react'; +import { Flex, IconCompact, SelectList } from 'gestalt'; + +export default function Example() { + const compactIconsList = IconCompact.icons; + const [selectedValue, setSelectedValue] = useState(compactIconsList[0]); + + return ( + + + { + setSelectedValue(value); + }} + > + {compactIconsList.map((value) => ( + + ))} + + + + + + ); +} diff --git a/docs/pages/web/icon.tsx b/docs/pages/web/icon.tsx index d8a177ba46..ccf3b46224 100644 --- a/docs/pages/web/icon.tsx +++ b/docs/pages/web/icon.tsx @@ -10,6 +10,7 @@ import PageHeader from '../../docs-components/PageHeader'; import QualityChecklist from '../../docs-components/QualityChecklist'; import SandpackExample from '../../docs-components/SandpackExample'; import builtInIcon from '../../examples/icon/builtInIcon'; +import compactIcon from '../../examples/icon/compactIcon'; import customIcon from '../../examples/icon/customIcon'; import doClarity from '../../examples/icon/doClarity'; import doIntentional from '../../examples/icon/doIntentional'; @@ -222,6 +223,20 @@ Should be used sparingly and only in places where the UI is very dense and a lar title="Custom SVG icon" /> + They can be used with the \`IconCompact\` component.`} + title="Compact icon" + > + + } + title="Compact Icon" + /> + diff --git a/packages/gestalt/src/Icon.test.tsx b/packages/gestalt/src/Icon.test.tsx index 0500470ef8..65246df7f0 100644 --- a/packages/gestalt/src/Icon.test.tsx +++ b/packages/gestalt/src/Icon.test.tsx @@ -1,6 +1,6 @@ import { create } from 'react-test-renderer'; import Icon from './Icon'; -import InternalIcon from './Icon/InternalIcon'; +import IconCompact from './IconCompact'; test('Icon renders', () => { const tree = create().toJSON(); @@ -24,9 +24,9 @@ test('Icon flipped if its in the flip on rtl list', () => { expect(tree).toMatchSnapshot(); }); -test('Internal Icons Component supports 16x16 and private icons', () => { +test('Compact Icons Component supports 16x16', () => { const tree = create( - , + , ).toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/packages/gestalt/src/Icon/InternalIcon.tsx b/packages/gestalt/src/Icon/InternalIcon.tsx index de4d35d384..8ebf7b9969 100644 --- a/packages/gestalt/src/Icon/InternalIcon.tsx +++ b/packages/gestalt/src/Icon/InternalIcon.tsx @@ -1,7 +1,8 @@ import classnames from 'classnames'; import styles from '../Icon.css'; +import compactIconsClassic from '../icons/compact/index'; import icons from '../icons/index'; -import componentIcons from '../icons-vr-theme/components/index'; +import compactIconsVR from '../icons-vr-theme/compact/index'; import vrIcons from '../icons-vr-theme/index'; import useInExperiment from '../useInExperiment'; @@ -20,7 +21,7 @@ export type IconColor = | 'light' | 'dark'; -type IconName = keyof typeof icons | keyof typeof componentIcons; +type IconName = keyof typeof icons | keyof typeof compactIconsVR | keyof typeof compactIconsClassic; type Props = { accessibilityLabel: string; color?: IconColor; @@ -76,7 +77,6 @@ const flipOnRtlIconNames = [ * ![Icon dark mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/Icon-list-dark.spec.ts-snapshots/Icon-list-dark-chromium-darwin.png) * */ - function InternalIcon({ accessibilityLabel, color = 'subtle', @@ -99,16 +99,24 @@ function InternalIcon({ }); const getIconPath = (iconToUse?: IconName) => { - let iconName = iconToUse; + const iconName = iconToUse; + + if (!iconName) return undefined; + + if (isInExperiment) { + if (iconName in vrIcons) { + return vrIcons[iconName as keyof typeof vrIcons]; + } - if (icon && isInExperiment) { - iconName = icon as keyof typeof vrIcons; - return vrIcons[iconName]; + if (iconName in compactIconsVR) { + return compactIconsVR[iconName as keyof typeof compactIconsVR]; + } } - if (icon && icon in componentIcons) { - iconName = icon as keyof typeof componentIcons; - return componentIcons[iconName]; + + if (iconName in compactIconsClassic) { + return compactIconsClassic[iconName as keyof typeof compactIconsClassic]; } + return icons[iconName as keyof typeof icons]; }; @@ -149,7 +157,7 @@ function InternalIcon({ let viewBox = '0 0 24 24'; // if it's a component icon use a 16x16 view box - if (iconToUse && iconToUse in componentIcons) { + if (iconToUse && iconToUse in compactIconsVR) { viewBox = '0 0 16 16'; } diff --git a/packages/gestalt/src/IconCompact.tsx b/packages/gestalt/src/IconCompact.tsx new file mode 100644 index 0000000000..6735ce8b27 --- /dev/null +++ b/packages/gestalt/src/IconCompact.tsx @@ -0,0 +1,101 @@ +import InternalIcon from './Icon/InternalIcon'; +import compactIconsVR from './icons-vr-theme/compact/index'; + +export type IconColor = + | 'default' + | 'disabled' + | 'subtle' + | 'success' + | 'error' + | 'warning' + | 'info' + | 'recommendation' + | 'inverse' + | 'shopping' + | 'brandPrimary' + | 'light' + | 'dark'; + +type Props = { + /** + * Label for screen readers to announce Icon. This populates the `aria-label` attribute. If the label is hidden, use an empty string for the label (`accessibilityLabel=""`) to set `aria-hidden`. + * + * See the [Accessibility guidelines](https://gestalt.pinterest.systems/web/icon#Accessibility) for details on proper usage. + */ + accessibilityLabel: string; + /** + * The colors available to apply to Icon. + * + * See the [color variant](https://gestalt.pinterest.systems/web/icon#Colors) to learn more. + */ + color?: IconColor; + /** + * Available for testing purposes, if needed. Consider [better queries](https://testing-library.com/docs/queries/about/#priority) before using this prop. + */ + dataTestId?: string; + /** + * SVG icon from the Gestalt icon library to use within Icon. + * + * See the [icon library](https://gestalt.pinterest.systems/foundations/iconography/library) to explore available options. + */ + icon?: keyof typeof compactIconsVR; + /** + * Defines a new icon different from the built-in Gestalt icons. + * + * See the [custom icon](https://gestalt.pinterest.systems/web/icon#Custom-icon) variant to learn more. + */ + dangerouslySetSvgPath?: { + __path: string; + }; + /** + * Properly positions Icon relative to an inline element, such as Text using the inline property. + */ + inline?: boolean; + /** + * Use a number for pixel sizes or a string for percentage based sizes. + * + * See the [size](https://gestalt.pinterest.systems/web/icon#Size) variant to learn more. + */ + size?: number | string; +}; + +// @ts-expect-error - TS2322 - Type 'string[]' is not assignable to type 'readonly ("replace" | "search" | "link" | "text" | "dash" | "3D" | "3D-move" | "360" | "accessibility" | "ad" | "ad-group" | "add" | "add-circle" | "add-layout" | "add-pin" | "add-section" | ... 317 more ... | "wave")[]'. +const IconNames: ReadonlyArray = Object.keys(compactIconsVR); + +/** + * [Icons](https://gestalt.pinterest.systems/web/icon) are the symbolic representation of an action or information, providing visual context and improving usability. + * + * See the [Iconography and SVG guidelines](https://gestalt.pinterest.systems/foundations/iconography/library) to explore the full icon library. + * + * ![Icon light mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/Icon-list.spec.ts-snapshots/Icon-list-chromium-darwin.png) + * ![Icon dark mode](https://raw.githubusercontent.com/pinterest/gestalt/master/playwright/visual-test/Icon-list-dark.spec.ts-snapshots/Icon-list-dark-chromium-darwin.png) + * + */ + +function IconCompact({ + accessibilityLabel, + color = 'subtle', + dangerouslySetSvgPath, + dataTestId, + icon, + inline = false, + size = 16, +}: Props) { + return ( + + ); +} + +IconCompact.icons = IconNames; + +IconCompact.displayName = 'IconCompact'; + +export default IconCompact; diff --git a/packages/gestalt/src/__snapshots__/Icon.test.tsx.snap b/packages/gestalt/src/__snapshots__/Icon.test.tsx.snap index 970271df88..78beef29bd 100644 --- a/packages/gestalt/src/__snapshots__/Icon.test.tsx.snap +++ b/packages/gestalt/src/__snapshots__/Icon.test.tsx.snap @@ -1,5 +1,21 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Compact Icons Component supports 16x16 1`] = ` + + + +`; + exports[`Icon flipped if its in the flip on rtl list 1`] = ` `; - -exports[`Internal Icons Component supports 16x16 and private icons 1`] = ` - - - -`; diff --git a/packages/gestalt/src/index.ts b/packages/gestalt/src/index.ts index c386e5b777..b79994f1be 100644 --- a/packages/gestalt/src/index.ts +++ b/packages/gestalt/src/index.ts @@ -36,6 +36,7 @@ import Icon from './Icon'; import IconButton from './IconButton'; import IconButtonFloating from './IconButtonFloating'; import IconButtonLink from './IconButtonLink'; +import IconCompact from './IconCompact'; import Image from './Image'; import Label from './Label'; import Layer from './Layer'; @@ -129,6 +130,7 @@ export { IconButton, IconButtonFloating, IconButtonLink, + IconCompact, Image, Label, Layer,