diff --git a/__snapshots__/checkbox/patternhub/checkbox-properties-should-match-screenshot.png b/__snapshots__/checkbox/patternhub/checkbox-properties-should-match-screenshot.png index 395cdf740bc9..6555d9e78464 100644 Binary files a/__snapshots__/checkbox/patternhub/checkbox-properties-should-match-screenshot.png and b/__snapshots__/checkbox/patternhub/checkbox-properties-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/chromium-highContrast/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/chromium-highContrast/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png index 2bea7dc0179e..121316621a89 100644 Binary files a/__snapshots__/input/showcase/chromium-highContrast/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/chromium-highContrast/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml b/__snapshots__/input/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml index f73edee0a499..9c572177f758 100644 --- a/__snapshots__/input/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/input/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml @@ -86,6 +86,16 @@ - textbox "Label" - status - text: x_placeholder" / " + - link "Example - Length arrow_up_right\" / \"" + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status - link "Example - Types arrow_up_right\" / \"" - text: Label - textbox "Label" @@ -148,9 +158,6 @@ - textbox "Label" - status - text: Label - - spinbutton "Label" - - status - - text: Label - textbox "Label" - status - text: Label diff --git a/__snapshots__/input/showcase/chromium/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/chromium/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png index 8a325eec0147..008fa130711e 100644 Binary files a/__snapshots__/input/showcase/chromium/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/chromium/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/chromium/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml b/__snapshots__/input/showcase/chromium/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml index f73edee0a499..9c572177f758 100644 --- a/__snapshots__/input/showcase/chromium/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/input/showcase/chromium/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml @@ -86,6 +86,16 @@ - textbox "Label" - status - text: x_placeholder" / " + - link "Example - Length arrow_up_right\" / \"" + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status - link "Example - Types arrow_up_right\" / \"" - text: Label - textbox "Label" @@ -148,9 +158,6 @@ - textbox "Label" - status - text: Label - - spinbutton "Label" - - status - - text: Label - textbox "Label" - status - text: Label diff --git a/__snapshots__/input/showcase/firefox/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/firefox/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png index 9094bc43645b..88b2e9c248f6 100644 Binary files a/__snapshots__/input/showcase/firefox/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/firefox/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/firefox/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml b/__snapshots__/input/showcase/firefox/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml index 6d16f9680157..91313029165a 100644 --- a/__snapshots__/input/showcase/firefox/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/input/showcase/firefox/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml @@ -85,6 +85,16 @@ - text: Label - textbox "Label" - status + - link "Example - Length arrow_up_right\" / \"" + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status - link "Example - Types arrow_up_right\" / \"" - text: Label - textbox "Label" @@ -147,9 +157,6 @@ - textbox "Label" - status - text: Label - - spinbutton "Label" - - status - - text: Label - textbox "Label" - status - text: Label diff --git a/__snapshots__/input/showcase/mobile-chrome/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/mobile-chrome/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png index 9a220bdf88e2..796e53e0e90c 100644 Binary files a/__snapshots__/input/showcase/mobile-chrome/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/mobile-chrome/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/mobile-chrome/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml b/__snapshots__/input/showcase/mobile-chrome/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml index f73edee0a499..9c572177f758 100644 --- a/__snapshots__/input/showcase/mobile-chrome/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/input/showcase/mobile-chrome/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml @@ -86,6 +86,16 @@ - textbox "Label" - status - text: x_placeholder" / " + - link "Example - Length arrow_up_right\" / \"" + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status - link "Example - Types arrow_up_right\" / \"" - text: Label - textbox "Label" @@ -148,9 +158,6 @@ - textbox "Label" - status - text: Label - - spinbutton "Label" - - status - - text: Label - textbox "Label" - status - text: Label diff --git a/__snapshots__/input/showcase/mobile-safari/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/mobile-safari/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png index 4978bace777c..f0f9cf64aed9 100644 Binary files a/__snapshots__/input/showcase/mobile-safari/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/mobile-safari/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/mobile-safari/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml b/__snapshots__/input/showcase/mobile-safari/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml index f73edee0a499..9c572177f758 100644 --- a/__snapshots__/input/showcase/mobile-safari/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/input/showcase/mobile-safari/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml @@ -86,6 +86,16 @@ - textbox "Label" - status - text: x_placeholder" / " + - link "Example - Length arrow_up_right\" / \"" + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status - link "Example - Types arrow_up_right\" / \"" - text: Label - textbox "Label" @@ -148,9 +158,6 @@ - textbox "Label" - status - text: Label - - spinbutton "Label" - - status - - text: Label - textbox "Label" - status - text: Label diff --git a/__snapshots__/input/showcase/webkit/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/webkit/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png index 23a49635ee82..cd0a5fc3a160 100644 Binary files a/__snapshots__/input/showcase/webkit/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/webkit/DBInput-should-match-screenshot-1/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/webkit/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml b/__snapshots__/input/showcase/webkit/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml index f73edee0a499..9c572177f758 100644 --- a/__snapshots__/input/showcase/webkit/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/input/showcase/webkit/should-have-same-aria-snapshot/DBInput-should-have-same-aria-snapshot.yaml @@ -86,6 +86,16 @@ - textbox "Label" - status - text: x_placeholder" / " + - link "Example - Length arrow_up_right\" / \"" + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status + - text: Label + - textbox "Label" + - status - link "Example - Types arrow_up_right\" / \"" - text: Label - textbox "Label" @@ -148,9 +158,6 @@ - textbox "Label" - status - text: Label - - spinbutton "Label" - - status - - text: Label - textbox "Label" - status - text: Label diff --git a/packages/components/src/components/checkbox/checkbox.lite.tsx b/packages/components/src/components/checkbox/checkbox.lite.tsx index ae1915cd217a..e2e440d9e153 100644 --- a/packages/components/src/components/checkbox/checkbox.lite.tsx +++ b/packages/components/src/components/checkbox/checkbox.lite.tsx @@ -52,34 +52,26 @@ export default function DBCheckbox(props: DBCheckboxProps) { _invalidMessageId: undefined, _descByIds: '', _voiceOverFallback: '', - handleChange: (event: ChangeEvent) => { - if (props.onChange) { - props.onChange(event); - } - - if (props.change) { - props.change(event); - } - - useTarget({ - angular: () => - handleFrameworkEventAngular(this, event, 'checked'), - vue: () => handleFrameworkEventVue(() => {}, event, 'checked') - }); - + _invalidMessage: '', + hasValidState: () => { + return !!(props.validMessage ?? props.validation === 'valid'); + }, + handleValidation: () => { /* For a11y reasons we need to map the correct message with the checkbox */ if (!_ref?.validity.valid || props.validation === 'invalid') { state._descByIds = state._invalidMessageId; + state._invalidMessage = + props.invalidMessage || + _ref?.validationMessage || + DEFAULT_INVALID_MESSAGE; if (hasVoiceOver()) { - state._voiceOverFallback = - props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE; + state._voiceOverFallback = state._invalidMessage; delay(() => (state._voiceOverFallback = ''), 1000); } } else if ( - props.validation === 'valid' || - (_ref?.validity.valid && props.required) + state.hasValidState() && + _ref?.validity.valid && + props.required ) { state._descByIds = state._validMessageId; if (hasVoiceOver()) { @@ -93,6 +85,22 @@ export default function DBCheckbox(props: DBCheckboxProps) { state._descByIds = ''; } }, + handleChange: (event: ChangeEvent) => { + if (props.onChange) { + props.onChange(event); + } + + if (props.change) { + props.change(event); + } + + useTarget({ + angular: () => + handleFrameworkEventAngular(this, event, 'checked'), + vue: () => handleFrameworkEventVue(() => {}, event, 'checked') + }); + state.handleValidation(); + }, handleBlur: (event: InteractionEvent) => { if (props.onBlur) { props.onBlur(event); @@ -120,6 +128,7 @@ export default function DBCheckbox(props: DBCheckboxProps) { state._messageId = mId + DEFAULT_MESSAGE_ID_SUFFIX; state._validMessageId = mId + DEFAULT_VALID_MESSAGE_ID_SUFFIX; state._invalidMessageId = mId + DEFAULT_INVALID_MESSAGE_ID_SUFFIX; + state._invalidMessage = props.invalidMessage || DEFAULT_INVALID_MESSAGE; }); onUpdate(() => { @@ -213,21 +222,20 @@ export default function DBCheckbox(props: DBCheckboxProps) { {props.message} - - - {props.validMessage ?? DEFAULT_VALID_MESSAGE} - + + + {props.validMessage || DEFAULT_VALID_MESSAGE} + + - {props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE} + {state._invalidMessage} {/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html diff --git a/packages/components/src/components/checkbox/model.ts b/packages/components/src/components/checkbox/model.ts index fb9c1b7c7d85..1f6de378056e 100644 --- a/packages/components/src/components/checkbox/model.ts +++ b/packages/components/src/components/checkbox/model.ts @@ -7,6 +7,7 @@ import { FormMessageProps, FormProps, FormState, + FromValidState, GlobalProps, GlobalState, InitializedState, @@ -36,4 +37,5 @@ export type DBCheckboxState = DBCheckboxDefaultState & ChangeEventState & FocusEventState & FormState & - InitializedState; + InitializedState & + FromValidState; diff --git a/packages/components/src/components/input/input.lite.tsx b/packages/components/src/components/input/input.lite.tsx index c212054ff23d..b4b9781358cb 100644 --- a/packages/components/src/components/input/input.lite.tsx +++ b/packages/components/src/components/input/input.lite.tsx @@ -64,6 +64,42 @@ export default function DBInput(props: DBInputProps) { _descByIds: '', _value: '', _voiceOverFallback: '', + _invalidMessage: '', + hasValidState: () => { + return !!(props.validMessage ?? props.validation === 'valid'); + }, + handleValidation: () => { + /* For a11y reasons we need to map the correct message with the input */ + if (!_ref?.validity.valid || props.validation === 'invalid') { + state._descByIds = state._invalidMessageId; + state._invalidMessage = + props.invalidMessage || + _ref?.validationMessage || + DEFAULT_INVALID_MESSAGE; + if (hasVoiceOver()) { + state._voiceOverFallback = state._invalidMessage; + delay(() => (state._voiceOverFallback = ''), 1000); + } + } else if ( + state.hasValidState() && + _ref?.validity.valid && + (props.required || + props.minLength || + props.maxLength || + props.pattern) + ) { + state._descByIds = state._validMessageId; + if (hasVoiceOver()) { + state._voiceOverFallback = + props.validMessage ?? DEFAULT_VALID_MESSAGE; + delay(() => (state._voiceOverFallback = ''), 1000); + } + } else if (stringPropVisible(props.message, props.showMessage)) { + state._descByIds = state._messageId; + } else { + state._descByIds = ''; + } + }, handleInput: (event: InputEvent) => { if (props.onInput) { props.onInput(event); @@ -72,6 +108,12 @@ export default function DBInput(props: DBInputProps) { if (props.input) { props.input(event); } + + useTarget({ + angular: () => handleFrameworkEventAngular(this, event), + vue: () => handleFrameworkEventVue(() => {}, event) + }); + state.handleValidation(); }, handleChange: (event: ChangeEvent) => { if (props.onChange) { @@ -86,36 +128,7 @@ export default function DBInput(props: DBInputProps) { angular: () => handleFrameworkEventAngular(this, event), vue: () => handleFrameworkEventVue(() => {}, event) }); - - /* For a11y reasons we need to map the correct message with the input */ - if (!_ref?.validity.valid || props.validation === 'invalid') { - state._descByIds = state._invalidMessageId; - if (hasVoiceOver()) { - state._voiceOverFallback = - props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE; - delay(() => (state._voiceOverFallback = ''), 1000); - } - } else if ( - props.validation === 'valid' || - (_ref?.validity.valid && - (props.required || - props.minLength || - props.maxLength || - props.pattern)) - ) { - state._descByIds = state._validMessageId; - if (hasVoiceOver()) { - state._voiceOverFallback = - props.validMessage ?? DEFAULT_VALID_MESSAGE; - delay(() => (state._voiceOverFallback = ''), 1000); - } - } else if (stringPropVisible(props.message, props.showMessage)) { - state._descByIds = state._messageId; - } else { - state._descByIds = ''; - } + state.handleValidation(); }, handleBlur: (event: InteractionEvent) => { if (props.onBlur) { @@ -156,6 +169,7 @@ export default function DBInput(props: DBInputProps) { state._validMessageId = mId + DEFAULT_VALID_MESSAGE_ID_SUFFIX; state._invalidMessageId = mId + DEFAULT_INVALID_MESSAGE_ID_SUFFIX; state._dataListId = mId + DEFAULT_DATALIST_ID_SUFFIX; + state._invalidMessage = props.invalidMessage || DEFAULT_INVALID_MESSAGE; }); onUpdate(() => { @@ -257,20 +271,20 @@ export default function DBInput(props: DBInputProps) { - - {props.validMessage ?? DEFAULT_VALID_MESSAGE} - + + + {props.validMessage || DEFAULT_VALID_MESSAGE} + + - {props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE} + {state._invalidMessage} {/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html diff --git a/packages/components/src/components/input/model.ts b/packages/components/src/components/input/model.ts index 4e007a3e1e33..e47f74fc36da 100644 --- a/packages/components/src/components/input/model.ts +++ b/packages/components/src/components/input/model.ts @@ -8,6 +8,7 @@ import { FormSizeProps, FormState, FormTextProps, + FromValidState, GlobalProps, GlobalState, IconAfterProps, @@ -93,4 +94,5 @@ export type DBInputState = DBInputDefaultState & InputEventState & ChangeEventState & FocusEventState & - FormState; + FormState & + FromValidState; diff --git a/packages/components/src/components/select/model.ts b/packages/components/src/components/select/model.ts index 9432d81b898e..6c70326ab142 100644 --- a/packages/components/src/components/select/model.ts +++ b/packages/components/src/components/select/model.ts @@ -9,6 +9,7 @@ import { FormProps, FormSizeProps, FormState, + FromValidState, GlobalProps, GlobalState, IconProps, @@ -86,4 +87,5 @@ export type DBSelectState = DBSelectDefaultState & FocusEventState & InputEventState & FormState & - InitializedState; + InitializedState & + FromValidState; diff --git a/packages/components/src/components/select/select.lite.tsx b/packages/components/src/components/select/select.lite.tsx index b421230aa374..d5175ad77619 100644 --- a/packages/components/src/components/select/select.lite.tsx +++ b/packages/components/src/components/select/select.lite.tsx @@ -62,6 +62,39 @@ export default function DBSelect(props: DBSelectProps) { _value: '', initialized: false, _voiceOverFallback: '', + _invalidMessage: '', + hasValidState: () => { + return !!(props.validMessage ?? props.validation === 'valid'); + }, + handleValidation: () => { + /* For a11y reasons we need to map the correct message with the select */ + if (!_ref?.validity.valid || props.validation === 'invalid') { + state._descByIds = state._invalidMessageId; + state._invalidMessage = + props.invalidMessage || + _ref?.validationMessage || + DEFAULT_INVALID_MESSAGE; + if (hasVoiceOver()) { + state._voiceOverFallback = state._invalidMessage; + delay(() => (state._voiceOverFallback = ''), 1000); + } + } else if ( + state.hasValidState() && + _ref?.validity.valid && + props.required + ) { + state._descByIds = state._validMessageId; + if (hasVoiceOver()) { + state._voiceOverFallback = + props.validMessage ?? DEFAULT_VALID_MESSAGE; + delay(() => (state._voiceOverFallback = ''), 1000); + } + } else if (stringPropVisible(props.message, props.showMessage)) { + state._descByIds = state._messageId; + } else { + state._descByIds = state._placeholderId; + } + }, handleClick: (event: ClickEvent) => { if (props.onClick) { props.onClick(event); @@ -75,6 +108,12 @@ export default function DBSelect(props: DBSelectProps) { if (props.input) { props.input(event); } + + useTarget({ + angular: () => handleFrameworkEventAngular(this, event), + vue: () => handleFrameworkEventVue(() => {}, event) + }); + state.handleValidation(); }, handleChange: (event: ChangeEvent) => { if (props.onChange) { @@ -89,32 +128,7 @@ export default function DBSelect(props: DBSelectProps) { angular: () => handleFrameworkEventAngular(this, event), vue: () => handleFrameworkEventVue(() => {}, event) }); - - /* For a11y reasons we need to map the correct message with the select */ - if (!_ref?.validity.valid || props.validation === 'invalid') { - state._descByIds = state._invalidMessageId; - if (hasVoiceOver()) { - state._voiceOverFallback = - props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE; - delay(() => (state._voiceOverFallback = ''), 1000); - } - } else if ( - props.validation === 'valid' || - (_ref?.validity.valid && props.required) - ) { - state._descByIds = state._validMessageId; - if (hasVoiceOver()) { - state._voiceOverFallback = - props.validMessage ?? DEFAULT_VALID_MESSAGE; - delay(() => (state._voiceOverFallback = ''), 1000); - } - } else if (stringPropVisible(props.message, props.showMessage)) { - state._descByIds = state._messageId; - } else { - state._descByIds = state._placeholderId; - } + state.handleValidation(); }, handleBlur: (event: InteractionEvent) => { if (props.onBlur) { @@ -147,6 +161,7 @@ export default function DBSelect(props: DBSelectProps) { state._validMessageId = mId + DEFAULT_VALID_MESSAGE_ID_SUFFIX; state._invalidMessageId = mId + DEFAULT_INVALID_MESSAGE_ID_SUFFIX; state._placeholderId = mId + DEFAULT_PLACEHOLDER_ID_SUFFIX; + state._invalidMessage = props.invalidMessage || DEFAULT_INVALID_MESSAGE; }); onUpdate(() => { @@ -264,20 +279,20 @@ export default function DBSelect(props: DBSelectProps) { - - {props.validMessage ?? DEFAULT_VALID_MESSAGE} - + + + {props.validMessage || DEFAULT_VALID_MESSAGE} + + - {props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE} + {state._invalidMessage} {/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html diff --git a/packages/components/src/components/switch/switch.scss b/packages/components/src/components/switch/switch.scss index 1810812c4251..4950e92ee03c 100644 --- a/packages/components/src/components/switch/switch.scss +++ b/packages/components/src/components/switch/switch.scss @@ -36,7 +36,7 @@ $checked-active-transition-size: calc( } .db-switch { - @include form-components.set-default-check-element(check); + @include form-components.set-default-check-element(switch); user-select: none; diff --git a/packages/components/src/components/textarea/model.ts b/packages/components/src/components/textarea/model.ts index 8af0617785a5..c8c68a67ca8b 100644 --- a/packages/components/src/components/textarea/model.ts +++ b/packages/components/src/components/textarea/model.ts @@ -7,6 +7,7 @@ import { FormProps, FormState, FormTextProps, + FromValidState, GlobalProps, GlobalState, InputEventProps, @@ -64,4 +65,5 @@ export type DBTextareaState = DBTextareaDefaultState & InputEventState & FocusEventState & FormState & - GlobalState; + GlobalState & + FromValidState; diff --git a/packages/components/src/components/textarea/textarea.lite.tsx b/packages/components/src/components/textarea/textarea.lite.tsx index f2e2d5dd4301..c956f86e78dc 100644 --- a/packages/components/src/components/textarea/textarea.lite.tsx +++ b/packages/components/src/components/textarea/textarea.lite.tsx @@ -56,6 +56,39 @@ export default function DBTextarea(props: DBTextareaProps) { _descByIds: '', _value: '', _voiceOverFallback: '', + _invalidMessage: '', + hasValidState: () => { + return !!(props.validMessage ?? props.validation === 'valid'); + }, + handleValidation: () => { + /* For a11y reasons we need to map the correct message with the textarea */ + if (!_ref?.validity.valid || props.validation === 'invalid') { + state._descByIds = state._invalidMessageId; + state._invalidMessage = + props.invalidMessage || + _ref?.validationMessage || + DEFAULT_INVALID_MESSAGE; + if (hasVoiceOver()) { + state._voiceOverFallback = state._invalidMessage; + delay(() => (state._voiceOverFallback = ''), 1000); + } + } else if ( + state.hasValidState() && + _ref?.validity.valid && + (props.required || props.minLength || props.maxLength) + ) { + state._descByIds = state._validMessageId; + if (hasVoiceOver()) { + state._voiceOverFallback = + props.validMessage ?? DEFAULT_VALID_MESSAGE; + delay(() => (state._voiceOverFallback = ''), 1000); + } + } else if (stringPropVisible(props.message, props.showMessage)) { + state._descByIds = state._messageId; + } else { + state._descByIds = ''; + } + }, handleInput: (event: InputEvent) => { if (props.onInput) { props.onInput(event); @@ -64,6 +97,11 @@ export default function DBTextarea(props: DBTextareaProps) { if (props.input) { props.input(event); } + useTarget({ + angular: () => handleFrameworkEventAngular(this, event), + vue: () => handleFrameworkEventVue(() => {}, event) + }); + state.handleValidation(); }, handleChange: (event: ChangeEvent) => { if (props.onChange) { @@ -77,33 +115,7 @@ export default function DBTextarea(props: DBTextareaProps) { angular: () => handleFrameworkEventAngular(this, event), vue: () => handleFrameworkEventVue(() => {}, event) }); - - /* For a11y reasons we need to map the correct message with the textarea */ - if (!_ref?.validity.valid || props.validation === 'invalid') { - state._descByIds = state._invalidMessageId; - if (hasVoiceOver()) { - state._voiceOverFallback = - props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE; - delay(() => (state._voiceOverFallback = ''), 1000); - } - } else if ( - props.validation === 'valid' || - (_ref?.validity.valid && - (props.required || props.minLength || props.maxLength)) - ) { - state._descByIds = state._validMessageId; - if (hasVoiceOver()) { - state._voiceOverFallback = - props.validMessage ?? DEFAULT_VALID_MESSAGE; - delay(() => (state._voiceOverFallback = ''), 1000); - } - } else if (stringPropVisible(props.message, props.showMessage)) { - state._descByIds = state._messageId; - } else { - state._descByIds = ''; - } + state.handleValidation(); }, handleBlur: (event: InteractionEvent) => { if (props.onBlur) { @@ -131,6 +143,7 @@ export default function DBTextarea(props: DBTextareaProps) { state._messageId = mId + DEFAULT_MESSAGE_ID_SUFFIX; state._validMessageId = mId + DEFAULT_VALID_MESSAGE_ID_SUFFIX; state._invalidMessageId = mId + DEFAULT_INVALID_MESSAGE_ID_SUFFIX; + state._invalidMessage = props.invalidMessage || DEFAULT_INVALID_MESSAGE; }); onUpdate(() => { @@ -204,21 +217,20 @@ export default function DBTextarea(props: DBTextareaProps) { {props.message} - - - {props.validMessage ?? DEFAULT_VALID_MESSAGE} - + + + {props.validMessage || DEFAULT_VALID_MESSAGE} + + - {props.invalidMessage ?? - _ref?.validationMessage ?? - DEFAULT_INVALID_MESSAGE} + {state._invalidMessage} {/* * https://www.davidmacd.com/blog/test-aria-describedby-errormessage-aria-live.html diff --git a/packages/components/src/shared/model.ts b/packages/components/src/shared/model.ts index 4d387a4a590c..7b31406f6650 100644 --- a/packages/components/src/shared/model.ts +++ b/packages/components/src/shared/model.ts @@ -424,6 +424,12 @@ export type FormMessageProps = { showMessage?: boolean | string; }; +export type FromValidState = { + hasValidState: () => boolean; + handleValidation: () => void; + _invalidMessage: string; +}; + export type FormState = { _messageId?: string; _validMessageId?: string; diff --git a/packages/components/src/styles/internal/_form-components.scss b/packages/components/src/styles/internal/_form-components.scss index bffc1acf1777..0e558590b9a3 100644 --- a/packages/components/src/styles/internal/_form-components.scss +++ b/packages/components/src/styles/internal/_form-components.scss @@ -225,17 +225,13 @@ $input-valid-types: } @mixin get-validity($selector, $key: "valid") { - @if ($key == "valid") { - $boolean: "false"; - } - $user: ""; - @if ($selector == check) { + @if ($selector == check or $selector == switch) { $user: "user-"; } - @if ($selector == check or $selector == radio) { + @if ($selector == check or $selector == radio or $selector == switch) { $selector: input; &:has( @@ -288,7 +284,9 @@ $input-valid-types: @include set-required-label($selector); @include get-validity($selector) { - @include get-validity-color($selector, "valid"); + &:has(.db-infotext[data-semantic="successful"]) { + @include get-validity-color($selector, "valid"); + } } @include get-validity($selector, "invalid") { @@ -405,7 +403,7 @@ $input-valid-types: @include get-validity-message($key); - input { + input:not([role="switch"]) { --db-adaptive-bg-basic-transparent-semi: var( --db-#{$variant}-bg-basic-transparent-semi-default ); @@ -433,9 +431,11 @@ $input-valid-types: } } - &:is(label), - label { - color: var(--db-#{$variant}-on-bg-basic-emphasis-80-default); + &:has(input:not([role="switch"])) { + &:is(label), + label { + color: var(--db-#{$variant}-on-bg-basic-emphasis-80-default); + } } } @@ -445,7 +445,14 @@ $input-valid-types: @include set-required-label(input); @include get-validity($selector) { - @include get-validity-color-check("valid"); + @if ($selector == check) { + &:has(.db-infotext[data-semantic="successful"]) { + @include get-validity-color-check("valid"); + } + /* stylelint-disable-next-line at-rule-empty-line-before */ + } @else { + @include get-validity-color-check("valid"); + } } @include get-validity($selector, "invalid") { diff --git a/showcases/angular-showcase/src/app/components/input/input.component.html b/showcases/angular-showcase/src/app/components/input/input.component.html index 45186e747e2b..74c9ecc3b279 100644 --- a/showcases/angular-showcase/src/app/components/input/input.component.html +++ b/showcases/angular-showcase/src/app/components/input/input.component.html @@ -11,6 +11,7 @@ let-variantIndex="variantIndex" > { return (