-
Notifications
You must be signed in to change notification settings - Fork 217
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
feat(action-bar): Refactor ActionBar component #1396
Changes from 9 commits
6239925
b4acd4d
89f6a1f
658029f
bc11ed1
9065cd4
aa859e2
a305ddd
4de8686
07c1b33
6ce5bcb
9f94d91
4e0ff55
b045b99
07580cd
801597a
d583fdc
c5f898a
d97852a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import {API, FileInfo, Options, JSXElement} from 'jscodeshift'; | ||
import {getImportRenameMap} from './utils/getImportRenameMap'; | ||
|
||
export default function transformer(file: FileInfo, api: API, options: Options) { | ||
const j = api.jscodeshift; | ||
|
||
const root = j(file.source); | ||
|
||
const {containsCanvasImports, importMap, styledMap} = getImportRenameMap( | ||
j, | ||
root, | ||
'@workday/canvas-kit-react/action-bar' | ||
); | ||
|
||
if (!containsCanvasImports) { | ||
return file.source; | ||
} | ||
|
||
root | ||
.find( | ||
j.JSXElement, | ||
(value: JSXElement) => | ||
value.openingElement.name.type === 'JSXIdentifier' && | ||
(value.openingElement.name.name === importMap.ActionBar || | ||
value.openingElement.name.name === styledMap.ActionBar) | ||
) | ||
.forEach(nodePath => { | ||
const attributes = nodePath.value.openingElement.attributes; | ||
|
||
if (attributes) { | ||
// remove these attributes from ActionBar | ||
nodePath.value.openingElement.attributes = attributes.filter(item => | ||
item.type === 'JSXAttribute' && | ||
item.name.type === 'JSXIdentifier' && | ||
['fixed'].includes(item.name.name) | ||
? false | ||
: true | ||
); | ||
} | ||
}); | ||
|
||
return root.toSource(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import {expectTransformFactory} from './expectTransformFactory'; | ||
import transform from '../compoundActionBar'; | ||
import {stripIndent} from 'common-tags'; | ||
|
||
const expectTransform = expectTransformFactory(transform); | ||
|
||
describe('ActionBar', () => { | ||
it('should restructure ActionBar usages with props', () => { | ||
const input = stripIndent` | ||
import {ActionBar} from '@workday/canvas-kit-react/action-bar' | ||
|
||
<ActionBar fixed="true" /> | ||
`; | ||
|
||
const expected = stripIndent` | ||
import {ActionBar} from '@workday/canvas-kit-react/action-bar' | ||
|
||
<ActionBar /> | ||
`; | ||
|
||
expectTransform(input, expected); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,6 @@ | ||
# Canvas Kit Action Bar | ||
# Canvas Kit React Action Bar | ||
|
||
Full width toolbar fixed to bottom of screen. | ||
`ActionBar` contains primary and secondary actions related to a page or task. | ||
|
||
Although not required, [buttons](../../button/react) are often used in in action bars. The primary | ||
action button should be left aligned followed by secondary buttons. The primary button is on the | ||
right only in task orchestration and on mobile devices. | ||
|
||
## Installation | ||
|
||
```sh | ||
yarn add @workday/canvas-kit-react | ||
``` | ||
|
||
## Usage | ||
|
||
```tsx | ||
import * as React from 'react'; | ||
import {PrimaryButton, SecondaryButton} from '@workday/canvas-kit-react/button'; | ||
import {ActionBar} from '@workday/canvas-kit-react/action-bar'; | ||
|
||
<ActionBar> | ||
<PrimaryButton variant="primary">Button</PrimaryButton> | ||
<SecondaryButton>Button</SecondaryButton> | ||
<SecondaryButton>Button</SecondaryButton> | ||
</ActionBar>; | ||
``` | ||
|
||
## Static Properties | ||
|
||
> None | ||
|
||
## Component Props | ||
|
||
### Required | ||
|
||
> None | ||
|
||
### Optional | ||
|
||
#### `fixed: boolean` | ||
|
||
> Fixes the toolbar to the bottom of the window (uses `position: fixed`) | ||
|
||
## Responsive Behavior | ||
|
||
At 575px, responsive styles will take effect: | ||
|
||
- Applies a flex box to the buttons | ||
- Makes single-button groups full width | ||
- All buttons will become the same width (`flex: 1`). | ||
- Button order will become reversed, making left-aligned primary buttons right-aligned. | ||
|
||
> When on a mobile form factor, the button placement should flip to have the primary button on the | ||
> far right. | ||
For more detailed information on this component, please refer to the | ||
[storybook documentation](https://workday.github.io/canvas-kit/?path=/docs/components-buttons-action-bar-react--basic) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1 @@ | ||
import ActionBar from './lib/ActionBar'; | ||
|
||
export default ActionBar; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WIll the codemod also update any default imports to named imports? E.g. import ActionBar from '@workday/canvas-kit-react/action-bar'; becomes this: import { ActionBar } from '@workday/canvas-kit-react/action-bar'; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for catching it! I've updated existing codemod to add a script that changes default import to named or renamed import from |
||
export {ActionBar}; | ||
export * from './lib/ActionBar'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,55 @@ | ||
import * as React from 'react'; | ||
import {styled} from '@workday/canvas-kit-react/common'; | ||
import {colors, commonColors, space, CSSProperties} from '@workday/canvas-kit-react/tokens'; | ||
import {Globals} from 'csstype'; | ||
import {createComponent, styled, StyledType} from '@workday/canvas-kit-react/common'; | ||
import {commonColors, colors, space} from '@workday/canvas-kit-react/tokens'; | ||
import {HStack, HStackProps} from '@workday/canvas-kit-labs-react'; | ||
|
||
export interface ActionBarProps extends React.HTMLAttributes<HTMLDivElement> { | ||
type PropertyPosition = | ||
| Globals | ||
| '-webkit-sticky' | ||
| 'absolute' | ||
| 'fixed' | ||
| 'relative' | ||
| 'static' | ||
| 'sticky'; | ||
|
||
export interface ActionBarProps { | ||
/** | ||
* If true, fix the ActionBar to the bottom of the screen. | ||
* @default false | ||
* Sets the position for the container | ||
* @default "fixed" | ||
*/ | ||
fixed?: boolean; | ||
} | ||
|
||
function getFixedStyles(fixed = false): CSSProperties { | ||
return fixed | ||
? { | ||
position: 'fixed', | ||
left: 0, | ||
bottom: 0, | ||
right: 0, | ||
} | ||
: {}; | ||
position?: PropertyPosition; | ||
} | ||
|
||
const ActionBarContainer = styled('div')<ActionBarProps>( | ||
{ | ||
borderTop: `solid 1px ${colors.soap400}`, | ||
background: commonColors.background, | ||
const ResponsiveHStack = styled(HStack)<HStackProps & StyledType>(({theme}) => ({ | ||
[theme.canvas.breakpoints.down('s')]: { | ||
padding: space.s, | ||
boxShadow: '0 -2px 4px rgba(0, 0, 0, 0.08)', | ||
}, | ||
({fixed, theme}) => { | ||
return { | ||
...getFixedStyles(fixed), | ||
[theme.canvas.breakpoints.down('s')]: { | ||
padding: space.xxs, | ||
}, | ||
}; | ||
} | ||
); | ||
|
||
const ChildrenContainer = styled('div')( | ||
{ | ||
display: 'inline-block', | ||
padding: `0 ${space.m}`, | ||
'*:not(:first-of-type)': { | ||
marginLeft: space.s, | ||
'> *:not(div)': { | ||
flex: 1, | ||
}, | ||
}, | ||
({theme}) => ({ | ||
[theme.canvas.breakpoints.down('s')]: { | ||
display: 'flex', | ||
padding: space.xxs, | ||
justifyContent: 'center', | ||
flexDirection: 'row-reverse', | ||
'> *': { | ||
flex: 1, | ||
'&:not(:first-of-type)': { | ||
marginRight: space.s, | ||
marginLeft: 0, | ||
}, | ||
}, | ||
}, | ||
}) | ||
); | ||
})); | ||
|
||
export default class ActionBar extends React.Component<ActionBarProps> { | ||
public render() { | ||
const {fixed, children, ...elemProps} = this.props; | ||
const containerStyles: Omit<HStackProps, 'spacing'> = { | ||
background: commonColors.background, | ||
borderTop: `solid 1px ${colors.soap400}`, | ||
bottom: 0, | ||
depth: 1, | ||
left: 0, | ||
padding: `${space.s} ${space.xl} `, | ||
width: '100%', | ||
}; | ||
|
||
return ( | ||
<ActionBarContainer {...elemProps} fixed={fixed}> | ||
<ChildrenContainer>{children}</ChildrenContainer> | ||
</ActionBarContainer> | ||
); | ||
} | ||
} | ||
export const ActionBar = createComponent('div')({ | ||
displayName: 'ActionBar', | ||
Component: ({position = 'fixed', ...elProps}: ActionBarProps, ref, Element) => ( | ||
<ResponsiveHStack | ||
ref={ref} | ||
as={Element} | ||
position={position} | ||
spacing="s" | ||
{...containerStyles} | ||
{...elProps} | ||
/> | ||
), | ||
}); | ||
RayRedGoose marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,5 @@ | ||
import * as React from 'react'; | ||
import {mount} from 'enzyme'; | ||
import ActionBar from '../index'; | ||
import {ActionBar} from '../lib/ActionBar'; | ||
|
||
describe('ActionBar', () => { | ||
const cb = jest.fn(); | ||
afterEach(() => { | ||
cb.mockReset(); | ||
}); | ||
|
||
test('render a action bar with id', () => { | ||
const component = mount(<ActionBar id="myActionBar">Button Label</ActionBar>); | ||
expect(component.find(ActionBar).props().id).toBe('myActionBar'); | ||
component.unmount(); | ||
}); | ||
|
||
test('ActionBar should spread extra props', () => { | ||
const component = mount(<ActionBar data-propspread="test" />); | ||
const container = component.at(0).getDOMNode(); | ||
expect(container.getAttribute('data-propspread')).toBe('test'); | ||
component.unmount(); | ||
}); | ||
verifyComponent(ActionBar, {}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two questions:
import ActionBar from '@workday/canvas-kit-react/action-bar
@workday/canvas-kit-react
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.