diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b82d20935..163c31c144 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] + ### Features +- Add `Toolbar` component @miroslavstastny ([#1408](https://github.com/stardust-ui/react/pull/1408)) + ## [v0.32.0](https://github.com/stardust-ui/react/tree/v0.32.0) (2019-06-03) [Compare changes](https://github.com/stardust-ui/react/compare/v0.31.0...v0.32.0) diff --git a/docs/src/app.tsx b/docs/src/app.tsx index 35aa4adc90..ffc41f9ef7 100644 --- a/docs/src/app.tsx +++ b/docs/src/app.tsx @@ -22,7 +22,6 @@ class App extends React.Component { { + const [isBold, setBold] = React.useState(true) + const [isItalic, setItalic] = React.useState(false) + const [isUnderline, setUnderline] = React.useState(false) + const [isStrike, setStrike] = React.useState(false) + + return ( + { + setBold(!isBold) + }, + }, + { + key: 'italic', + active: isItalic, + icon: { name: 'italic', outline: true }, + onClick: () => { + setItalic(!isItalic) + }, + }, + { + key: 'underline', + active: isUnderline, + icon: { name: 'underline', outline: true }, + onClick: () => { + setUnderline(!isUnderline) + }, + }, + { + key: 'strike', + active: isStrike, + disabled: true, + icon: { name: 'strike', outline: true }, + onClick: () => { + setStrike(!isStrike) + }, + }, + { key: 'divider1', kind: 'divider' }, + { key: 'highlight', icon: { name: 'highlight', outline: true } }, + { key: 'font-color', icon: { name: 'font-color', outline: true } }, + { key: 'font-size', icon: { name: 'font-size', outline: true } }, + { key: 'remove-format', icon: { name: 'remove-format', outline: true } }, + { key: 'divider2', kind: 'divider' }, + { key: 'outdent', icon: { name: 'outdent', outline: true } }, + { key: 'indent', icon: { name: 'indent', outline: true } }, + { key: 'bullets', icon: { name: 'bullets', outline: true } }, + { key: 'number-list', icon: { name: 'number-list', outline: true } }, + { key: 'divider3', kind: 'divider' }, + { key: 'more', icon: { name: 'more', outline: true } }, + ]} + /> + ) +} + +export default ToolbarExampleShorthand diff --git a/docs/src/examples/components/Toolbar/Types/index.tsx b/docs/src/examples/components/Toolbar/Types/index.tsx new file mode 100644 index 0000000000..d70c19e927 --- /dev/null +++ b/docs/src/examples/components/Toolbar/Types/index.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' +import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection' + +const Types = () => ( + + + +) + +export default Types diff --git a/docs/src/examples/components/Toolbar/index.tsx b/docs/src/examples/components/Toolbar/index.tsx new file mode 100644 index 0000000000..212985429c --- /dev/null +++ b/docs/src/examples/components/Toolbar/index.tsx @@ -0,0 +1,11 @@ +import * as React from 'react' + +import Types from './Types' + +const ToolbarExamples = () => ( + <> + + +) + +export default ToolbarExamples diff --git a/packages/react/src/components/Menu/MenuItem.tsx b/packages/react/src/components/Menu/MenuItem.tsx index 3ffc87ff73..9cad9fec28 100644 --- a/packages/react/src/components/Menu/MenuItem.tsx +++ b/packages/react/src/components/Menu/MenuItem.tsx @@ -72,8 +72,7 @@ export interface MenuItemProps itemsCount?: number /** - * Called on click. When passed, the component will render as an `a` - * tag by default instead of a `div`. + * Called on click. * * @param {SyntheticEvent} event - React's original SyntheticEvent. * @param {object} data - All props. @@ -87,6 +86,13 @@ export interface MenuItemProps */ onFocus?: ComponentEventHandler + /** + * Called after item blur. + * @param {SyntheticEvent} event - React's original SyntheticEvent. + * @param {object} data - All props. + */ + onBlur?: ComponentEventHandler + /** A menu can adjust its appearance to de-emphasize its contents. */ pills?: boolean @@ -165,6 +171,7 @@ class MenuItem extends AutoControlledComponent, MenuIt itemsCount: PropTypes.number, onClick: PropTypes.func, onFocus: PropTypes.func, + onBlur: PropTypes.func, pills: PropTypes.bool, pointing: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['start', 'end'])]), primary: customPropTypes.every([customPropTypes.disallow(['secondary']), PropTypes.bool]), diff --git a/packages/react/src/components/Toolbar/Toolbar.tsx b/packages/react/src/components/Toolbar/Toolbar.tsx new file mode 100644 index 0000000000..66908e3016 --- /dev/null +++ b/packages/react/src/components/Toolbar/Toolbar.tsx @@ -0,0 +1,105 @@ +import * as React from 'react' +import * as _ from 'lodash' +import * as customPropTypes from '@stardust-ui/react-proptypes' + +import { + childrenExist, + createShorthandFactory, + UIComponent, + UIComponentProps, + ContentComponentProps, + ChildrenComponentProps, + commonPropTypes, + ColorComponentProps, +} from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' +import { ShorthandCollection, WithAsProp, withSafeTypeForAs } from '../../types' + +import ToolbarItem from './ToolbarItem' +import ToolbarDivider from './ToolbarDivider' +import ToolbarRadioGroup from './ToolbarRadioGroup' + +export type ToolbarItemShorthandKinds = 'divider' | 'item' | 'group' + +export interface ToolbarProps + extends UIComponentProps, + ContentComponentProps, + ChildrenComponentProps, + ColorComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility + + /** Shorthand array of props for Toolbar. */ + items?: ShorthandCollection +} + +class Toolbar extends UIComponent, any> { + static create: Function + + static className = 'ui-toolbar' + + static displayName = 'Toolbar' + + static propTypes = { + ...commonPropTypes.createCommon(), + items: customPropTypes.collectionShorthandWithKindProp(['divider', 'item', 'group']), + } + + static defaultProps = { + accessibility: defaultBehavior, + } + + static Item = ToolbarItem + static Divider = ToolbarDivider + static RadioGroup = ToolbarRadioGroup + + handleItemOverrides = variables => predefinedProps => ({ + variables: { + ...variables, + ...predefinedProps.variables, + }, + }) + + private renderItems(items, variables) { + const itemOverridesFn = this.handleItemOverrides(variables) + return _.map(items, (item, index) => { + const kind = _.get(item, 'kind', 'item') + + switch (kind) { + case 'divider': + return ToolbarDivider.create(item, { overrideProps: itemOverridesFn }) + case 'group': + return ToolbarRadioGroup.create(item, { overrideProps: itemOverridesFn }) + default: + return ToolbarItem.create(item, { overrideProps: itemOverridesFn }) + } + }) + } + + renderComponent({ + accessibility, + ElementType, + classes, + variables, + unhandledProps, + }): React.ReactNode { + const { children, items } = this.props + + return ( + + {childrenExist(children) ? children : this.renderItems(items, variables)} + + ) + } +} + +Toolbar.create = createShorthandFactory({ Component: Toolbar, mappedProp: 'content' }) + +/** + * A Toolbar component displays grouped actions. + */ +export default withSafeTypeForAs(Toolbar) diff --git a/packages/react/src/components/Toolbar/ToolbarDivider.tsx b/packages/react/src/components/Toolbar/ToolbarDivider.tsx new file mode 100644 index 0000000000..db04570596 --- /dev/null +++ b/packages/react/src/components/Toolbar/ToolbarDivider.tsx @@ -0,0 +1,57 @@ +import * as React from 'react' +import { + ChildrenComponentProps, + ContentComponentProps, + createShorthandFactory, + UIComponentProps, + UIComponent, + commonPropTypes, +} from '../../lib' +import { Accessibility } from '../../lib/accessibility/types' +import { WithAsProp, withSafeTypeForAs } from '../../types' +import { defaultBehavior } from '../../lib/accessibility' + +export interface ToolbarDividerProps + extends UIComponentProps, + ChildrenComponentProps, + ContentComponentProps { + /** + * Accessibility behavior if overridden by the user. + * @default defaultBehavior + */ + accessibility?: Accessibility +} + +class ToolbarDivider extends UIComponent> { + static displayName = 'ToolbarDivider' + + static create: Function + + static className = 'ui-toolbar__divider' + + static propTypes = { + ...commonPropTypes.createCommon(), + } + + static defaultProps = { + accessibility: defaultBehavior as Accessibility, + } + + renderComponent({ ElementType, classes, unhandledProps, accessibility }) { + return ( + + ) + } +} + +ToolbarDivider.create = createShorthandFactory({ Component: ToolbarDivider, mappedProp: 'content' }) + +/** + * Toolbar divider. + * Adds visual non-selectable separator between items. + */ +export default withSafeTypeForAs(ToolbarDivider) diff --git a/packages/react/src/components/Toolbar/ToolbarItem.tsx b/packages/react/src/components/Toolbar/ToolbarItem.tsx new file mode 100644 index 0000000000..51d1d7a8c7 --- /dev/null +++ b/packages/react/src/components/Toolbar/ToolbarItem.tsx @@ -0,0 +1,136 @@ +import * as React from 'react' +import * as _ from 'lodash' +import * as PropTypes from 'prop-types' +import * as customPropTypes from '@stardust-ui/react-proptypes' + +import { + UIComponent, + createShorthandFactory, + UIComponentProps, + ChildrenComponentProps, + ContentComponentProps, + commonPropTypes, + childrenExist, + isFromKeyboard, +} from '../../lib' +import { ComponentEventHandler, ShorthandValue, WithAsProp, withSafeTypeForAs } from '../../types' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' + +import Icon from '../Icon/Icon' + +export interface ToolbarItemProps + extends UIComponentProps, + ChildrenComponentProps, + ContentComponentProps { + /** + * Accessibility behavior if overridden by the user. + */ + accessibility?: Accessibility + + /** A toolbar item can be active. */ + active?: boolean + + /** A toolbar item can show it is currently unable to be interacted with. */ + disabled?: boolean + + /** Name or shorthand for Toolbar Item Icon */ + icon?: ShorthandValue + + /** + * Called on click. + * + * @param {SyntheticEvent} event - React's original SyntheticEvent. + * @param {object} data - All props. + */ + onClick?: ComponentEventHandler + + /** + * Called after user's focus. + * @param {SyntheticEvent} event - React's original SyntheticEvent. + * @param {object} data - All props. + */ + onFocus?: ComponentEventHandler + + /** + * Called after item blur. + * @param {SyntheticEvent} event - React's original SyntheticEvent. + * @param {object} data - All props. + */ + onBlur?: ComponentEventHandler +} + +export interface ToolbarItemState { + isFromKeyboard: boolean +} + +class ToolbarItem extends UIComponent, ToolbarItemState> { + static displayName = 'ToolbarItem' + + static className = 'ui-toolbar__item' + + static create: Function + + static propTypes = { + ...commonPropTypes.createCommon(), + active: PropTypes.bool, + disabled: PropTypes.bool, + icon: customPropTypes.itemShorthand, + onClick: PropTypes.func, + onFocus: PropTypes.func, + onBlur: PropTypes.func, + } + + static defaultProps = { + as: 'button', + accessibility: defaultBehavior as Accessibility, + } + + renderComponent({ ElementType, classes, unhandledProps, accessibility }) { + const { icon, children, disabled } = this.props + return ( + + {childrenExist(children) ? children : Icon.create(icon)} + + ) + } + + private handleBlur = (e: React.SyntheticEvent) => { + this.setState({ isFromKeyboard: false }) + + _.invoke(this.props, 'onBlur', e, this.props) + } + + private handleFocus = (e: React.SyntheticEvent) => { + this.setState({ isFromKeyboard: isFromKeyboard() }) + + _.invoke(this.props, 'onFocus', e, this.props) + } + + private handleClick = (e: React.SyntheticEvent) => { + const { disabled } = this.props + + if (disabled) { + e.preventDefault() + return + } + + _.invoke(this.props, 'onClick', e, this.props) + } +} + +ToolbarItem.create = createShorthandFactory({ Component: ToolbarItem, mappedProp: 'content' }) + +/** + * Toolbar item. + * The item renders as a button with an icon. + */ +export default withSafeTypeForAs(ToolbarItem) diff --git a/packages/react/src/components/Toolbar/ToolbarRadioGroup.tsx b/packages/react/src/components/Toolbar/ToolbarRadioGroup.tsx new file mode 100644 index 0000000000..c06d5e315e --- /dev/null +++ b/packages/react/src/components/Toolbar/ToolbarRadioGroup.tsx @@ -0,0 +1,92 @@ +import * as React from 'react' +import * as _ from 'lodash' +import * as customPropTypes from '@stardust-ui/react-proptypes' + +import { + ChildrenComponentProps, + ContentComponentProps, + createShorthandFactory, + UIComponentProps, + UIComponent, + childrenExist, + commonPropTypes, +} from '../../lib' +import { ShorthandCollection, WithAsProp, withSafeTypeForAs } from '../../types' +import { Accessibility } from '../../lib/accessibility/types' +import { defaultBehavior } from '../../lib/accessibility' + +import ToolbarDivider from './ToolbarDivider' +import ToolbarItem from './ToolbarItem' + +export type ToolbarRadioGroupItemShorthandKinds = 'divider' | 'item' + +export interface ToolbarRadioGroupProps + extends UIComponentProps, + ChildrenComponentProps, + ContentComponentProps { + /** + * Accessibility behavior if overridden by the user. + */ + accessibility?: Accessibility + + /** Shorthand array of props for ToolbarRadioGroup. */ + items?: ShorthandCollection +} + +class ToolbarRadioGroup extends UIComponent> { + static displayName = 'ToolbarRadioGroup' + + static className = 'ui-toolbars' // FIXME: required by getComponentInfo/isConformant. But this is group inside a toolbar not a group of toolbars + + static create: Function + + static propTypes = { + ...commonPropTypes.createCommon(), + items: customPropTypes.collectionShorthandWithKindProp(['divider', 'item']), + } + + static defaultProps = { + accessibility: defaultBehavior as Accessibility, + } + + handleItemOverrides = variables => predefinedProps => ({ + variables: { + ...variables, + ...predefinedProps.variables, + }, + }) + + private renderItems(items, variables) { + const itemOverridesFn = this.handleItemOverrides(variables) + return _.map(items, (item, index) => { + const kind = _.get(item, 'kind', 'item') + + if (kind === 'divider') { + return ToolbarDivider.create(item, { overrideProps: itemOverridesFn }) + } + return ToolbarItem.create(item, { overrideProps: itemOverridesFn }) + }) + } + + renderComponent({ ElementType, classes, variables, accessibility, unhandledProps }) { + const { children, items } = this.props + return ( + + {childrenExist(children) ? children : this.renderItems(items, variables)} + + ) + } +} + +ToolbarRadioGroup.create = createShorthandFactory({ + Component: ToolbarRadioGroup, + mappedProp: 'content', +}) + +/** + * Toolbar radiogroup groups items where only one item can be active. + * The radiogroup does not guarantee that, it just serves accessibility purposes. + */ +export default withSafeTypeForAs( + ToolbarRadioGroup, +) diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index d79617d4ee..fd5bed843f 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -150,6 +150,15 @@ export { default as Text } from './components/Text/Text' export * from './components/Animation/Animation' export { default as Animation } from './components/Animation/Animation' +export * from './components/Toolbar/Toolbar' +export { default as Toolbar } from './components/Toolbar/Toolbar' +export * from './components/Toolbar/ToolbarDivider' +export { default as ToolbarDivider } from './components/Toolbar/ToolbarDivider' +export * from './components/Toolbar/ToolbarItem' +export { default as ToolbarItem } from './components/Toolbar/ToolbarItem' +export * from './components/Toolbar/ToolbarRadioGroup' +export { default as ToolbarRadioGroup } from './components/Toolbar/ToolbarRadioGroup' + export * from './components/Tree' export { default as Tree } from './components/Tree' diff --git a/packages/react/src/themes/base/componentStyles.ts b/packages/react/src/themes/base/componentStyles.ts index b98a1357bb..43abaa2992 100644 --- a/packages/react/src/themes/base/componentStyles.ts +++ b/packages/react/src/themes/base/componentStyles.ts @@ -15,6 +15,8 @@ export { default as ProviderBox } from './components/Provider/providerBoxStyles' export { default as Text } from './components/Text/textStyles' +export { default as Toolbar } from './components/Toolbar/toolbarStyles' + export { default as Grid } from './components/Grid/gridStyles' export { default as Image } from './components/Image/imageStyles' diff --git a/packages/react/src/themes/base/components/Toolbar/toolbarStyles.ts b/packages/react/src/themes/base/components/Toolbar/toolbarStyles.ts new file mode 100644 index 0000000000..73d4d37e0e --- /dev/null +++ b/packages/react/src/themes/base/components/Toolbar/toolbarStyles.ts @@ -0,0 +1,10 @@ +import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' + +const toolbarStyles: ComponentSlotStylesInput = { + root: (): ICSSInJSStyle => ({ + display: 'flex', + alignItems: 'center', + }), +} + +export default toolbarStyles diff --git a/packages/react/src/themes/teams-high-contrast/componentVariables.ts b/packages/react/src/themes/teams-high-contrast/componentVariables.ts index 9d3000c44d..d0a745ba83 100644 --- a/packages/react/src/themes/teams-high-contrast/componentVariables.ts +++ b/packages/react/src/themes/teams-high-contrast/componentVariables.ts @@ -11,6 +11,7 @@ export { default as ListItem } from './components/List/listItemVariables' export { default as Menu } from './components/Menu/menuVariables' export { default as RadioGroupItem } from './components/RadioGroup/radioGroupItemVariables' export { default as Text } from './components/Text/textVariables' +export { default as Toolbar } from './components/Toolbar/toolbarVariables' export { default as TreeTitle } from './components/Tree/treeTitleVariables' export { default as Status } from './components/Status/statusVariables' export { default as Reaction } from './components/Reaction/reactionVariables' diff --git a/packages/react/src/themes/teams-high-contrast/components/Toolbar/toolbarVariables.ts b/packages/react/src/themes/teams-high-contrast/components/Toolbar/toolbarVariables.ts new file mode 100644 index 0000000000..2cfb722d7a --- /dev/null +++ b/packages/react/src/themes/teams-high-contrast/components/Toolbar/toolbarVariables.ts @@ -0,0 +1,22 @@ +import { + toolbarColorAreas, + ToolbarVariables, +} from '../../../teams/components/Toolbar/toolbarVariables' +import { extendColorScheme, pickValuesFromColorScheme } from '../../../colorUtils' + +export default (siteVars: any): Partial => ({ + colorScheme: pickValuesFromColorScheme( + extendColorScheme(siteVars.colorScheme, { + default: { + foregroundHover: siteVars.colorScheme.brand.foregroundHover, + borderFocus: undefined, + foregroundActive: siteVars.accessibleYellow, + backgroundFocus: siteVars.colorScheme.default.backgroundHover, + }, + }), + toolbarColorAreas, + ), + + borderWidth: '0', + borderRadius: undefined, +}) diff --git a/packages/react/src/themes/teams/componentStyles.ts b/packages/react/src/themes/teams/componentStyles.ts index 2107757ae7..b8f9ea6d4e 100644 --- a/packages/react/src/themes/teams/componentStyles.ts +++ b/packages/react/src/themes/teams/componentStyles.ts @@ -69,6 +69,9 @@ export { default as Status } from './components/Status/statusStyles' export { default as Text } from './components/Text/textStyles' +export { default as ToolbarDivider } from './components/Toolbar/toolbarDividerStyles' +export { default as ToolbarItem } from './components/Toolbar/toolbarItemStyles' + export { default as Tree } from './components/Tree/treeStyles' export { default as TreeItem } from './components/Tree/treeItemStyles' export { default as TreeTitle } from './components/Tree/treeTitleStyles' diff --git a/packages/react/src/themes/teams/componentVariables.ts b/packages/react/src/themes/teams/componentVariables.ts index 2188c79ad2..3accd062c0 100644 --- a/packages/react/src/themes/teams/componentVariables.ts +++ b/packages/react/src/themes/teams/componentVariables.ts @@ -65,6 +65,10 @@ export { default as Status } from './components/Status/statusVariables' export { default as Text } from './components/Text/textVariables' +export { default as Toolbar } from './components/Toolbar/toolbarVariables' +export { default as ToolbarItem } from './components/Toolbar/toolbarItemVariables' +export { default as ToolbarDivider } from './components/Toolbar/toolbarDividerVariables' + export { default as TreeTitle } from './components/Tree/treeTitleVariables' export { default as Animation } from './components/Animation/animationVariables' diff --git a/packages/react/src/themes/teams/components/Menu/menuVariables.ts b/packages/react/src/themes/teams/components/Menu/menuVariables.ts index c5d63357f3..5d70a9770c 100644 --- a/packages/react/src/themes/teams/components/Menu/menuVariables.ts +++ b/packages/react/src/themes/teams/components/Menu/menuVariables.ts @@ -12,7 +12,6 @@ export const menuColorAreas = stringLiteralsArray( 'backgroundHover', 'backgroundActive', 'backgroundFocus', - 'foregroundFocus', 'foregroundDisabled', ) export type MenuColorSchemeMapping = TeamsSchemeMappingWithAreas> diff --git a/packages/react/src/themes/teams/components/Toolbar/toolbarDividerStyles.ts b/packages/react/src/themes/teams/components/Toolbar/toolbarDividerStyles.ts new file mode 100644 index 0000000000..ab43ab490c --- /dev/null +++ b/packages/react/src/themes/teams/components/Toolbar/toolbarDividerStyles.ts @@ -0,0 +1,16 @@ +import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' +import { ToolbarVariables } from './toolbarVariables' +import { getColorScheme } from '../../colors' + +const toolbarDividerStyles: ComponentSlotStylesInput<{}, ToolbarVariables> = { + root: ({ variables: v }): ICSSInJSStyle => { + const colors = getColorScheme(v.colorScheme) + return { + borderLeft: `1px solid ${v.dividerBorder || colors.border}`, + margin: v.dividerMargin, + alignSelf: 'stretch', + } + }, +} + +export default toolbarDividerStyles diff --git a/packages/react/src/themes/teams/components/Toolbar/toolbarDividerVariables.ts b/packages/react/src/themes/teams/components/Toolbar/toolbarDividerVariables.ts new file mode 100644 index 0000000000..d0e9fa26c8 --- /dev/null +++ b/packages/react/src/themes/teams/components/Toolbar/toolbarDividerVariables.ts @@ -0,0 +1,3 @@ +import toolbarVariables from './toolbarVariables' + +export default toolbarVariables diff --git a/packages/react/src/themes/teams/components/Toolbar/toolbarItemStyles.ts b/packages/react/src/themes/teams/components/Toolbar/toolbarItemStyles.ts new file mode 100644 index 0000000000..3ec572712b --- /dev/null +++ b/packages/react/src/themes/teams/components/Toolbar/toolbarItemStyles.ts @@ -0,0 +1,60 @@ +import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' +import { ToolbarItemProps, ToolbarItemState } from '../../../../components/Toolbar/ToolbarItem' +import { ToolbarVariables } from './toolbarVariables' +import getIconFillOrOutlineStyles from '../../getIconFillOrOutlineStyles' +import { getColorScheme } from '../../colors' + +type ToolbarItemPropsAndState = ToolbarItemProps & ToolbarItemState + +const toolbarItemStyles: ComponentSlotStylesInput = { + root: ({ props: p, variables: v }): ICSSInJSStyle => { + const { active, disabled, isFromKeyboard } = p + const colors = getColorScheme(v.colorScheme) + + return { + backgroundColor: v.background, + borderWidth: v.borderWidth, + borderStyle: 'solid', + borderColor: 'transparent', + borderRadius: v.borderRadius, + height: v.itemHeight, + minWidth: v.itemHeight, + color: v.foreground || colors.foreground1, + cursor: 'pointer', + + ':focus': { + outline: 0, + }, + + ...(active && { + color: v.foregroundActive || colors.foregroundActive, + backgroundColor: v.backgroundActive, + ...getIconFillOrOutlineStyles({ outline: false }), + }), + + ':hover': { + color: v.foregroundHover || colors.foregroundHover, + backgroundColor: v.backgroundHover || colors.backgroundHover, + ...getIconFillOrOutlineStyles({ outline: false }), + }, + + ...(isFromKeyboard && { + color: v.foregroundFocus || colors.foregroundFocus, + backgroundColor: v.backgroundFocus || colors.backgroundFocus, + borderColor: v.borderFocus || colors.borderFocus, + ...getIconFillOrOutlineStyles({ outline: false }), + }), + + ...(disabled && { + color: v.foregroundDisabled || colors.foregroundDisabled1, + backgroundColor: v.backgroundDisabled, + cursor: 'default', + ':hover': { + // empty to overwrite all existing hover styles + }, + }), + } + }, +} + +export default toolbarItemStyles diff --git a/packages/react/src/themes/teams/components/Toolbar/toolbarItemVariables.ts b/packages/react/src/themes/teams/components/Toolbar/toolbarItemVariables.ts new file mode 100644 index 0000000000..d0e9fa26c8 --- /dev/null +++ b/packages/react/src/themes/teams/components/Toolbar/toolbarItemVariables.ts @@ -0,0 +1,3 @@ +import toolbarVariables from './toolbarVariables' + +export default toolbarVariables diff --git a/packages/react/src/themes/teams/components/Toolbar/toolbarVariables.ts b/packages/react/src/themes/teams/components/Toolbar/toolbarVariables.ts new file mode 100644 index 0000000000..ba81e54d32 --- /dev/null +++ b/packages/react/src/themes/teams/components/Toolbar/toolbarVariables.ts @@ -0,0 +1,86 @@ +import { pxToRem, stringLiteralsArray } from '../../../../lib' +import { extendColorScheme, pickValuesFromColorScheme } from '../../../colorUtils' +import { ItemType } from '../../../types' +import { TeamsSchemeMappingWithAreas } from '../../types' + +export const toolbarColorAreas = stringLiteralsArray( + 'foreground1', + 'border', + + 'foregroundActive', + + 'foregroundHover', + 'backgroundHover', + + 'foregroundFocus', + 'backgroundFocus', + 'borderFocus', + + 'foregroundDisabled1', +) + +export type ToolbarColorSchemeMapping = TeamsSchemeMappingWithAreas< + ItemType +> + +export interface ToolbarVariables { + colorScheme: ToolbarColorSchemeMapping + foreground: string + background: string + dividerBorder: string + + foregroundHover: string + backgroundHover: string + + foregroundFocus: string + backgroundFocus: string + borderFocus: string + + foregroundActive: string + backgroundActive: string + + foregroundDisabled: string + backgroundDisabled: string + + itemHeight: string + borderWidth: string + borderRadius: string + dividerMargin: string +} + +export default (siteVars: any): ToolbarVariables => ({ + colorScheme: pickValuesFromColorScheme( + extendColorScheme(siteVars.colorScheme, { + default: { + borderFocus: siteVars.colorScheme.brand.borderFocus1, + foregroundHover: siteVars.colorScheme.brand.foregroundHover, + backgroundHover: 'transparent', + foregroundFocus: siteVars.colorScheme.brand.foregroundFocus, + backgroundFocus: 'transparent', + foregroundActive: siteVars.colorScheme.brand.foregroundActive, + }, + }), + toolbarColorAreas, + ), + foreground: undefined, + background: 'transparent', + dividerBorder: undefined, + + foregroundHover: undefined, + backgroundHover: undefined, + + foregroundFocus: undefined, + backgroundFocus: undefined, + borderFocus: undefined, + + foregroundActive: undefined, + backgroundActive: 'transparent', + + foregroundDisabled: undefined, + backgroundDisabled: 'transparent', + + itemHeight: pxToRem(32), + borderWidth: '2px', + borderRadius: '50%', + dividerMargin: `${pxToRem(10)} ${pxToRem(4)}`, +}) diff --git a/packages/react/test/specs/components/Toolbar/Toolbar-test.ts b/packages/react/test/specs/components/Toolbar/Toolbar-test.ts new file mode 100644 index 0000000000..6ca77e5c04 --- /dev/null +++ b/packages/react/test/specs/components/Toolbar/Toolbar-test.ts @@ -0,0 +1,7 @@ +import { isConformant } from 'test/specs/commonTests' + +import Toolbar from 'src/components/Toolbar/Toolbar' + +describe('Toolbar', () => { + isConformant(Toolbar) +}) diff --git a/packages/react/test/specs/components/Toolbar/ToolbarDivider-test.ts b/packages/react/test/specs/components/Toolbar/ToolbarDivider-test.ts new file mode 100644 index 0000000000..41c32e772b --- /dev/null +++ b/packages/react/test/specs/components/Toolbar/ToolbarDivider-test.ts @@ -0,0 +1,7 @@ +import { isConformant } from 'test/specs/commonTests' + +import ToolbarDivider from 'src/components/Toolbar/ToolbarDivider' + +describe('ToolbarDivider', () => { + isConformant(ToolbarDivider) +}) diff --git a/packages/react/test/specs/components/Toolbar/ToolbarItem-test.ts b/packages/react/test/specs/components/Toolbar/ToolbarItem-test.ts new file mode 100644 index 0000000000..233e03a262 --- /dev/null +++ b/packages/react/test/specs/components/Toolbar/ToolbarItem-test.ts @@ -0,0 +1,7 @@ +import { isConformant } from 'test/specs/commonTests' + +import ToolbarItem from 'src/components/Toolbar/ToolbarItem' + +describe('ToolbarItem', () => { + isConformant(ToolbarItem) +}) diff --git a/packages/react/test/specs/components/Toolbar/ToolbarRadioGroup-test.ts b/packages/react/test/specs/components/Toolbar/ToolbarRadioGroup-test.ts new file mode 100644 index 0000000000..7868c03046 --- /dev/null +++ b/packages/react/test/specs/components/Toolbar/ToolbarRadioGroup-test.ts @@ -0,0 +1,7 @@ +import { isConformant } from 'test/specs/commonTests' + +import ToolbarRadioGroup from 'src/components/Toolbar/ToolbarRadioGroup' + +describe('ToolbarRadioGroup', () => { + isConformant(ToolbarRadioGroup) +})