Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Action Bar - Experimental component #4233

Merged
merged 17 commits into from
Feb 26, 2024
Merged
5 changes: 5 additions & 0 deletions .changeset/old-peas-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Add a new experimental component ActionBar
8 changes: 4 additions & 4 deletions packages/react/src/UnderlineNav/UnderlineNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ export type UnderlineNavProps = {
}
// When page is loaded, we don't have ref for the more button as it is not on the DOM yet.
// However, we need to calculate number of possible items when the more button present as well. So using the width of the more button as a constant.
const MORE_BTN_WIDTH = 86
export const MORE_BTN_WIDTH = 86
// The height is needed to make sure we don't have a layout shift when the more button is the only item in the nav.
const MORE_BTN_HEIGHT = 45

// Needed this because passing a ref using HTMLULListElement to `Box` causes a type error
const NavigationList = styled.ul`
export const NavigationList = styled.ul`
${sx};
`

const MoreMenuListItem = styled.li`
export const MoreMenuListItem = styled.li`
display: flex;
align-items: center;
height: ${MORE_BTN_HEIGHT}px;
Expand Down Expand Up @@ -113,7 +113,7 @@ const overflowEffect = (
updateListAndMenu({items, menuItems}, iconsVisible)
}

const getValidChildren = (children: React.ReactNode) => {
export const getValidChildren = (children: React.ReactNode) => {
return React.Children.toArray(children).filter(child => React.isValidElement(child)) as React.ReactElement[]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ exports[`@primer/react/deprecated should not update exports without a semver cha

