Skip to content

Commit

Permalink
Formatting API
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Oct 2, 2018
1 parent 78d1254 commit b8ad7bd
Show file tree
Hide file tree
Showing 29 changed files with 577 additions and 385 deletions.
1 change: 1 addition & 0 deletions packages/components/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export { default as TextControl } from './text-control';
export { default as TextareaControl } from './textarea-control';
export { default as ToggleControl } from './toggle-control';
export { default as Toolbar } from './toolbar';
export { default as ToolbarButton } from './toolbar-button';
export { default as Tooltip } from './tooltip';
export { default as TreeSelect } from './tree-select';
export { createSlotFill, Slot, Fill, Provider as SlotFillProvider } from './slot-fill';
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@
@import "./textarea-control/style.scss";
@import "./toggle-control/style.scss";
@import "./toolbar/style.scss";
@import "./toolbar-button/style.scss";
@import "./tooltip/style.scss";
50 changes: 50 additions & 0 deletions packages/components/src/toolbar-button/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* Internal dependencies
*/
import IconButton from '../icon-button';
import ToolbarButtonContainer from './toolbar-button-container';

function ToolbarButton( {
containerClassName,
icon,
title,
shortcut,
subscript,
onClick,
className,
isActive,
isDisabled,
extraProps,
children,
} ) {
return (
<ToolbarButtonContainer className={ containerClassName }>
<IconButton
icon={ icon }
label={ title }
shortcut={ shortcut }
data-subscript={ subscript }
onClick={ ( event ) => {
event.stopPropagation();
onClick();
} }
className={ classnames(
'components-toolbar__control',
className,
{ 'is-active': isActive }
) }
aria-pressed={ isActive }
disabled={ isDisabled }
{ ...extraProps }
/>
{ children }
</ToolbarButtonContainer>
);
}

export default ToolbarButton;
77 changes: 77 additions & 0 deletions packages/components/src/toolbar-button/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
.components-toolbar__control.components-button {
display: inline-flex;
align-items: flex-end;
margin: 0;
padding: 3px;
outline: none;
cursor: pointer;
position: relative;
width: $icon-button-size;
height: $icon-button-size;

// Unset icon button styles
&:active,
&:not([aria-disabled="true"]):hover,
&:not([aria-disabled="true"]):focus {
outline: none;
box-shadow: none;
background: none;
border: none;
}

// Disabled
&:disabled {
cursor: default;
}

& > svg {
padding: 5px;
border-radius: $radius-round-rectangle;
height: 30px;
width: 30px;
}

// Subscript for numbered icon buttons, like headings
&[data-subscript] svg {
padding: 5px 10px 5px 0;
}

&[data-subscript]::after {
content: attr(data-subscript);
font-family: $default-font;
font-size: $default-font-size;
font-weight: 600;
line-height: 12px;
position: absolute;
right: 8px;
bottom: 10px;
}

// Assign hover style to child element, not the button itself
&:not(:disabled):not([aria-disabled="true"]):hover {
box-shadow: none;
}

&:not(:disabled).is-active > svg,
&:not(:disabled):hover > svg {
@include formatting-button-style__hover;
}

// Active & toggled style
&:not(:disabled).is-active > svg {
@include formatting-button-style__active;
}

&:not(:disabled).is-active[data-subscript]::after {
color: $white;
}

// Focus style
&:not(:disabled):focus > svg {
@include formatting-button-style__focus;
}
}

.components-toolbar__control .dashicon {
display: block;
}
26 changes: 4 additions & 22 deletions packages/components/src/toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { flatMap } from 'lodash';
/**
* Internal dependencies
*/
import IconButton from '../icon-button';
import ToolbarButton from '../toolbar-button';
import DropdownMenu from '../dropdown-menu';
import ToolbarContainer from './toolbar-container';
import ToolbarButtonContainer from './toolbar-button-container';

