v35.0.0
版本发布时间: 2022-03-10 05:23:22
primer/react最新发布版本:@primer/react@37.0.0-rc.10(2024-10-09 16:43:51)
Major Changes
-
#1910
e1e8d478
Thanks @colebemis! -ActionList2
exported types are now prefixed withActionList
:ListProps → ActionListProps GroupProps → ActionListGroupProps ItemProps → ActionListItemProps DescriptionProps → ActionListDescriptionProps LeadingVisualProps → ActionListLeadingVisualProps, TrailingVisualProps → ActionListTrailingVisualProps
ActionMenu2
exported types are now prefixed withActionMenu
:MenuButtonProps → ActionMenuButtonProps MenuAnchorProps → ActionMenuAnchorProps
-
#1910
e1e8d478
Thanks @colebemis! -ActionList
ActionList has been rewritten with a composable API, design updates and accessibility fixes.
See full list of props and examples: https://primer.style/react/ActionList
Before (v34) After (v35) <ActionList items={[ {text: 'New file'}, {text: 'Copy link'}, {text: 'Edit file'}, ActionList.Divider, {text: 'Delete file', variant: 'danger'} ]} />
<ActionList> <ActionList.Item>New file</ActionList.Item> <ActionList.Item>Copy link</ActionList.Item> <ActionList.Item>Edit file</ActionList.Item> <ActionList.Divider /> <ActionList.Item variant="danger">Delete file</ActionList.Item> </ActionList>
<ActionList showItemDividers items={[ { key: '0', leadingVisual: LinkIcon, text: 'github/primer' }, { key: '1', leadingVisual: () => <Avatar src="https://github.com/mona.png" />, text: 'mona', description: 'Monalisa Octocat', descriptionVariant: 'block' }, { key: '2', leadingVisual: GearIcon, text: 'View Settings', trailingVisual: ArrowRightIcon } ]} />
<ActionList showDividers> <ActionList.Item> <ActionList.LeadingVisual> <LinkIcon /> </ActionList.LeadingVisual> github/primer </ActionList.Item> <ActionList.Item> <ActionList.LeadingVisual> <Avatar src="https://github.com/mona.png" /> </ActionList.LeadingVisual> mona <ActionList.Description variant="block">Monalisa Octocat</ActionList.Description> </ActionList.Item> <ActionList.Item> <ActionList.LeadingVisual> <GearIcon /> </ActionList.LeadingVisual> View settings <ActionList.TrailingVisual> <ArrowRightIcon /> </ActionList.TrailingVisual> </ActionList.Item> </ActionList>
<ActionList groupMetadata={[ {groupId: '0', header: {title: 'Live query'}}, {groupId: '1', header: {title: 'Layout'}} ]} items={[ {key: '0', text: 'repo:github/github', groupId: '0'}, {key: '1', text: 'Table', groupId: '1'}, {key: '2', text: 'Board', groupId: '1'}, {key: '3', text: 'View settings'} ]} />
<ActionList> <ActionList.Group title="Live query"> <ActionList.Item>repo:github/github</ActionList.Item> </ActionList.Group> <ActionList.Divider /> <ActionList.Group title="Layout"> <ActionList.Item>Table</ActionList.Item> <ActionList.Item>Board Description</ActionList.Item> </ActionList.Group> <ActionList.Divider /> <ActionList.Item>View settings</ActionList.Item> </ActionList>
To continue to use the deprecated API for now, change the import path to
@primer/react/deprecated
:import {ActionList} from '@primer/react/deprecated'
You can use the one-time codemod to change your import statements automatically.
-
#1910
e1e8d478
Thanks @colebemis! -ActionMenu
ActionMenu has been rewritten with a composable API, design updates and accessibility fixes.
See full list of props and examples: https://primer.style/react/ActionMenu
Main changes:
- Instead of using
items
prop, useActionList
insideActionMenu
- Instead of using
anchorContent
onActionMenu
, useActionMenu.Button
withchildren
- Instead of using
onAction
prop onActionMenu
, useonSelect
prop onActionList.Item
- Instead of using
groupMetadata
onActionMenu
, useActionList.Group
- Instead of
overlayProps
onActionMenu
, useActionMenu.Overlay
Before (v34) After (v35) <ActionMenu anchorContent="Menu" onAction={fn} items={[ {text: 'New file'}, {text: 'Copy link'}, {text: 'Edit file'}, ActionMenu.Divider, {text: 'Delete file', variant: 'danger'} ]} overlayProps={{width: 'small'}} />
<ActionMenu> <ActionMenu.Button>Menu</ActionMenu.Button> <ActionMenu.Overlay width="small"> <ActionList> <ActionList.Item onSelect={fn}>New file</ActionList.Item> <ActionList.Item>Copy link</ActionList.Item> <ActionList.Item>Edit file</ActionList.Item> <ActionList.Divider /> <ActionList.Item variant="danger">Delete file</ActionList.Item> </ActionList> </ActionMenu.Overlay> </ActionMenu>
To continue to use the deprecated API for now, change the import path to
@primer/react/deprecated
:import {ActionMenu} from '@primer/react/deprecated'
You can use the one-time codemod to change your import statements automatically.
- Instead of using
-
#1910
e1e8d478
Thanks @colebemis! -DropdownMenu
DropdownMenu has been deprecated in favor of ActionMenu with ActionList
See example with selection: https://primer.style/react/ActionMenu#with-selection
Migration guide:
- Instead of using
items
prop, useActionList
insideActionMenu
- Use
selectionVariant="single"
onActionList
to set the right semantics for selection - Instead of using
selectedItem
prop, useselected
prop onActionList.Item
- Instead of using
renderAnchor
andplaceholder
props onDropdownMenu
, useActionMenu.Button
orActionMenu.Anchor
- Instead of using
onChange
prop onDropdownMenu
, useonSelect
prop onActionList.Item
- Instead of using
groupMetadata
onDropdownMenu
, useActionList.Group
- Instead of
overlayProps
onDropdownMenu
, useActionMenu.Overlay
Before (v34) After (v35) const fieldTypes = [ {key: 0, text: 'Text'}, {key: 1, text: 'Number'}, {key: 3, text: 'Date'}, {key: 4, text: 'Single select'}, {key: 5, text: 'Iteration'} ] const Example = () => { const [selectedType, setSelectedType] = React.useState() return ( <DropdownMenu renderAnchor={({children, ...anchorProps}) => ( <ButtonInvisible {...anchorProps}> {children} <GearIcon /> </ButtonInvisible> )} placeholder="Field type" items={fieldTypes} selectedItem={selectedType} onChange={setSelectedType} overlayProps={{width: 'medium'}} /> ) }
const fieldTypes = [ {id: 0, text: 'Text'}, {id: 1, text: 'Number'}, {id: 3, text: 'Date'}, {id: 4, text: 'Single select'}, {id: 5, text: 'Iteration'} ] const Example = () => { const [selectedType, setSelectedType] = React.useState() render( <ActionMenu> <ActionMenu.Button aria-label="Select field type">{selectedType.name || 'Field type'}</ActionMenu.Button> <ActionMenu.Overlay width="medium"> <ActionList selectionVariant="single"> {fieldTypes.map(type => ( <ActionList.Item key={type.id} selected={type.id === selectedType.id} onSelect={() => setSelectedType(type)} > {type.name} </ActionList.Item> ))} </ActionList> </ActionMenu.Overlay> </ActionMenu> ) }
To continue to use the deprecated API for now, change the import path to
@primer/react/deprecated
:import {DropdownMenu} from '@primer/react/deprecated'
You can use the one-time codemod to change your import statements automatically.
drafts/DropdownMenu2
DropdownMenu2 has been removed in favor of ActionMenu with ActionList
- Instead of using
-
#1910
e1e8d478
Thanks @colebemis! -Label
The Label component's API and visual design have been updated to be consistent with its counterpart in Primer ViewComponents' Label component.
Major changes in the new Label component:
- No more
medium
size - onlysmall
andlarge
- Labels are outlined by default, so the
outline
prop has been removed - Custom text and background colors are discouraged, but still possible via the
sx
prop
If you were using the
Label
component to render issue/PR labels, use the IssueLabelToken component instead.Before (v34) After (v35) import {Label} from '@primer/react' function Example() { return ( <> <Label outline>default</Label> <Label variant="small" outline sx={{borderColor: 'danger.emphasis', color: 'danger.fg'}}> danger </Label> </> ) }
import {Label} from '@primer/react' function Example() { return ( <> <Label>default</Label> <Label size="small" variant="danger"> danger </Label> </> ) }
To continue to use the deprecated API for now, change the import path to
@primer/react/deprecated
:import {Label} from '@primer/react/deprecated'
You can use the one-time codemod to change your import statements automatically.
- No more
-
#1910
e1e8d478
Thanks @colebemis! -Button
Before
v35
,Button
was a set of seven independent components. Inv35
, we've simplified theButton
API.Button variants
We now support a variant property which takes values
primary
,invisible
,outline
anddanger
Before (v34) After (v35) import {ButtonPrimary, ButtonInvisible, ButtonOutline, ButtonDanger} from '@primer/react' function Example() { return ( <> <ButtonPrimary>Primary Button</ButtonPrimary> <ButtonInvisible>Invisible Button</ButtonInvisible> <ButtonOutline>Outline Button</ButtonOutline> <ButtonDanger>Danger Button</ButtonDanger> </> ) }
import {Button} from '@primer/react' function Example() { return ( <> <Button variant="primary">Primary Button</Button> <Button variant="invisible">Invisible Button</Button> <Button variant="outline">Outline Button</Button> <Button variant="danger">Danger Button</Button> </> ) }
Leading and trailing icons
Previously including icons inside buttons required a lot of custom styling. In the new
Button
component, we now support first-classleadingIcon
andtrailingIcon
props:Before (v34) After (v35) <Button> <SearchIcon /> Search </Button>
<Button leadingIcon={SearchIcon}>Search</Button>
Icon buttons
Icon-only buttons are common in many applications. We now have a component designed for this use-case:
Before (v34) After (v35) <Button> <XIcon /> </Button>
<IconButton aria-label="Close button" icon={XIcon} />
Size property
Previously, we used a
variant
prop to set the size of buttons. We now have a prop calledsize
which is more semantically correct.Before (v34) After (v35) <Button variant="small">Small button</Button>
<Button size="small">Small button</Button>
-
#1910
e1e8d478
Thanks @colebemis! -ChoiceFieldset
The
CheckboxGroup
andRadioGroup
components are replacing theChoiceFieldset
component.CheckboxGroup
andRadioGroup
have the ability to render contextual content with your fieldset: labels, validation statuses, captions. They also handle the ARIA attributes that make the form controls accessible to assistive technology.Before (v34) After (v35) import {ChoiceFieldset} from '@primer/react' function Example() { return ( <> {/* Multi-select */} <ChoiceFieldset> <ChoiceFieldset.Legend>Preferred Primer component interface</ChoiceFieldset.Legend> <ChoiceFieldset.List selectionVariant="multiple"> <ChoiceFieldset.Item value="figma">Figma library</ChoiceFieldset.Item> <ChoiceFieldset.Item value="css">Primer CSS</ChoiceFieldset.Item> <ChoiceFieldset.Item value="react">Primer React components</ChoiceFieldset.Item> <ChoiceFieldset.Item value="viewcomponents">Primer ViewComponents</ChoiceFieldset.Item> </ChoiceFieldset.List> </ChoiceFieldset> {/* Single select */} <ChoiceFieldset> <ChoiceFieldset.Legend>Preferred Primer component interface</ChoiceFieldset.Legend> <ChoiceFieldset.List> <ChoiceFieldset.Item value="figma">Figma library</ChoiceFieldset.Item> <ChoiceFieldset.Item value="css">Primer CSS</ChoiceFieldset.Item> <ChoiceFieldset.Item value="react">Primer React components</ChoiceFieldset.Item> <ChoiceFieldset.Item value="viewcomponents">Primer ViewComponents</ChoiceFieldset.Item> </ChoiceFieldset.List> </ChoiceFieldset> </> ) }
import {CheckboxGroup, RadioGroup, FormControl, Checkbox, Radio} from '@primer/react' function Example() { return ( <> {/* Multi-select */} <CheckboxGroup> <CheckboxGroup.Label>Preferred Primer component interface</CheckboxGroup.Label> <FormControl> <Checkbox value="figma" /> <FormControl.Label>Figma</FormControl.Label> </FormControl> <FormControl> <Checkbox value="css" /> <FormControl.Label>CSS</FormControl.Label> </FormControl> <FormControl> <Checkbox value="react" /> <FormControl.Label>Primer React components</FormControl.Label> </FormControl> <FormControl> <Checkbox value="viewcomponents" /> <FormControl.Label>Primer ViewComponents</FormControl.Label> </FormControl> </CheckboxGroup> {/* Single select */} <RadioGroup name="preferred-primer"> <RadioGroup.Label>Preferred Primer component interface</RadioGroup.Label> <FormControl> <Radio value="figma" /> <FormControl.Label>Figma</FormControl.Label> </FormControl> <FormControl> <Radio value="css" /> <FormControl.Label>CSS</FormControl.Label> </FormControl> <FormControl> <Radio value="react" /> <FormControl.Label>Primer React components</FormControl.Label> </FormControl> <FormControl> <Radio value="viewcomponents" /> <FormControl.Label>Primer ViewComponents</FormControl.Label> </FormControl> </RadioGroup> </> ) }
To continue to use the deprecated API for now, change the import path to
@primer/react/deprecated
:import {ChoiceFieldset} from '@primer/react/deprecated'
You can use the one-time codemod to change your import statements automatically.
-
#1910
e1e8d478
Thanks @colebemis! -PageLayout
PageLayout
is being graduated from thedrafts
bundle to themain
bundle.To upgrade, rewrite your imports accordingly:
- import {PageLayout} from '@primer/react/drafts' + import {PageLayout} from '@primer/react'
-
#1910
e1e8d478
Thanks @colebemis! -FormGroup, InputField, ChoiceInputField
The
FormControl
component is replacing theFormGroup
,InputField
, andChoiceInputField
components. It has the ability to render contextual content with your inputs: labels, validation statuses, captions. It also handles the ARIA attributes that make the form controls accessible to assistive technology.Before (v34) After (v35) import {FormControl, Checkbox, TextInput} from '@primer/react' function Example() { return ( <> <FormGroup> <FormGroup.Label htmlFor="example-text">Example text</FormGroup.Label> <TextInput id="example-text" /> </FormGroup> {/* OR */} <InputField> <InputField.Label>Example text</InputField.Label> <TextInput /> </InputField> {/* OR */} <ChoiceInputField> <ChoiceInputField.Label>Example text</ChoiceInputField.Label> <Checkbox /> </ChoiceInputField> </> ) }
import {FormGroup, TextInput} from '@primer/react' function Example() { return ( <> <FormControl> <FormControl.Label>Example text</FormControl.Label> <TextInput /> </FormControl> {/* OR */} <FormControl> <FormControl.Label>Example text</FormControl.Label> <Checkbox /> </FormControl> </> ) }
import {InputField, TextInput} from '@primer/react' function Example() { return ( <InputField> <InputField.Label>Example text</InputField.Label> <TextInput /> </InputField> ) }
import {FormControl, TextInput} from '@primer/react' function Example() { return ( <FormControl> <FormControl.Label>Example text</FormControl.Label> <TextInput /> </FormControl> ) }
To continue to use the deprecated API for now, change the import path to
@primer/react/deprecated
:import {FormGroup, ChoiceInputField, InputField} from '@primer/react/deprecated'
You can use the one-time codemod to change your import statements automatically.
-
#1910
e1e8d478
Thanks @colebemis! -SelectMenu
⚠️
SelectMenu
has been deprecated. Please useActionMenu
instead.Before After <SelectMenu> <Button as="summary">Projects</Button> <SelectMenu.Modal> <SelectMenu.Header>Projects</SelectMenu.Header> <SelectMenu.List> <SelectMenu.Item href="#">Primer React bugs</SelectMenu.Item> <SelectMenu.Item href="#">Primer React roadmap</SelectMenu.Item> <SelectMenu.Item href="#">Project 3</SelectMenu.Item> <SelectMenu.Item href="#">Project 4</SelectMenu.Item> </SelectMenu.List> </SelectMenu.Modal> </SelectMenu>
<ActionMenu> <ActionMenu.Button>Projects</ActionMenu.Button> <ActionMenu.Overlay> <ActionList showDividers> <ActionList.Group title="Projects"> <ActionList.Item>Primer React bugs</ActionList.Item> <ActionList.Item>Primer React roadmap</ActionList.Item> <ActionList.Item>Project three</ActionList.Item> <ActionList.Item>Project four</ActionList.Item> </ActionList.Group> </ActionList> </ActionMenu.Overlay> </ActionMenu>
See https://primer.style/react/ActionMenu for more migration examples.
Dropdown
⚠️
Dropdown
has been deprecated. Please useActionMenu
instead.Before After const fieldTypes = [ {leadingVisual: TypographyIcon, text: 'Text'}, {leadingVisual: NumberIcon, text: 'Number'} ] const Example = () => { const [selectedItem, setSelectedItem] = React.useState() return ( <DropdownMenu renderAnchor={({children, ...anchorProps}) => <ButtonInvisible {...anchorProps}>{children}</ButtonInvisible>} placeholder="Select a field type" items={fieldTypes} selectedItem={selectedItem} onChange={() => setSelectedIndex(index)} /> ) }
const fieldTypes = [ {icon: <TypographyIcon />, name: 'Text'}, {icon: <NumberIcon />, name: 'Number'} ] const Example = () => { const [selectedItem, setSelectedItem] = React.useState() return ( <ActionMenu> <ActionMenu.Button>{selectedItem ? selectedItem.name : 'Select a field type'}</ActionMenu.Button> <ActionMenu.Overlay> <ActionList selectionVariant="single"> {fieldTypes.map(field => ( <ActionList.Item onSelect={() => setSelectedItem(field)} key={field.name}> <ActionList.LeadingVisual>{field.icon}</ActionList.LeadingVisual> {field.name} </ActionList.Item> ))} </ActionList> </ActionMenu.Overlay> </ActionMenu> ) }
See https://primer.style/react/ActionMenu for more migration examples.
Flex
⚠️
Flex
has been deprecated. Please useBox
instead.Before After <Flex flexWrap="nowrap"> <Box p={3} color="fg.onEmphasis" bg="accent.emphasis"> Item 1 </Box> </Flex>
<Box display="flex" flexWrap="nowrap"> <Box p={3} color="fg.onEmphasis" bg="accent.emphasis"> Item 1 </Box> </Box>
Grid
⚠️
Grid
has been deprecated. Please useBox
instead.Before After <Grid gridTemplateColumns="repeat(2, auto)" gridGap={3}> <Box p={3} color="fg.onEmphasis" bg="accent.emphasis"> 1 </Box> <Box p={3} color="fg.onEmphasis" bg="attention.emphasis"> 2 </Box> </Grid>
<Box display="grid" gridTemplateColumns="repeat(2, auto)" gridGap={3}> <Box p={3} color="fg.onEmphasis" bg="accent.emphasis"> 1 </Box> <Box p={3} color="fg.onEmphasis" bg="attention.emphasis"> 2 </Box> </Box>
BorderBox
⚠️
BorderBox
has been deprecated. Please useBox
instead.Before After <BorderBox>Item 1</BorderBox>
<Box borderWidth="1px" borderStyle="solid" borderColor="border.default" borderRadius={2}> Item 1 </Box>
Position
⚠️
Position
has been deprecated. Please useBox
instead.Before After <> <Position position="absolute">...</Position> <Absolute>...</Absolute> <Relative>...</Relative> <Fixed>...</Fixed> <Sticky>...</Sticky> </>
<> <Box position="absolute">...</Box> <Box position="absolute">...</Box> <Box position="relative">...</Box> <Box position="fixed">...</Box> <Box position="sticky">...</Box> </>
Minor Changes
-
#1910
e1e8d478
Thanks @colebemis! - Add align prop on ActionMenu.Overlay to pass through to AnchoredOverlay
Patch Changes
-
#1910
e1e8d478
Thanks @colebemis! - ActionMenu.Button: Fix spacing between text and caret -
#1910
e1e8d478
Thanks @colebemis! - - Update styles for default variant of Button's active state- Use active state for Button when it is used to open an Overlay
-
#1910
e1e8d478
Thanks @colebemis! - Surfaced the following components and hooks from the root index:- Portal
- AnchoredOverlay
- useFocusTrap
- useFocusZone (and types)
- sx (and types)
- ConfirmationDialogProps
These exports can now be imported from the root index, rather than from their nested subfolders.
E.g.
- import { ConfirmationDialogProps } from '@primer/react/lib-esm/Dialog/ConfirmationDialog'; + import { ConfirmationDialogProps } from '@primer/react';