-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(controls): Add media settings control item components (#1341)
Co-authored-by: Mingze Xiao <[email protected]>
- Loading branch information
Showing
10 changed files
with
437 additions
and
1 deletion.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
src/lib/viewers/controls/media/MediaSettingsControls/MediaSettingsMenuBack.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
@import './styles'; | ||
|
||
.bp-MediaSettingsMenuBack { | ||
@include bp-MediaSettingsRow; | ||
|
||
&:hover { | ||
background-color: $hover-blue-background; | ||
|
||
.bp-MediaSettingsMenuBack-label { | ||
color: lighten($blue-steel, 50%); | ||
} | ||
} | ||
|
||
.bp-is-focused &:focus { | ||
background-color: $box-blue; | ||
|
||
.bp-MediaSettingsMenuBack-arrow { | ||
fill: $white; | ||
} | ||
|
||
.bp-MediaSettingsMenuBack-label { | ||
color: $white; | ||
} | ||
} | ||
} | ||
|
||
.bp-MediaSettingsMenuBack-arrow { | ||
@include bp-MediaSettingsRow-cell; | ||
} | ||
|
||
.bp-MediaSettingsMenuBack-label { | ||
@include bp-MediaSettingsRow-label; | ||
|
||
text-align: center; | ||
} |
48 changes: 48 additions & 0 deletions
48
src/lib/viewers/controls/media/MediaSettingsControls/MediaSettingsMenuBack.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react'; | ||
import IconArrowLeft24 from '../../icons/IconArrowLeft24'; | ||
import MediaSettingsContext, { Menu } from './MediaSettingsContext'; | ||
import { decodeKeydown } from '../../../../util'; | ||
import './MediaSettingsMenuBack.scss'; | ||
|
||
export type Props = { | ||
label: string; | ||
}; | ||
export type Ref = HTMLDivElement; | ||
|
||
function MediaSettingsMenuBack({ label }: Props, ref: React.Ref<Ref>): JSX.Element { | ||
const { setActiveMenu } = React.useContext(MediaSettingsContext); | ||
|
||
const handleClick = (): void => { | ||
setActiveMenu(Menu.MAIN); | ||
}; | ||
|
||
const handleKeydown = (event: React.KeyboardEvent<HTMLDivElement>): void => { | ||
const key = decodeKeydown(event); | ||
|
||
if (key !== 'ArrowLeft' && key !== 'Enter' && key !== 'Space') { | ||
return; | ||
} | ||
|
||
setActiveMenu(Menu.MAIN); | ||
}; | ||
|
||
return ( | ||
<div | ||
ref={ref} | ||
className="bp-MediaSettingsMenuBack" | ||
onClick={handleClick} | ||
onKeyDown={handleKeydown} | ||
role="menuitem" | ||
tabIndex={0} | ||
> | ||
<div className="bp-MediaSettingsMenuBack-arrow"> | ||
<IconArrowLeft24 height={18} width={18} /> | ||
</div> | ||
<div aria-label={label} className="bp-MediaSettingsMenuBack-label"> | ||
{label} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default React.forwardRef(MediaSettingsMenuBack); |
42 changes: 42 additions & 0 deletions
42
src/lib/viewers/controls/media/MediaSettingsControls/MediaSettingsMenuItem.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
@import './styles'; | ||
|
||
.bp-MediaSettingsMenuItem { | ||
@include bp-MediaSettingsRow; | ||
|
||
&:hover { | ||
background-color: $hover-blue-background; | ||
|
||
.bp-MediaSettingsMenuItem-label { | ||
color: lighten($blue-steel, 50%); | ||
} | ||
|
||
.bp-MediaSettingsMenuItem-value { | ||
color: $blue-steel; | ||
} | ||
} | ||
|
||
.bp-is-focused &:focus { | ||
background-color: $box-blue; | ||
|
||
.bp-MediaSettingsMenuItem-arrow { | ||
fill: $white; | ||
} | ||
|
||
.bp-MediaSettingsMenuItem-label, | ||
.bp-MediaSettingsMenuItem-value { | ||
color: $white; | ||
} | ||
} | ||
} | ||
|
||
.bp-MediaSettingsMenuItem-arrow { | ||
@include bp-MediaSettingsRow-cell; | ||
} | ||
|
||
.bp-MediaSettingsMenuItem-label { | ||
@include bp-MediaSettingsRow-label; | ||
} | ||
|
||
.bp-MediaSettingsMenuItem-value { | ||
@include bp-MediaSettingsRow-value; | ||
} |
55 changes: 55 additions & 0 deletions
55
src/lib/viewers/controls/media/MediaSettingsControls/MediaSettingsMenuItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import React from 'react'; | ||
import classNames from 'classnames'; | ||
import IconArrowRight24 from '../../icons/IconArrowRight24'; | ||
import MediaSettingsContext, { Menu } from './MediaSettingsContext'; | ||
import { decodeKeydown } from '../../../../util'; | ||
import './MediaSettingsMenuItem.scss'; | ||
|
||
export type Props = { | ||
className?: string; | ||
label: string; | ||
target: Menu; | ||
value: string; | ||
}; | ||
export type Ref = HTMLDivElement; | ||
|
||
function MediaSettingsMenuItem(props: Props, ref: React.Ref<Ref>): JSX.Element { | ||
const { className, label, target, value } = props; | ||
const { setActiveMenu } = React.useContext(MediaSettingsContext); | ||
|
||
const handleClick = (): void => { | ||
setActiveMenu(target); | ||
}; | ||
|
||
const handleKeydown = (event: React.KeyboardEvent<Ref>): void => { | ||
const key = decodeKeydown(event); | ||
|
||
if (key !== 'ArrowRight' && key !== 'Enter' && key !== 'Space') { | ||
return; | ||
} | ||
|
||
setActiveMenu(target); | ||
}; | ||
|
||
return ( | ||
<div | ||
ref={ref} | ||
aria-haspopup="true" | ||
className={classNames('bp-MediaSettingsMenuItem', className)} | ||
onClick={handleClick} | ||
onKeyDown={handleKeydown} | ||
role="menuitem" | ||
tabIndex={0} | ||
> | ||
<div aria-label={label} className="bp-MediaSettingsMenuItem-label"> | ||
{label} | ||
</div> | ||
<div className="bp-MediaSettingsMenuItem-value">{value}</div> | ||
<div className="bp-MediaSettingsMenuItem-arrow"> | ||
<IconArrowRight24 height={18} width={18} /> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default React.forwardRef(MediaSettingsMenuItem); |
51 changes: 51 additions & 0 deletions
51
src/lib/viewers/controls/media/MediaSettingsControls/MediaSettingsRadioItem.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
@import './styles'; | ||
|
||
.bp-MediaSettingsRadioItem { | ||
@include bp-MediaSettingsRow; | ||
|
||
&.bp-is-selected { | ||
.bp-MediaSettingsRadioItem-check-icon { | ||
visibility: visible; | ||
} | ||
|
||
.bp-MediaSettingsRadioItem-value { | ||
color: $box-blue; | ||
} | ||
} | ||
|
||
&:hover { | ||
background-color: $hover-blue-background; | ||
|
||
.bp-MediaSettingsRadioItem-check-icon { | ||
fill: $blue-steel; | ||
} | ||
|
||
.bp-MediaSettingsRadioItem-value { | ||
color: $blue-steel; | ||
} | ||
} | ||
|
||
.bp-is-focused &:focus { | ||
background-color: $box-blue; | ||
|
||
.bp-MediaSettingsRadioItem-check-icon { | ||
fill: $white; | ||
} | ||
|
||
.bp-MediaSettingsRadioItem-value { | ||
color: $white; | ||
} | ||
} | ||
} | ||
|
||
.bp-MediaSettingsRadioItem-check { | ||
@include bp-MediaSettingsRow-cell; | ||
} | ||
|
||
.bp-MediaSettingsRadioItem-check-icon { | ||
visibility: hidden; | ||
} | ||
|
||
.bp-MediaSettingsRadioItem-value { | ||
@include bp-MediaSettingsRow-value; | ||
} |
54 changes: 54 additions & 0 deletions
54
src/lib/viewers/controls/media/MediaSettingsControls/MediaSettingsRadioItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import React from 'react'; | ||
import classNames from 'classnames'; | ||
import IconCheckMark24 from '../../icons/IconCheckMark24'; | ||
import { decodeKeydown } from '../../../../util'; | ||
import './MediaSettingsRadioItem.scss'; | ||
|
||
export type Props<V extends Value> = { | ||
className?: string; | ||
isSelected?: boolean; | ||
label?: string; | ||
onChange: (value: V) => void; | ||
value: V; | ||
}; | ||
export type Ref = HTMLDivElement; | ||
export type Value = boolean | number | string; | ||
|
||
function MediaSettingsRadioItem<V extends Value>(props: Props<V>, ref: React.Ref<Ref>): JSX.Element { | ||
const { className, isSelected, label, onChange, value } = props; | ||
|
||
const handleClick = (): void => { | ||
onChange(value); | ||
}; | ||
|
||
const handleKeydown = (event: React.KeyboardEvent<Ref>): void => { | ||
const key = decodeKeydown(event); | ||
|
||
if (key !== 'ArrowLeft' && key !== 'Enter' && key !== 'Space') { | ||
return; | ||
} | ||
|
||
onChange(value); | ||
}; | ||
|
||
return ( | ||
<div | ||
ref={ref} | ||
aria-checked={isSelected ? 'true' : 'false'} | ||
className={classNames('bp-MediaSettingsRadioItem', className, { | ||
'bp-is-selected': isSelected, | ||
})} | ||
onClick={handleClick} | ||
onKeyDown={handleKeydown} | ||
role="menuitemradio" | ||
tabIndex={0} | ||
> | ||
<div className="bp-MediaSettingsRadioItem-check"> | ||
<IconCheckMark24 className="bp-MediaSettingsRadioItem-check-icon" height={16} width={16} /> | ||
</div> | ||
<div className="bp-MediaSettingsRadioItem-value">{label || value}</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default React.forwardRef(MediaSettingsRadioItem) as typeof MediaSettingsRadioItem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
...lib/viewers/controls/media/MediaSettingsControls/__tests__/MediaSettingsMenuBack-test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React from 'react'; | ||
import { mount, ReactWrapper } from 'enzyme'; | ||
import IconArrowLeft24 from '../../../icons/IconArrowLeft24'; | ||
import MediaSettingsContext, { Context } from '../MediaSettingsContext'; | ||
import MediaSettingsMenuBack from '../MediaSettingsMenuBack'; | ||
|
||
describe('MediaSettingsMenuBack', () => { | ||
const getContext = (): Partial<Context> => ({ setActiveMenu: jest.fn() }); | ||
const getWrapper = (props = {}, context = {}): ReactWrapper => | ||
mount(<MediaSettingsMenuBack label="Autoplay" {...props} />, { | ||
wrappingComponent: MediaSettingsContext.Provider, | ||
wrappingComponentProps: { value: context }, | ||
}); | ||
|
||
describe('event handlers', () => { | ||
test('should set the active menu when clicked', () => { | ||
const context = getContext(); | ||
const wrapper = getWrapper({}, context); | ||
|
||
wrapper.simulate('click'); | ||
|
||
expect(context.setActiveMenu).toBeCalled(); | ||
}); | ||
|
||
test.each` | ||
key | calledTimes | ||
${'ArrowLeft'} | ${1} | ||
${'Enter'} | ${1} | ||
${'Escape'} | ${0} | ||
${'Space'} | ${1} | ||
`('should set the active menu $calledTimes times when $key is pressed', ({ key, calledTimes }) => { | ||
const context = getContext(); | ||
const wrapper = getWrapper({}, context); | ||
|
||
wrapper.simulate('keydown', { key }); | ||
|
||
expect(context.setActiveMenu).toBeCalledTimes(calledTimes); | ||
}); | ||
}); | ||
|
||
describe('render', () => { | ||
test('should return a valid wrapper', () => { | ||
const wrapper = getWrapper(); | ||
|
||
expect(wrapper.getDOMNode()).toHaveClass('bp-MediaSettingsMenuBack'); | ||
expect(wrapper.find('.bp-MediaSettingsMenuBack-label').contains('Autoplay')).toBe(true); | ||
expect(wrapper.exists(IconArrowLeft24)).toBe(true); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.