From a544a1e985c1615e21f4aa51a7667b3f2ff332c7 Mon Sep 17 00:00:00 2001 From: Maja Zarkova <60856270+MajaZarkova@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:47:45 +0100 Subject: [PATCH] feat(OnyxForm): Add successMessage to useCustomValidity composable (#2031) Relates to #573 Add successMessage prop to useCustomValidity composable. This property will be provided in OnyxForm component and later injected by it's child input components to represent the success state. --- .../OnyxErrorTooltip/OnyxErrorTooltip.vue | 6 +-- .../src/components/OnyxFormElement/types.ts | 4 +- .../src/components/OnyxInput/OnyxInput.ct.tsx | 4 +- .../components/OnyxSelect/OnyxSelect.ct.tsx | 4 +- .../components/OnyxStepper/OnyxStepper.ct.tsx | 4 +- .../src/composables/useCustomValidity.ts | 53 ++++++++++++------- 6 files changed, 44 insertions(+), 31 deletions(-) diff --git a/packages/sit-onyx/src/components/OnyxErrorTooltip/OnyxErrorTooltip.vue b/packages/sit-onyx/src/components/OnyxErrorTooltip/OnyxErrorTooltip.vue index d819a65c68..158743db30 100644 --- a/packages/sit-onyx/src/components/OnyxErrorTooltip/OnyxErrorTooltip.vue +++ b/packages/sit-onyx/src/components/OnyxErrorTooltip/OnyxErrorTooltip.vue @@ -1,6 +1,6 @@ diff --git a/packages/sit-onyx/src/components/OnyxFormElement/types.ts b/packages/sit-onyx/src/components/OnyxFormElement/types.ts index e7528184ed..55bd186f30 100644 --- a/packages/sit-onyx/src/components/OnyxFormElement/types.ts +++ b/packages/sit-onyx/src/components/OnyxFormElement/types.ts @@ -1,5 +1,5 @@ import type { RequiredMarkerProp } from "../../composables/required"; -import type { FormErrorMessages } from "../../composables/useCustomValidity"; +import type { FormMessages } from "../../composables/useCustomValidity"; export type OnyxFormElementProps = RequiredMarkerProp & { /** @@ -40,7 +40,7 @@ export type OnyxFormElementProps = RequiredMarkerProp & { /** * Error messages that inform about causes for invalidity of form components */ - errorMessages?: FormErrorMessages; + errorMessages?: FormMessages; /** * Maximum number of characters that are allowed to be entered. * Warning: when the value is (pre)set programmatically, diff --git a/packages/sit-onyx/src/components/OnyxInput/OnyxInput.ct.tsx b/packages/sit-onyx/src/components/OnyxInput/OnyxInput.ct.tsx index 14e720caf0..a6730dbfb6 100644 --- a/packages/sit-onyx/src/components/OnyxInput/OnyxInput.ct.tsx +++ b/packages/sit-onyx/src/components/OnyxInput/OnyxInput.ct.tsx @@ -1,5 +1,5 @@ import { DENSITIES } from "../../composables/density"; -import type { FormErrorMessages } from "../../composables/useCustomValidity"; +import type { FormMessages } from "../../composables/useCustomValidity"; import { expect, test } from "../../playwright/a11y"; import { executeMatrixScreenshotTest } from "../../playwright/screenshots"; import { createFormElementUtils } from "../OnyxFormElement/OnyxFormElement.ct-utils"; @@ -108,7 +108,7 @@ test.describe("Screenshot tests", () => { const message = showLongMessage ? "Very long message that should be truncated" : "Test message"; - const errorMessages: FormErrorMessages = { + const errorMessages: FormMessages = { shortMessage: showLongMessage ? "Very long error preview that should be truncated" : "Test error", diff --git a/packages/sit-onyx/src/components/OnyxSelect/OnyxSelect.ct.tsx b/packages/sit-onyx/src/components/OnyxSelect/OnyxSelect.ct.tsx index 06202691a5..a86646fac8 100644 --- a/packages/sit-onyx/src/components/OnyxSelect/OnyxSelect.ct.tsx +++ b/packages/sit-onyx/src/components/OnyxSelect/OnyxSelect.ct.tsx @@ -1,7 +1,7 @@ import type { MountResultJsx } from "@playwright/experimental-ct-vue"; import { comboboxSelectOnlyTesting, comboboxTesting } from "@sit-onyx/headless/playwright"; import { DENSITIES } from "../../composables/density"; -import type { FormErrorMessages } from "../../composables/useCustomValidity"; +import type { FormMessages } from "../../composables/useCustomValidity"; import { expect, test } from "../../playwright/a11y"; import { adjustAbsolutePositionScreenshot, @@ -315,7 +315,7 @@ test.describe("Invalidity handling screenshots", () => { const message = showLongMessage ? "Very long message that should be truncated" : "Test message"; - const errorMessages: FormErrorMessages = { + const errorMessages: FormMessages = { shortMessage: showLongMessage ? "Very long error preview that should be truncated" : "Test error", diff --git a/packages/sit-onyx/src/components/OnyxStepper/OnyxStepper.ct.tsx b/packages/sit-onyx/src/components/OnyxStepper/OnyxStepper.ct.tsx index 2b66d28bad..4d1a6c56dd 100644 --- a/packages/sit-onyx/src/components/OnyxStepper/OnyxStepper.ct.tsx +++ b/packages/sit-onyx/src/components/OnyxStepper/OnyxStepper.ct.tsx @@ -1,5 +1,5 @@ import { DENSITIES } from "../../composables/density"; -import type { FormErrorMessages } from "../../composables/useCustomValidity"; +import type { FormMessages } from "../../composables/useCustomValidity"; import { expect, test } from "../../playwright/a11y"; import { executeMatrixScreenshotTest } from "../../playwright/screenshots"; import { createFormElementUtils } from "../OnyxFormElement/OnyxFormElement.ct-utils"; @@ -100,7 +100,7 @@ test.describe("Screenshot tests", () => { const message = showLongMessage ? "Very long message that should be truncated" : "Test message"; - const errorMessages: FormErrorMessages = { + const errorMessages: FormMessages = { shortMessage: showLongMessage ? "Very long error preview that should be truncated" : "Test error", diff --git a/packages/sit-onyx/src/composables/useCustomValidity.ts b/packages/sit-onyx/src/composables/useCustomValidity.ts index 7b70686bd6..1d49a38706 100644 --- a/packages/sit-onyx/src/composables/useCustomValidity.ts +++ b/packages/sit-onyx/src/composables/useCustomValidity.ts @@ -6,13 +6,17 @@ import type { BaseSelectOption } from "../types"; import { areObjectsFlatEqual } from "../utils/objects"; import { getFirstInvalidType, transformValidityStateToObject } from "../utils/validity"; -export type CustomErrorType = string | FormErrorMessages; +export type CustomMessageType = string | FormMessages; export type CustomValidityProp = { /** * Custom error message to show. Will only show up after the user has interacted with the input. */ - customError?: CustomErrorType; + customError?: CustomMessageType; + /** + * Success message to show. Will only show up after the user has interacted with the input. + */ + successMessage?: CustomMessageType; }; export type UseCustomValidityOptions = { @@ -45,39 +49,38 @@ export const TRANSLATED_INPUT_TYPES = Object.keys( export type TranslatedInputType = (typeof TRANSLATED_INPUT_TYPES)[number]; /** - * Translated error messages that inform about causes for invalidity of form components + * Translated messages that inform about the validity state of form components */ -export type FormErrorMessages = { +export type FormMessages = { /** - * A short error message preview to inform the user about the cause of the error + * A short message preview to inform the user about the validity state */ shortMessage: string; /** - * An extended informative error message to provide more info - * how the error cause can be resolved + * An extended informative message to provide more info */ longMessage?: string; }; /** - * Transforms a customError into the format needed to display an error preview and extended message + * Transforms a customMessage into the format needed to display an error preview and extended message */ -export const getCustomErrors = (customError?: CustomErrorType): FormErrorMessages | undefined => { - if (!customError) return; - if (typeof customError === "string") { - // we can't guarantee a custom error message will be short, +export const getFormMessages = (customMessage?: CustomMessageType): FormMessages | undefined => { + if (!customMessage) return; + if (typeof customMessage === "string") { + // we can't guarantee a custom message will be short, // so in case it overflows, by adding it to "longMessage", // it will still be visible in a tooltip - return { shortMessage: customError, longMessage: customError }; + return { shortMessage: customMessage, longMessage: customMessage }; } - return customError; + return customMessage; }; /** - * Returns a string combining short + long message or just the customError if it was provided as single string. + * Returns a string combining short + long message or just the customMessage if it was provided as single string. * Will be used e.g. for customInvalidity and showing a tooltip e.g. in RadioButtons */ -export const getCustomErrorText = (customError?: CustomErrorType): string | undefined => { +export const getFormMessageText = (customError?: CustomMessageType): string | undefined => { if (!customError) return; if (typeof customError === "string") { return customError; @@ -90,7 +93,7 @@ export const getCustomErrorText = (customError?: CustomErrorType): string | unde }; /** - * Composable for unified handling of custom error messages for form components. + * Composable for unified handling of custom messages for form components. * Will call `setCustomValidity()` accordingly and emit the "validityChange" event * whenever the input value / error changes. * @@ -128,7 +131,7 @@ export const useCustomValidity = (options: UseCustomValidityOptions) => { /** * Sync custom error with the native input validity. */ - watchEffect(() => el.setCustomValidity(getCustomErrorText(options.props.customError) ?? "")); + watchEffect(() => el.setCustomValidity(getFormMessageText(options.props.customError) ?? "")); watch( // we need to watch all props instead of only modelValue so the validity is re-checked @@ -166,11 +169,11 @@ export const useCustomValidity = (options: UseCustomValidityOptions) => { }, } satisfies Directive; - const errorMessages = computed(() => { + const errorMessages = computed(() => { if (!validityState.value || validityState.value.valid) return; const errorType = getFirstInvalidType(validityState.value); - const customErrors = getCustomErrors(options.props.customError); + const customErrors = getFormMessages(options.props.customError); // a custom error message always is considered first if (customErrors || errorType === "customError") { if (!customErrors) return; @@ -207,6 +210,12 @@ export const useCustomValidity = (options: UseCustomValidityOptions) => { }; }); + const successMessages = computed(() => { + if (validityState.value === undefined || !validityState.value.valid) return; + + return getFormMessages(options.props.successMessage); + }); + return { /** * Directive to set the custom error message and emit validityChange event. @@ -216,5 +225,9 @@ export const useCustomValidity = (options: UseCustomValidityOptions) => { * A custom error or the default translation of the first invalid state if one exists. */ errorMessages, + /** + * A custom success message if provided by the user. + */ + successMessages, }; };