+}
+
+/**
+ * `Divider` fulfills the `ItemPropsWithCustomRenderer` contract,
+ * so it can be used inline in an `ActionList`’s `items` prop.
+ * In other words, `items={[ActionList.Divider]}` is supported as a concise
+ * alternative to `items={[{renderItem: () =>
}]}`.
+ */
+Divider.renderItem = Divider
diff --git a/src/deprecated/ActionList/Group.tsx b/src/deprecated/ActionList/Group.tsx
new file mode 100644
index 00000000000..638ea4abf64
--- /dev/null
+++ b/src/deprecated/ActionList/Group.tsx
@@ -0,0 +1,45 @@
+import React from 'react'
+import styled from 'styled-components'
+import sx, {SxProp} from '../../sx'
+import {Header, HeaderProps} from './Header'
+
+/**
+ * Contract for props passed to the `Group` component.
+ */
+export interface GroupProps extends React.ComponentPropsWithoutRef<'div'>, SxProp {
+ /**
+ * Props for a `Header` to render in the `Group`.
+ */
+ header?: HeaderProps
+
+ /**
+ * The id of the group.
+ */
+ groupId?: string
+
+ /**
+ * `Items` to render in the `Group`.
+ */
+ items?: JSX.Element[]
+
+ /**
+ * Whether to display a divider above each `Item` in this `Group` when it does not follow a `Header` or `Divider`.
+ */
+ showItemDividers?: boolean
+}
+
+const StyledGroup = styled.div`
+ ${sx}
+`
+
+/**
+ * Collects related `Items` in an `ActionList`.
+ */
+export function Group({header, items, ...props}: GroupProps): JSX.Element {
+ return (
+
+ {header && }
+ {items}
+
+ )
+}
diff --git a/src/ActionList/Header.tsx b/src/deprecated/ActionList/Header.tsx
similarity index 96%
rename from src/ActionList/Header.tsx
rename to src/deprecated/ActionList/Header.tsx
index 9ac7cbd318d..c165e324efb 100644
--- a/src/ActionList/Header.tsx
+++ b/src/deprecated/ActionList/Header.tsx
@@ -1,7 +1,7 @@
import React from 'react'
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
/**
* Contract for props passed to the `Header` component.
diff --git a/src/deprecated/ActionList/Item.tsx b/src/deprecated/ActionList/Item.tsx
new file mode 100644
index 00000000000..70f4a3db399
--- /dev/null
+++ b/src/deprecated/ActionList/Item.tsx
@@ -0,0 +1,481 @@
+import {CheckIcon, IconProps} from '@primer/octicons-react'
+import React, {useCallback} from 'react'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import Truncate from '../../Truncate'
+import {ItemInput} from './List'
+import styled from 'styled-components'
+import {StyledHeader} from './Header'
+import {StyledDivider} from './Divider'
+import {useTheme} from '../../ThemeProvider'
+import {
+ activeDescendantActivatedDirectly,
+ activeDescendantActivatedIndirectly,
+ isActiveDescendantAttribute
+} from '@primer/behaviors'
+import {useSSRSafeId} from '@react-aria/ssr'
+import {ForwardRefComponent as PolymorphicForwardRefComponent} from '@radix-ui/react-polymorphic'
+import {AriaRole} from '../../utils/types'
+
+/**
+ * Contract for props passed to the `Item` component.
+ */
+export interface ItemProps extends SxProp {
+ /**
+ * Primary text which names an `Item`.
+ */
+ text?: string
+
+ /**
+ * Secondary text which provides additional information about an `Item`.
+ */
+ description?: string
+
+ /**
+ * Secondary text style variations. Usage is discretionary.
+ *
+ * - `"inline"` - Secondary text is positioned beside primary text.
+ * - `"block"` - Secondary text is positioned below primary text.
+ */
+ descriptionVariant?: 'inline' | 'block'
+
+ /**
+ * Icon (or similar) positioned before `Item` text.
+ */
+ leadingVisual?: React.FunctionComponent
+
+ /**
+ * @deprecated Use `trailingVisual` instead
+ * Icon (or similar) positioned after `Item` text.
+ */
+ trailingIcon?: React.FunctionComponent
+
+ /**
+ * @deprecated Use `trailingVisual` instead
+ * Text positioned after `Item` text and optional trailing icon.
+ */
+ trailingText?: string
+
+ /**
+ * Icon or text positioned after `Item` text.
+ */
+ trailingVisual?: React.ReactNode
+
+ /**
+ * Style variations associated with various `Item` types.
+ *
+ * - `"default"` - An action `Item`.
+ * - `"danger"` - A destructive action `Item`.
+ */
+ variant?: 'default' | 'danger'
+
+ /**
+ * Whether to display a divider above the `Item` when it does not follow a `Header` or `Divider`.
+ */
+ showDivider?: boolean
+
+ /**
+ * For `Item`s which can be selected, whether the `Item` is currently selected.
+ */
+ selected?: boolean
+
+ /**
+ * For `Item`s which can be selected, whether `multiple` `Item`s or a `single` `Item` can be selected
+ */
+ selectionVariant?: 'single' | 'multiple'
+
+ /**
+ * Designates the group that an item belongs to.
+ */
+ groupId?: string
+
+ /**
+ * Items that are disabled can not be clicked, selected, or navigated through.
+ */
+ disabled?: boolean
+
+ /**
+ * Callback that will trigger both on click selection and keyboard selection.
+ */
+ onAction?: (item: ItemProps, event: React.MouseEvent | React.KeyboardEvent) => void
+
+ /**
+ * An id associated with this item. Should be unique between items
+ */
+ id?: number | string
+
+ /**
+ * Node to be included inside the item before the text.
+ */
+ children?: React.ReactNode
+
+ /**
+ * The ARIA role describing the function of `List` component. `option` is a common value.
+ */
+ role?: AriaRole
+
+ /**
+ * An item to pass back in the `onAction` callback, meant as
+ */
+ item?: ItemInput
+}
+
+const getItemVariant = (variant = 'default', disabled?: boolean) => {
+ if (disabled) {
+ return {
+ color: get('colors.primer.fg.disabled'),
+ iconColor: get('colors.primer.fg.disabled'),
+ annotationColor: get('colors.primer.fg.disabled'),
+ hoverCursor: 'default'
+ }
+ }
+
+ switch (variant) {
+ case 'danger':
+ return {
+ color: get('colors.danger.fg'),
+ iconColor: get('colors.danger.fg'),
+ annotationColor: get('colors.fg.muted'),
+ hoverCursor: 'pointer',
+ hoverBg: get('colors.actionListItem.danger.hoverBg'),
+ focusBg: get('colors.actionListItem.danger.activeBg'),
+ hoverText: get('colors.actionListItem.danger.hoverText')
+ }
+ default:
+ return {
+ color: get('colors.fg.default'),
+ iconColor: get('colors.fg.muted'),
+ annotationColor: get('colors.fg.muted'),
+ hoverCursor: 'pointer',
+ hoverBg: get('colors.actionListItem.default.hoverBg'),
+ focusBg: get('colors.actionListItem.default.activeBg')
+ }
+ }
+}
+
+const DividedContent = styled.div`
+ display: flex;
+ min-width: 0;
+
+ /* Required for dividers */
+ position: relative;
+ flex-grow: 1;
+`
+
+const MainContent = styled.div`
+ align-items: baseline;
+ display: flex;
+ min-width: 0;
+ flex-direction: var(--main-content-flex-direction);
+ flex-grow: 1;
+`
+
+const StyledItem = styled.div<
+ {
+ variant: ItemProps['variant']
+ showDivider: ItemProps['showDivider']
+ item?: ItemInput
+ } & SxProp
+>`
+ /* 6px vertical padding + 20px line height = 32px total height
+ *
+ * TODO: When rem-based spacing on a 4px scale lands, replace
+ * hardcoded '6px' with 'calc((${get('space.s32')} - ${get('space.20')}) / 2)'.
+ */
+ padding: 6px ${get('space.2')};
+ display: flex;
+ border-radius: ${get('radii.2')};
+ color: ${({variant, item}) => getItemVariant(variant, item?.disabled).color};
+ // 2 frames on a 60hz monitor
+ transition: background 33.333ms linear;
+ text-decoration: none;
+
+ @media (hover: hover) and (pointer: fine) {
+ :hover {
+ // allow override in case another item in the list is active/focused
+ background: var(
+ --item-hover-bg-override,
+ ${({variant, item}) => getItemVariant(variant, item?.disabled).hoverBg}
+ );
+ color: ${({variant, item}) => getItemVariant(variant, item?.disabled).hoverText};
+ cursor: ${({variant, item}) => getItemVariant(variant, item?.disabled).hoverCursor};
+ }
+ }
+
+ // Item dividers
+ :not(:first-of-type):not(${StyledDivider} + &):not(${StyledHeader} + &) {
+ margin-top: ${({showDivider}) => (showDivider ? `1px` : '0')};
+
+ ${DividedContent}::before {
+ content: ' ';
+ display: block;
+ position: absolute;
+ width: 100%;
+ top: -7px;
+ // NB: This 'get' won’t execute if it’s moved into the arrow function below.
+ border: 0 solid ${get('colors.border.muted')};
+ border-top-width: ${({showDivider}) => (showDivider ? `1px` : '0')};
+ }
+ }
+
+ // Item dividers should not be visible:
+ // - above Hovered
+ &:hover ${DividedContent}::before,
+ // - below Hovered
+ // '*' instead of '&' because '&' maps to separate class names depending on 'variant'
+ :hover + * ${DividedContent}::before {
+ // allow override in case another item in the list is active/focused
+ border-color: var(--item-hover-divider-border-color-override, transparent) !important;
+ }
+
+ // - above Focused
+ &:focus ${DividedContent}::before,
+ // - below Focused
+ // '*' instead of '&' because '&' maps to separate class names depending on 'variant'
+ :focus + * ${DividedContent}::before,
+ // - above Active Descendent
+ &[${isActiveDescendantAttribute}] ${DividedContent}::before,
+ // - below Active Descendent
+ [${isActiveDescendantAttribute}] + & ${DividedContent}::before {
+ // '!important' because all the ':not's above give higher specificity
+ border-color: transparent !important;
+ }
+
+ // Active Descendant
+ &[${isActiveDescendantAttribute}='${activeDescendantActivatedDirectly}'] {
+ background: ${({variant, item}) => getItemVariant(variant, item?.disabled).focusBg};
+ }
+ &[${isActiveDescendantAttribute}='${activeDescendantActivatedIndirectly}'] {
+ background: ${({variant, item}) => getItemVariant(variant, item?.disabled).hoverBg};
+ }
+
+ &:focus {
+ background: ${({variant, item}) => getItemVariant(variant, item?.disabled).focusBg};
+ outline: none;
+ }
+
+ &:active {
+ background: ${({variant, item}) => getItemVariant(variant, item?.disabled).focusBg};
+ }
+
+ ${sx}
+`
+
+export const TextContainer = styled.span<{
+ dangerouslySetInnerHtml?: React.DOMAttributes['dangerouslySetInnerHTML']
+}>``
+
+const BaseVisualContainer = styled.div<{variant?: ItemProps['variant']; disabled?: boolean}>`
+ // Match visual height to adjacent text line height.
+ // TODO: When rem-based spacing on a 4px scale lands, replace
+ // hardcoded '20px' with '${get('space.s20')}'.
+ height: 20px;
+ width: ${get('space.3')};
+ margin-right: ${get('space.2')};
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-shrink: 0;
+`
+
+const ColoredVisualContainer = styled(BaseVisualContainer)`
+ svg {
+ fill: ${({variant, disabled}) => getItemVariant(variant, disabled).iconColor};
+ font-size: ${get('fontSizes.0')};
+ }
+`
+
+const LeadingVisualContainer = styled(ColoredVisualContainer)`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+`
+
+const TrailingContent = styled(ColoredVisualContainer)`
+ color: ${({variant, disabled}) => getItemVariant(variant, disabled).annotationColor}};
+ margin-left: ${get('space.2')};
+ margin-right: 0;
+ width: auto;
+ div:nth-child(2) {
+ margin-left: ${get('space.2')};
+ }
+`
+
+const DescriptionContainer = styled.span`
+ color: ${get('colors.fg.muted')};
+ font-size: ${get('fontSizes.0')};
+ // TODO: When rem-based spacing on a 4px scale lands, replace
+ // hardcoded '16px' with '${get('lh-12')}'.
+ line-height: 16px;
+ margin-left: var(--description-container-margin-left);
+ min-width: 0;
+ flex-grow: 1;
+ flex-basis: var(--description-container-flex-basis);
+`
+
+const MultiSelectIcon = styled.svg<{selected?: boolean}>`
+ rect {
+ fill: ${({selected}) => (selected ? get('colors.accent.fg') : get('colors.canvas.default'))};
+ stroke: ${({selected}) => (selected ? get('colors.accent.fg') : get('colors.border.default'))};
+ shape-rendering: auto; // this is a workaround to override global style in github/github, see primer/react#1666
+ }
+ path {
+ fill: ${get('colors.fg.onEmphasis')};
+ boxshadow: ${get('shadow.small')};
+ opacity: ${({selected}) => (selected ? 1 : 0)};
+ }
+`
+
+/**
+ * An actionable or selectable `Item` with an optional icon and description.
+ */
+export const Item = React.forwardRef((itemProps, ref) => {
+ const {
+ as: Component,
+ text,
+ description,
+ descriptionVariant = 'inline',
+ selected,
+ selectionVariant,
+ leadingVisual: LeadingVisual,
+ trailingIcon: TrailingIcon,
+ trailingVisual: TrailingVisual,
+ trailingText,
+ variant = 'default',
+ showDivider,
+ disabled,
+ onAction,
+ onKeyPress,
+ children,
+ onClick,
+ id,
+ ...props
+ } = itemProps
+
+ const labelId = useSSRSafeId()
+ const descriptionId = useSSRSafeId()
+
+ const keyPressHandler = useCallback(
+ event => {
+ if (disabled) {
+ return
+ }
+ onKeyPress?.(event)
+
+ if (!event.defaultPrevented && [' ', 'Enter'].includes(event.key)) {
+ onAction?.(itemProps, event)
+ }
+ },
+ [onAction, disabled, itemProps, onKeyPress]
+ )
+
+ const clickHandler = useCallback(
+ event => {
+ if (disabled) {
+ return
+ }
+ onClick?.(event)
+ if (!event.defaultPrevented) {
+ onAction?.(itemProps, event)
+ }
+ },
+ [onAction, disabled, itemProps, onClick]
+ )
+
+ const {theme} = useTheme()
+
+ return (
+
+ {!!selected === selected && (
+
+ {selectionVariant === 'multiple' ? (
+ <>
+ {/**
+ * we use a svg instead of an input because there should not
+ * be an interactive element inside an option
+ * svg copied from primer/css
+ */}
+
+
+
+
+ >
+ ) : (
+ selected &&
+ )}
+
+ )}
+ {LeadingVisual && (
+
+
+
+ )}
+
+
+ {children}
+ {text ? {text} : null}
+ {description ? (
+
+ {descriptionVariant === 'block' ? (
+ description
+ ) : (
+
+ {description}
+
+ )}
+
+ ) : null}
+
+ {/* backward compatibility: prefer TrailingVisual but fallback to TrailingIcon */}
+ {TrailingVisual ? (
+
+ {typeof TrailingVisual === 'function' ? : TrailingVisual}
+
+ ) : TrailingIcon || trailingText ? (
+
+ {trailingText}
+ {TrailingIcon && }
+
+ ) : null}
+
+
+ )
+}) as PolymorphicForwardRefComponent<'div', ItemProps>
+
+Item.displayName = 'ActionList.Item'
diff --git a/src/deprecated/ActionList/List.tsx b/src/deprecated/ActionList/List.tsx
new file mode 100644
index 00000000000..0af5190d7c1
--- /dev/null
+++ b/src/deprecated/ActionList/List.tsx
@@ -0,0 +1,258 @@
+import React, {Key} from 'react'
+import type {AriaRole} from '../../utils/types'
+import {Group, GroupProps} from './Group'
+import {Item, ItemProps} from './Item'
+import {Divider} from './Divider'
+import styled from 'styled-components'
+import {get} from '../../constants'
+import {SystemCssProperties} from '@styled-system/css'
+import {hasActiveDescendantAttribute} from '@primer/behaviors'
+import {Merge} from '../../utils/types/Merge'
+
+type RenderItemFn = (props: ItemProps) => React.ReactElement
+
+export type ItemInput =
+ | Merge, ItemProps>
+ | ((Partial & {renderItem: RenderItemFn}) & {key?: Key})
+
+/**
+ * Contract for props passed to the `List` component.
+ */
+export interface ListPropsBase {
+ /**
+ * A collection of `Item` props and `Item`-level custom `Item` renderers.
+ */
+ items: ItemInput[]
+
+ /**
+ * The ARIA role describing the function of `List` component. `listbox` is a common value.
+ */
+ role?: AriaRole
+
+ /**
+ * id to attach to the base DOM node of the list
+ */
+ id?: string
+
+ /**
+ * A `List`-level custom `Item` renderer. Every `Item` within this `List`
+ * without a `Group`-level or `Item`-level custom `Item` renderer will be
+ * rendered using this function component.
+ */
+ renderItem?: RenderItemFn
+
+ /**
+ * A `List`-level custom `Group` renderer. Every `Group` within this `List`
+ * without a `Group`-level custom `Item` renderer will be rendered using
+ * this function component.
+ */
+ renderGroup?: typeof Group
+
+ /**
+ * Style variations. Usage is discretionary.
+ *
+ * - `"inset"` - `List` children are offset (vertically and horizontally) from `List`’s edges
+ * - `"full"` - `List` children are flush (vertically and horizontally) with `List` edges
+ */
+ variant?: 'inset' | 'full'
+
+ /**
+ * For `Item`s which can be selected, whether `multiple` `Item`s or a `single` `Item` can be selected
+ */
+ selectionVariant?: 'single' | 'multiple'
+
+ /**
+ * Whether to display a divider above each `Item` in this `List` when it does not follow a `Header` or `Divider`.
+ */
+ showItemDividers?: boolean
+}
+
+/**
+ * Contract for props passed to the `List` component, when its `Item`s are collected in `Group`s.
+ */
+export interface GroupedListProps extends ListPropsBase {
+ /**
+ * A collection of `Group` props (except `items`), plus a unique group identifier
+ * and `Group`-level custom `Item` or `Group` renderers.
+ */
+ groupMetadata: ((
+ | Omit
+ | Omit & {renderItem?: RenderItemFn; renderGroup?: typeof Group}, 'items'>
+ ) & {groupId: string})[]
+
+ /**
+ * A collection of `Item` props, plus associated group identifiers
+ * and `Item`-level custom `Item` renderers.
+ */
+ items: ((ItemProps | (Partial & {renderItem: RenderItemFn})) & {groupId: string})[]
+}
+
+/**
+ * Asserts that the given value fulfills the `GroupedListProps` contract.
+ * @param props A value which fulfills either the `ListPropsBase` or the `GroupedListProps` contract.
+ */
+function isGroupedListProps(props: ListProps): props is GroupedListProps {
+ return 'groupMetadata' in props
+}
+
+/**
+ * Contract for props passed to the `List` component.
+ */
+export type ListProps = ListPropsBase | GroupedListProps
+
+const StyledList = styled.div`
+ font-size: ${get('fontSizes.1')};
+ /* 14px font-size * 1.428571429 = 20px line height
+ *
+ * TODO: When rem-based spacing on a 4px scale lands, replace
+ * hardcoded '20px'
+ */
+ line-height: 20px;
+
+ &[${hasActiveDescendantAttribute}], &:focus-within {
+ --item-hover-bg-override: none;
+ --item-hover-divider-border-color-override: ${get('colors.border.muted')};
+ }
+`
+
+/**
+ * Returns `sx` prop values for `List` children matching the given `List` style variation.
+ * @param variant `List` style variation.
+ */
+function useListVariant(variant: ListProps['variant'] = 'inset'): {
+ firstGroupStyle?: SystemCssProperties
+ lastGroupStyle?: SystemCssProperties
+ headerStyle?: SystemCssProperties
+ itemStyle?: SystemCssProperties
+} {
+ switch (variant) {
+ case 'full':
+ return {
+ headerStyle: {paddingX: get('space.2')},
+ itemStyle: {borderRadius: 0}
+ }
+ default:
+ return {
+ firstGroupStyle: {marginTop: get('space.2')},
+ lastGroupStyle: {marginBottom: get('space.2')},
+ itemStyle: {marginX: get('space.2')}
+ }
+ }
+}
+
+/**
+ * Lists `Item`s, either grouped or ungrouped, with a `Divider` between each `Group`.
+ */
+export const List = React.forwardRef((props, forwardedRef): JSX.Element => {
+ // Get `sx` prop values for `List` children matching the given `List` style variation.
+ const {firstGroupStyle, lastGroupStyle, headerStyle, itemStyle} = useListVariant(props.variant)
+
+ /**
+ * Render a `Group` using the first of the following renderers that is defined:
+ * A `Group`-level or `List`-level custom `Group` renderer, or
+ * the default `Group` renderer.
+ */
+ const renderGroup = (
+ groupProps: GroupProps | (Partial & {renderItem?: typeof Item; renderGroup?: typeof Group})
+ ) => {
+ const GroupComponent = (('renderGroup' in groupProps && groupProps.renderGroup) ?? props.renderGroup) || Group
+ return
+ }
+
+ /**
+ * Render an `Item` using the first of the following renderers that is defined:
+ * An `Item`-level, `Group`-level, or `List`-level custom `Item` renderer,
+ * or the default `Item` renderer.
+ */
+ const renderItem = (itemProps: ItemInput, item: ItemInput, itemIndex: number) => {
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+ const ItemComponent = ('renderItem' in itemProps && itemProps.renderItem) || props.renderItem || Item
+ const key = ('key' in itemProps ? itemProps.key : undefined) ?? itemProps.id?.toString() ?? itemIndex.toString()
+ return (
+
+ )
+ }
+
+ /**
+ * An array of `Group`s, each with an associated `Header` and with an array of `Item`s belonging to that `Group`.
+ */
+ let groups: (GroupProps | (Partial & {renderItem?: typeof Item; renderGroup?: typeof Group}))[] = []
+
+ // Collect rendered `Item`s into `Group`s, avoiding excess iteration over the lists of `items` and `groupMetadata`:
+ if (!isGroupedListProps(props)) {
+ // When no `groupMetadata`s is provided, collect rendered `Item`s into a single anonymous `Group`.
+ groups = [{items: props.items.map((item, index) => renderItem(item, item, index)), groupId: '0'}]
+ } else {
+ // When `groupMetadata` is provided, collect rendered `Item`s into their associated `Group`s.
+
+ /**
+ * A map of group identifiers to `Group`s, each with an associated array of `Item`s belonging to that `Group`.
+ */
+ const groupMap = props.groupMetadata.reduce(
+ (groupAccumulator, groupMetadata) => groupAccumulator.set(groupMetadata.groupId, groupMetadata),
+ new Map & {renderItem?: typeof Item; renderGroup?: typeof Group})>()
+ )
+
+ for (const itemProps of props.items) {
+ // Look up the group associated with the current item.
+ const group = groupMap.get(itemProps.groupId)
+ const itemIndex = group?.items?.length ?? 0
+
+ // Upsert the group to include the current item (rendered).
+ groupMap.set(itemProps.groupId, {
+ ...group,
+ items: [
+ ...(group?.items ?? []),
+ renderItem(
+ {
+ showDivider: group?.showItemDividers,
+ ...(group && 'renderItem' in group && {renderItem: group.renderItem}),
+ ...itemProps
+ },
+ itemProps,
+ itemIndex
+ )
+ ]
+ })
+ }
+
+ groups = [...groupMap.values()]
+ }
+
+ return (
+
+ {groups.map(({header, ...groupProps}, index) => {
+ const hasFilledHeader = header?.variant === 'filled'
+ const shouldShowDivider = index > 0 && !hasFilledHeader
+ return (
+
+ {shouldShowDivider ? : null}
+ {renderGroup({
+ sx: {
+ ...(index === 0 && firstGroupStyle),
+ ...(index === groups.length - 1 && lastGroupStyle),
+ ...(index > 0 && !shouldShowDivider && {mt: 2})
+ },
+ ...(header && {
+ header: {
+ ...header,
+ sx: {...headerStyle, ...header.sx}
+ }
+ }),
+ ...groupProps
+ })}
+
+ )
+ })}
+
+ )
+})
+
+List.displayName = 'ActionList'
diff --git a/src/deprecated/ActionList/index.ts b/src/deprecated/ActionList/index.ts
new file mode 100644
index 00000000000..ab78d4249fc
--- /dev/null
+++ b/src/deprecated/ActionList/index.ts
@@ -0,0 +1,21 @@
+import {List} from './List'
+import {Group} from './Group'
+import {Item} from './Item'
+import {Divider} from './Divider'
+export type {ListProps as ActionListProps} from './List'
+export type {GroupProps} from './Group'
+export type {ItemProps} from './Item'
+
+/**
+ * @deprecated Use ActionList with composable API instead. See https://primer.style/react/ActionList for more details.
+ */
+export const ActionList = Object.assign(List, {
+ /** Collects related `Items` in an `ActionList`. */
+ Group,
+
+ /** An actionable or selectable `Item` with an optional icon and description. */
+ Item,
+
+ /** Visually separates `Item`s or `Group`s in an `ActionList`. */
+ Divider
+})
diff --git a/src/deprecated/ActionMenu.tsx b/src/deprecated/ActionMenu.tsx
new file mode 100644
index 00000000000..81bbcb824bc
--- /dev/null
+++ b/src/deprecated/ActionMenu.tsx
@@ -0,0 +1,109 @@
+import {GroupedListProps, List, ListPropsBase} from './ActionList/List'
+import {Item, ItemProps} from './ActionList/Item'
+import {Divider} from './ActionList/Divider'
+import Button, {ButtonProps} from './Button'
+import React, {useCallback, useMemo} from 'react'
+import {AnchoredOverlay} from '../AnchoredOverlay'
+import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate'
+import {OverlayProps} from '../Overlay'
+import {useProvidedRefOrCreate} from '../hooks'
+import {AnchoredOverlayWrapperAnchorProps} from '../AnchoredOverlay/AnchoredOverlay'
+
+interface ActionMenuBaseProps extends Partial>, ListPropsBase {
+ /**
+ * Content that is passed into the renderAnchor component, which is a button by default.
+ */
+ anchorContent?: React.ReactNode
+
+ /**
+ * A callback that triggers both on clicks and keyboard events. This callback will be overridden by item level `onAction` callbacks.
+ */
+ onAction?: (props: ItemProps, event?: React.MouseEvent | React.KeyboardEvent) => void
+
+ /**
+ * If defined, will control the open/closed state of the overlay. Must be used in conjuction with `setOpen`.
+ */
+ open?: boolean
+
+ /**
+ * If defined, will control the open/closed state of the overlay. Must be used in conjuction with `open`.
+ */
+ setOpen?: (s: boolean) => void
+
+ /**
+ * Props to be spread on the internal `Overlay` component.
+ */
+ overlayProps?: Partial
+}
+
+export type ActionMenuProps = ActionMenuBaseProps & AnchoredOverlayWrapperAnchorProps
+
+const ActionMenuItem = (props: ItemProps) =>
+
+ActionMenuItem.displayName = 'ActionMenu.Item'
+
+const ActionMenuBase = ({
+ anchorContent,
+ renderAnchor = (props: T) => ,
+ anchorRef: externalAnchorRef,
+ onAction,
+ open,
+ setOpen,
+ overlayProps,
+ items,
+ ...listProps
+}: ActionMenuProps): JSX.Element => {
+ const [combinedOpenState, setCombinedOpenState] = useProvidedStateOrCreate(open, setOpen, false)
+ const anchorRef = useProvidedRefOrCreate(externalAnchorRef)
+ const onOpen = useCallback(() => setCombinedOpenState(true), [setCombinedOpenState])
+ const onClose = useCallback(() => setCombinedOpenState(false), [setCombinedOpenState])
+
+ const renderMenuAnchor = useMemo(() => {
+ if (renderAnchor === null) {
+ return null
+ }
+ return >(props: T) => {
+ return renderAnchor({
+ 'aria-label': 'menu',
+ children: anchorContent,
+ ...props
+ })
+ }
+ }, [anchorContent, renderAnchor])
+
+ const itemsToRender = useMemo(() => {
+ return items.map(item => {
+ return {
+ ...item,
+ role: 'menuitem',
+ onAction: (props, event) => {
+ const actionCallback = item.onAction ?? onAction
+ actionCallback?.(props as ItemProps, event)
+ if (!event.defaultPrevented) {
+ onClose()
+ }
+ }
+ } as ItemProps
+ })
+ }, [items, onAction, onClose])
+
+ return (
+
+
+
+ )
+}
+
+ActionMenuBase.displayName = 'ActionMenu'
+
+/**
+ * @deprecated Use ActionMenu with composable API instead. See https://primer.style/react/ActionMenu for more details.
+ */
+export const ActionMenu = Object.assign(ActionMenuBase, {Divider, Item: ActionMenuItem})
diff --git a/src/BorderBox.tsx b/src/deprecated/BorderBox.tsx
similarity index 92%
rename from src/BorderBox.tsx
rename to src/deprecated/BorderBox.tsx
index 9d40a7e47c2..56183fbc455 100644
--- a/src/BorderBox.tsx
+++ b/src/deprecated/BorderBox.tsx
@@ -1,5 +1,5 @@
import styled from 'styled-components'
-import Box, {BoxProps} from './Box'
+import Box, {BoxProps} from '../Box'
export type BorderBoxProps = BoxProps
diff --git a/src/deprecated/Button/Button.tsx b/src/deprecated/Button/Button.tsx
new file mode 100644
index 00000000000..ef9cd8d28bd
--- /dev/null
+++ b/src/deprecated/Button/Button.tsx
@@ -0,0 +1,40 @@
+import styled from 'styled-components'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
+import ButtonBase, {ButtonBaseProps} from './ButtonBase'
+
+/** @deprecated Use the new Label instead. See https://primer.style/react/Button for more details. */
+const Button = styled(ButtonBase)`
+ color: ${get('colors.btn.text')};
+ background-color: ${get('colors.btn.bg')};
+ border: 1px solid ${get('colors.btn.border')};
+ box-shadow: ${get('shadows.btn.shadow')}, ${get('shadows.btn.insetShadow')}};
+
+ &:hover {
+ background-color: ${get('colors.btn.hoverBg')};
+ border-color: ${get('colors.btn.hoverBorder')};
+ }
+
+ // focus must come before :active so that the active box shadow overrides
+ &:focus {
+ border-color: ${get('colors.btn.focusBorder')};
+ box-shadow: ${get('shadows.btn.focusShadow')};
+ }
+
+ &:active {
+ background-color: ${get('colors.btn.selectedBg')};
+ box-shadow: ${get('shadows.btn.shadowActive')};
+ }
+
+ &:disabled {
+ color: ${get('colors.primer.fg.disabled')};
+ background-color: ${get('colors.btn.bg')};
+ border-color: ${get('colors.btn.border')};
+ }
+
+ ${sx};
+`
+
+export type ButtonProps = ComponentProps
+export default Button
diff --git a/src/deprecated/Button/ButtonBase.tsx b/src/deprecated/Button/ButtonBase.tsx
new file mode 100644
index 00000000000..d0f6237db43
--- /dev/null
+++ b/src/deprecated/Button/ButtonBase.tsx
@@ -0,0 +1,39 @@
+import styled from 'styled-components'
+import {variant} from 'styled-system'
+import {ComponentProps} from '../../utils/types'
+import buttonBaseStyles from './ButtonStyles'
+
+const variants = variant({
+ variants: {
+ small: {
+ p: '4px 12px',
+ fontSize: 0
+ },
+ medium: {
+ fontSize: 1
+ },
+ large: {
+ fontSize: 2,
+ p: '10px 20px'
+ }
+ }
+})
+
+type StyledButtonBaseProps = {
+ as?: 'button' | 'a' | 'summary' | 'input' | string | React.ReactType
+ variant?: 'small' | 'medium' | 'large'
+}
+
+const ButtonBase = styled.button.attrs(({disabled, onClick}) => ({
+ onClick: disabled ? undefined : onClick
+}))`
+ ${buttonBaseStyles}
+ ${variants}
+`
+
+ButtonBase.defaultProps = {
+ variant: 'medium'
+}
+
+export type ButtonBaseProps = ComponentProps
+export default ButtonBase
diff --git a/src/Button/ButtonClose.tsx b/src/deprecated/Button/ButtonClose.tsx
similarity index 86%
rename from src/Button/ButtonClose.tsx
rename to src/deprecated/Button/ButtonClose.tsx
index ae8dda017e9..016a96ca1ea 100644
--- a/src/Button/ButtonClose.tsx
+++ b/src/deprecated/Button/ButtonClose.tsx
@@ -1,9 +1,9 @@
import {XIcon} from '@primer/octicons-react'
import React, {forwardRef} from 'react'
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const StyledButton = styled.button`
border: none;
diff --git a/src/Button/ButtonDanger.tsx b/src/deprecated/Button/ButtonDanger.tsx
similarity index 91%
rename from src/Button/ButtonDanger.tsx
rename to src/deprecated/Button/ButtonDanger.tsx
index 8c97b5f41f7..f9b215c66b6 100644
--- a/src/Button/ButtonDanger.tsx
+++ b/src/deprecated/Button/ButtonDanger.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import ButtonBase, {ButtonBaseProps} from './ButtonBase'
const ButtonDanger = styled(ButtonBase)`
diff --git a/src/Button/ButtonInvisible.tsx b/src/deprecated/Button/ButtonInvisible.tsx
similarity index 85%
rename from src/Button/ButtonInvisible.tsx
rename to src/deprecated/Button/ButtonInvisible.tsx
index 36ca8ac5c68..18726480557 100644
--- a/src/Button/ButtonInvisible.tsx
+++ b/src/deprecated/Button/ButtonInvisible.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import ButtonBase, {ButtonBaseProps} from './ButtonBase'
const ButtonInvisible = styled(ButtonBase)`
diff --git a/src/Button/ButtonOutline.tsx b/src/deprecated/Button/ButtonOutline.tsx
similarity index 91%
rename from src/Button/ButtonOutline.tsx
rename to src/deprecated/Button/ButtonOutline.tsx
index d678e096c5a..a2a3b089585 100644
--- a/src/Button/ButtonOutline.tsx
+++ b/src/deprecated/Button/ButtonOutline.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import ButtonBase, {ButtonBaseProps} from './ButtonBase'
const ButtonOutline = styled(ButtonBase)`
diff --git a/src/Button/ButtonPrimary.tsx b/src/deprecated/Button/ButtonPrimary.tsx
similarity index 91%
rename from src/Button/ButtonPrimary.tsx
rename to src/deprecated/Button/ButtonPrimary.tsx
index eb146a8bff2..0c4ea3ae12c 100644
--- a/src/Button/ButtonPrimary.tsx
+++ b/src/deprecated/Button/ButtonPrimary.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import ButtonBase, {ButtonBaseProps} from './ButtonBase'
export const ButtonPrimary = styled(ButtonBase)`
diff --git a/src/Button/ButtonStyles.tsx b/src/deprecated/Button/ButtonStyles.tsx
similarity index 94%
rename from src/Button/ButtonStyles.tsx
rename to src/deprecated/Button/ButtonStyles.tsx
index b399261d887..93562ace2d9 100644
--- a/src/Button/ButtonStyles.tsx
+++ b/src/deprecated/Button/ButtonStyles.tsx
@@ -1,5 +1,5 @@
import {css} from 'styled-components'
-import {get} from '../constants'
+import {get} from '../../constants'
export default css`
position: relative;
diff --git a/src/Button/ButtonTableList.tsx b/src/deprecated/Button/ButtonTableList.tsx
similarity index 88%
rename from src/Button/ButtonTableList.tsx
rename to src/deprecated/Button/ButtonTableList.tsx
index 3bf07783a91..cb98f74ccde 100644
--- a/src/Button/ButtonTableList.tsx
+++ b/src/deprecated/Button/ButtonTableList.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const ButtonTableList = styled.summary`
display: inline-block;
diff --git a/src/deprecated/Button/index.ts b/src/deprecated/Button/index.ts
new file mode 100644
index 00000000000..81bef292776
--- /dev/null
+++ b/src/deprecated/Button/index.ts
@@ -0,0 +1,14 @@
+export {default} from './Button'
+export type {ButtonProps} from './Button'
+export {default as ButtonDanger} from './ButtonDanger'
+export type {ButtonDangerProps} from './ButtonDanger'
+export {default as ButtonOutline} from './ButtonOutline'
+export type {ButtonOutlineProps} from './ButtonOutline'
+export {default as ButtonPrimary} from './ButtonPrimary'
+export type {ButtonPrimaryProps} from './ButtonPrimary'
+export {default as ButtonInvisible} from './ButtonInvisible'
+export type {ButtonInvisibleProps} from './ButtonInvisible'
+export {default as ButtonTableList} from './ButtonTableList'
+export type {ButtonTableListProps} from './ButtonTableList'
+export {default as ButtonClose} from './ButtonClose'
+export type {ButtonCloseProps} from './ButtonClose'
diff --git a/src/ChoiceFieldset/ChoiceFieldCaption.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldCaption.tsx
similarity index 77%
rename from src/ChoiceFieldset/ChoiceFieldCaption.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldCaption.tsx
index ac46ffc67a8..40179709359 100644
--- a/src/ChoiceFieldset/ChoiceFieldCaption.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldCaption.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import {ChoiceInputField} from '..'
+import ChoiceInputField from '../ChoiceInputField'
const ChoiceFieldCaption: React.FC = ({children}) => {children}
diff --git a/src/ChoiceFieldset/ChoiceFieldLabel.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldLabel.tsx
similarity index 77%
rename from src/ChoiceFieldset/ChoiceFieldLabel.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldLabel.tsx
index 3c23d15abff..5f40e1ab932 100644
--- a/src/ChoiceFieldset/ChoiceFieldLabel.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldLabel.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import {ChoiceInputField} from '..'
+import ChoiceInputField from '../ChoiceInputField'
const ChoiceFieldLabel: React.FC = ({children}) => {children}
diff --git a/src/ChoiceFieldset/ChoiceFieldset.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldset.tsx
similarity index 90%
rename from src/ChoiceFieldset/ChoiceFieldset.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldset.tsx
index cd97ded0d37..cca5c52370f 100644
--- a/src/ChoiceFieldset/ChoiceFieldset.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldset.tsx
@@ -1,9 +1,9 @@
import React from 'react'
-import {Box, useSSRSafeId} from '..'
-import createSlots from '../utils/create-slots'
-import {FormValidationStatus} from '../utils/types/FormValidationStatus'
-import ValidationAnimationContainer from '../_ValidationAnimationContainer'
-import InputValidation from '../_InputValidation'
+import {Box, useSSRSafeId} from '../..'
+import createSlots from '../../utils/create-slots'
+import {FormValidationStatus} from '../../utils/types/FormValidationStatus'
+import ValidationAnimationContainer from '../../_ValidationAnimationContainer'
+import InputValidation from '../../_InputValidation'
import ChoiceFieldsetListItem from './ChoiceFieldsetListItem'
import ChoiceFieldsetDescription from './ChoiceFieldsetDescription'
import ChoiceFieldsetLegend from './ChoiceFieldsetLegend'
@@ -56,9 +56,6 @@ export interface ChoiceFieldsetContext extends ChoiceFieldsetProps {
const {Slots, Slot} = createSlots(['Description', 'ChoiceList', 'Legend', 'Validation'])
export {Slot}
-/**
- * @deprecated Use `CheckboxGroup` or `RadioGroup` instead.
- */
const ChoiceFieldset = >({
children,
disabled,
@@ -130,6 +127,9 @@ const ChoiceFieldset = >({
export type {ChoiceFieldsetListProps} from './ChoiceFieldsetList'
export type {ChoiceFieldsetLegendProps} from './ChoiceFieldsetLegend'
export type {ChoiceFieldProps} from './ChoiceFieldsetListItem'
+/**
+ * @deprecated Use `CheckboxGroup` or `RadioGroup` instead. See https://primer.style/react/CheckboxGroup and https://primer.style/react/RadioGroup for more info
+ */
export default Object.assign(ChoiceFieldset, {
Description: ChoiceFieldsetDescription,
Item: ChoiceFieldsetListItem,
diff --git a/src/ChoiceFieldset/ChoiceFieldsetDescription.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldsetDescription.tsx
similarity index 93%
rename from src/ChoiceFieldset/ChoiceFieldsetDescription.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldsetDescription.tsx
index 9e8ff620325..f9a756e5fbe 100644
--- a/src/ChoiceFieldset/ChoiceFieldsetDescription.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldsetDescription.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import {Text} from '..'
+import {Text} from '../..'
import {ChoiceFieldsetContext, Slot} from './ChoiceFieldset'
const ChoiceFieldsetDescription: React.FC = ({children}) => (
diff --git a/src/ChoiceFieldset/ChoiceFieldsetLegend.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldsetLegend.tsx
similarity index 92%
rename from src/ChoiceFieldset/ChoiceFieldsetLegend.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldsetLegend.tsx
index ce5ec7077aa..08d1eddebd6 100644
--- a/src/ChoiceFieldset/ChoiceFieldsetLegend.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldsetLegend.tsx
@@ -1,6 +1,6 @@
import React from 'react'
-import {Box} from '..'
-import VisuallyHidden from '../_VisuallyHidden'
+import {Box} from '../..'
+import VisuallyHidden from '../../_VisuallyHidden'
import {ChoiceFieldsetContext, Slot} from './ChoiceFieldset'
export interface ChoiceFieldsetLegendProps {
diff --git a/src/ChoiceFieldset/ChoiceFieldsetList.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldsetList.tsx
similarity index 96%
rename from src/ChoiceFieldset/ChoiceFieldsetList.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldsetList.tsx
index 5fb69f9595e..8d872796a41 100644
--- a/src/ChoiceFieldset/ChoiceFieldsetList.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldsetList.tsx
@@ -1,7 +1,7 @@
import React from 'react'
import styled from 'styled-components'
-import {useSSRSafeId} from '..'
-import {get} from '../constants'
+import {useSSRSafeId} from '../..'
+import {get} from '../../constants'
import {Slot, ChoiceFieldsetContext} from './ChoiceFieldset'
import ChoiceFieldsetListContext from './ChoiceFieldsetListContext'
diff --git a/src/ChoiceFieldset/ChoiceFieldsetListContext.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldsetListContext.tsx
similarity index 100%
rename from src/ChoiceFieldset/ChoiceFieldsetListContext.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldsetListContext.tsx
diff --git a/src/ChoiceFieldset/ChoiceFieldsetListItem.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldsetListItem.tsx
similarity index 94%
rename from src/ChoiceFieldset/ChoiceFieldsetListItem.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldsetListItem.tsx
index bca97f0d744..443e329ec4b 100644
--- a/src/ChoiceFieldset/ChoiceFieldsetListItem.tsx
+++ b/src/deprecated/ChoiceFieldset/ChoiceFieldsetListItem.tsx
@@ -1,6 +1,7 @@
import React, {useContext} from 'react'
-import {Checkbox, ChoiceInputField, Radio, useSSRSafeId} from '..'
-import {ComponentProps} from '../utils/types'
+import {Checkbox, Radio, useSSRSafeId} from '../..'
+import ChoiceInputField from '../ChoiceInputField'
+import {ComponentProps} from '../../utils/types'
import ChoiceInputLeadingVisual from '../_ChoiceInputLeadingVisual'
import ChoiceFieldCaption from './ChoiceFieldCaption'
import ChoiceFieldLabel from './ChoiceFieldLabel'
diff --git a/src/ChoiceFieldset/ChoiceFieldsetValidation.tsx b/src/deprecated/ChoiceFieldset/ChoiceFieldsetValidation.tsx
similarity index 100%
rename from src/ChoiceFieldset/ChoiceFieldsetValidation.tsx
rename to src/deprecated/ChoiceFieldset/ChoiceFieldsetValidation.tsx
diff --git a/src/ChoiceFieldset/index.ts b/src/deprecated/ChoiceFieldset/index.ts
similarity index 100%
rename from src/ChoiceFieldset/index.ts
rename to src/deprecated/ChoiceFieldset/index.ts
diff --git a/src/ChoiceInputField.tsx b/src/deprecated/ChoiceInputField.tsx
similarity index 94%
rename from src/ChoiceInputField.tsx
rename to src/deprecated/ChoiceInputField.tsx
index dc329766fba..5f8a27e39bf 100644
--- a/src/ChoiceInputField.tsx
+++ b/src/deprecated/ChoiceInputField.tsx
@@ -1,10 +1,10 @@
import React from 'react'
-import {Box, Checkbox, Radio, useSSRSafeId} from '.'
-import {get} from './constants'
+import {Box, Checkbox, Radio, useSSRSafeId} from '..'
+import {get} from '../constants'
import {Slots} from './InputField/slots'
import ChoiceInputLeadingVisual from './_ChoiceInputLeadingVisual'
import InputField, {Props as InputFieldProps} from './InputField/InputField'
-import {FormValidationStatus} from './utils/types/FormValidationStatus'
+import {FormValidationStatus} from '../utils/types/FormValidationStatus'
import InputFieldCaption from './InputField/_InputFieldCaption'
export interface Props extends Pick {
@@ -127,6 +127,9 @@ const ChoiceInputField: React.FC = ({children, disabled, id: idProp, vali
const Label: React.FC = ({children}) => {children}
+/**
+ * @deprecated Use `FormControl` instead. See https://primer.style/react/FormControl for more info
+ */
export default Object.assign(ChoiceInputField, {
Label,
Caption: InputField.Caption,
diff --git a/src/Dropdown.tsx b/src/deprecated/Dropdown.tsx
similarity index 90%
rename from src/Dropdown.tsx
rename to src/deprecated/Dropdown.tsx
index 70fea52a980..dadd7833548 100644
--- a/src/Dropdown.tsx
+++ b/src/deprecated/Dropdown.tsx
@@ -1,12 +1,12 @@
import React from 'react'
import styled from 'styled-components'
import Button, {ButtonProps} from './Button'
-import {get} from './constants'
-import Details, {DetailsProps} from './Details'
-import getDirectionStyles from './DropdownStyles'
-import useDetails from './hooks/useDetails'
-import sx, {SxProp} from './sx'
-import {ComponentProps} from './utils/types'
+import {get} from '../constants'
+import Details, {DetailsProps} from '../Details'
+import getDirectionStyles from '../DropdownStyles'
+import useDetails from '../hooks/useDetails'
+import sx, {SxProp} from '../sx'
+import {ComponentProps} from '../utils/types'
const StyledDetails = styled(Details)`
position: relative;
@@ -146,6 +146,9 @@ Dropdown.defaultProps = Details.defaultProps
export type DropdownCaretProps = ComponentProps
export type DropdownMenuProps = ComponentProps
export type DropdownItemProps = ComponentProps
+/**
+ * @deprecated Use ActionMenu instead. See https://primer.style/react/ActionMenu for more details.
+ */
export default Object.assign(Dropdown, {
Caret: DropdownCaret,
Menu: DropdownMenu,
diff --git a/src/DropdownMenu/DropdownButton.tsx b/src/deprecated/DropdownMenu/DropdownButton.tsx
similarity index 73%
rename from src/DropdownMenu/DropdownButton.tsx
rename to src/deprecated/DropdownMenu/DropdownButton.tsx
index 9c5fd216857..187f7f80a5a 100644
--- a/src/DropdownMenu/DropdownButton.tsx
+++ b/src/deprecated/DropdownMenu/DropdownButton.tsx
@@ -1,10 +1,13 @@
import React from 'react'
import {TriangleDownIcon} from '@primer/octicons-react'
import Button, {ButtonProps} from '../Button/Button'
-import StyledOcticon from '../StyledOcticon'
+import StyledOcticon from '../../StyledOcticon'
export type DropdownButtonProps = ButtonProps
+/**
+ * @deprecated Use Button with Octicons instead. See https://primer.style/react/drafts/Button2#appending-an-icon for more details.
+ */
export const DropdownButton = React.forwardRef>(
({children, ...props}: React.PropsWithChildren, ref): JSX.Element => (
diff --git a/src/DropdownMenu/DropdownMenu.tsx b/src/deprecated/DropdownMenu/DropdownMenu.tsx
similarity index 83%
rename from src/DropdownMenu/DropdownMenu.tsx
rename to src/deprecated/DropdownMenu/DropdownMenu.tsx
index 1fa70e13f9b..74e79934fcf 100644
--- a/src/DropdownMenu/DropdownMenu.tsx
+++ b/src/deprecated/DropdownMenu/DropdownMenu.tsx
@@ -2,11 +2,11 @@ import React, {useCallback, useMemo} from 'react'
import {List, GroupedListProps, ListPropsBase, ItemInput} from '../ActionList/List'
import {DropdownButton, DropdownButtonProps} from './DropdownButton'
import {ItemProps} from '../ActionList/Item'
-import {AnchoredOverlay} from '../AnchoredOverlay'
-import {OverlayProps} from '../Overlay'
-import {AnchoredOverlayWrapperAnchorProps} from '../AnchoredOverlay/AnchoredOverlay'
-import {useProvidedRefOrCreate} from '../hooks/useProvidedRefOrCreate'
-import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate'
+import {AnchoredOverlay} from '../../AnchoredOverlay'
+import {OverlayProps} from '../../Overlay'
+import {AnchoredOverlayWrapperAnchorProps} from '../../AnchoredOverlay/AnchoredOverlay'
+import {useProvidedRefOrCreate} from '../../hooks/useProvidedRefOrCreate'
+import {useProvidedStateOrCreate} from '../../hooks/useProvidedStateOrCreate'
interface DropdownMenuBaseProps extends Partial>, ListPropsBase {
/**
@@ -45,9 +45,7 @@ interface DropdownMenuBaseProps extends Partial(props: T) => ,
diff --git a/src/DropdownMenu/index.ts b/src/deprecated/DropdownMenu/index.ts
similarity index 100%
rename from src/DropdownMenu/index.ts
rename to src/deprecated/DropdownMenu/index.ts
diff --git a/src/Flex.tsx b/src/deprecated/Flex.tsx
similarity index 87%
rename from src/Flex.tsx
rename to src/deprecated/Flex.tsx
index 853a0ba8ead..e4444ab2b26 100644
--- a/src/Flex.tsx
+++ b/src/deprecated/Flex.tsx
@@ -1,5 +1,5 @@
import styled from 'styled-components'
-import Box, {BoxProps} from './Box'
+import Box, {BoxProps} from '../Box'
export type FlexProps = BoxProps
diff --git a/src/FormGroup.tsx b/src/deprecated/FormGroup.tsx
similarity index 65%
rename from src/FormGroup.tsx
rename to src/deprecated/FormGroup.tsx
index 4ecd657a62a..83dfbfaacec 100644
--- a/src/FormGroup.tsx
+++ b/src/deprecated/FormGroup.tsx
@@ -1,7 +1,7 @@
import styled from 'styled-components'
-import {get} from './constants'
-import sx, {SxProp} from './sx'
-import {ComponentProps} from './utils/types'
+import {get} from '../constants'
+import sx, {SxProp} from '../sx'
+import {ComponentProps} from '../utils/types'
const FormGroup = styled.div`
margin: ${get('space.3')} 0;
@@ -9,6 +9,7 @@ const FormGroup = styled.div`
${sx};
`
+/** @deprecated Use FormControl instead. See https://primer.style/react/FormControl for more details. */
const FormGroupLabel = styled.label`
display: block;
margin: 0 0 ${get('space.2')};
@@ -21,4 +22,5 @@ FormGroupLabel.displayName = 'FormGroup.Label'
export type FormGroupProps = ComponentProps
export type FormGroupLabelProps = ComponentProps
+/** @deprecated Use FormControl instead. See https://primer.style/react/FormControl for more details. */
export default Object.assign(FormGroup, {Label: FormGroupLabel})
diff --git a/src/Grid.tsx b/src/deprecated/Grid.tsx
similarity index 87%
rename from src/Grid.tsx
rename to src/deprecated/Grid.tsx
index 69046fd9873..eb476b43d1b 100644
--- a/src/Grid.tsx
+++ b/src/deprecated/Grid.tsx
@@ -1,5 +1,5 @@
import styled from 'styled-components'
-import Box, {BoxProps} from './Box'
+import Box, {BoxProps} from '../Box'
export type GridProps = BoxProps
diff --git a/src/InputField/InputField.tsx b/src/deprecated/InputField/InputField.tsx
similarity index 93%
rename from src/InputField/InputField.tsx
rename to src/deprecated/InputField/InputField.tsx
index 32c780bfe2a..2aeb961d22b 100644
--- a/src/InputField/InputField.tsx
+++ b/src/deprecated/InputField/InputField.tsx
@@ -1,13 +1,13 @@
import React from 'react'
-import {Autocomplete, Box, Select, TextInput, TextInputWithTokens, useSSRSafeId} from '..'
-import InputValidation from '../_InputValidation'
-import {ComponentProps} from '../utils/types'
-import {FormValidationStatus} from '../utils/types/FormValidationStatus'
+import {Autocomplete, Box, Select, TextInput, TextInputWithTokens, useSSRSafeId} from '../../'
+import InputValidation from '../../_InputValidation'
+import {ComponentProps} from '../../utils/types'
+import {FormValidationStatus} from '../../utils/types/FormValidationStatus'
import InputFieldCaption from './_InputFieldCaption'
import InputFieldLabel from './_InputFieldLabel'
import InputFieldValidation from './_InputFieldValidation'
import {Slots} from './slots'
-import ValidationAnimationContainer from '../_ValidationAnimationContainer'
+import ValidationAnimationContainer from '../../_ValidationAnimationContainer'
export interface Props> {
children?: React.ReactNode
/**
@@ -40,6 +40,7 @@ export interface InputFieldContext
validationMessageId: string
}
+/** @deprecated Use FormControl instead. See https://primer.style/react/FormControl for more details. */
const InputField = >({
children,
disabled,
diff --git a/src/InputField/_InputFieldCaption.tsx b/src/deprecated/InputField/_InputFieldCaption.tsx
similarity index 89%
rename from src/InputField/_InputFieldCaption.tsx
rename to src/deprecated/InputField/_InputFieldCaption.tsx
index 1a67ccc6e59..9e39a68de12 100644
--- a/src/InputField/_InputFieldCaption.tsx
+++ b/src/deprecated/InputField/_InputFieldCaption.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import InputCaption from '../_InputCaption'
+import InputCaption from '../../_InputCaption'
import {InputFieldContext} from './InputField'
import {Slot} from './slots'
diff --git a/src/InputField/_InputFieldLabel.tsx b/src/deprecated/InputField/_InputFieldLabel.tsx
similarity index 92%
rename from src/InputField/_InputFieldLabel.tsx
rename to src/deprecated/InputField/_InputFieldLabel.tsx
index 10b27710226..843234da761 100644
--- a/src/InputField/_InputFieldLabel.tsx
+++ b/src/deprecated/InputField/_InputFieldLabel.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import InputLabel from '../_InputLabel'
+import InputLabel from '../../_InputLabel'
import {InputFieldContext} from './InputField'
import {Slot} from './slots'
diff --git a/src/InputField/_InputFieldValidation.tsx b/src/deprecated/InputField/_InputFieldValidation.tsx
similarity index 100%
rename from src/InputField/_InputFieldValidation.tsx
rename to src/deprecated/InputField/_InputFieldValidation.tsx
diff --git a/src/InputField/index.ts b/src/deprecated/InputField/index.ts
similarity index 100%
rename from src/InputField/index.ts
rename to src/deprecated/InputField/index.ts
diff --git a/src/InputField/slots.ts b/src/deprecated/InputField/slots.ts
similarity index 63%
rename from src/InputField/slots.ts
rename to src/deprecated/InputField/slots.ts
index 1df9b0ed419..4418ab896c6 100644
--- a/src/InputField/slots.ts
+++ b/src/deprecated/InputField/slots.ts
@@ -1,3 +1,3 @@
-import createSlots from '../utils/create-slots'
+import createSlots from '../../utils/create-slots'
export const {Slots, Slot} = createSlots(['Caption', 'Input', 'Label', 'LeadingVisual'])
diff --git a/src/deprecated/Label.tsx b/src/deprecated/Label.tsx
new file mode 100644
index 00000000000..d4a49982042
--- /dev/null
+++ b/src/deprecated/Label.tsx
@@ -0,0 +1,75 @@
+import styled, {css} from 'styled-components'
+import {borderColor, BorderColorProps, variant} from 'styled-system'
+import {get} from '../constants'
+import sx, {SxProp} from '../sx'
+import {ComponentProps} from '../utils/types'
+
+const outlineStyles = css`
+ margin-top: -1px; // offsets the 1px border
+ margin-bottom: -1px; // offsets the 1px border
+ color: ${get('colors.fg.muted')};
+ border: ${get('borderWidths.1')} solid ${get('colors.border.default')};
+ box-shadow: none;
+ ${borderColor};
+ background-color: transparent;
+`
+
+const sizeVariant = variant({
+ variants: {
+ small: {
+ fontSize: 0,
+ lineHeight: '16px',
+ padding: '0px 8px'
+ },
+ medium: {
+ fontSize: 0,
+ lineHeight: '20px',
+ padding: '0 8px'
+ },
+ large: {
+ fontSize: 0,
+ lineHeight: '24px',
+ padding: '0 12px'
+ },
+ // corresponds to StateLabel fontSize/lineHeight/padding
+ xl: {
+ fontSize: 1,
+ lineHeight: '16px',
+ padding: '8px 12px'
+ }
+ }
+})
+
+/** @deprecated Use the new Label instead. See https://primer.style/react/Label for more details. */
+const Label = styled.span<
+ {
+ variant?: 'small' | 'medium' | 'large' | 'xl'
+ dropshadow?: boolean
+ outline?: boolean
+ } & BorderColorProps &
+ SxProp
+>`
+ display: inline-block;
+ font-weight: ${get('fontWeights.semibold')};
+ color: ${get('colors.fg.onEmphasis')};
+ border-radius: ${get('radii.3')};
+ background-color: ${get('colors.neutral.emphasis')};
+
+ &:hover {
+ text-decoration: none;
+ }
+
+ ${sizeVariant}
+ ${props => (props.dropshadow ? 'box-shadow: inset 0 -1px 0 rgba(27, 31, 35, 0.12)' : '')}
+ ${props => (props.outline ? outlineStyles : '')} // must be last to override other values
+ ${sx}
+`
+
+Label.defaultProps = {
+ variant: 'medium'
+}
+
+Label.displayName = 'Label'
+
+export type LabelProps = ComponentProps
+export default Label
diff --git a/src/Position.tsx b/src/deprecated/Position.tsx
similarity index 96%
rename from src/Position.tsx
rename to src/deprecated/Position.tsx
index 8a4b518d956..7805af67ba5 100644
--- a/src/Position.tsx
+++ b/src/deprecated/Position.tsx
@@ -1,7 +1,7 @@
import React from 'react'
import styled from 'styled-components'
-import Box from './Box'
-import {ComponentProps} from './utils/types'
+import Box from '../Box'
+import {ComponentProps} from '../utils/types'
type StyledPositionProps = {as?: React.ElementType}
diff --git a/src/SelectMenu/SelectMenu.tsx b/src/deprecated/SelectMenu/SelectMenu.tsx
similarity index 95%
rename from src/SelectMenu/SelectMenu.tsx
rename to src/deprecated/SelectMenu/SelectMenu.tsx
index 5a6d3ff356c..51a6ff16186 100644
--- a/src/SelectMenu/SelectMenu.tsx
+++ b/src/deprecated/SelectMenu/SelectMenu.tsx
@@ -1,7 +1,7 @@
import React, {useCallback, useEffect, useRef, useState} from 'react'
import styled from 'styled-components'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import useKeyboardNav from './hooks/useKeyboardNav'
import {MenuContext} from './SelectMenuContext'
import SelectMenuDivider from './SelectMenuDivider'
@@ -107,6 +107,10 @@ export type {SelectMenuModalProps} from './SelectMenuModal'
export type {SelectMenuTabProps} from './SelectMenuTab'
export type {SelectMenuTabPanelProps} from './SelectMenuTabPanel'
export type {SelectMenuTabsProps} from './SelectMenuTabs'
+
+/**
+ * @deprecated Use ActionMenu instead. See https://primer.style/react/ActionMenu for more details.
+ */
export default Object.assign(SelectMenu, {
MenuContext,
List: SelectMenuList,
diff --git a/src/SelectMenu/SelectMenuContext.tsx b/src/deprecated/SelectMenu/SelectMenuContext.tsx
similarity index 100%
rename from src/SelectMenu/SelectMenuContext.tsx
rename to src/deprecated/SelectMenu/SelectMenuContext.tsx
diff --git a/src/SelectMenu/SelectMenuDivider.tsx b/src/deprecated/SelectMenu/SelectMenuDivider.tsx
similarity index 83%
rename from src/SelectMenu/SelectMenuDivider.tsx
rename to src/deprecated/SelectMenu/SelectMenuDivider.tsx
index e437ed1ea89..1b978dfc5bb 100644
--- a/src/SelectMenu/SelectMenuDivider.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuDivider.tsx
@@ -1,7 +1,7 @@
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const dividerStyles = css`
padding: ${get('space.1')} ${get('space.3')};
diff --git a/src/SelectMenu/SelectMenuFilter.tsx b/src/deprecated/SelectMenu/SelectMenuFilter.tsx
similarity index 88%
rename from src/SelectMenu/SelectMenuFilter.tsx
rename to src/deprecated/SelectMenu/SelectMenuFilter.tsx
index 5e96a9edc27..2d6e4d36667 100644
--- a/src/SelectMenu/SelectMenuFilter.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuFilter.tsx
@@ -1,9 +1,9 @@
import React, {forwardRef, useContext, useEffect, useRef} from 'react'
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import TextInput, {TextInputProps} from '../TextInput'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import TextInput, {TextInputProps} from '../../TextInput'
+import {ComponentProps} from '../../utils/types'
import {MenuContext} from './SelectMenuContext'
const StyledForm = styled.form`
diff --git a/src/SelectMenu/SelectMenuFooter.tsx b/src/deprecated/SelectMenu/SelectMenuFooter.tsx
similarity index 84%
rename from src/SelectMenu/SelectMenuFooter.tsx
rename to src/deprecated/SelectMenu/SelectMenuFooter.tsx
index 0765979fbf9..30d0c8d201c 100644
--- a/src/SelectMenu/SelectMenuFooter.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuFooter.tsx
@@ -1,7 +1,7 @@
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const footerStyles = css`
margin-top: -1px;
diff --git a/src/SelectMenu/SelectMenuHeader.tsx b/src/deprecated/SelectMenu/SelectMenuHeader.tsx
similarity index 90%
rename from src/SelectMenu/SelectMenuHeader.tsx
rename to src/deprecated/SelectMenu/SelectMenuHeader.tsx
index ab255e5ffb4..f29e69872b3 100644
--- a/src/SelectMenu/SelectMenuHeader.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuHeader.tsx
@@ -1,8 +1,8 @@
import React from 'react'
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
// SelectMenu.Header is intentionally not exported, it's an internal component used in
// SelectMenu.Modal
diff --git a/src/SelectMenu/SelectMenuItem.tsx b/src/deprecated/SelectMenu/SelectMenuItem.tsx
similarity index 95%
rename from src/SelectMenu/SelectMenuItem.tsx
rename to src/deprecated/SelectMenu/SelectMenuItem.tsx
index 725c30bfe63..c8a043309e0 100644
--- a/src/SelectMenu/SelectMenuItem.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuItem.tsx
@@ -1,10 +1,10 @@
import {CheckIcon} from '@primer/octicons-react'
import React, {forwardRef, useContext, useRef} from 'react'
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import StyledOcticon from '../StyledOcticon'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import StyledOcticon from '../../StyledOcticon'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import {MenuContext} from './SelectMenuContext'
export const listItemStyles = css`
diff --git a/src/SelectMenu/SelectMenuList.tsx b/src/deprecated/SelectMenu/SelectMenuList.tsx
similarity index 88%
rename from src/SelectMenu/SelectMenuList.tsx
rename to src/deprecated/SelectMenu/SelectMenuList.tsx
index 587409b13ed..b765a705ae8 100644
--- a/src/SelectMenu/SelectMenuList.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuList.tsx
@@ -1,7 +1,7 @@
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const listStyles = css`
position: relative;
diff --git a/src/SelectMenu/SelectMenuLoadingAnimation.tsx b/src/deprecated/SelectMenu/SelectMenuLoadingAnimation.tsx
similarity index 76%
rename from src/SelectMenu/SelectMenuLoadingAnimation.tsx
rename to src/deprecated/SelectMenu/SelectMenuLoadingAnimation.tsx
index a719e0d3716..b5efa3ce1cf 100644
--- a/src/SelectMenu/SelectMenuLoadingAnimation.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuLoadingAnimation.tsx
@@ -1,9 +1,9 @@
import React from 'react'
import styled from 'styled-components'
-import {get} from '../constants'
-import Spinner from '../Spinner'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import Spinner from '../../Spinner'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const Animation = styled.div`
padding: ${get('space.6')} ${get('space.4')};
diff --git a/src/SelectMenu/SelectMenuModal.tsx b/src/deprecated/SelectMenu/SelectMenuModal.tsx
similarity index 96%
rename from src/SelectMenu/SelectMenuModal.tsx
rename to src/deprecated/SelectMenu/SelectMenuModal.tsx
index d845620f3ad..6fe36dd3ffe 100644
--- a/src/SelectMenu/SelectMenuModal.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuModal.tsx
@@ -1,9 +1,9 @@
import React from 'react'
import styled, {css, keyframes} from 'styled-components'
import {width, WidthProps} from 'styled-system'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
type StyledModalProps = {
filter?: boolean
diff --git a/src/SelectMenu/SelectMenuTab.tsx b/src/deprecated/SelectMenu/SelectMenuTab.tsx
similarity index 95%
rename from src/SelectMenu/SelectMenuTab.tsx
rename to src/deprecated/SelectMenu/SelectMenuTab.tsx
index 177a3a0a859..4803bd57c32 100644
--- a/src/SelectMenu/SelectMenuTab.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuTab.tsx
@@ -1,9 +1,9 @@
import classnames from 'classnames'
import React, {useContext, useEffect} from 'react'
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import {MenuContext} from './SelectMenuContext'
const tabStyles = css`
diff --git a/src/SelectMenu/SelectMenuTabPanel.tsx b/src/deprecated/SelectMenu/SelectMenuTabPanel.tsx
similarity index 86%
rename from src/SelectMenu/SelectMenuTabPanel.tsx
rename to src/deprecated/SelectMenu/SelectMenuTabPanel.tsx
index 593c3c1d7ae..d9537d51db7 100644
--- a/src/SelectMenu/SelectMenuTabPanel.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuTabPanel.tsx
@@ -1,8 +1,8 @@
import React, {useContext} from 'react'
import styled from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
import {MenuContext} from './SelectMenuContext'
import SelectMenuList from './SelectMenuList'
diff --git a/src/SelectMenu/SelectMenuTabs.tsx b/src/deprecated/SelectMenu/SelectMenuTabs.tsx
similarity index 88%
rename from src/SelectMenu/SelectMenuTabs.tsx
rename to src/deprecated/SelectMenu/SelectMenuTabs.tsx
index 06e978b32e3..1a23525f759 100644
--- a/src/SelectMenu/SelectMenuTabs.tsx
+++ b/src/deprecated/SelectMenu/SelectMenuTabs.tsx
@@ -1,8 +1,8 @@
import React from 'react'
import styled, {css} from 'styled-components'
-import {get} from '../constants'
-import sx, {SxProp} from '../sx'
-import {ComponentProps} from '../utils/types'
+import {get} from '../../constants'
+import sx, {SxProp} from '../../sx'
+import {ComponentProps} from '../../utils/types'
const tabWrapperStyles = css`
display: flex;
diff --git a/src/SelectMenu/hooks/useKeyboardNav.js b/src/deprecated/SelectMenu/hooks/useKeyboardNav.js
similarity index 100%
rename from src/SelectMenu/hooks/useKeyboardNav.js
rename to src/deprecated/SelectMenu/hooks/useKeyboardNav.js
diff --git a/src/SelectMenu/index.ts b/src/deprecated/SelectMenu/index.ts
similarity index 100%
rename from src/SelectMenu/index.ts
rename to src/deprecated/SelectMenu/index.ts
diff --git a/src/_ChoiceInputLeadingVisual.tsx b/src/deprecated/_ChoiceInputLeadingVisual.tsx
similarity index 76%
rename from src/_ChoiceInputLeadingVisual.tsx
rename to src/deprecated/_ChoiceInputLeadingVisual.tsx
index beecb6e32ea..60dbf3cedb8 100644
--- a/src/_ChoiceInputLeadingVisual.tsx
+++ b/src/deprecated/_ChoiceInputLeadingVisual.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import {Slot} from './InputField/slots'
+import {Slot} from '../deprecated/InputField/slots'
const ChoiceInputLeadingVisual: React.FC = ({children}) => {children}
diff --git a/src/deprecated/index.ts b/src/deprecated/index.ts
new file mode 100644
index 00000000000..e52d8869b1c
--- /dev/null
+++ b/src/deprecated/index.ts
@@ -0,0 +1,71 @@
+/** This is the place where we keep components that are deprecated.
+ * We don't recommend using it in production.
+ * If you already use them, please move to the suggested alternative components
+ *
+ * But, they are published on npm and you can import them.
+ * example: import {FormGroup} from '@primer/react/deprecated
+ */
+
+export {default as BorderBox} from './BorderBox'
+export type {BorderBoxProps} from './BorderBox'
+export {default as ChoiceFieldset, Item} from './ChoiceFieldset'
+export {default as ChoiceInputField} from './ChoiceInputField'
+export {default as Flex} from './Flex'
+export type {FlexProps} from './Flex'
+export {default as Grid} from './Grid'
+export type {GridProps} from './Grid'
+export {default as Position, Absolute, Fixed, Relative, Sticky} from './Position'
+export type {PositionProps, AbsoluteProps, FixedProps, RelativeProps, StickyProps} from './Position'
+export {default as Dropdown} from './Dropdown'
+export type {
+ DropdownProps,
+ DropdownCaretProps,
+ DropdownButtonProps,
+ DropdownItemProps,
+ DropdownMenuProps
+} from './Dropdown'
+export {default as FormGroup} from './FormGroup'
+export type {FormGroupProps, FormGroupLabelProps} from './FormGroup'
+export {default as InputField} from './InputField'
+export {default as Label} from './Label'
+export type {LabelProps} from './Label'
+export {default as SelectMenu} from './SelectMenu'
+export type {
+ SelectMenuProps,
+ SelectMenuDividerProps,
+ SelectMenuFilterProps,
+ SelectMenuFooterProps,
+ SelectMenuItemProps,
+ SelectMenuListProps,
+ SelectMenuModalProps,
+ SelectMenuTabsProps,
+ SelectMenuHeaderProps,
+ SelectMenuTabProps,
+ SelectMenuTabPanelProps,
+ SelectMenuLoadingAnimationProps
+} from './SelectMenu'
+export {ActionList} from './ActionList'
+export type {ActionListProps} from './ActionList'
+export {ActionMenu} from './ActionMenu'
+export type {ActionMenuProps} from './ActionMenu'
+export {DropdownButton, DropdownMenu} from './DropdownMenu'
+// (copied over from src/index) not exporting new DropdownMenu types yet due to conflict with Dropdown types above
+// export type {DropdownButtonProps, DropdownMenuProps} from './DropdownMenu'
+export {
+ default as Button,
+ ButtonDanger,
+ ButtonOutline,
+ ButtonPrimary,
+ ButtonInvisible,
+ ButtonTableList,
+ ButtonClose
+} from './Button'
+export type {
+ ButtonProps,
+ ButtonDangerProps,
+ ButtonOutlineProps,
+ ButtonPrimaryProps,
+ ButtonInvisibleProps,
+ ButtonTableListProps,
+ ButtonCloseProps
+} from './Button'
diff --git a/src/drafts/index.ts b/src/drafts/index.ts
index 291e56dafbb..42fe62fe81f 100644
--- a/src/drafts/index.ts
+++ b/src/drafts/index.ts
@@ -4,11 +4,3 @@
* But, they are published on npm and you can import them for experimentation/feedback.
* example: import {ActionList} from '@primer/react/drafts
*/
-
-// Components
-export * from '../ActionList2'
-export * from '../Button2'
-export * from '../ActionMenu2'
-export * from '../DropdownMenu2'
-export * from '../Label2'
-export * from '../PageLayout'
diff --git a/src/index.ts b/src/index.ts
index 32b75833bd4..c1aa54499cc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -6,32 +6,49 @@ export {default as ThemeProvider, useTheme, useColorSchemeVar} from './ThemeProv
export type {ThemeProviderProps} from './ThemeProvider'
// Layout
-export {default as BorderBox} from './BorderBox'
-export type {BorderBoxProps} from './BorderBox'
export {default as Box} from './Box'
export type {BoxProps} from './Box'
-export {default as Flex} from './Flex'
-export type {FlexProps} from './Flex'
-export {default as Grid} from './Grid'
-export type {GridProps} from './Grid'
-export {default as Position, Absolute, Fixed, Relative, Sticky} from './Position'
-export type {PositionProps, AbsoluteProps, FixedProps, RelativeProps, StickyProps} from './Position'
+export * from './Button'
+export {PageLayout} from './PageLayout'
+export type {
+ PageLayoutProps,
+ PageLayoutHeaderProps,
+ PageLayoutContentProps,
+ PageLayoutPaneProps,
+ PageLayoutFooterProps
+} from './PageLayout'
// Hooks
export {default as useDetails} from './hooks/useDetails'
export {default as useSafeTimeout} from './hooks/useSafeTimeout'
export {useOnOutsideClick} from './hooks/useOnOutsideClick'
+export type {TouchOrMouseEvent} from './hooks/useOnOutsideClick'
export {useOpenAndCloseFocus} from './hooks/useOpenAndCloseFocus'
export {useOnEscapePress} from './hooks/useOnEscapePress'
export {useOverlay} from './hooks/useOverlay'
export {useConfirm} from './Dialog/ConfirmationDialog'
+export {useFocusTrap} from './hooks/useFocusTrap'
+export type {FocusTrapHookSettings} from './hooks/useFocusTrap'
+export {useFocusZone} from './hooks/useFocusZone'
+export type {FocusZoneHookSettings} from './hooks/useFocusZone'
// Components
export {default as Radio} from './Radio'
export type {RadioProps} from './Radio'
export {ActionList} from './ActionList'
+export type {
+ ActionListProps,
+ ActionListGroupProps,
+ ActionListItemProps,
+ ActionListLinkItemProps,
+ ActionListDescriptionProps,
+ ActionListLeadingVisualProps,
+ ActionListTrailingVisualProps
+} from './ActionList'
export {ActionMenu} from './ActionMenu'
-export type {ActionMenuProps} from './ActionMenu'
+export type {ActionMenuProps, ActionMenuAnchorProps, ActionMenuButtonProps} from './ActionMenu'
+export {AnchoredOverlay} from './AnchoredOverlay'
+export type {AnchoredOverlayProps} from './AnchoredOverlay'
export {default as Autocomplete} from './Autocomplete'
export type {AutocompleteMenuProps, AutocompleteInputProps, AutocompleteOverlayProps} from './Autocomplete'
export {default as Avatar} from './Avatar'
@@ -44,53 +61,23 @@ export {default as BranchName} from './BranchName'
export type {BranchNameProps} from './BranchName'
export {default as Breadcrumbs, Breadcrumb} from './Breadcrumbs'
export type {BreadcrumbsProps, BreadcrumbsItemProps, BreadcrumbProps, BreadcrumbItemProps} from './Breadcrumbs'
-export {
- default as Button,
- ButtonDanger,
- ButtonOutline,
- ButtonPrimary,
- ButtonInvisible,
- ButtonTableList,
- ButtonClose,
- ButtonGroup
-} from './Button'
-export type {
- ButtonProps,
- ButtonDangerProps,
- ButtonOutlineProps,
- ButtonPrimaryProps,
- ButtonInvisibleProps,
- ButtonTableListProps,
- ButtonCloseProps,
- ButtonGroupProps
-} from './Button'
+export {default as ButtonGroup} from './ButtonGroup'
+export type {ButtonGroupProps} from './ButtonGroup'
export {default as Caret} from './Caret'
-export type {CaretProps} from './Caret'
-export {default as ChoiceInputField} from './ChoiceInputField'
-export {default as CircleBadge} from './CircleBadge'
export type {CircleBadgeProps, CircleBadgeIconProps} from './CircleBadge'
export {default as CircleOcticon} from './CircleOcticon'
export type {CircleOcticonProps} from './CircleOcticon'
-export {default as ChoiceFieldset, Item} from './ChoiceFieldset'
export {default as CheckboxGroup} from './CheckboxGroup'
+export type {CaretProps} from './Caret'
+export {default as CircleBadge} from './CircleBadge'
export {default as CounterLabel} from './CounterLabel'
export type {CounterLabelProps} from './CounterLabel'
export {default as Details} from './Details'
export type {DetailsProps} from './Details'
export {default as Dialog} from './Dialog'
export type {DialogProps, DialogHeaderProps} from './Dialog'
+export type {ConfirmationDialogProps} from './Dialog/ConfirmationDialog'
export {ConfirmationDialog} from './Dialog/ConfirmationDialog'
-export {default as Dropdown} from './Dropdown'
-export type {
- DropdownProps,
- DropdownCaretProps,
- DropdownButtonProps,
- DropdownItemProps,
- DropdownMenuProps
-} from './Dropdown'
-export {DropdownButton, DropdownMenu} from './DropdownMenu'
-// not exporting new DropdownMenu types yet due to conflict with Dropdown types above
-// export type {DropdownButtonProps, DropdownMenuProps} from './DropdownMenu'
export {default as FilteredSearch} from './FilteredSearch'
export type {FilteredSearchProps} from './FilteredSearch'
export {default as FilterList} from './FilterList'
@@ -98,17 +85,14 @@ export type {FilterListProps, FilterListItemProps} from './FilterList'
export {default as Flash} from './Flash'
export type {FlashProps} from './Flash'
export {default as FormControl} from './FormControl'
-export {default as FormGroup} from './FormGroup'
-export type {FormGroupProps, FormGroupLabelProps} from './FormGroup'
export {default as Header} from './Header'
export type {HeaderProps, HeaderItemProps, HeaderLinkProps} from './Header'
export {default as Heading} from './Heading'
export type {HeadingProps} from './Heading'
-export {default as InputField} from './InputField'
-export {default as LabelGroup} from './LabelGroup'
-export type {LabelGroupProps} from './LabelGroup'
export {default as Label} from './Label'
export type {LabelProps} from './Label'
+export {default as LabelGroup} from './LabelGroup'
+export type {LabelGroupProps} from './LabelGroup'
export {default as Link} from './Link'
export type {LinkProps} from './Link'
export {default as Overlay} from './Overlay'
@@ -121,27 +105,12 @@ export {default as PointerBox} from './PointerBox'
export type {PointerBoxProps} from './PointerBox'
export {default as Popover} from './Popover'
export type {PopoverProps, PopoverContentProps} from './Popover'
-// export {default as Portal, registerPortalRoot} from './Portal'
-// export type {PortalProps} from './Portal'
+export {default as Portal, registerPortalRoot} from './Portal'
+export type {PortalProps} from './Portal'
export {default as ProgressBar} from './ProgressBar'
export type {ProgressBarProps} from './ProgressBar'
export {default as RadioGroup} from './RadioGroup'
-export {default as SelectMenu} from './SelectMenu'
export {default as Select} from './Select'
-export type {
- SelectMenuProps,
- SelectMenuDividerProps,
- SelectMenuFilterProps,
- SelectMenuFooterProps,
- SelectMenuItemProps,
- SelectMenuListProps,
- SelectMenuModalProps,
- SelectMenuTabsProps,
- SelectMenuHeaderProps,
- SelectMenuTabProps,
- SelectMenuTabPanelProps,
- SelectMenuLoadingAnimationProps
-} from './SelectMenu'
export {SelectPanel} from './SelectPanel'
export type {SelectPanelProps} from './SelectPanel'
export {default as SideNav} from './SideNav'
@@ -171,6 +140,7 @@ export type {
TimelineItemsProps
} from './Timeline'
export {default as Token, IssueLabelToken, AvatarToken} from './Token'
+export type {TokenProps} from './Token'
export {default as Tooltip} from './Tooltip'
export type {TooltipProps} from './Tooltip'
export {default as Truncate} from './Truncate'
@@ -185,3 +155,5 @@ export {default as Textarea} from './Textarea'
export type {TextareaProps} from './Textarea'
export {SSRProvider, useSSRSafeId} from './utils/ssr'
+export {default as sx, merge} from './sx'
+export type {SxProp} from './sx'
diff --git a/src/stories/ActionList2/examples.stories.tsx b/src/stories/ActionList/examples.stories.tsx
similarity index 98%
rename from src/stories/ActionList2/examples.stories.tsx
rename to src/stories/ActionList/examples.stories.tsx
index bb923be9c4f..fdf306934bd 100644
--- a/src/stories/ActionList2/examples.stories.tsx
+++ b/src/stories/ActionList/examples.stories.tsx
@@ -16,8 +16,7 @@ import {
} from '@primer/octicons-react'
import {ThemeProvider} from '../..'
-import {ActionList as _ActionList} from '../../ActionList2'
-import {Header} from '../../ActionList/Header'
+import {ActionList} from '../../ActionList'
import BaseStyles from '../../BaseStyles'
import Avatar from '../../Avatar'
import TextInput from '../../TextInput'
@@ -25,12 +24,8 @@ import Spinner from '../../Spinner'
import Box from '../../Box'
import Text from '../../Text'
-const ActionList = Object.assign(_ActionList, {
- Header
-})
-
const meta: Meta = {
- title: 'Composite components/ActionList2/examples',
+ title: 'Composite components/ActionList/examples',
component: ActionList,
decorators: [
(Story: React.ComponentType): JSX.Element => (
diff --git a/src/stories/ActionList2/fixtures.stories.tsx b/src/stories/ActionList/fixtures.stories.tsx
similarity index 98%
rename from src/stories/ActionList2/fixtures.stories.tsx
rename to src/stories/ActionList/fixtures.stories.tsx
index a7fbcddd3c9..c002bbd4d42 100644
--- a/src/stories/ActionList2/fixtures.stories.tsx
+++ b/src/stories/ActionList/fixtures.stories.tsx
@@ -28,20 +28,15 @@ import styled from 'styled-components'
import {DndProvider, useDrag, useDrop} from 'react-dnd'
import {HTML5Backend} from 'react-dnd-html5-backend'
import {Label, ThemeProvider} from '../..'
-import {ActionList as _ActionList, ItemProps} from '../../ActionList2'
-import {Header} from '../../ActionList/Header'
+import {ActionList, ActionListItemProps} from '../../ActionList'
import BaseStyles from '../../BaseStyles'
import Avatar from '../../Avatar'
-import {ButtonInvisible} from '../../Button'
+import {ButtonInvisible} from '../../deprecated/Button'
import Box from '../../Box'
import {AnchoredOverlay} from '../../AnchoredOverlay'
-const ActionList = Object.assign(_ActionList, {
- Header
-})
-
const meta: Meta = {
- title: 'Composite components/ActionList2/fixtures',
+ title: 'Composite components/ActionList/fixtures',
component: ActionList,
decorators: [
(Story: React.ComponentType): JSX.Element => (
@@ -476,14 +471,14 @@ export function LinkItemStory(): JSX.Element {
as ReactRouterLink
-
+
@@ -491,7 +486,7 @@ export function LinkItemStory(): JSX.Element {
NextJS style Link
-
+
@@ -534,9 +529,7 @@ export function CustomItemChildren(): JSX.Element {
-
- Choose this one
-
+ Choose this one
@@ -995,8 +988,8 @@ MemexSortable.storyName = 'Memex Sortable List'
type SortableItemProps = {
option: Option
- role: ItemProps['role']
- onSelect: ItemProps['onSelect']
+ role: ActionListItemProps['role']
+ onSelect: ActionListItemProps['onSelect']
reorder: ({optionToMove, moveAfterOption}: {optionToMove: Option; moveAfterOption: Option}) => void
}
const SortableItem: React.FC = ({option, role, onSelect, reorder}) => {
diff --git a/src/stories/ActionMenu2/examples.stories.tsx b/src/stories/ActionMenu/examples.stories.tsx
similarity index 97%
rename from src/stories/ActionMenu2/examples.stories.tsx
rename to src/stories/ActionMenu/examples.stories.tsx
index 8f3592d316b..5070006af39 100644
--- a/src/stories/ActionMenu2/examples.stories.tsx
+++ b/src/stories/ActionMenu/examples.stories.tsx
@@ -1,7 +1,6 @@
import React from 'react'
import {Meta} from '@storybook/react'
-import {ThemeProvider, BaseStyles, Box, Text, Avatar} from '../..'
-import {ActionMenu, ActionList} from '../../drafts'
+import {ThemeProvider, BaseStyles, Box, Text, Avatar, ActionMenu, ActionList} from '../..'
import {
GearIcon,
MilestoneIcon,
@@ -17,7 +16,7 @@ import {
} from '@primer/octicons-react'
const meta: Meta = {
- title: 'Composite components/ActionMenu2/examples',
+ title: 'Composite components/ActionMenu/examples',
component: ActionMenu,
decorators: [
(Story: React.ComponentType): JSX.Element => (
@@ -165,7 +164,7 @@ export function GroupsAndDescription(): JSX.Element {
paddingX: 0,
gridTemplateColumns: 'min-content 1fr min-content',
textAlign: 'left',
- ':hover, :focus': {background: 'none !important', color: 'accent.fg'}
+ ':hover, :focus, &[aria-expanded=true]': {background: 'none !important', color: 'accent.fg'}
}}
>
Milestone
@@ -261,7 +260,7 @@ export function MultipleSelection(): JSX.Element {
paddingX: 0,
gridTemplateColumns: 'min-content 1fr min-content',
textAlign: 'left',
- ':hover, :focus': {background: 'none !important', color: 'accent.fg'}
+ ':hover, :focus, &[aria-expanded=true]': {background: 'none !important', color: 'accent.fg'}
}}
>
Assignees
diff --git a/src/stories/ActionMenu2/fixtures.stories.tsx b/src/stories/ActionMenu/fixtures.stories.tsx
similarity index 93%
rename from src/stories/ActionMenu2/fixtures.stories.tsx
rename to src/stories/ActionMenu/fixtures.stories.tsx
index bc867f300f4..ab6876e9313 100644
--- a/src/stories/ActionMenu2/fixtures.stories.tsx
+++ b/src/stories/ActionMenu/fixtures.stories.tsx
@@ -1,7 +1,18 @@
import React from 'react'
import {Meta} from '@storybook/react'
-import {ThemeProvider, BaseStyles, Box, Text, TextInput, StyledOcticon, FormGroup} from '../..'
-import {ActionMenu, ActionList, Button, IconButton} from '../../drafts'
+import {
+ ThemeProvider,
+ BaseStyles,
+ Box,
+ Text,
+ TextInput,
+ StyledOcticon,
+ FormControl,
+ ActionMenu,
+ ActionList,
+ Button,
+ IconButton
+} from '../..'
import {
ServerIcon,
PlusCircleIcon,
@@ -25,7 +36,7 @@ import {
} from '@primer/octicons-react'
const meta: Meta = {
- title: 'Composite components/ActionMenu2/fixtures',
+ title: 'Composite components/ActionMenu/fixtures',
component: ActionMenu,
decorators: [
(Story: React.ComponentType): JSX.Element => (
@@ -302,7 +313,7 @@ const LayoutToggleItem = ({
Icon: React.ComponentType
}) => {
return (
-
-
{children}
-
-
+
+
)
}
@@ -593,30 +604,33 @@ export function OverlayProps(): JSX.Element {
Disable `onClickOutside` and `onEscape`. Only way to close is to select an action which takes focus on a
TextInput
-
- Menu
- {
- /* do nothing, keep it open*/
- }}
- onEscape={() => {
- /* do nothing, keep it open*/
- }}
- returnFocusRef={inputRef}
- >
-
- Option 1
- Option 2
- Option 2
- Option 2
- Option 2
- Option 2
- Option 2
- Option 2
-
-
-
+
+
+ Menu
+ {
+ /* do nothing, keep it open*/
+ }}
+ onEscape={() => {
+ /* do nothing, keep it open*/
+ }}
+ returnFocusRef={inputRef}
+ >
+
+ Option 1
+ Option 2
+ Option 2
+ Option 2
+ Option 2
+ Option 2
+ Option 2
+ Option 2
+
+
+
+
diff --git a/src/stories/AnchoredOverlay.stories.tsx b/src/stories/AnchoredOverlay.stories.tsx
index 54b5a63b198..1d7c1da8fc1 100644
--- a/src/stories/AnchoredOverlay.stories.tsx
+++ b/src/stories/AnchoredOverlay.stories.tsx
@@ -3,7 +3,7 @@ import {Meta} from '@storybook/react'
import {BaseStyles, Box, ThemeProvider} from '..'
import Heading from '../Heading'
-import DropdownButton from '../Button'
+import DropdownButton from '../deprecated/Button'
import {AnchoredOverlay} from '../AnchoredOverlay'
import {registerPortalRoot} from '../Portal'
diff --git a/src/stories/Autocomplete.stories.tsx b/src/stories/Autocomplete.stories.tsx
index 5946637f0b9..0968cd9691c 100644
--- a/src/stories/Autocomplete.stories.tsx
+++ b/src/stories/Autocomplete.stories.tsx
@@ -5,7 +5,7 @@ import {BaseStyles, Box, Text, TextInput, ThemeProvider} from '..'
import TextInputTokens from '../TextInputWithTokens'
import Autocomplete from '../Autocomplete/Autocomplete'
import {AnchoredOverlay} from '../AnchoredOverlay'
-import {ButtonInvisible} from '../Button'
+import {ButtonInvisible} from '../deprecated/Button'
type ItemMetadata = {
fillColor: React.CSSProperties['backgroundColor']
diff --git a/src/stories/ConfirmationDialog.stories.tsx b/src/stories/ConfirmationDialog.stories.tsx
index 69e9619f4e9..b7b25c5da3f 100644
--- a/src/stories/ConfirmationDialog.stories.tsx
+++ b/src/stories/ConfirmationDialog.stories.tsx
@@ -1,9 +1,9 @@
import React, {useState, useRef, useCallback} from 'react'
import {Meta} from '@storybook/react'
-
-import {BaseStyles, Button, Box, ThemeProvider, useTheme} from '..'
+import {BaseStyles, Box, ThemeProvider, useTheme} from '..'
+import {Button} from '../deprecated'
import {ConfirmationDialog, useConfirm} from '../Dialog/ConfirmationDialog'
-import {ActionMenu} from '../ActionMenu'
+import {ActionMenu} from '../deprecated/ActionMenu'
export default {
title: 'Internal components/ConfirmationDialog',
diff --git a/src/stories/Dialog.stories.tsx b/src/stories/Dialog.stories.tsx
index 45068cb75ae..3470e01fb59 100644
--- a/src/stories/Dialog.stories.tsx
+++ b/src/stories/Dialog.stories.tsx
@@ -1,7 +1,8 @@
import React, {useState, useRef, useCallback} from 'react'
import {Meta} from '@storybook/react'
-import {BaseStyles, Button, ThemeProvider, Box} from '..'
+import {BaseStyles, ThemeProvider, Box} from '..'
+import {Button} from '../deprecated'
import {Dialog, DialogProps, DialogWidth, DialogHeight} from '../Dialog/Dialog'
export default {
diff --git a/src/stories/DropdownMenu2/examples.stories.tsx b/src/stories/DropdownMenu2/examples.stories.tsx
deleted file mode 100644
index a461dbbf47f..00000000000
--- a/src/stories/DropdownMenu2/examples.stories.tsx
+++ /dev/null
@@ -1,246 +0,0 @@
-import React from 'react'
-import {Meta} from '@storybook/react'
-import {ThemeProvider} from '../..'
-import BaseStyles from '../../BaseStyles'
-import {DropdownMenu} from '../../DropdownMenu2'
-import {ActionList} from '../../ActionList2'
-import Box from '../../Box'
-import Text from '../../Text'
-import {
- GearIcon,
- MilestoneIcon,
- CalendarIcon,
- IterationsIcon,
- NumberIcon,
- SingleSelectIcon,
- TypographyIcon,
- IssueOpenedIcon,
- TableIcon,
- PeopleIcon,
- XIcon
-} from '@primer/octicons-react'
-
-const meta: Meta = {
- title: 'Composite components/DropdownMenu2/examples',
- component: DropdownMenu,
- decorators: [
- (Story: React.ComponentType): JSX.Element => (
-
-
-
-
-
- )
- ],
- parameters: {
- controls: {
- disabled: true
- }
- }
-}
-export default meta
-
-const fieldTypes = [
- {icon: TypographyIcon, name: 'Text'},
- {icon: NumberIcon, name: 'Number'},
- {icon: CalendarIcon, name: 'Date'},
- {icon: SingleSelectIcon, name: 'Single select'},
- {icon: IterationsIcon, name: 'Iteration'}
-]
-
-export function SingleSelection(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(0)
- const selectedType = fieldTypes[selectedIndex]
- return (
- <>
- Simple Dropdown Menu
-
- This pattern is the classic dropdown menu - single section with the selected value shown in the button
-
-
-
- {selectedType.name}
-
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}>
- {type.name}
-
- ))}
-
-
-
- >
- )
-}
-
-export function WithPlaceholder(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(-1)
- const selectedType = fieldTypes[selectedIndex] || {}
-
- return (
- <>
- With placeholder
-
- This pattern is the starting state of the dropdown menu with a placeholder when there is default value
-
-
-
- {selectedType.name || 'Pick a field type'}
-
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}>
- {type.name}
-
- ))}
-
-
-
- >
- )
-}
-
-const milestones = [
- {name: 'FY21 - Q2', due: 'December 31, 2021', progress: 90},
- {name: 'FY22 - Q3', due: 'March 31, 2022', progress: 10},
- {name: 'FY23 - Q1', due: 'June 30, 2022', progress: 0},
- {name: 'FY23 - Q2', due: 'December 30, 2022', progress: 0}
-]
-
-export function GroupsAndDescription(): JSX.Element {
- const [selectedMilestone, setSelectedMilestone] = React.useState()
-
- return (
- <>
- Milestone selector
-
-
-
- Milestone
-
-
-
-
- {milestones
- .filter(milestone => !milestone.name.includes('21'))
- .map((milestone, index) => (
- setSelectedMilestone(milestone)}
- >
-
-
-
- {milestone.name}
- Due by {milestone.due}
-
- ))}
-
-
- {milestones
- .filter(milestone => milestone.name.includes('21'))
- .map((milestone, index) => (
- setSelectedMilestone(milestone)}
- >
-
-
-
- {milestone.name}
- Due by {milestone.due}
-
- ))}
-
-
-
-
- {selectedMilestone ? (
-
- {selectedMilestone.name}
-
- ) : (
-
- No milestone
-
- )}
-
- >
- )
-}
-
-export function MixedSelection(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(1)
-
- const options = [
- {text: 'Status', icon: IssueOpenedIcon},
- {text: 'Stage', icon: TableIcon},
- {text: 'Assignee', icon: PeopleIcon},
- {text: 'Team', icon: TypographyIcon},
- {text: 'Estimate', icon: NumberIcon},
- {text: 'Due Date', icon: CalendarIcon}
- ]
-
- const selectedOption = selectedIndex && options[selectedIndex]
-
- return (
- <>
- List with mixed selection
-
-
- In this list, there is a ActionList.Group with single selection for picking one option, followed by a Item that
- is an action. This pattern appears inside a DropdownMenu for selection view options in Memex
-
-
-
-
- {selectedOption ? `Group by ${selectedOption.text}` : 'Group items by'}
-
-
-
-
- {options.map((option, index) => (
- setSelectedIndex(index)}
- >
- {option.icon}
- {option.text}
-
- ))}
-
- {typeof selectedIndex === 'number' && (
-
-
- setSelectedIndex(null)} role="menuitem">
-
-
-
- Clear Group by
-
-
- )}
-
-
-
- >
- )
-}
diff --git a/src/stories/DropdownMenu2/fixtures.stories.tsx b/src/stories/DropdownMenu2/fixtures.stories.tsx
deleted file mode 100644
index d39782e46c1..00000000000
--- a/src/stories/DropdownMenu2/fixtures.stories.tsx
+++ /dev/null
@@ -1,335 +0,0 @@
-import React from 'react'
-import {Meta} from '@storybook/react'
-import {ThemeProvider} from '../..'
-import BaseStyles from '../../BaseStyles'
-import {DropdownMenu} from '../../DropdownMenu2'
-import {ActionList} from '../../ActionList2'
-import {Button} from '../../Button2'
-import Box from '../../Box'
-import Text from '../../Text'
-import TextInput from '../../TextInput'
-import ProgressBar from '../../ProgressBar'
-import {
- GearIcon,
- MilestoneIcon,
- CalendarIcon,
- IterationsIcon,
- NumberIcon,
- SingleSelectIcon,
- TypographyIcon
-} from '@primer/octicons-react'
-
-const meta: Meta = {
- title: 'Composite components/DropdownMenu2/fixtures',
- component: DropdownMenu,
- decorators: [
- (Story: React.ComponentType): JSX.Element => (
-
-
-
-
-
- )
- ],
- parameters: {
- controls: {
- disabled: true
- }
- }
-}
-export default meta
-
-const fieldTypes = [
- {icon: TypographyIcon, name: 'Text'},
- {icon: NumberIcon, name: 'Number'},
- {icon: CalendarIcon, name: 'Date'},
- {icon: SingleSelectIcon, name: 'Single select'},
- {icon: IterationsIcon, name: 'Iteration'}
-]
-
-export function SimpleDropdownMenu(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(0)
- const selectedType = fieldTypes[selectedIndex]
- return (
- <>
- Simple Dropdown Menu
-
-
-
- {selectedType.name}
-
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}>
- {type.name}
-
- ))}
-
-
-
- >
- )
-}
-SimpleDropdownMenu.storyName = 'Simple DropdownMenu'
-
-export function Placeholder(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(-1)
- const selectedType = fieldTypes[selectedIndex] || {}
-
- return (
- <>
- With placeholder
-
-
-
- {selectedType.name || 'Pick a field type'}
-
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}>
- {type.name}
-
- ))}
-
-
-
- >
- )
-}
-Placeholder.storyName = 'Placeholder'
-
-export function MemexIteration(): JSX.Element {
- const [duration, setDuration] = React.useState(1)
-
- return (
- <>
- Memex Iteration Menu
-
-
-
- {duration} {duration > 1 ? 'weeks' : 'week'}
-
-
-
- {[1, 2, 3, 4, 5, 6].map(weeks => (
- setDuration(weeks)}>
- {weeks} {weeks > 1 ? 'weeks' : 'week'}
-
- ))}
-
-
-
- >
- )
-}
-MemexIteration.storyName = 'Memex Iteration Menu'
-
-const milestones = [
- {name: 'v29.2.0', due: 'September 30, 2021', progress: 95},
- {name: 'v30.0.0', due: 'December 1, 2021', progress: 40},
- {name: 'FY22 - Q3', due: 'December 31, 2021', progress: 10}
-]
-
-export function MemexAddColumn(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(0)
- const selectedType = fieldTypes[selectedIndex]
-
- const [duration, setDuration] = React.useState(1)
-
- return (
- <>
- Memex Add column
-
-
-
-
-
- {selectedType.name}
-
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}
- >
- {type.icon} {type.name}
-
- ))}
-
-
-
- Options
-
-
- Duration:
-
-
- {duration} {duration > 1 ? 'weeks' : 'week'}
-
-
-
- {[1, 2, 3, 4, 5, 6].map(weeks => (
- setDuration(weeks)}>
- {weeks} {weeks > 1 ? 'weeks' : 'week'}
-
- ))}
-
-
-
-
-
- >
- )
-}
-MemexAddColumn.storyName = 'Memex Add Column'
-
-export function MilestoneStory(): JSX.Element {
- const [selectedIndex, setSelectedIndex] = React.useState(-1)
-
- const selectedMilestone = milestones[selectedIndex] as typeof milestones[0] | undefined
-
- return (
- <>
- Milestone selector
-
-
-
-
-
- Milestone
-
-
-
-
-
- {milestones.map((milestone, index) => (
- setSelectedIndex(index)}
- >
-
-
-
- {milestone.name}
- Due by {milestone.due}
-
- ))}
-
-
-
- {selectedMilestone ? (
-
-
- {selectedMilestone.name}
-
- ) : (
-
- No milestone
-
- )}
-
- >
- )
-}
-MilestoneStory.storyName = 'Milestone selector'
-
-export function ControlledMenu(): JSX.Element {
- const [open, setOpen] = React.useState(false)
- const [selectedIndex, setSelectedIndex] = React.useState(0)
-
- return (
- <>
- Controlled Menu
-
- External Open State: {open ? 'Open' : 'Closed'}
- selected Value: {fieldTypes[selectedIndex].name}
-
-
- setOpen(!open)}>{open ? 'Close Menu' : 'Open Menu'}
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}>
- {type.name}
-
- ))}
-
-
-
- >
- )
-}
-ControlledMenu.storyName = 'Controlled Menu'
-
-export function ExternalAnchor(): JSX.Element {
- const [open, setOpen] = React.useState(false)
- const triggerRef = React.createRef()
- const anchorRef = React.createRef()
-
- const [selectedIndex, setSelectedIndex] = React.useState(0)
-
- return (
- <>
- External Anchor
-
- External Open State: {open ? 'Open' : 'Closed'}
- selected Value: {fieldTypes[selectedIndex].name}
-
- setOpen(!open)}>
- {open ? 'Close Menu' : 'Open Menu'}
-
-
-
- Anchored on me!
-
-
-
-
-
- {fieldTypes.map((type, index) => (
- setSelectedIndex(index)}>
- {type.name}
-
- ))}
-
-
-
- >
- )
-}
-ExternalAnchor.storyName = 'External Anchor'
diff --git a/src/stories/Label2.stories.tsx b/src/stories/Label.stories.tsx
similarity index 94%
rename from src/stories/Label2.stories.tsx
rename to src/stories/Label.stories.tsx
index 74fa851a372..8b2a5d27959 100644
--- a/src/stories/Label2.stories.tsx
+++ b/src/stories/Label.stories.tsx
@@ -2,12 +2,11 @@ import React from 'react'
import {Meta} from '@storybook/react'
import {BaseStyles, ThemeProvider} from '..'
import {ComponentProps} from '../utils/types'
-import {Label} from '../Label2'
+import Label from '../Label'
type Args = ComponentProps
export default {
- // TODO: update story nesting
title: 'Labels/Label',
component: Label,
argTypes: {
diff --git a/src/stories/Overlay.stories.tsx b/src/stories/Overlay.stories.tsx
index dd635c6338a..5d2b59f7132 100644
--- a/src/stories/Overlay.stories.tsx
+++ b/src/stories/Overlay.stories.tsx
@@ -5,26 +5,23 @@ import {TriangleDownIcon, PlusIcon, IssueDraftIcon} from '@primer/octicons-react
import {
BaseStyles,
Overlay,
- Button,
- ButtonInvisible,
- ButtonPrimary,
ButtonGroup,
Text,
- ButtonDanger,
ThemeProvider,
Box,
StyledOcticon,
Checkbox,
- ChoiceInputField,
+ FormControl,
TextInput,
- ActionList,
Link,
- Label
+ Label,
+ ActionList,
+ ActionMenu
} from '..'
+import {Button, ButtonInvisible, ButtonPrimary, ButtonDanger} from '../deprecated'
import type {AnchorSide} from '@primer/behaviors'
-import {DropdownMenu, DropdownButton} from '../DropdownMenu'
-import {ActionMenu, ActionList as ActionList2} from '../drafts'
-import {ItemInput} from '../ActionList/List'
+import {DropdownMenu, DropdownButton} from '../deprecated/DropdownMenu'
+import {ItemInput} from '../deprecated/ActionList/List'
export default {
title: 'Internal components/Overlay',
@@ -279,14 +276,14 @@ export const NestedOverlays = () => {
Add to list
-
- My stack
-
-
-
- Want to try
-
-
+
+ My stack
+
+
+
+ Want to try
+
+
@@ -367,13 +364,13 @@ export const MemexNestedOverlays = () => {
{duration}
-
+
{durations.map(item => (
- setDuration(item)}>
+ setDuration(item)}>
{item}
-
+
))}
-
+
@@ -437,7 +434,7 @@ export const MemexIssueOverlay = () => {
>
-
+
Draft
opened 2 days ago,
diff --git a/src/stories/SelectPanel.stories.tsx b/src/stories/SelectPanel.stories.tsx
index 31bd00556fd..8c6ced294ce 100644
--- a/src/stories/SelectPanel.stories.tsx
+++ b/src/stories/SelectPanel.stories.tsx
@@ -2,9 +2,9 @@ import type {OverlayProps} from '../Overlay'
import {Meta} from '@storybook/react'
import React, {useRef, useState} from 'react'
import {theme, ThemeProvider} from '..'
-import {ItemInput} from '../ActionList/List'
+import {ItemInput} from '../deprecated/ActionList/List'
import BaseStyles from '../BaseStyles'
-import {DropdownButton} from '../DropdownMenu'
+import {DropdownButton} from '../deprecated/DropdownMenu'
import {SelectPanel} from '../SelectPanel'
import Box from '../Box'
diff --git a/src/stories/ActionList.stories.tsx b/src/stories/deprecated/ActionList.stories.tsx
similarity index 97%
rename from src/stories/ActionList.stories.tsx
rename to src/stories/deprecated/ActionList.stories.tsx
index 46e21e2c660..615511ac43d 100644
--- a/src/stories/ActionList.stories.tsx
+++ b/src/stories/deprecated/ActionList.stories.tsx
@@ -14,18 +14,18 @@ import {
import {Meta} from '@storybook/react'
import React, {forwardRef} from 'react'
import styled from 'styled-components'
-import {Label, ThemeProvider} from '..'
-import {ActionList as _ActionList} from '../ActionList'
-import {Header} from '../ActionList/Header'
-import BaseStyles from '../BaseStyles'
-import sx from '../sx'
+import {Label, ThemeProvider} from '../..'
+import {ActionList as _ActionList} from '../../deprecated/ActionList'
+import {Header} from '../../deprecated/ActionList/Header'
+import BaseStyles from '../../BaseStyles'
+import sx from '../../sx'
const ActionList = Object.assign(_ActionList, {
Header
})
const meta: Meta = {
- title: 'Composite components/ActionList',
+ title: 'Deprecated components/ActionList',
component: ActionList,
decorators: [
(Story: React.ComponentType): JSX.Element => (
diff --git a/src/stories/ActionMenu.stories.tsx b/src/stories/deprecated/ActionMenu.stories.tsx
similarity index 96%
rename from src/stories/ActionMenu.stories.tsx
rename to src/stories/deprecated/ActionMenu.stories.tsx
index 5d9165b5969..1f3dd602f41 100644
--- a/src/stories/ActionMenu.stories.tsx
+++ b/src/stories/deprecated/ActionMenu.stories.tsx
@@ -13,16 +13,14 @@ import {
import {Meta} from '@storybook/react'
import React, {useCallback, useState, useRef} from 'react'
import styled from 'styled-components'
-import {ThemeProvider} from '..'
-import {ActionMenu, ActionMenuProps} from '../ActionMenu'
-import Link, {LinkProps} from '../Link'
-import Button from '../Button'
-import {ActionList, ItemProps} from '../ActionList'
-import BaseStyles from '../BaseStyles'
-import {DropdownButton} from '../DropdownMenu'
+import {ThemeProvider} from '../..'
+import Link, {LinkProps} from '../../Link'
+import {ActionMenu, ActionMenuProps, ActionList, DropdownButton, Button} from '../../deprecated'
+import {ItemProps} from '../../deprecated/ActionList'
+import BaseStyles from '../../BaseStyles'
const meta: Meta = {
- title: 'Composite components/ActionMenu',
+ title: 'Deprecated components/ActionMenu',
component: ActionMenu,
decorators: [
(Story: React.ComponentType): JSX.Element => (
diff --git a/src/stories/Button.stories.tsx b/src/stories/deprecated/Button.stories.tsx
similarity index 91%
rename from src/stories/Button.stories.tsx
rename to src/stories/deprecated/Button.stories.tsx
index b56fcd84a8a..2b107c9fa79 100644
--- a/src/stories/Button.stories.tsx
+++ b/src/stories/deprecated/Button.stories.tsx
@@ -2,23 +2,21 @@ import React from 'react'
import {Meta} from '@storybook/react'
import {
- BaseStyles,
Button,
ButtonClose,
ButtonDanger,
- ButtonGroup,
ButtonInvisible,
ButtonOutline,
ButtonPrimary,
- ButtonTableList,
- ThemeProvider
-} from '..'
+ ButtonTableList
+} from '../../deprecated'
+import {BaseStyles, ButtonGroup, ThemeProvider} from '../..'
import {ButtonStyleProps} from 'styled-system'
-import {ButtonBaseProps} from '../Button/ButtonBase'
+import {ButtonBaseProps} from '../../deprecated/Button/ButtonBase'
type StrictButtonStyleProps = ButtonStyleProps & {variant: ButtonBaseProps['variant']}
export default {
- title: 'Composite components/Button',
+ title: 'Deprecated components/Button',
decorators: [
Story => {
diff --git a/src/stories/DropdownMenu.stories.tsx b/src/stories/deprecated/DropdownMenu.stories.tsx
similarity index 88%
rename from src/stories/DropdownMenu.stories.tsx
rename to src/stories/deprecated/DropdownMenu.stories.tsx
index 1f524c0de8d..bdeaf0c3ef2 100644
--- a/src/stories/DropdownMenu.stories.tsx
+++ b/src/stories/deprecated/DropdownMenu.stories.tsx
@@ -1,14 +1,14 @@
import {Meta} from '@storybook/react'
import React from 'react'
-import {theme, ThemeProvider} from '..'
-import {ItemInput} from '../ActionList/List'
-import BaseStyles from '../BaseStyles'
-import Box from '../Box'
-import {DropdownMenu, DropdownButton} from '../DropdownMenu'
-import TextInput from '../TextInput'
+import {theme, ThemeProvider} from '../..'
+import {ItemInput} from '../../deprecated/ActionList/List'
+import BaseStyles from '../../BaseStyles'
+import Box from '../../Box'
+import {DropdownMenu, DropdownButton} from '../../deprecated'
+import TextInput from '../../TextInput'
const meta: Meta = {
- title: 'Composite components/DropdownMenu',
+ title: 'Deprecated components/DropdownMenu',
component: DropdownMenu,
decorators: [
(Story: React.ComponentType): JSX.Element => {
diff --git a/src/stories/useAnchoredPosition.stories.tsx b/src/stories/useAnchoredPosition.stories.tsx
index 093bf801efa..ff68b1b28dc 100644
--- a/src/stories/useAnchoredPosition.stories.tsx
+++ b/src/stories/useAnchoredPosition.stories.tsx
@@ -1,6 +1,7 @@
import React from 'react'
import {Meta} from '@storybook/react'
-import {BaseStyles, Box, ButtonPrimary, ThemeProvider} from '..'
+import {BaseStyles, Box, ThemeProvider} from '..'
+import {ButtonPrimary} from '../deprecated'
import {useAnchoredPosition} from '../hooks'
import styled from 'styled-components'
import {get} from '../constants'
diff --git a/src/stories/useFocusZone.stories.tsx b/src/stories/useFocusZone.stories.tsx
index 634286f17be..686ca285233 100644
--- a/src/stories/useFocusZone.stories.tsx
+++ b/src/stories/useFocusZone.stories.tsx
@@ -2,13 +2,13 @@ import React, {useCallback, useRef, useState} from 'react'
import {Meta} from '@storybook/react'
import styled, {createGlobalStyle} from 'styled-components'
-import {Box, BaseStyles, Button, Flash, theme, ThemeProvider} from '..'
+import {Box, BaseStyles, Flash, theme, ThemeProvider} from '..'
+import {Button, ButtonDanger, ButtonPrimary} from '../deprecated'
import {FocusKeys} from '@primer/behaviors'
import type {Direction} from '@primer/behaviors'
import {themeGet} from '@styled-system/theme-get'
import {useFocusZone} from '../hooks/useFocusZone'
import {useTheme} from '../ThemeProvider'
-import {ButtonDanger, ButtonPrimary} from '../Button'
export default {
title: 'Hooks/useFocusZone',