/**
* Renders a toolbar with controls.
Expand Down Expand Up @@ -71,28 +70,11 @@ function Toolbar( { controls = [], children, className, isCollapsed, icon, label
<ToolbarContainer className={ classnames( 'components-toolbar', className ) }>
{ flatMap( controlSets, ( controlSet, indexOfSet ) => (
controlSet.map( ( control, indexOfControl ) => (
<ToolbarButtonContainer
<ToolbarButton
key={ [ indexOfSet, indexOfControl ].join() }
className={ indexOfSet > 0 && indexOfControl === 0 ? 'has-left-divider' : null }
>
<IconButton
icon={ control.icon }
label={ control.title }
shortcut={ control.shortcut }
data-subscript={ control.subscript }
onClick={ ( event ) => {
event.stopPropagation();
control.onClick();
} }
className={ classnames( 'components-toolbar__control', control.className, {
'is-active': control.isActive,
} ) }
aria-pressed={ control.isActive }
disabled={ control.isDisabled }
{ ...control.extraProps }
/>
{ control.children }
</ToolbarButtonContainer>
{ ...control }
/>
) )
) ) }
{ children }
Expand Down
78 changes: 0 additions & 78 deletions packages/components/src/toolbar/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,81 +39,3 @@ div.components-toolbar {
}
}
}

.components-toolbar__control.components-button {
display: inline-flex;
align-items: flex-end;
margin: 0;
padding: 3px;
outline: none;
cursor: pointer;
position: relative;
width: $icon-button-size;
height: $icon-button-size;

// Unset icon button styles
&:active,
&:not([aria-disabled="true"]):hover,
&:not([aria-disabled="true"]):focus {
outline: none;
box-shadow: none;
background: none;
border: none;
}

// Disabled
&:disabled {
cursor: default;
}

& > svg {
padding: 5px;
border-radius: $radius-round-rectangle;
height: 30px;
width: 30px;
}

// Subscript for numbered icon buttons, like headings
&[data-subscript] svg {
padding: 5px 10px 5px 0;
}

&[data-subscript]::after {
content: attr(data-subscript);
font-family: $default-font;
font-size: $default-font-size;
font-weight: 600;
line-height: 12px;
position: absolute;
right: 8px;
bottom: 10px;
}

// Assign hover style to child element, not the button itself
&:not(:disabled):not([aria-disabled="true"]):hover {
box-shadow: none;
}

&:not(:disabled).is-active > svg,
&:not(:disabled):hover > svg {
@include formatting-button-style__hover;
}

// Active & toggled style
&:not(:disabled).is-active > svg {
@include formatting-button-style__active;
}

&:not(:disabled).is-active[data-subscript]::after {
color: $white;
}

// Focus style
&:not(:disabled):focus > svg {
@include formatting-button-style__focus;
}
}

.components-toolbar__control .dashicon {
display: block;
}
18 changes: 8 additions & 10 deletions packages/components/src/toolbar/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@ describe( 'Toolbar', () => {
},
];
const toolbar = shallow( <Toolbar controls={ controls } /> );
const listItem = toolbar.find( 'IconButton' );
const listItem = toolbar.find( 'ToolbarButton' );
expect( listItem.props() ).toMatchObject( {
icon: 'wordpress',
label: 'WordPress',
'data-subscript': 'wp',
'aria-pressed': false,
className: 'components-toolbar__control',
title: 'WordPress',
subscript: 'wp',
className: null,
} );
} );

Expand All @@ -54,10 +53,9 @@ describe( 'Toolbar', () => {
},
];
const toolbar = shallow( <Toolbar controls={ controls } /> );
const listItem = toolbar.find( 'IconButton' );
const listItem = toolbar.find( 'ToolbarButton' );
expect( listItem.props() ).toMatchObject( {
'aria-pressed': true,
className: 'components-toolbar__control is-active',
className: null,
} );
} );

Expand Down Expand Up @@ -96,10 +94,10 @@ describe( 'Toolbar', () => {
},
];
const toolbar = shallow( <Toolbar controls={ controls } /> );
const listItem = toolbar.find( 'IconButton' );
const listItem = toolbar.find( 'ToolbarButton' );
listItem.simulate( 'click', event );
expect( clickHandler ).toHaveBeenCalledTimes( 1 );
expect( clickHandler ).toHaveBeenCalledWith();
expect( clickHandler ).toHaveBeenCalledWith( event );
} );
} );
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Fragment } from '@wordpress/element';
import { Fill, ToolbarButton } from '@wordpress/components';
import { toggleFormat } from '@wordpress/rich-text';

const Shortcut = () => null;

export const bold = {
format: 'bold',
selector: 'strong',
edit( { isActive, value, onChange } ) {
const onToggle = () => onChange( toggleFormat( value, { type: 'strong' } ) );

return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ onToggle }
/>
<Fill name="RichText.ToolbarControls.bold">
<ToolbarButton
icon="editor-bold"
title={ __( 'Bold' ) }
onClick={ onToggle }
isActive={ isActive }
/>
</Fill>
</Fragment>
);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* WordPress dependencies
*/
import { Fragment } from '@wordpress/element';
import { toggleFormat } from '@wordpress/rich-text';

const Shortcut = () => null;

export const code = {
format: 'code',
selector: 'code',
edit( { value, onChange } ) {
const onToggle = () => onChange( toggleFormat( value, { type: 'code' } ) );

return (
<Fragment>
<Shortcut
type="access"
key="x"
onUse={ onToggle }
/>
</Fragment>
);
},
};
13 changes: 13 additions & 0 deletions packages/editor/src/components/rich-text/format-controls/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { bold } from './bold';
import { code } from './code';
import { italic } from './italic';
import { link } from './link';
import { strikethrough } from './strikethrough';

export const formatControls = [
bold,
code,
italic,
link,
strikethrough,
];
Loading

0 comments on commit b8ad7bd

Please sign in to comment.