From 0c1f23378c7745aa42b21b1f9a30514bca5098d7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 22 Sep 2025 16:58:34 +0200 Subject: [PATCH 1/5] feat(components/atom/input): Add button accessibility --- .../src/Input/Wrappers/Icons/InputIcons.js | 94 +++++++++++++++---- .../input/src/Input/Wrappers/Icons/config.js | 3 +- .../input/src/Input/Wrappers/Icons/index.scss | 32 ++++--- components/atom/input/src/Input/index.js | 16 ++++ 4 files changed, 114 insertions(+), 31 deletions(-) diff --git a/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js b/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js index dbc5617aa8..9ba0838af8 100644 --- a/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js +++ b/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js @@ -1,17 +1,30 @@ import cx from 'classnames' import PropTypes from 'prop-types' +import Button from '@s-ui/react-atom-button' + import { BASE_CLASS_ICON, + BASE_CLASS_ICON_BUTTON, + BASE_CLASS_ICON_BUTTON_CONTAINER, BASE_CLASS_ICON_COMPONENT, - BASE_CLASS_ICON_COMPONENT_HANDLER, BASE_CLASS_ICON_COMPONENT_LEFT, BASE_CLASS_ICON_COMPONENT_RIGHT, BASE_CLASS_ICON_LEFT, BASE_CLASS_ICON_RIGHT } from './config.js' -const InputIcons = ({leftIcon, rightIcon, onClickLeftIcon, onClickRightIcon, children}) => { +const InputIcons = ({ + leftIcon, + rightIcon, + onClickLeftIcon, + onClickRightIcon, + ariaLabelLeftIcon, + ariaLabelRightIcon, + leftIconButtonProps, + rightIconButtonProps, + children +}) => { if (!(leftIcon || rightIcon)) { return children } @@ -23,6 +36,12 @@ const InputIcons = ({leftIcon, rightIcon, onClickLeftIcon, onClickRightIcon, chi onClickRightIcon && onClickRightIcon(event) } + const defaultButtonProps = { + design: 'flat', + color: 'neutral', + type: 'button' + } + return (
{leftIcon && ( - - {leftIcon} - + <> + {onClickLeftIcon ? ( + + ) : ( + {leftIcon} + )} + )} {children} {rightIcon && ( - - {rightIcon} - + <> + {onClickRightIcon ? ( + + ) : ( + {rightIcon} + )} + )}
) @@ -69,7 +113,19 @@ InputIcons.propTypes = { onClickLeftIcon: PropTypes.func, /* Right icon click callback */ - onClickRightIcon: PropTypes.func + onClickRightIcon: PropTypes.func, + + /* Right icon aria-label */ + ariaLabelRightIcon: PropTypes.string, + + /* Left icon aria-label */ + ariaLabelLeftIcon: PropTypes.string, + + /* Left icon button props */ + leftIconButtonProps: PropTypes.object, + + /* Right icon button props */ + rightIconButtonProps: PropTypes.object } export default InputIcons diff --git a/components/atom/input/src/Input/Wrappers/Icons/config.js b/components/atom/input/src/Input/Wrappers/Icons/config.js index 4d415eb0d6..3989a116a1 100644 --- a/components/atom/input/src/Input/Wrappers/Icons/config.js +++ b/components/atom/input/src/Input/Wrappers/Icons/config.js @@ -9,6 +9,7 @@ export const BASE_CLASS_ICON = `${BASE}--withIcon` export const BASE_CLASS_ICON_LEFT = `${BASE_CLASS_ICON}--${ICON_TYPES.LEFT}` export const BASE_CLASS_ICON_RIGHT = `${BASE_CLASS_ICON}--${ICON_TYPES.RIGHT}` export const BASE_CLASS_ICON_COMPONENT = `${BASE_CLASS_ICON}-icon` -export const BASE_CLASS_ICON_COMPONENT_HANDLER = `${BASE_CLASS_ICON_COMPONENT}--withHandler` +export const BASE_CLASS_ICON_BUTTON = `${BASE_CLASS_ICON}-button` +export const BASE_CLASS_ICON_BUTTON_CONTAINER = `${BASE_CLASS_ICON}-button-container` export const BASE_CLASS_ICON_COMPONENT_LEFT = `${BASE_CLASS_ICON_COMPONENT}--${ICON_TYPES.LEFT}` export const BASE_CLASS_ICON_COMPONENT_RIGHT = `${BASE_CLASS_ICON_COMPONENT}--${ICON_TYPES.RIGHT}` diff --git a/components/atom/input/src/Input/Wrappers/Icons/index.scss b/components/atom/input/src/Input/Wrappers/Icons/index.scss index f493df3295..7fd6d8e40d 100644 --- a/components/atom/input/src/Input/Wrappers/Icons/index.scss +++ b/components/atom/input/src/Input/Wrappers/Icons/index.scss @@ -10,6 +10,27 @@ padding-right: $pr-atom-input-input; } + &-button { + position: relative; + padding: 0; + min-width: 0; + + // Expand clickable area + &::before { + content: ''; + position: absolute; + top: -8px; + bottom: -8px; + left: -8px; + right: -8px; + background: transparent; + } + + &-container { + width: 24px; + } + } + &-icon { align-items: center; color: $c-atom-input-icon; @@ -21,12 +42,6 @@ top: $t-atom-input-icon; transform: translateY($trf-ty-atom-input-icon); width: $w-atom-input-icon; - pointer-events: none; - - &--withHandler { - cursor: pointer; - pointer-events: auto; - } &--left { left: $l-atom-input-icon; @@ -35,10 +50,5 @@ &--right { right: $r-atom-input-icon; } - - & > * { - height: 100%; - width: 100%; - } } } diff --git a/components/atom/input/src/Input/index.js b/components/atom/input/src/Input/index.js index 979558b829..2a03e1f6a1 100644 --- a/components/atom/input/src/Input/index.js +++ b/components/atom/input/src/Input/index.js @@ -19,6 +19,10 @@ const BaseInput = forwardRef( children, onClickLeftIcon, onClickRightIcon, + ariaLabelLeftIcon, + ariaLabelRightIcon, + leftIconButtonProps, + rightIconButtonProps, size = SIZES.MEDIUM, shape, ...inputProps @@ -33,6 +37,10 @@ const BaseInput = forwardRef( rightIcon={rightIcon} onClickLeftIcon={onClickLeftIcon} onClickRightIcon={onClickRightIcon} + ariaLabelLeftIcon={ariaLabelLeftIcon} + ariaLabelRightIcon={ariaLabelRightIcon} + leftIconButtonProps={leftIconButtonProps} + rightIconButtonProps={rightIconButtonProps} > {children} @@ -61,6 +69,14 @@ BaseInput.propTypes = { onClickLeftIcon: PropTypes.func, /* Right icon click callback */ onClickRightIcon: PropTypes.func, + /* Right icon aria-label */ + ariaLabelRightIcon: PropTypes.string, + /* Left icon aria-label */ + ariaLabelLeftIcon: PropTypes.string, + /* Left icon button props */ + leftIconButtonProps: PropTypes.object, + /* Right icon button props */ + rightIconButtonProps: PropTypes.object, /* Sets the size of the inputAddon */ size: PropTypes.oneOf(Object.values(SIZES)), /* Sets the shape of the input */ From dee346476eea3e041573a6d8d6ea02be454ca22c Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 22 Sep 2025 16:59:58 +0200 Subject: [PATCH 2/5] feat(components/atom/input/demo): add Interactive Icons section --- .../demo/articles/ArticleAddonAndIcon.js | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/components/atom/input/demo/articles/ArticleAddonAndIcon.js b/components/atom/input/demo/articles/ArticleAddonAndIcon.js index edb5d084fd..38e58c04e4 100644 --- a/components/atom/input/demo/articles/ArticleAddonAndIcon.js +++ b/components/atom/input/demo/articles/ArticleAddonAndIcon.js @@ -130,6 +130,87 @@ const ArticleAddonAndIcon = ({className}) => { /> +

Interactive Icons

+ + Icons can be made interactive by adding click handlers. This is useful for actions like search, clear input, or + triggering additional functionality. + + + + Left Icon Actions + + + + + } + ariaLabelLeftIcon="Show help information" + onClickLeftIcon={() => alert('Email format: example@domain.com')} + /> + + + + Right Icon Actions + + + + } + ariaLabelRightIcon="Clear input" + onClickRightIcon={() => { + document.getElementById('input-clear-action').value = '' + }} + /> + + + +

Button Customization

+ + Use leftIconButtonProps and rightIconButtonProps to customize the appearance and + behavior of icon buttons with any AtomButton properties. + + + + + + Custom Button Designs + + + + + } + ariaLabelLeftIcon="Search" + onClickLeftIcon={() => alert('Searching...')} + leftIconButtonProps={{ + design: 'solid', + color: 'primary' + }} + /> + + + + + + + } + ariaLabelRightIcon="Apply filters" + onClickRightIcon={() => alert('Applying filters...')} + rightIconButtonProps={{ + design: 'outline' + }} + /> + + ) } From edd2aabb10231e514142baa49e88708187e46588 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 26 Sep 2025 13:30:56 +0200 Subject: [PATCH 3/5] feat(components/atom/input): use css vars --- .../atom/input/src/Input/Wrappers/Icons/index.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/atom/input/src/Input/Wrappers/Icons/index.scss b/components/atom/input/src/Input/Wrappers/Icons/index.scss index 7fd6d8e40d..5cbe3a9e71 100644 --- a/components/atom/input/src/Input/Wrappers/Icons/index.scss +++ b/components/atom/input/src/Input/Wrappers/Icons/index.scss @@ -19,15 +19,15 @@ &::before { content: ''; position: absolute; - top: -8px; - bottom: -8px; - left: -8px; - right: -8px; + top: -$m-m; + bottom: -$m-m; + left: -$m-m; + right: -$m-m; background: transparent; } &-container { - width: 24px; + width: $sz-icon-m; } } From 87045b49a407fc264fdad75b6885a6abb0f8e382 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 10 Oct 2025 14:28:08 +0200 Subject: [PATCH 4/5] feat(components/atom/input): change sui button for unstyled button --- .../input/src/Input/Wrappers/Icons/InputIcons.js | 12 ++++-------- .../atom/input/src/Input/Wrappers/Icons/index.scss | 6 ++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js b/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js index 9ba0838af8..1cae700cad 100644 --- a/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js +++ b/components/atom/input/src/Input/Wrappers/Icons/InputIcons.js @@ -1,8 +1,6 @@ import cx from 'classnames' import PropTypes from 'prop-types' -import Button from '@s-ui/react-atom-button' - import { BASE_CLASS_ICON, BASE_CLASS_ICON_BUTTON, @@ -37,8 +35,6 @@ const InputIcons = ({ } const defaultButtonProps = { - design: 'flat', - color: 'neutral', type: 'button' } @@ -52,7 +48,7 @@ const InputIcons = ({ {leftIcon && ( <> {onClickLeftIcon ? ( - + ) : ( {leftIcon} )} @@ -76,7 +72,7 @@ const InputIcons = ({ {rightIcon && ( <> {onClickRightIcon ? ( - + ) : ( {rightIcon} )} diff --git a/components/atom/input/src/Input/Wrappers/Icons/index.scss b/components/atom/input/src/Input/Wrappers/Icons/index.scss index 5cbe3a9e71..b699cafdcd 100644 --- a/components/atom/input/src/Input/Wrappers/Icons/index.scss +++ b/components/atom/input/src/Input/Wrappers/Icons/index.scss @@ -11,6 +11,7 @@ } &-button { + @include reset-button; position: relative; padding: 0; min-width: 0; @@ -29,6 +30,11 @@ &-container { width: $sz-icon-m; } + + &:hover { + background-color: $c-gray-light-3; + border-radius: $p-xs; + } } &-icon { From 8fe9ecea7065e7470caac257b3a6d36f0301ff87 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 10 Oct 2025 14:28:32 +0200 Subject: [PATCH 5/5] feat(components/atom/input/demo): change sui button for unstyled button --- components/atom/input/demo/articles/ArticleAddonAndIcon.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/atom/input/demo/articles/ArticleAddonAndIcon.js b/components/atom/input/demo/articles/ArticleAddonAndIcon.js index 38e58c04e4..25567576c0 100644 --- a/components/atom/input/demo/articles/ArticleAddonAndIcon.js +++ b/components/atom/input/demo/articles/ArticleAddonAndIcon.js @@ -171,7 +171,7 @@ const ArticleAddonAndIcon = ({className}) => {

Button Customization

Use leftIconButtonProps and rightIconButtonProps to customize the appearance and - behavior of icon buttons with any AtomButton properties. + behavior of icon buttons. @@ -189,8 +189,7 @@ const ArticleAddonAndIcon = ({className}) => { ariaLabelLeftIcon="Search" onClickLeftIcon={() => alert('Searching...')} leftIconButtonProps={{ - design: 'solid', - color: 'primary' + style: {backgroundColor: '#1890ff', color: '#fff'} }} /> @@ -206,7 +205,7 @@ const ArticleAddonAndIcon = ({className}) => { ariaLabelRightIcon="Apply filters" onClickRightIcon={() => alert('Applying filters...')} rightIconButtonProps={{ - design: 'outline' + style: {backgroundColor: 'red', color: '#fff'} }} />