exports[`@primer/react/drafts should not update exports without a semver change 1`] = `
[
"type ActionBarProps",
"Blankslate",
"type BlankslateProps",
"callbackCancelledResult",
Expand All @@ -249,6 +250,7 @@ exports[`@primer/react/drafts should not update exports without a semver change
"type DataTableProps",
"default",
"default",
"default",
"Dialog",
"type DialogButtonProps",
"type DialogHeaderProps",
Expand Down Expand Up @@ -320,6 +322,7 @@ exports[`@primer/react/drafts should not update exports without a semver change

exports[`@primer/react/experimental should not update exports without a semver change 1`] = `
[
"type ActionBarProps",
"Blankslate",
"type BlankslateProps",
"callbackCancelledResult",
Expand All @@ -332,6 +335,7 @@ exports[`@primer/react/experimental should not update exports without a semver c
"type DataTableProps",
"default",
"default",
"default",
"Dialog",
"type DialogButtonProps",
"type DialogHeaderProps",
Expand Down
59 changes: 59 additions & 0 deletions packages/react/src/drafts/ActionBar/ActionBar.docs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"id": "actionbar",
"name": "ActionBar",
"status": "draft",
"a11yReviewed": false,
"stories": [],
"props": [
{
"name": "size",
"type": "'small' | 'medium' | 'large'",
"required": false,
"description": "Size of the action bar"
},
{
"name": "aria-label",
"type": "string",
"description": "When provided, a label is added to the action bar"
},
{
"name": "children",
"type": "React.ReactElement",
"required": true
}
],
"subcomponents": [
{
"name": "ActionBar.Icon",
"props": [
{
"name": "children",
"type": "React.ReactNode",
"defaultValue": "",
"required": true,
"description": "This will be the Button description."
},
{
"name": "icon",
"type": "Component",
"defaultValue": "",
"description": "provide an octicon. It will be placed in the center of the button"
},
{
"name": "aria-label",
"type": "string",
"defaultValue": "",
"description": "Use an aria label to describe the functionality of the button. Please refer to [our guidance on alt text](https://primer.style/guides/accessibility/alternative-text-for-images) for tips on writing good alternative text."
},
{
"name": "sx",
"type": "SystemStyleObject"
}
]
},
{
"name": "ActionBar.Divider",
"props": []
}
]
}
127 changes: 127 additions & 0 deletions packages/react/src/drafts/ActionBar/ActionBar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import React from 'react'
import type {Meta} from '@storybook/react'
import ActionBar from '.'
import {
BoldIcon,
CodeIcon,
ItalicIcon,
SearchIcon,
LinkIcon,
FileAddedIcon,
HeadingIcon,
QuoteIcon,
ListUnorderedIcon,
ListOrderedIcon,
TasklistIcon,
} from '@primer/octicons-react'
import {MarkdownInput} from '../MarkdownEditor/_MarkdownInput'
import {ViewSwitch} from '../MarkdownEditor/_ViewSwitch'
import type {MarkdownViewMode} from '../MarkdownEditor/_ViewSwitch'
import {Box} from '../..'

export default {
title: 'Drafts/Components/ActionBar',
} as Meta<typeof ActionBar>

export const Default = () => (
<ActionBar>
<ActionBar.IconButton icon={BoldIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={ItalicIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={CodeIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={LinkIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.Divider />
<ActionBar.IconButton icon={FileAddedIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={SearchIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={FileAddedIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={SearchIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={FileAddedIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={SearchIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={FileAddedIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={SearchIcon} aria-label="Default"></ActionBar.IconButton>
</ActionBar>
)

export const SmallActionBar = () => (
<ActionBar size="small">
<ActionBar.IconButton icon={BoldIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={ItalicIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={CodeIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={LinkIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.Divider />
<ActionBar.IconButton icon={FileAddedIcon} aria-label="Default"></ActionBar.IconButton>
<ActionBar.IconButton icon={SearchIcon} aria-label="Default"></ActionBar.IconButton>
</ActionBar>
)

export const CommentBox = () => {
const [view, setView] = React.useState<MarkdownViewMode>('edit')
const loadPreview = React.useCallback(() => {
//console.log('loadPreview')
}, [])
const [value, setValue] = React.useState('')
return (
<Box
sx={{
maxWidth: 800,
display: 'flex',
flexDirection: 'column',
width: '100%',
borderColor: 'border.default',
borderWidth: 1,
borderStyle: 'solid',
borderRadius: 2,
minInlineSize: 'auto',
bg: 'canvas.default',
color: 'fg.default',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'row',
backgroundColor: 'canvas.subtle',
borderTopLeftRadius: 2,
borderTopRightRadius: 2,
justifyContent: 'space-between',
}}
as="header"
>
<Box sx={{width: '50%'}}>
<ViewSwitch
selectedView={view}
onViewSelect={setView}
//disabled={fileHandler?.uploadProgress !== undefined}
onLoadPreview={loadPreview}
/>
</Box>
<Box sx={{width: '50%'}}>
<ActionBar>
<ActionBar.IconButton icon={HeadingIcon} aria-label="Heading"></ActionBar.IconButton>
<ActionBar.IconButton icon={BoldIcon} aria-label="Bold"></ActionBar.IconButton>
<ActionBar.IconButton icon={ItalicIcon} aria-label="Italic"></ActionBar.IconButton>
<ActionBar.IconButton icon={CodeIcon} aria-label="Insert Code"></ActionBar.IconButton>
<ActionBar.IconButton icon={LinkIcon} aria-label="Insert Link"></ActionBar.IconButton>
<ActionBar.Divider />
<ActionBar.IconButton icon={QuoteIcon} aria-label="Insert Quote"></ActionBar.IconButton>
<ActionBar.IconButton icon={ListUnorderedIcon} aria-label="Unordered List"></ActionBar.IconButton>
<ActionBar.IconButton icon={ListOrderedIcon} aria-label="Ordered List"></ActionBar.IconButton>
<ActionBar.IconButton icon={TasklistIcon} aria-label="Task List"></ActionBar.IconButton>
</ActionBar>
</Box>
</Box>
<MarkdownInput
value={value}
visible={view === 'edit'}
onChange={e => {
setValue(e.target.value)
}}
id={'markdowninput'}
isDraggedOver={false}
minHeightLines={5}
maxHeightLines={35}
monospace={false}
pasteUrlsAsPlainText={false}
/>
</Box>
)
}
Loading
Loading