diff --git a/src/__snapshots__/storybook.test.js.snap b/src/__snapshots__/storybook.test.js.snap index 8998f5e6e..24a789b8f 100644 --- a/src/__snapshots__/storybook.test.js.snap +++ b/src/__snapshots__/storybook.test.js.snap @@ -153,7 +153,7 @@ Array [ , +
, +
, +

+ Text + Right Icon +

, + + +
+ A tooltip +
+
+ +
, +
, +
, +

+ Medium +

, +
+ + +
+ +
+
+ A tooltip +
+
+ +
, +
, +
, +

+ Small +

, +
+ + +
+ +
+
+ A tooltip +
+
+ +
, +
, +
, +] +`; + exports[`Storyshots List Default 1`] = ` Array [

@@ -5488,7 +5794,7 @@ Array [ aria-disabled={false} aria-expanded={false} aria-haspopup={true} - className="referenceWrapper button buttonDefault" + className="button buttonDefault" defaultChecked={false} disabled={false} onClick={[Function]} @@ -5514,7 +5820,7 @@ Array [ aria-disabled={false} aria-expanded={false} aria-haspopup={true} - className="referenceWrapper button buttonDefault buttonDisruptive" + className="button buttonDefault buttonDisruptive" defaultChecked={false} disabled={false} onClick={[Function]} @@ -5899,7 +6205,7 @@ Array [ ); diff --git a/src/components/Button/button.module.scss b/src/components/Button/button.module.scss index 2a341a901..a86f08d55 100644 --- a/src/components/Button/button.module.scss +++ b/src/components/Button/button.module.scss @@ -125,6 +125,30 @@ } } + &.icon-left { + span { + transform: none; + } + } + + &.icon-right { + span { + transform: scaleX(-1); + } + + &.left { + span { + justify-content: right; + } + } + + &.right { + span { + justify-content: left; + } + } + } + &:disabled, &.disabled { opacity: $disabled-alpha-value; diff --git a/src/components/COMPONENTS.md b/src/components/COMPONENTS.md index a32b1ac01..2c8e78f90 100644 --- a/src/components/COMPONENTS.md +++ b/src/components/COMPONENTS.md @@ -40,21 +40,21 @@ Create a file called `/src/components/Component/Component.tsx` ```tsx import React, { FC } from 'react'; import { ComponentProps, ComponentType } from './Component.types'; -import { classNames } from '../../shared/utilities'; +import { mergeClasses } from '../../shared/utilities'; import styles from 'component.module.scss'; export const Component: FC = ({ - className, + classNames, style, // How to set defaults for props type = ComponentType.base, ... }) => { - // Combining class names can be done using the classNames utility - const componentClasses: string = classNames([ + // Combining class names can be done using the mergeClasses utility + const componentClasses: string = mergeClasses([ styles.componentWrapper, - className, + classNames, // Conditional classes can also be handled as follows { [styles.active]: type === ComponentType.base } ]); @@ -109,10 +109,10 @@ export interface ComponentProps { */ children: React.ReactNode; /** - * Custom class name + * Custom class names * @default null */ - className?: string; + classNames?: string; /** * Style of the component * @default null diff --git a/src/components/ConfigProvider/ConfigProvider.stories.tsx b/src/components/ConfigProvider/ConfigProvider.stories.tsx index 13a803ae8..6cbc58948 100644 --- a/src/components/ConfigProvider/ConfigProvider.stories.tsx +++ b/src/components/ConfigProvider/ConfigProvider.stories.tsx @@ -106,13 +106,13 @@ const ThemedComponents = () => { ariaLabel="Primary Button" onClick={click} size={ButtonSize.Large} - icon={IconName.mdiCardsHeart} + iconProps={{ path: IconName.mdiCardsHeart }} />

@@ -127,7 +127,7 @@ const ThemedComponents = () => { /> @@ -136,7 +136,7 @@ const ThemedComponents = () => { onClick={click} size={ButtonSize.Large} text="Secondary Button" - icon={IconName.mdiCardsHeart} + iconProps={{ path: IconName.mdiCardsHeart }} />

@@ -150,13 +150,13 @@ const ThemedComponents = () => { /> = ({ width, zIndex, header, - headerClassName, + headerClassNames, body, - bodyClassName, + bodyClassNames, actions, - actionsClassName, - dialogWrapperClassName, - dialogClassName, + actionsClassNames, + dialogWrapperClassNames, + dialogClassNames, }) => { const labelId = uniqueId('dialog-label-'); const { lockScroll, unlockScroll } = useScrollLock(parent); - const dialogBackdropClasses: string = classNames([ + const dialogBackdropClasses: string = mergeClasses([ styles.dialogBackdrop, - dialogWrapperClassName, + dialogWrapperClassNames, { [styles.visible]: visible }, ]); - const dialogClasses: string = classNames([styles.dialog, dialogClassName]); + const dialogClasses: string = mergeClasses([ + styles.dialog, + dialogClassNames, + ]); - const headerClasses: string = classNames([styles.header, headerClassName]); + const headerClasses: string = mergeClasses([ + styles.header, + headerClassNames, + ]); const dialogStyle: React.CSSProperties = { zIndex, @@ -76,10 +82,13 @@ export const BaseDialog: FC = ({ >
{header} - +
-
{body}
- {actions &&
{actions}
} +
{body}
+ {actions &&
{actions}
} ); diff --git a/src/components/Dialog/BaseDialog/BaseDialog.types.ts b/src/components/Dialog/BaseDialog/BaseDialog.types.ts index 3783e754d..3ec9eea8a 100644 --- a/src/components/Dialog/BaseDialog/BaseDialog.types.ts +++ b/src/components/Dialog/BaseDialog/BaseDialog.types.ts @@ -25,25 +25,25 @@ export interface BaseDialogProps { */ onVisibleChange?: (visible: boolean) => void; /** - * Custom class for the dialog wrapper + * Custom classes for the dialog wrapper */ - dialogWrapperClassName?: string; + dialogWrapperClassNames?: string; /** - * Custom class for the dialog + * Custom classes for the dialog */ - dialogClassName?: string; + dialogClassNames?: string; /** - * Custom class for the header + * Custom classes for the header */ - headerClassName?: string; + headerClassNames?: string; /** - * Custom class for the body + * Custom classes for the body */ - bodyClassName?: string; + bodyClassNames?: string; /** - * Custom class for the actions wrapper + * Custom classes for the actions wrapper */ - actionsClassName?: string; + actionsClassNames?: string; /** * The header of the dialog */ diff --git a/src/components/Dialog/Dialog.tsx b/src/components/Dialog/Dialog.tsx index 8c0748be3..a2cce9bb0 100644 --- a/src/components/Dialog/Dialog.tsx +++ b/src/components/Dialog/Dialog.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { DialogProps, DialogSize } from './Dialog.types'; -import { classNames } from '../../shared/utilities'; +import { mergeClasses } from '../../shared/utilities'; import { DefaultButton, PrimaryButton } from '../Button'; import { BaseDialog } from './BaseDialog/BaseDialog'; @@ -9,39 +9,42 @@ import styles from './dialog.module.scss'; export const Dialog: FC = ({ parent = document.body, size = DialogSize.medium, - headerClassName, - bodyClassName, - actionsClassName, - dialogClassName, + headerClassNames, + bodyClassNames, + actionsClassNames, + dialogClassNames, okButtonProps, cancelButtonProps, onOk, onCancel, ...rest }) => { - const dialogClasses: string = classNames([ + const dialogClasses: string = mergeClasses([ styles.dialog, - dialogClassName, + dialogClassNames, { [styles.small]: size === DialogSize.small }, { [styles.medium]: size === DialogSize.medium }, ]); - const headerClasses: string = classNames([styles.header, headerClassName]); + const headerClasses: string = mergeClasses([ + styles.header, + headerClassNames, + ]); - const bodyClasses: string = classNames([styles.body, bodyClassName]); + const bodyClasses: string = mergeClasses([styles.body, bodyClassNames]); - const actionClasses: string = classNames([ + const actionClasses: string = mergeClasses([ styles.actions, - actionsClassName, + actionsClassNames, ]); return ( {cancelButtonProps && ( diff --git a/src/components/Dropdown/Dropdown.tsx b/src/components/Dropdown/Dropdown.tsx index 84f804b20..6a1174a5c 100644 --- a/src/components/Dropdown/Dropdown.tsx +++ b/src/components/Dropdown/Dropdown.tsx @@ -2,7 +2,7 @@ import React, { cloneElement, FC, useEffect, useState } from 'react'; import { DropdownProps } from './Dropdown.types'; import { autoUpdate, shift, useFloating } from '@floating-ui/react-dom'; import { offset as fOffset } from '@floating-ui/core'; -import { classNames, uniqueId } from '../../shared/utilities'; +import { mergeClasses, uniqueId } from '../../shared/utilities'; import { useOnClickOutside } from '../../hooks/useOnClickOutside'; import styles from './dropdown.module.scss'; @@ -17,9 +17,9 @@ const ANIMATION_DURATION = 200; export const Dropdown: FC = ({ trigger = 'click', - className, + classNames, style, - dropdownClassName, + dropdownClassNames, dropdownStyle, children, placement = 'bottom-start', @@ -70,19 +70,19 @@ export const Dropdown: FC = ({ ); }, [refs.reference, refs.floating, update]); - const dropdownClasses: string = classNames([ - dropdownClassName, + const dropdownClasses: string = mergeClasses([ + dropdownClassNames, styles.dropdownWrapper, { [styles.open]: visible }, { [styles.close]: closing }, ]); - const mainWrapperClasses: string = classNames([ - className, + const mainWrapperClasses: string = mergeClasses([ + classNames, styles.mainWrapper, ]); - const referenceWrapperClasses: string = classNames([ + const referenceWrapperClasses: string = mergeClasses([ styles.referenceWrapper, { [styles.disabled]: false }, ]); diff --git a/src/components/Dropdown/Dropdown.types.ts b/src/components/Dropdown/Dropdown.types.ts index 7c17396f1..56c81fd90 100644 --- a/src/components/Dropdown/Dropdown.types.ts +++ b/src/components/Dropdown/Dropdown.types.ts @@ -20,9 +20,9 @@ export interface DropdownProps { */ disabled?: boolean; /** - * Class name of the main wrapper + * Class names of the main wrapper */ - className?: string; + classNames?: string; /** * Style of the main wrapper */ @@ -43,9 +43,9 @@ export interface DropdownProps { */ offset?: number; /** - * Custom dropdown class name + * Custom dropdown class names */ - dropdownClassName?: string; + dropdownClassNames?: string; /** * Dropdown custom style */ diff --git a/src/components/Icon/Icon.tsx b/src/components/Icon/Icon.tsx index 264da5d16..57cdd1e83 100644 --- a/src/components/Icon/Icon.tsx +++ b/src/components/Icon/Icon.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import { classNames } from '../../shared/utilities'; +import { mergeClasses } from '../../shared/utilities'; import { Icon as MdiIcon } from '@mdi/react'; import { IconProps, IconSize } from './index'; @@ -7,7 +7,7 @@ import styles from './icon.module.scss'; export const Icon: FC = ({ ariaHidden = false, - className, + classNames, color, description, horizontal, @@ -20,7 +20,10 @@ export const Icon: FC = ({ title, vertical, }) => { - const iconClassNames: string = classNames([className, styles.iconWrapper]); + const iconClassNames: string = mergeClasses([ + classNames, + styles.iconWrapper, + ]); return ( = ({ closable, onClose, style, - className, + classNames, closeIcon = IconName.mdiClose, closeButtonProps, actionButtonProps, role = 'presentation', }) => { - const infoBarClasses: string = classNames([ + const infoBarClasses: string = mergeClasses([ styles.infoBar, - className, + classNames, { [styles.neutral]: type === InfoBarType.neutral }, { [styles.positive]: type === InfoBarType.positive }, { [styles.warning]: type === InfoBarType.warning }, { [styles.disruptive]: type === InfoBarType.disruptive }, ]); - const messageClasses: string = classNames([styles.message, 'body2']); + const messageClasses: string = mergeClasses([styles.message, 'body2']); const getIconName = (): IconName => { if (icon) { @@ -47,12 +47,12 @@ export const InfoBar: FC = ({ return (
- +
{content}
{actionButtonProps && } {closable && ( { /** * The icon img alt text. */ alt?: string; /** - * The icon is aria-hidden. - * @default false - */ - ariaHidden?: boolean; - /** - * The icon color. - */ - color?: string; - /** - * The icon description. + * The optional icon svg path name. */ - description?: string; - /** - * The icon is horizontal. - * @default false - */ - horizontal?: boolean; - /** - * The icon id. - */ - id?: string; + path?: IconName; /** * The icon image source url. */ imageSrc?: string; - /** - * The icon svg path name. - */ - path?: IconName; - /** - * The icon is rotated. - * @default 0 - */ - rotate?: number; - /** - * The icon title. - */ - title?: string; - /** - * The icon is vertical. - * @default false - */ - vertical?: boolean; } export interface InputIconButtonProps { @@ -96,9 +61,9 @@ export interface InputIconButtonProps { */ htmlType?: 'button' | 'submit' | 'reset'; /** - * The input button icon path. + * The input button icon props. */ - icon?: IconName; + iconProps?: IconProps; /** * The input icon button id. */ @@ -125,13 +90,9 @@ export interface InputLabelIconButtonProps { */ disabled?: boolean; /** - * The label icon button path. + * The label icon button props. */ - icon?: IconName; - /** - * The label icon button color. - */ - iconColor?: string; + iconProps?: IconProps; /** * The label icon button id. */ @@ -232,7 +193,7 @@ export interface InputProps { /** * The input class names. */ - className?: string; + classNames?: string; /** * The input clear button aria label text. */ @@ -264,13 +225,9 @@ export interface InputProps { */ imageSource?: string; /** - * The input label text. - */ - label?: string; - /** - * The input label icon button props. + * The input label props. */ - labelIconButtonProps?: InputLabelIconButtonProps; + labelProps?: LabelProps; /** * The input maxlength. */ diff --git a/src/components/Inputs/SearchBox/SearchBox.stories.tsx b/src/components/Inputs/SearchBox/SearchBox.stories.tsx index 55f9d4146..71e309bb5 100644 --- a/src/components/Inputs/SearchBox/SearchBox.stories.tsx +++ b/src/components/Inputs/SearchBox/SearchBox.stories.tsx @@ -11,21 +11,27 @@ export const Search = () => ( <>

Search Boxes

Search Box Stretch (Rectangle)

- +

Search Box with Icon and Icon Button (Rectangle)

+ _alertClicked(_event), + }, + text: 'Label', + }} iconProps={{ path: IconName.mdiCardsHeart, color: 'red' }} iconButtonProps={{ - icon: IconName.mdiMagnify, - onClick: (_event: React.MouseEvent) => _alertClicked(_event), - }} - labelIconButtonProps={{ - show: true, - toolTipContent: 'A tooltip', - toolTipPlacement: 'top', + iconProps: { path: IconName.mdiMagnify }, onClick: (_event: React.MouseEvent) => _alertClicked(_event), }} /> @@ -33,13 +39,13 @@ export const Search = () => (

Search Box with Image Icon (Rectangle)

_alertClicked(_event), }} /> @@ -47,11 +53,11 @@ export const Search = () => (

Search Box Stretch (Pill)

_alertClicked(_event), }} /> @@ -59,10 +65,10 @@ export const Search = () => (

Search Box with Icon (Pill)

_alertClicked(_event), }} shape={TextInputShape.Pill} @@ -71,13 +77,13 @@ export const Search = () => (

Search Box with Image Icon (Pill)

_alertClicked(_event), }} shape={TextInputShape.Pill} diff --git a/src/components/Inputs/SearchBox/SearchBox.tsx b/src/components/Inputs/SearchBox/SearchBox.tsx index 559ce3ad1..b12e18bb6 100644 --- a/src/components/Inputs/SearchBox/SearchBox.tsx +++ b/src/components/Inputs/SearchBox/SearchBox.tsx @@ -12,18 +12,17 @@ export const SearchBox: FC = ({ allowDisabledFocus = false, ariaLabel, autoFocus = false, - className, + classNames, clearButtonAriaLabel, disabled = false, iconProps, iconButtonProps = { allowDisabledFocus: false, disabled: false, - icon: IconName.mdiMagnify, + iconProps: { path: IconName.mdiMagnify }, }, inputWidth = TextInputWidth.fitContent, - label, - labelIconButtonProps, + labelProps, maxlength, minlength, name, @@ -43,15 +42,14 @@ export const SearchBox: FC = ({ allowDisabledFocus={allowDisabledFocus} ariaLabel={ariaLabel} autoFocus={autoFocus} - className={className} + classNames={classNames} clearButtonAriaLabel={clearButtonAriaLabel} disabled={disabled} htmlType="search" iconProps={iconProps} iconButtonProps={iconButtonProps} inputWidth={inputWidth} - label={label} - labelIconButtonProps={labelIconButtonProps} + labelProps={labelProps} maxlength={maxlength} minlength={minlength} name={name} diff --git a/src/components/Inputs/TextArea/TextArea.stories.tsx b/src/components/Inputs/TextArea/TextArea.stories.tsx index 7095d387a..34b237843 100644 --- a/src/components/Inputs/TextArea/TextArea.stories.tsx +++ b/src/components/Inputs/TextArea/TextArea.stories.tsx @@ -10,23 +10,28 @@ export const Area = () => ( <>

Text Areas

Text Area No Expand Stretch (Rectangle)

-