diff --git a/apps/website/pages/components/number-input/code.tsx b/apps/website/pages/components/number-input/code.tsx new file mode 100644 index 0000000000..367f94ebbb --- /dev/null +++ b/apps/website/pages/components/number-input/code.tsx @@ -0,0 +1,17 @@ +import Head from "next/head"; +import type { ReactElement } from "react"; +import NumberInputCodePage from "screens/components/number-input/code/NumberInputCodePage"; +import NumberInputPageLayout from "screens/components/number-input/NumberInputPageLayout"; + +const Code = () => ( + <> + + Number input code — Halstack Design System + + + +); + +Code.getLayout = (page: ReactElement) => {page}; + +export default Code; diff --git a/apps/website/pages/components/number-input/index.tsx b/apps/website/pages/components/number-input/index.tsx index 7c7a89aa9e..63d76c1baf 100644 --- a/apps/website/pages/components/number-input/index.tsx +++ b/apps/website/pages/components/number-input/index.tsx @@ -1,21 +1,17 @@ import Head from "next/head"; import type { ReactElement } from "react"; -import NumberInputCodePage from "screens/components/number-input/code/NumberInputCodePage"; import NumberInputPageLayout from "screens/components/number-input/NumberInputPageLayout"; +import NumberInputOverviewPage from "screens/components/number-input/overview/NumberInputOverviewPage"; -const Index = () => { - return ( - <> - - Number Input — Halstack Design System - - - - ); -}; +const Index = () => ( + <> + + Number input — Halstack Design System + + + +); -Index.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; +Index.getLayout = (page: ReactElement) => {page}; export default Index; diff --git a/apps/website/pages/components/number-input/specifications.tsx b/apps/website/pages/components/number-input/specifications.tsx deleted file mode 100644 index 0856042747..0000000000 --- a/apps/website/pages/components/number-input/specifications.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Head from "next/head"; -import type { ReactElement } from "react"; -import NumberInputSpecsPage from "screens/components/number-input/specs/NumberInputSpecsPage"; -import NumberInputPageLayout from "screens/components/number-input/NumberInputPageLayout"; - -const Specifications = () => { - return ( - <> - - Number Input Specs — Halstack Design System - - - - ); -}; - -Specifications.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Specifications; diff --git a/apps/website/pages/components/number-input/usage.tsx b/apps/website/pages/components/number-input/usage.tsx deleted file mode 100644 index 18d4c42338..0000000000 --- a/apps/website/pages/components/number-input/usage.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Head from "next/head"; -import type { ReactElement } from "react"; -import NumberInputPageLayout from "screens/components/number-input/NumberInputPageLayout"; -import NumberInputUsagePage from "screens/components/number-input/usage/NumberInputUsagePage"; - -const Usage = () => { - return ( - <> - - Number Input Usage — Halstack Design System - - - - ); -}; - -Usage.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Usage; diff --git a/apps/website/pages/components/password-input/code.tsx b/apps/website/pages/components/password-input/code.tsx new file mode 100644 index 0000000000..26f5d826b0 --- /dev/null +++ b/apps/website/pages/components/password-input/code.tsx @@ -0,0 +1,17 @@ +import Head from "next/head"; +import type { ReactElement } from "react"; +import PasswordInputPageLayout from "screens/components/password-input/PasswordInputPageLayout"; +import PasswordInputCodePage from "screens/components/password-input/code/PasswordInputCodePage"; + +const Code = () => ( + <> + + Password input code — Halstack Design System + + + +); + +Code.getLayout = (page: ReactElement) => {page}; + +export default Code; diff --git a/apps/website/pages/components/password-input/index.tsx b/apps/website/pages/components/password-input/index.tsx index f7a08991ce..ffbaf4818e 100644 --- a/apps/website/pages/components/password-input/index.tsx +++ b/apps/website/pages/components/password-input/index.tsx @@ -1,21 +1,17 @@ import Head from "next/head"; import type { ReactElement } from "react"; -import PasswordInputCodePage from "screens/components/password-input/code/PasswordInputCodePage"; +import PasswordInputOverviewPage from "screens/components/password-input/overview/PasswordInputOverviewPage"; import PasswordInputPageLayout from "screens/components/password-input/PasswordInputPageLayout"; -const Index = () => { - return ( - <> - - Password Input — Halstack Design System - - - - ); -}; +const Index = () => ( + <> + + Password input — Halstack Design System + + + +); -Index.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; +Index.getLayout = (page: ReactElement) => {page}; export default Index; diff --git a/apps/website/pages/components/password-input/specifications.tsx b/apps/website/pages/components/password-input/specifications.tsx deleted file mode 100644 index 2cc2c497e7..0000000000 --- a/apps/website/pages/components/password-input/specifications.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Head from "next/head"; -import type { ReactElement } from "react"; -import PasswordInputSpecsPage from "screens/components/password-input/specs/PasswordInputSpecsPage"; -import PasswordInputPageLayout from "screens/components/password-input/PasswordInputPageLayout"; - -const Specifications = () => { - return ( - <> - - Password Input Specs — Halstack Design System - - - - ); -}; - -Specifications.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Specifications; diff --git a/apps/website/pages/components/password-input/usage.tsx b/apps/website/pages/components/password-input/usage.tsx deleted file mode 100644 index 7c2d9ee71e..0000000000 --- a/apps/website/pages/components/password-input/usage.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Head from "next/head"; -import type { ReactElement } from "react"; -import PasswordInputUsagePage from "screens/components/password-input/usage/PasswordInputUsagePage"; -import PasswordInputPageLayout from "screens/components/password-input/PasswordInputPageLayout"; - -const Usage = () => { - return ( - <> - - Password Input Usage — Halstack Design System - - - - ); -}; - -Usage.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Usage; diff --git a/apps/website/pages/components/text-input/code.tsx b/apps/website/pages/components/text-input/code.tsx new file mode 100644 index 0000000000..0a9d99f248 --- /dev/null +++ b/apps/website/pages/components/text-input/code.tsx @@ -0,0 +1,17 @@ +import Head from "next/head"; +import type { ReactElement } from "react"; +import TextInputPageLayout from "screens/components/text-input/TextInputPageLayout"; +import TextInputCodePage from "screens/components/text-input/code/TextInputCodePage"; + +const Code = () => ( + <> + + Text input code — Halstack Design System + + + +); + +Code.getLayout = (page: ReactElement) => {page}; + +export default Code; diff --git a/apps/website/pages/components/text-input/index.tsx b/apps/website/pages/components/text-input/index.tsx index 8e172a08a5..ce50bf4f32 100644 --- a/apps/website/pages/components/text-input/index.tsx +++ b/apps/website/pages/components/text-input/index.tsx @@ -1,21 +1,17 @@ import Head from "next/head"; import type { ReactElement } from "react"; -import TextInputCodePage from "screens/components/text-input/code/TextInputCodePage"; +import TextInputOverviewPage from "screens/components/text-input/overview/TextInputOverviewPage"; import TextInputPageLayout from "screens/components/text-input/TextInputPageLayout"; -const Index = () => { - return ( - <> - - Text Input — Halstack Design System - - - - ); -}; +const Index = () => ( + <> + + Text input — Halstack Design System + + + +); -Index.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; +Index.getLayout = (page: ReactElement) => {page}; export default Index; diff --git a/apps/website/pages/components/text-input/specifications.tsx b/apps/website/pages/components/text-input/specifications.tsx deleted file mode 100644 index 6341df4f44..0000000000 --- a/apps/website/pages/components/text-input/specifications.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Head from "next/head"; -import type { ReactElement } from "react"; -import TextInputSpecsPage from "screens/components/text-input/specs/TextInputSpecsPage"; -import TextInputPageLayout from "screens/components/text-input/TextInputPageLayout"; - -const Specifications = () => { - return ( - <> - - Text Input Specs — Halstack Design System - - - - ); -}; - -Specifications.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Specifications; diff --git a/apps/website/pages/components/text-input/usage.tsx b/apps/website/pages/components/text-input/usage.tsx deleted file mode 100644 index 79032ee103..0000000000 --- a/apps/website/pages/components/text-input/usage.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Head from "next/head"; -import type { ReactElement } from "react"; -import TextInputPageLayout from "screens/components/text-input/TextInputPageLayout"; -import TextInputUsagePage from "screens/components/text-input/usage/TextInputUsagePage"; - -const Usage = () => { - return ( - <> - - Text Input Usage — Halstack Design System - - - - ); -}; - -Usage.getLayout = function getLayout(page: ReactElement) { - return {page}; -}; - -export default Usage; diff --git a/apps/website/screens/components/alert/code/AlertCodePage.tsx b/apps/website/screens/components/alert/code/AlertCodePage.tsx index a7a26fb7f8..0ecb57222c 100644 --- a/apps/website/screens/components/alert/code/AlertCodePage.tsx +++ b/apps/website/screens/components/alert/code/AlertCodePage.tsx @@ -11,7 +11,7 @@ import Code from "@/common/Code"; import StatusBadge from "@/common/StatusBadge"; const actionTypeString = `{ - icon?: (React.ReactNode + icon?: string | (React.ReactNode & React.SVGProps); label: string; onClick: () => void; diff --git a/apps/website/screens/components/number-input/NumberInputPageLayout.tsx b/apps/website/screens/components/number-input/NumberInputPageLayout.tsx index dabcadd6b2..4fcf8bc14a 100644 --- a/apps/website/screens/components/number-input/NumberInputPageLayout.tsx +++ b/apps/website/screens/components/number-input/NumberInputPageLayout.tsx @@ -6,24 +6,20 @@ import { ReactNode } from "react"; const NumberInputPageHeading = ({ children }: { children: ReactNode }) => { const tabs = [ - { label: "Code", path: "/components/number-input" }, - { label: "Usage", path: "/components/number-input/usage" }, - { - label: "Specifications", - path: "/components/number-input/specifications", - }, + { label: "Overview", path: "/components/number-input" }, + { label: "Code", path: "/components/number-input/code" }, ]; return ( - + - The number input is a text input component that only allows numerical values and it has controls for - incrementing or decrementing them. + Number inputs are fields specifically used to capture numeric user input in a structured and accessible + format. - + {children} diff --git a/apps/website/screens/components/number-input/code/NumberInputCodePage.tsx b/apps/website/screens/components/number-input/code/NumberInputCodePage.tsx index 9536cda0a0..e70c4a4331 100644 --- a/apps/website/screens/components/number-input/code/NumberInputCodePage.tsx +++ b/apps/website/screens/components/number-input/code/NumberInputCodePage.tsx @@ -25,54 +25,40 @@ const sections = [ - defaultValue + ariaLabel string - Initial value of the input element, only when it is uncontrolled. - - - - - value - string + Specifies a string to be used as the name for the number input element when no label is + provided. - Value of the input element. If undefined, the component will be uncontrolled and the value will be managed - internally by the component. + 'Number input' - - - label + autocomplete string - Text to be placed above the number input. - - - - - name - string + HTML autocomplete attribute. Lets the user specify if any permission the user agent has to + provide automated assistance in filling out the input value. Its value must be one of all the possible + values of the HTML autocomplete attribute. See{" "} + MDN{" "} + for further information. - Name attribute of the input element. - - - - - helperText - string + 'off' - Helper text to be placed above the number. - - - placeholder + defaultValue string - Text to be put as placeholder of the number. + Initial value of the input element, only when it is uncontrolled. - @@ -86,55 +72,52 @@ const sections = [ - optional - - boolean - + error - If true, the number will be optional, showing the text '(Optional)' next to the label. Otherwise, the - field will be considered required and an error will be passed as a parameter to the onBlur{" "} - and onChange functions when it has not been filled. + string - false + If it is a defined value and also a truthy string, the component will change its appearance, showing the + error below the input component. If the defined value is an empty string, it will reserve a space below + the component for a future error, but it would not change its look. In case of being undefined or null, + both the appearance and the space for the error message would not be modified. + - - readOnly - - boolean - - - If true, the component will not be mutable, meaning the user can not edit the control. The value won't - change when pressing on the up or down arrows and neither on the spin buttons. - + helperText - false + string + Helper text to be placed above the number. + - - prefix + label string - Prefix to be placed before the number value. + Text to be placed above the number input. - - suffix + margin - string + 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin + + + Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and + 'right' properties in order to specify different margin sizes. - Suffix to be placed after the number value. - - min + max number - Minimum value allowed by the number input. If the typed value by the user is lower than min, the{" "} + Maximum value allowed by the number input. If the typed value by the user surpasses max, the{" "} onBlur and onChange functions will be called with the current value and an internal error informing that the current value is not correct. If a valid state is reached, the error parameter will not be defined in both events. @@ -142,12 +125,12 @@ const sections = [ - - max + min number - Maximum value allowed by the number input. If the typed value by the user surpasses max, the{" "} + Minimum value allowed by the number input. If the typed value by the user is lower than min, the{" "} onBlur and onChange functions will be called with the current value and an internal error informing that the current value is not correct. If a valid state is reached, the error parameter will not be defined in both events. @@ -155,14 +138,24 @@ const sections = [ - - step + name - number + string + + Name attribute of the input element. + - + + + onBlur + + {"(val: { value: string; error?: string }) => void"} - The step interval to use when using the up and down arrows to adjust the value. - 1 + This function will be called when the input element loses the focus. An object including the input value + and the error (if the value entered is not valid) will be passed to this function. If there is no error,{" "} + error will not be defined. + - onChange @@ -177,56 +170,70 @@ const sections = [ - - onBlur + optional - {"(val: { value: string; error?: string }) => void"} + boolean - This function will be called when the input element loses the focus. An object including the input value - and the error (if the value entered is not valid) will be passed to this function. If there is no error,{" "} - error will not be defined. + If true, the number will be optional, showing the text '(Optional)' next to the label. Otherwise, the + field will be considered required and an error will be passed as a parameter to the onBlur{" "} + and onChange functions when it has not been filled. + + + false - - - error + placeholder string + Text to be put as placeholder of the number. + - + + + prefix - If it is a defined value and also a truthy string, the component will change its appearance, showing the - error below the input component. If the defined value is an empty string, it will reserve a space below - the component for a future error, but it would not change its look. In case of being undefined or null, - both the appearance and the space for the error message would not be modified. + string + Prefix to be placed before the number value. - - autocomplete + readOnly - string + boolean - HTML autocomplete attribute. Lets the user specify if any permission the user agent has to - provide automated assistance in filling out the input value. Its value must be one of all the possible - values of the HTML autocomplete attribute. See{" "} - MDN{" "} - for further information. + If true, the component will not be mutable, meaning the user can not edit the control. The value won't + change when pressing on the up or down arrows and neither on the spin buttons. - 'off' + false - margin + ref - 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin + {"React.Ref"} + + Reference to the component. + - + + + + + + showControls + - Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and - 'right' properties in order to specify different margin sizes. + boolean + + Decides whether the number input displays or not the spin buttons to adjust the value. + + true - - size @@ -239,55 +246,45 @@ const sections = [ - tabIndex + step number + The step interval to use when using the spin buttons to adjust the value. - Value of the tabindex attribute. - - - 0 + 1 - ref + suffix - {"React.Ref"} + string - Reference to the component. + Suffix to be placed after the number value. - - ariaLabel + tabIndex - string + number - Specifies a string to be used as the name for the number input element when no label is - provided. + Value of the tabindex attribute. - 'Number input' + 0 + value - - - showControls - - - - boolean - - - Decides whether the number input has actions to increase or decrease the value, following the defined - step. + string - true + Value of the input element. If undefined, the component will be uncontrolled and the value will be managed + internally by the component. + - @@ -312,15 +309,13 @@ const sections = [ }, ]; -const NumberInputCodePage = () => { - return ( - - - - - - - ); -}; +const NumberInputCodePage = () => ( + + + + + + +); export default NumberInputCodePage; diff --git a/apps/website/screens/components/number-input/overview/NumberInputOverviewPage.tsx b/apps/website/screens/components/number-input/overview/NumberInputOverviewPage.tsx new file mode 100644 index 0000000000..92edc892d4 --- /dev/null +++ b/apps/website/screens/components/number-input/overview/NumberInputOverviewPage.tsx @@ -0,0 +1,289 @@ +import { DxcFlex, DxcParagraph, DxcBulletedList } from "@dxc-technology/halstack-react"; +import QuickNavContainer from "@/common/QuickNavContainer"; +import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; +import DocFooter from "@/common/DocFooter"; +import Image from "@/common/Image"; +import anatomy from "./images/number_anatomy.png"; +import spinButtons from "./images/number_spin_buttons.png"; +import Example from "@/common/example/Example"; +import Figure from "@/common/Figure"; +import prefixSuffix from "./examples/prefixSuffix"; +import Code from "@/common/Code"; + +const sections = [ + { + title: "Introduction", + content: ( + <> + + Number inputs are essential UI elements for collecting quantitative data from users. They are + designed to handle numerical values such as quantities, prices, percentages, or any input that requires + mathematical validation or calculations. Common use cases include forms involving payment amounts, product + quantities, ages, measurements, or ratings. + + + Unlike text inputs, number inputs offer built-in constraints like minimum and maximum values, step intervals, + and automatic validation of non-numeric entries. These features help reduce errors, guide users toward valid + entries, and ensure consistent data formatting. + + + Proper labeling, error messaging, and the use of increment/decrement controls can further enhance usability + and accessibility, leading to a more efficient and user-friendly experience. + + + ), + }, + { + title: "Anatomy", + content: ( + <> + Number input anatomy + + + Label (Optional): a descriptive text that helps users understand what information + is expected in the input field. It should be clear, concise, and placed near the input for better + readability. + + + Optional indicator (Optional): a small indicator that signals the input field is + not mandatory. It helps users know they can leave the field empty without causing validation errors. + + + Spin buttons increase/decrease (Optional): small interactive controls, displayed + as plus (+) and minus (-) icons, that allow users to increment or decrement the numeric value using mouse + clicks or keyboard input. These buttons improve usability by offering an alternative to manual typing, help + prevent entry errors, and support accessibility for users who may prefer step-based adjustments. + + + Helper text (Optional): additional text placed below the input label that provides + guidance, examples, or explanations to assist users in filling out the field correctly. + + + Container: the visual wrapper around the input field that provides structure, ensures + accessibility, and helps differentiate the input from other UI elements. + + + Placeholder/Value: a short hint displayed inside the input field before any text is + entered, offering a brief example or instruction on what type of data is expected. It disappears when the + user starts typing. The value represents the actual content entered by the user. Unlike the placeholder, the + value persists during interaction and is what gets submitted with the form. + + + Prefix (Optional): a visual element placed before or after the user input, like + currency symbols or units, to help clarify the expected data. + + + + ), + }, + { + title: "Form inputs", + content: ( + <> + + Form inputs are essential UI elements that allow users to interact with digital products by{" "} + entering or selecting data. Choosing the right input type and structure is key to designing + efficient, user-friendly forms that support task completion and data accuracy. + + + A form input (also known as a form field) is used to capture user data. Common input types include text + fields, date pickers, number fields, radio buttons, checkboxes, toggles, and dropdowns. Forms should always + include a submission method, such as a submit button, link, or keyboard trigger, to complete the interaction. + + + ), + subSections: [ + { + title: "Shared input characteristics", + content: ( + <> + + Although input fields vary in type and purpose, they often share a common set of features: + + + + Placeholder: a short hint displayed inside the input field that describes its expected + value or purpose. + + + Size and max length: inputs can have both a visual size (width of the field) and a + character limit that defines how much text can be entered. + + + Prefix or suffix: some inputs include a visual element before or after the user input, + like currency symbols or units, to help clarify the expected data. + + + Helper text: additional information displayed below the field to guide the user in + providing the correct input. + + + Optional label: inputs that are not mandatory can be marked with an "Optional" tag to + set clear expectations. + + + + ), + }, + { + title: "Common input states", + content: ( + <> + Most inputs can also present standard interactive or informative states: + + + Disabled: this state prevents users from interacting with the field. It's typically + used when a value is not applicable or editable under certain conditions or roles. + + + Error: when a user enters invalid or incomplete data, the input shows an error state, + often accompanied by a helpful message to guide corrections. + + + Read-only: the input is visible, focusable, and hoverable, but not editable. This is + ideal for fields with auto-calculated values. Unlike disabled fields, read-only inputs can still be + submitted with the form and are part of the form data. + + + + ), + }, + ], + }, + { + title: "Using number inputs", + content: ( + + Number inputs are commonly used in forms and interfaces where users are required to provide numeric values such + as quantities, prices, percentages, or other measurable data. Our number input component is highly configurable, + allowing designers and developers to tailor it to a wide range of use cases while ensuring consistency, + usability, and accessibility. In this section, we will highlight the key characteristics and behaviors of our + number input, helping you understand how and when to use it effectively. + + ), + subSections: [ + { + title: "Actions", + subSections: [ + { + title: "Using spin buttons", + content: ( + <> + + Spin buttons are one of the key interaction features of the number input. They allow users to{" "} + increment or decrement the value using simple clicks, rather than typing manually. + This is especially useful when working with step-based inputs, such as quantities or percentages, as + it ensures more accurate entries and improves overall efficiency for both keyboard and mouse users. + +
+ States for the spin buttons +
+ + ), + }, + ], + }, + { + title: "Prefix and suffix", + content: ( + <> + + Halstack number inputs also support the use of prefixes and suffixes, which are visual elements that help + users quickly understand the format or context of the numeric value being entered. These + elements clarify what type of number is expected, such as currency, units, or percentages, and ensure + greater consistency in data entry. + + + This added context is especially helpful in forms with multiple numeric fields, allowing users to scan and + comprehend each field's purpose at a glance, ultimately improving the overall experience and reducing + entry errors. + + + + ), + }, + ], + }, + { + title: "Best practices", + subSections: [ + { + title: "General", + content: ( + + + Always use clear labels: provide a clear and concise label to describe the expected + numeric input. Avoid relying solely on the placeholder to communicate the field's purpose. + + + Use helper text for additional guidance: if the expected input range, format, or units + might be unclear, add helper text to avoid confusion and input errors. + + + Indicate when the field is optional: use an "Optional" label when applicable to reduce + user hesitation or over-input. + + + Ensure consistent visual states: clearly differentiate between focus, error, disabled, + and read-only states using accessible visual cues and messages. + + + Set valid constraints: always define min, max, or{" "} + step values when the input must fall within a numeric range to improve accuracy and prevent + invalid entries. + + + ), + }, + { + title: "Actions", + content: ( + + + Enable keyboard and button control: users should be able to input values manually or use + the spin buttons to increment/decrement the value. + + + Avoid aggressive auto-corrections: do not override user input instantly or without + warning; let users control their interaction unless invalid input requires immediate correction. + + + Validate on interaction: validate values when the user finishes interacting with the + field, not while they're typing, to prevent frustration. + + + Allow incremental control: use appropriate step values to help users input + valid values more efficiently when using spin buttons. + + + ), + }, + { + title: "Prefix/suffix", + content: ( + + + Use prefixes and suffixes for context: clearly indicate units (e.g., kg, cm), currency + (e.g., USD, EUR), or domain-specific values to help users understand what's expected. + + + Avoid clutter: only use prefixes or suffixes when they add value and improve clarity. + Don't overload the field with unnecessary UI elements. + + + ), + }, + ], + }, +]; + +const NumberInputOverviewPage = () => ( + + + + + + +); + +export default NumberInputOverviewPage; diff --git a/apps/website/screens/components/number-input/overview/examples/prefixSuffix.ts b/apps/website/screens/components/number-input/overview/examples/prefixSuffix.ts new file mode 100644 index 0000000000..001a79333e --- /dev/null +++ b/apps/website/screens/components/number-input/overview/examples/prefixSuffix.ts @@ -0,0 +1,20 @@ +import { DxcNumberInput, DxcInset, DxcFlex } from "@dxc-technology/halstack-react"; + +const code = `() => { + return ( + + + + + + + ); + }`; + +const scope = { + DxcNumberInput, + DxcInset, + DxcFlex, +}; + +export default { code, scope }; diff --git a/apps/website/screens/components/number-input/overview/images/number_anatomy.png b/apps/website/screens/components/number-input/overview/images/number_anatomy.png new file mode 100644 index 0000000000..de0b8a3769 Binary files /dev/null and b/apps/website/screens/components/number-input/overview/images/number_anatomy.png differ diff --git a/apps/website/screens/components/number-input/overview/images/number_spin_buttons.png b/apps/website/screens/components/number-input/overview/images/number_spin_buttons.png new file mode 100644 index 0000000000..8eff3a50bd Binary files /dev/null and b/apps/website/screens/components/number-input/overview/images/number_spin_buttons.png differ diff --git a/apps/website/screens/components/number-input/specs/NumberInputSpecsPage.tsx b/apps/website/screens/components/number-input/specs/NumberInputSpecsPage.tsx deleted file mode 100644 index 46cd403b83..0000000000 --- a/apps/website/screens/components/number-input/specs/NumberInputSpecsPage.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { DxcParagraph, DxcFlex, DxcLink, DxcBulletedList } from "@dxc-technology/halstack-react"; -import Link from "next/link"; -import Figure from "@/common/Figure"; -import Code from "@/common/Code"; -import DocFooter from "@/common/DocFooter"; -import Image from "@/common/Image"; -import QuickNavContainer from "@/common/QuickNavContainer"; -import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; -import numberSpecs from "./images/number_specs.png"; -import numberInputSpecs from "./images/number_input_states.png"; -import numberInputStates from "./images/number_action_states.png"; -import numberAnatomy from "./images/number_anatomy.png"; - -const sections = [ - { - title: "Specifications", - content: ( - <> -
- Number input design specifications -
- - The number input color, typography, border, spacing,{" "} - width and margin specifications are inherited from the text input, for reference - check the{" "} - - text input - {" "} - component documentation. - - - ), - }, - { - title: "States", - subSections: [ - { - title: "Input", - content: ( - <> - - States: enabled, hover, focus, error{" "} - and disabled. - -
- Number input states -
- - ), - }, - { - title: "Spin button", - content: ( - <> - - States: enabled, hover, focus, active{" "} - and disabled. - -
- Spin button states -
- - ), - }, - ], - }, - { - title: "Anatomy", - content: ( - <> - Number input anatomy - - Label - - Helper text (Optional) - - - Suffix (Optional) - - Container - Spin button increase - Spin button decrease - Error indicator - Error message - Value - - - ), - }, - { - title: "Accessibility", - subSections: [ - { - title: "WAI-ARIA", - content: ( - - - WAI-ARIA Authoring practices 1.2 -{" "} - - 3.21 Spinbutton - - - - WAI-ARIA Authoring practices 1.2 -{" "} - - "Date Picker Spin Button" design pattern - - - - ), - }, - ], - }, -]; - -const NumberInputSpecsPage = () => { - return ( - - - - - - - ); -}; - -export default NumberInputSpecsPage; diff --git a/apps/website/screens/components/number-input/specs/images/number_action_states.png b/apps/website/screens/components/number-input/specs/images/number_action_states.png deleted file mode 100644 index 8e6369dff7..0000000000 Binary files a/apps/website/screens/components/number-input/specs/images/number_action_states.png and /dev/null differ diff --git a/apps/website/screens/components/number-input/specs/images/number_anatomy.png b/apps/website/screens/components/number-input/specs/images/number_anatomy.png deleted file mode 100644 index 0f6da22448..0000000000 Binary files a/apps/website/screens/components/number-input/specs/images/number_anatomy.png and /dev/null differ diff --git a/apps/website/screens/components/number-input/specs/images/number_input_states.png b/apps/website/screens/components/number-input/specs/images/number_input_states.png deleted file mode 100644 index 15d33dfd4e..0000000000 Binary files a/apps/website/screens/components/number-input/specs/images/number_input_states.png and /dev/null differ diff --git a/apps/website/screens/components/number-input/specs/images/number_specs.png b/apps/website/screens/components/number-input/specs/images/number_specs.png deleted file mode 100644 index 18c0b242f7..0000000000 Binary files a/apps/website/screens/components/number-input/specs/images/number_specs.png and /dev/null differ diff --git a/apps/website/screens/components/number-input/usage/NumberInputUsagePage.tsx b/apps/website/screens/components/number-input/usage/NumberInputUsagePage.tsx deleted file mode 100644 index 3130586445..0000000000 --- a/apps/website/screens/components/number-input/usage/NumberInputUsagePage.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { DxcFlex, DxcParagraph, DxcBulletedList } from "@dxc-technology/halstack-react"; -import QuickNavContainer from "@/common/QuickNavContainer"; -import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; -import DocFooter from "@/common/DocFooter"; - -const sections = [ - { - title: "Usage", - content: ( - <> - Considerations for the use of the number input component: - - - Don't use the number input component for amounts. Use a text input instead. - - Always enable typing in the input field. - Avoid using the component when large values are expected. - - - ), - }, -]; - -const NumberInputUsagePage = () => { - return ( - - - - - - - ); -}; - -export default NumberInputUsagePage; diff --git a/apps/website/screens/components/password-input/PasswordInputPageLayout.tsx b/apps/website/screens/components/password-input/PasswordInputPageLayout.tsx index 8a3c6208e9..6a8771e165 100644 --- a/apps/website/screens/components/password-input/PasswordInputPageLayout.tsx +++ b/apps/website/screens/components/password-input/PasswordInputPageLayout.tsx @@ -6,25 +6,21 @@ import { ReactNode } from "react"; const PasswordInputPageHeading = ({ children }: { children: ReactNode }) => { const tabs = [ - { label: "Code", path: "/components/password-input" }, - { label: "Usage", path: "/components/password-input/usage" }, - { - label: "Specifications", - path: "/components/password-input/specifications", - }, + { label: "Overview", path: "/components/password-input" }, + { label: "Code", path: "/components/password-input/code" }, ]; return ( - + - The password input component is very much like the text input, with the difference that their value is - obscured by default (by replacing its characters with dot symbol ("•"), and the mask can be toggled on/off - using the show and hide component action. + Password inputs provide a way for users to securely enter a password. Its value is obscured by default by + replacing its characters with dot symbol ("•"), and the mask can be toggled on/off using the show and hide + component action. - + {children} diff --git a/apps/website/screens/components/password-input/code/PasswordInputCodePage.tsx b/apps/website/screens/components/password-input/code/PasswordInputCodePage.tsx index 40c81df14d..cc0087fe4e 100644 --- a/apps/website/screens/components/password-input/code/PasswordInputCodePage.tsx +++ b/apps/website/screens/components/password-input/code/PasswordInputCodePage.tsx @@ -24,39 +24,33 @@ const sections = [ - value + ariaLabel string - Value of the input element. If undefined, the component will be uncontrolled and the value will be managed - internally by the component. + Specifies a string to be used as the name for the password input element when no label is + provided. - - - - - label - string + 'Password input' - Text to be placed above the password input. - - - name + autocomplete string - Name attribute of the input element. - - - - - helperText - string + HTML autocomplete attribute. Lets the user specify if any permission the user agent has to + provide automated assistance in filling out the input value. Its value must be one of all the possible + values of the HTML autocomplete attribute. See{" "} + MDN{" "} + for further information. + + + 'off' - Helper text to be placed above the password. - - clearable @@ -69,64 +63,53 @@ const sections = [ - onChange + error - {"(val: { value: string; error?: string }) => void"} + string - This function will be called when the user types within the input element of the component. An object - including the current value and the error (if the value entered is not valid) will be passed to this - function. If there is no error, error will not be defined. + If it is a defined value and also a truthy string, the component will change its appearance, showing the + error below the password input component. If the defined value is an empty string, it will reserve a space + below the component for a future error, but it would not change its look. In case of being undefined or + null, both the appearance and the space for the error message would not be modified. - - onBlur - - {"(val: { value: string; error?: string }) => void"} - + helperText - This function will be called when the input element loses the focus. An object including the input value - and the error (if the value entered is not valid) will be passed to this function. If there is no error,{" "} - error will not be defined. + string + Helper text to be placed above the password. - - error + label string - - If it is a defined value and also a truthy string, the component will change its appearance, showing the - error below the password input component. If the defined value is an empty string, it will reserve a space - below the component for a future error, but it would not change its look. In case of being undefined or - null, both the appearance and the space for the error message would not be modified. - + Text to be placed above the password input. - - pattern + margin - string + 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin - Regular expression that defines the valid format allowed by the password input. This will be checked both - when the input element loses the focus and while typing within it. If the string entered does not match - the pattern, the onBlur and onChange functions will be called with the current - value and an internal error informing that this value does not match the pattern. If the pattern is met, - the error parameter of both events will not be defined. + Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and + 'right' properties in order to specify different margin sizes. - - minLength + maxLength number - Specifies the minimum length allowed by the input. This will be checked both when the input element loses - the focus and while typing within it. If the string entered does not comply the minimum length, the{" "} + Specifies the maximum length allowed by the input. This will be checked both when the input element loses + the focus and while typing within it. If the string entered does not comply the maximum length, the{" "} onBlur and onChange functions will be called with the current value and an internal error informing that the value length does not comply the specified range. If a valid length is reached, the error parameter of both events will not be defined. @@ -134,13 +117,13 @@ const sections = [ - - maxLength + minLength number - Specifies the maximum length allowed by the input. This will be checked both when the input element loses - the focus and while typing within it. If the string entered does not comply the maximum length, the{" "} + Specifies the minimum length allowed by the input. This will be checked both when the input element loses + the focus and while typing within it. If the string entered does not comply the minimum length, the{" "} onBlur and onChange functions will be called with the current value and an internal error informing that the value length does not comply the specified range. If a valid length is reached, the error parameter of both events will not be defined. @@ -148,32 +131,59 @@ const sections = [ - - autocomplete + name string + Name attribute of the input element. + - + + + onBlur - HTML autocomplete attribute. Lets the user specify if any permission the user agent has to - provide automated assistance in filling out the input value. Its value must be one of all the possible - values of the HTML autocomplete attribute. See{" "} - MDN{" "} - for further information. + {"(val: { value: string; error?: string }) => void"} - 'off' + This function will be called when the input element loses the focus. An object including the input value + and the error (if the value entered is not valid) will be passed to this function. If there is no error,{" "} + error will not be defined. + - - margin + onChange - 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin + {"(val: { value: string; error?: string }) => void"} - Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and - 'right' properties in order to specify different margin sizes. + This function will be called when the user types within the input element of the component. An object + including the current value and the error (if the value entered is not valid) will be passed to this + function. If there is no error, error will not be defined. - + + pattern + + string + + + Regular expression that defines the valid format allowed by the password input. This will be checked both + when the input element loses the focus and while typing within it. If the string entered does not match + the pattern, the onBlur and onChange functions will be called with the current + value and an internal error informing that this value does not match the pattern. If the pattern is met, + the error parameter of both events will not be defined. + + - + + + ref + + {"React.Ref"} + + Reference to the component. + - + size @@ -197,23 +207,15 @@ const sections = [ - ref - - {"React.Ref"} - - Reference to the component. - - - - - ariaLabel + value string - Specifies a string to be used as the name for the password input element when no label is - provided. + Value of the input element. If undefined, the component will be uncontrolled and the value will be managed + internally by the component. - 'Password input' + - @@ -238,15 +240,13 @@ const sections = [ }, ]; -const PasswordInputCodePage = () => { - return ( - - - - - - - ); -}; +const PasswordInputCodePage = () => ( + + + + + + +); export default PasswordInputCodePage; diff --git a/apps/website/screens/components/password-input/overview/PasswordInputOverviewPage.tsx b/apps/website/screens/components/password-input/overview/PasswordInputOverviewPage.tsx new file mode 100644 index 0000000000..54e17506ae --- /dev/null +++ b/apps/website/screens/components/password-input/overview/PasswordInputOverviewPage.tsx @@ -0,0 +1,270 @@ +import { DxcBulletedList, DxcFlex, DxcParagraph } from "@dxc-technology/halstack-react"; +import QuickNavContainer from "@/common/QuickNavContainer"; +import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; +import DocFooter from "@/common/DocFooter"; +import Image from "@/common/Image"; +import anatomy from "./images/password_anatomy.png"; +import clearContent from "./images/password_clear_content.png"; +import Figure from "@/common/Figure"; +import Example from "@/common/example/Example"; +import showHide from "./examples/showHide"; + +const sections = [ + { + title: "Introduction", + content: ( + <> + + The password input component allows users to securely enter and manage sensitive data such as + credentials or authentication codes. It behaves similarly to a standard text input but masks the content to + protect the user's privacy. This component also includes functionality to toggle visibility, making it easier + for users to verify their input when needed. + + + Password inputs are essential in authentication forms, account settings, and any interaction where users need + to enter or confirm confidential information. Ensuring both usability and security is key to providing a + reliable password entry experience. + + + ), + }, + { + title: "Anatomy", + content: ( + <> + Password input anatomy + + + Label (Optional): a descriptive text that helps users understand what information + is expected in the input field. It should be clear, concise, and placed near the input for better + readability. + + + Optional indicator (Optional): a small indicator that signals the input field is + not mandatory. It helps users know they can leave the field empty without causing validation errors. + + + Input action (Optional): an interactive element, inside the input field that + triggers the action of revealing the password. + + + Close action (Optional): a small button, usually represented by an "X" icon, that + allows users to clear the entered password quickly without manually deleting it. + + + Helper text (Optional): additional text placed below the input field that provides + guidance, examples, or explanations to assist users in filling out the field correctly. + + + Container: the visual wrapper around the input field that provides structure, ensures + accessibility, and helps differentiate the input from other UI elements. + + + Value: displays the selected or manually entered date in the input field, following the + specified format. + + + + ), + }, + { + title: "Form inputs", + content: ( + <> + + Form inputs are essential UI elements that allow users to interact with digital products by{" "} + entering or selecting data. Choosing the right input type and structure is key to designing + efficient, user-friendly forms that support task completion and data accuracy. + + + A form input (also known as a form field) is used to capture user data. Common input types include text + fields, date pickers, number fields, radio buttons, checkboxes, toggles, and dropdowns. Forms should always + include a submission method, such as a submit button, link, or keyboard trigger, to complete the interaction. + + + ), + subSections: [ + { + title: "Shared input characteristics", + content: ( + <> + + Although input fields vary in type and purpose, they often share a common set of features: + + + + Placeholder: a short hint displayed inside the input field that describes its expected + value or purpose. + + + Size and max length: inputs can have both a visual size (width of the field) and a + character limit that defines how much text can be entered. + + + Prefix or suffix: some inputs include a visual element before or after the user input, + like currency symbols or units, to help clarify the expected data. + + + Helper text: additional information displayed below the field to guide the user in + providing the correct input. + + + Optional label: inputs that are not mandatory can be marked with an "Optional" tag to + set clear expectations. + + + + ), + }, + { + title: "Common input states", + content: ( + <> + Most inputs can also present standard interactive or informative states: + + + Disabled: this state prevents users from interacting with the field. It's typically + used when a value is not applicable or editable under certain conditions or roles. + + + Error: when a user enters invalid or incomplete data, the input shows an error state, + often accompanied by a helpful message to guide corrections. + + + Read-only: the input is visible, focusable, and hoverable, but not editable. This is + ideal for fields with auto-calculated values. Unlike disabled fields, read-only inputs can still be + submitted with the form and are part of the form data. + + + + ), + }, + ], + }, + { + title: "Using password inputs", + content: ( + + Password inputs are designed to handle sensitive information securely by masking the characters typed by the + user. Unlike regular text inputs, they include specific features to enhance privacy and usability, such as the + ability to toggle visibility and optionally clear the field. These inputs are commonly used for login forms, + account creation, and any scenario requiring authentication data. + + ), + subSections: [ + { + title: "Actions", + subSections: [ + { + title: "Clearing content", + content: ( + <> + + Password inputs can include a clear action icon, typically displayed when the field contains text. + This allows users to quickly remove the entire content of the input with a single + click or tap, making it easier to retype the password if necessary. This action enhances user + experience, particularly when correcting mistakes or switching between input attempts. + +
+ States for the clear content button +
+ + ), + }, + { + title: "Show/hide action", + content: ( + <> + + To improve usability without compromising security, our password input include a show/hide action + icon. This control allows users to reveal the password temporarily, helping prevent + input errors, especially on small screens or when dealing with complex passwords. By default, + passwords are hidden and masked with dots, and toggling the visibility should be a clearly labeled and + accessible action. + + + + ), + }, + ], + }, + ], + }, + { + title: "Best practices", + subSections: [ + { + title: "General", + content: ( + + + Use password inputs exclusively for sensitive or private data, such as account + credentials or security codes. + + + Always provide proper labeling and helper text if needed, especially when specifying + password requirements (e.g., minimum length, special characters). + + + ), + }, + { + title: "Show/hide action", + content: ( + + + Use clear, accessible labels for the action action (e.g., "Show password" / "Hide password") and ensure + they update dynamically based on the current state. + + + Avoid auto-enabling password visibility — keep the initial state masked for privacy. + + + ), + }, + { + title: "Close action", + content: ( + + + Use a clear (close) icon to help users quickly delete the entered password if needed. + + + Display the clear icon only when the field is not empty to avoid unnecessary + distractions. + + + ), + }, + { + title: "Security considerations", + content: ( + + + Never store passwords in local storage or pre-fill them without explicit user action. + + + Do not rely solely on masking or toggle visibility for security — always combine with backend encryption + and secure handling. + + + Prevent clipboard access via double-click or right-click when appropriate, depending on the app's security + level. + + + ), + }, + ], + }, +]; + +const PasswordInputOverviewPage = () => ( + + + + + + +); + +export default PasswordInputOverviewPage; diff --git a/apps/website/screens/components/password-input/overview/examples/showHide.ts b/apps/website/screens/components/password-input/overview/examples/showHide.ts new file mode 100644 index 0000000000..9539b1fe20 --- /dev/null +++ b/apps/website/screens/components/password-input/overview/examples/showHide.ts @@ -0,0 +1,30 @@ +import { DxcInset, DxcPasswordInput, DxcButton } from "@dxc-technology/halstack-react"; +import { useState, useRef } from "react"; + +const code = `() => { + const [value, setValue] = useState("J.Smith1961"); + const onChange = ({ value }) => { + setValue(value); + }; + + return ( + + + + ); +}`; + +const scope = { + useState, + useRef, + DxcPasswordInput, + DxcButton, + DxcInset, +}; + +export default { code, scope }; diff --git a/apps/website/screens/components/password-input/overview/images/password_anatomy.png b/apps/website/screens/components/password-input/overview/images/password_anatomy.png new file mode 100644 index 0000000000..cbc15ca132 Binary files /dev/null and b/apps/website/screens/components/password-input/overview/images/password_anatomy.png differ diff --git a/apps/website/screens/components/password-input/overview/images/password_clear_content.png b/apps/website/screens/components/password-input/overview/images/password_clear_content.png new file mode 100644 index 0000000000..48a5641ddc Binary files /dev/null and b/apps/website/screens/components/password-input/overview/images/password_clear_content.png differ diff --git a/apps/website/screens/components/password-input/specs/PasswordInputSpecsPage.tsx b/apps/website/screens/components/password-input/specs/PasswordInputSpecsPage.tsx deleted file mode 100644 index 120f9a5bd1..0000000000 --- a/apps/website/screens/components/password-input/specs/PasswordInputSpecsPage.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { DxcParagraph, DxcFlex, DxcLink, DxcBulletedList } from "@dxc-technology/halstack-react"; -import Link from "next/link"; -import Figure from "@/common/Figure"; -import Code from "@/common/Code"; -import DocFooter from "@/common/DocFooter"; -import Image from "@/common/Image"; -import QuickNavContainer from "@/common/QuickNavContainer"; -import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; -import passwordInputActions from "./images/password_actions.png"; -import passwordInputAnatomy from "./images/password_anatomy.png"; -import passwordInputSpecs from "./images/password_specs.png"; -import passworsInputStates from "./images/password_states.png"; - -const sections = [ - { - title: "Specifications", - content: ( - <> -
- Password input design specifications -
- - The password input color, typography, border, spacing,{" "} - width and margin specifications are inherited from the text input, for reference - check the{" "} - - text input - {" "} - component documentation. - - - The password input doesn't have the following text input elements, therefore their listed styles don't - apply: - - - Placeholder - Prefix / Suffix - - - ), - }, - { - title: "States", - content: ( - <> - The component password has the following states: - - States: enabled, hover, focus, error and{" "} - disabled. - -
- Password input states -
- - ), - }, - - { - title: "Anatomy", - content: ( - <> - Password input anatomy - - Label - - Helper text (Optional) - - Input container - Show/Hide action - Clear action - Error icon - Error message - Input value - - - ), - }, - { - title: "Actions", - content: ( - <> -
- Show and hide action to toggle the value visibility -
- - The value of the input can be toggled on or off using the default action the component provides. The password - input can also be clearable. - - - - The toggle indicates the action that will be performed when clicked, tapped, or pressing keyboard{" "} - Enter key. - - - The toggle has a title with a textual cue for the resulting action. - - - - ), - }, - { - title: "Accessibility", - subSections: [ - { - title: "WCAG", - content: ( - - - Understanding WCAG 2.2 -{" "} - - SC 1.3.5 Identify Input Purpose - - - - Understanding WCAG 2.2 -{" "} - - SC 3.3.3 Error Suggestion - - - - Understanding WCAG 2.2 -{" "} - - SC 3.3.7 Accessible Authentication - - - - ), - }, - { - title: "WAI Web Accessibility Tutorials", - content: ( - - - Forms -{" "} - - Full Password Example - - - - ), - }, - ], - }, -]; - -const PasswordInputSpecsPage = () => { - return ( - - - - - - - ); -}; - -export default PasswordInputSpecsPage; diff --git a/apps/website/screens/components/password-input/specs/images/password_actions.png b/apps/website/screens/components/password-input/specs/images/password_actions.png deleted file mode 100644 index a1c42a4c28..0000000000 Binary files a/apps/website/screens/components/password-input/specs/images/password_actions.png and /dev/null differ diff --git a/apps/website/screens/components/password-input/specs/images/password_anatomy.png b/apps/website/screens/components/password-input/specs/images/password_anatomy.png deleted file mode 100644 index fafab8427a..0000000000 Binary files a/apps/website/screens/components/password-input/specs/images/password_anatomy.png and /dev/null differ diff --git a/apps/website/screens/components/password-input/specs/images/password_specs.png b/apps/website/screens/components/password-input/specs/images/password_specs.png deleted file mode 100644 index 22cf69b69d..0000000000 Binary files a/apps/website/screens/components/password-input/specs/images/password_specs.png and /dev/null differ diff --git a/apps/website/screens/components/password-input/specs/images/password_states.png b/apps/website/screens/components/password-input/specs/images/password_states.png deleted file mode 100644 index e30241c947..0000000000 Binary files a/apps/website/screens/components/password-input/specs/images/password_states.png and /dev/null differ diff --git a/apps/website/screens/components/password-input/usage/PasswordInputUsagePage.tsx b/apps/website/screens/components/password-input/usage/PasswordInputUsagePage.tsx deleted file mode 100644 index 08bbd5f704..0000000000 --- a/apps/website/screens/components/password-input/usage/PasswordInputUsagePage.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { DxcBulletedList, DxcFlex } from "@dxc-technology/halstack-react"; -import QuickNavContainer from "@/common/QuickNavContainer"; -import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; -import DocFooter from "@/common/DocFooter"; - -const sections = [ - { - title: "Usage", - subSections: [ - { - title: "Do's", - content: ( - - - Use the component password input when the value expected is a password and need to be secured. - - Provide the requirements in the helper text. - - ), - }, - { - title: "Don'ts", - content: ( - - - Show the validation of the password input until the component loses the focus. - - Disable the copy/paste input functionality. - - ), - }, - ], - }, -]; - -const PasswordInputUsagePage = () => { - return ( - - - - - - - ); -}; - -export default PasswordInputUsagePage; diff --git a/apps/website/screens/components/text-input/TextInputPageLayout.tsx b/apps/website/screens/components/text-input/TextInputPageLayout.tsx index 422fc960f3..f3c164f366 100644 --- a/apps/website/screens/components/text-input/TextInputPageLayout.tsx +++ b/apps/website/screens/components/text-input/TextInputPageLayout.tsx @@ -6,21 +6,20 @@ import { ReactNode } from "react"; const TextInputPageHeading = ({ children }: { children: ReactNode }) => { const tabs = [ - { label: "Code", path: "/components/text-input" }, - { label: "Usage", path: "/components/text-input/usage" }, - { label: "Specifications", path: "/components/text-input/specifications" }, + { label: "Overview", path: "/components/text-input" }, + { label: "Code", path: "/components/text-input/code" }, ]; return ( - + - Text inputs are input fields typically used in forms that allow the user to enter text data in a structured + Text inputs are fields commonly used in forms to capture user-entered text in a structured and accessible format. - + {children} diff --git a/apps/website/screens/components/text-input/code/TextInputCodePage.tsx b/apps/website/screens/components/text-input/code/TextInputCodePage.tsx index 27e50064fe..5a0bde0068 100644 --- a/apps/website/screens/components/text-input/code/TextInputCodePage.tsx +++ b/apps/website/screens/components/text-input/code/TextInputCodePage.tsx @@ -9,7 +9,14 @@ import uncontrolled from "./examples/uncontrolled"; import action from "./examples/action"; import functionSuggestions from "./examples/functionSuggestions"; import errorHandling from "./examples/errorHandling"; -import TableCode from "@/common/TableCode"; +import TableCode, { ExtendedTableCode } from "@/common/TableCode"; + +const actionTypeString = `{ + icon?: string | (React.ReactNode + & React.SVGProps); + onClick: () => void; + title?: string; +}`; const sections = [ { @@ -26,90 +33,43 @@ const sections = [ - defaultValue - - string - - Initial value of the input, only when it is uncontrolled. - - - - - value + action - string + {actionTypeString} - Value of the input. If undefined, the component will be uncontrolled and the value will be managed - internally by the component. + Action to be displayed on the right side of the input. - - label + ariaLabel string - Text to be placed above the input. Under the hood, this prop also serves as an accessible label for the - list of suggestions. + Specifies a string to be used as the name for the textInput element when no label is + provided. - - - - - name - string + 'Text input' - Name attribute of the input element. - - - helperText - - string - - Helper text to be placed above the input. - - - - - placeholder + autocomplete string - Text to be put as placeholder of the input. - - - - - action - - { - "{ icon: string | (React.ReactNode & React.SVGProps ); onClick: () => void; title?: string }" - } - + HTML autocomplete attribute. Lets the user specify if any permission the user agent has to + provide automated assistance in filling out the input value. Its value must be one of all the possible + values of the HTML autocomplete attribute. See{" "} + MDN{" "} + for further information. - Action to be shown in the input. It has the following properties: -
    -
  • - icon: Icon to be placed in the action. It can be either an icon from{" "} - - Material Symbols - {" "} - (string) or a SVG component. -
  • -
  • - onClick: Function to be called when the action button is clicked. -
  • -
  • - title: Text representing advisory information related to the button's action. Under the hood, - this prop also serves as an accessible label for the component. -
  • -
- Note that if the icon is an URL (string), the component's color styling tokens will not be applied to the - image. + 'off' - - clearable @@ -121,6 +81,14 @@ const sections = [ false + + defaultValue + + string + + Initial value of the input, only when it is uncontrolled. + - + disabled @@ -132,61 +100,84 @@ const sections = [ - optional - - boolean - + error - If true, the input will be optional, showing '(Optional)' next to the label. Otherwise, the field will be - considered required and an error will be passed as a parameter to the onBlur and{" "} - onChange functions when it has not been filled. + string - false + If it is a defined value and also a truthy string, the component will change its appearance, showing the + error below the input component. If the defined value is an empty string, it will reserve a space below + the component for a future error, but it would not change its look. In case of being undefined or null, + both the appearance and the space for the error message would not be modified. + - - readOnly + helperText - boolean + string + Helper text to be placed above the input. + - + + + label - If true, the component will not be mutable, meaning the user can not edit the control. In addition, the - clear action will not be displayed even if the flag is set to true and the custom action will not execute - its onClick event. + string - false + Text to be placed above the input. Under the hood, this prop also serves as an accessible label for the + list of suggestions. + - - prefix + margin - string + 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin + + + Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and + 'right' properties in order to specify different margin sizes. - Prefix to be placed before the input value. - - suffix + maxLength - string + number + + + Specifies the maximum length allowed by the input. This will be checked both when the input element loses + the focus and while typing within it. If the string entered does not comply the maximum length, the{" "} + onBlur and onChange functions will be called with the current value and an + internal error informing that the value length does not comply the specified range. If a valid length is + reached, the error parameter of both events will not be defined. - Suffix to be placed after the input value. - - onChange + minLength - {"(val: { value: string; error?: string }) => void"} + number - This function will be called when the user types within the input element of the component. An object - including the current value and the error (if the value entered is not valid) will be passed to this - function. If there is no error, error will not be defined. + Specifies the minimum length allowed by the input. This will be checked both when the input element loses + the focus and while typing within it. If the string entered does not comply the minimum length, the{" "} + onBlur and onChange functions will be called with the current value and an + internal error informing that the value length does not comply the specified range. If a valid length is + reached, the error parameter of both events will not be defined. - + + name + + string + + Name attribute of the input element. + - + onBlur @@ -200,36 +191,30 @@ const sections = [ - - error + onChange - string + {"(val: { value: string; error?: string }) => void"} - If it is a defined value and also a truthy string, the component will change its appearance, showing the - error below the input component. If the defined value is an empty string, it will reserve a space below - the component for a future error, but it would not change its look. In case of being undefined or null, - both the appearance and the space for the error message would not be modified. + This function will be called when the user types within the input element of the component. An object + including the current value and the error (if the value entered is not valid) will be passed to this + function. If there is no error, error will not be defined. - - suggestions + optional - {"string[] | ((value: string) => Promise )"} + boolean - These are the options to be displayed as suggestions. It can be either an array or a function: -
    -
  • - Array: List of options that will be filtered by the user's input. -
  • -
  • - Function: This function will be called when the user changes the value. It will receive the new - value as a parameter and should return a promise that resolves to an array with the filtered options. -
  • -
+ If true, the input will be optional, showing '(Optional)' next to the label. Otherwise, the field will be + considered required and an error will be passed as a parameter to the onBlur and{" "} + onChange functions when it has not been filled. + + + false - - pattern @@ -246,58 +231,41 @@ const sections = [ - - minLength - - number - + placeholder - Specifies the minimum length allowed by the input. This will be checked both when the input element loses - the focus and while typing within it. If the string entered does not comply the minimum length, the{" "} - onBlur and onChange functions will be called with the current value and an - internal error informing that the value length does not comply the specified range. If a valid length is - reached, the error parameter of both events will not be defined. + string + Text to be put as placeholder of the input. - - maxLength - - number - + prefix - Specifies the maximum length allowed by the input. This will be checked both when the input element loses - the focus and while typing within it. If the string entered does not comply the maximum length, the{" "} - onBlur and onChange functions will be called with the current value and an - internal error informing that the value length does not comply the specified range. If a valid length is - reached, the error parameter of both events will not be defined. + string + Prefix to be placed before the input value. - - autocomplete + readOnly - string + boolean - HTML autocomplete attribute. Lets the user specify if any permission the user agent has to - provide automated assistance in filling out the input value. Its value must be one of all the possible - values of the HTML autocomplete attribute. See{" "} - MDN{" "} - for further information. + If true, the component will not be mutable, meaning the user can not edit the control. In addition, the + clear action will not be displayed even if the flag is set to true and the custom action will not execute + its onClick event. - 'off' + false - margin - - 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | Margin - + ref - Size of the margin to be applied to the component. You can pass an object with 'top', 'bottom', 'left' and - 'right' properties in order to specify different margin sizes. + {"React.Ref"} + Reference to the component. - @@ -311,35 +279,54 @@ const sections = [ - tabIndex + suffix - number + string + Suffix to be placed after the input value. + - + + + suggestions - Value of the tabindex attribute. + {"string[] | ((value: string) => Promise )"} - 0 + These are the options to be displayed as suggestions. It can be either an array or a function: +
    +
  • + Array: List of options that will be filtered by the user's input. +
  • +
  • + Function: This function will be called when the user changes the value. It will receive the new + value as a parameter and should return a promise that resolves to an array with the filtered options. +
  • +
+ - - ref + tabIndex - {"React.Ref"} + number + + + Value of the tabindex attribute. + + + 0 - Reference to the component. - - - ariaLabel + value string - Specifies a string to be used as the name for the textInput element when no label is - provided. + Value of the input. If undefined, the component will be uncontrolled and the value will be managed + internally by the component. - 'Text input' + - @@ -372,15 +359,13 @@ const sections = [ }, ]; -const TextInputCodePage = () => { - return ( - - - - - - - ); -}; +const TextInputCodePage = () => ( + + + + + + +); export default TextInputCodePage; diff --git a/apps/website/screens/components/text-input/code/examples/action.ts b/apps/website/screens/components/text-input/code/examples/action.ts index a8c375ac50..4f5fc374b4 100644 --- a/apps/website/screens/components/text-input/code/examples/action.ts +++ b/apps/website/screens/components/text-input/code/examples/action.ts @@ -2,17 +2,34 @@ import { DxcTextInput, DxcInset } from "@dxc-technology/halstack-react"; import { useState } from "react"; const code = `() => { + const [value, setValue] = useState(""); + const onChange = ({ value }) => { + setValue(value); + }; const actionIcon = { + icon: "Content_Copy", onClick: () => { - console.log("Copied."); + navigator.clipboard + .writeText(value) + .then(() => { + alert("Code copied!"); + }) + .catch(() => { + alert("Failed attempt to copy the text."); + }); }, - icon: "Content_Copy", - title: "Copy", + title: "Copy the text", }; return ( - + ); }`; diff --git a/apps/website/screens/components/text-input/overview/TextInputOverviewPage.tsx b/apps/website/screens/components/text-input/overview/TextInputOverviewPage.tsx new file mode 100644 index 0000000000..ee7fef5067 --- /dev/null +++ b/apps/website/screens/components/text-input/overview/TextInputOverviewPage.tsx @@ -0,0 +1,335 @@ +import { DxcParagraph, DxcBulletedList, DxcFlex } from "@dxc-technology/halstack-react"; +import QuickNavContainer from "@/common/QuickNavContainer"; +import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; +import Figure from "@/common/Figure"; +import DocFooter from "@/common/DocFooter"; +import Image from "@/common/Image"; +import prefixSuffix from "./examples/prefixSuffix"; +import Example from "@/common/example/Example"; +import customAction from "./examples/customAction"; +import anatomy from "./images/text_input_anatomy.png"; +import textInputClearContent from "./images/text_input_clear_content.png"; +import textInputAutosuggest from "./images/text_input_autosuggest.png"; + +const sections = [ + { + title: "Introduction", + content: ( + + Text inputs are essential UI elements that enable users to enter and interact with{" "} + text-based information. They are widely used in forms for collecting data, performing searches, + and completing various user interactions. Use text inputs to facilitate user input in structured formats such as + usernames, descriptions, URLs, phone numbers, credit card details, emails, and addresses. Ensuring clear labels, + proper validation, and intuitive formatting enhances usability and improves the overall user experience. + + ), + }, + { + title: "Anatomy", + content: ( + <> + Text input anatomy + + + Label (Optional): a descriptive text that helps users understand what information + is expected in the input field. It should be clear, concise, and placed near the input for better + readability. + + + Optional indicator (Optional): a small indicator that signals the input field is + not mandatory. It helps users know they can leave the field empty without causing validation errors. + + + Input action (Optional): an interactive element, such as an icon or button, inside + the input field that triggers a specific action (e.g., revealing a password, opening a date picker, or + searching). + + + Close action (Optional): a small button, represented by an "X" icon, that allows + users to clear the entered text quickly without manually deleting it. + + + Helper text (Optional): additional text placed below the input field that provides + guidance, examples, or explanations to assist users in filling out the field correctly. + + + Container: the visual wrapper around the input field that provides structure, ensures + accessibility, and helps differentiate the input from other UI elements. + + + Prefix (Optional): a visual element placed before or after the user input, like + currency symbols or units, to help clarify the expected data. + + + Placeholder/Value: a short hint displayed inside the input field before any text is + entered, offering a brief example or instruction on what type of data is expected. It disappears when the + user starts typing. The value represents the actual content entered by the user. Unlike the placeholder, the + value persists during interaction and is what gets submitted with the form. + + + + ), + }, + { + title: "Form inputs", + content: ( + <> + + Form inputs are essential UI elements that allow users to interact with digital products by{" "} + entering or selecting data. Choosing the right input type and structure is key to designing + efficient, user-friendly forms that support task completion and data accuracy. + + + A form input (also known as a form field) is used to capture user data. Common input types include text + fields, date pickers, number fields, radio buttons, checkboxes, toggles, and dropdowns. Forms should always + include a submission method, such as a submit button, link, or keyboard trigger, to complete the interaction. + + + ), + subSections: [ + { + title: "Shared input characteristics", + content: ( + <> + + Although input fields vary in type and purpose, they often share a common set of features: + + + + Placeholder: a short hint displayed inside the input field that describes its expected + value or purpose. + + + Size and max length: inputs can have both a visual size (width of the field) and a + character limit that defines how much text can be entered. + + + Prefix or suffix: some inputs include a visual element before or after the user input, + like currency symbols or units, to help clarify the expected data. + + + Helper text: additional information displayed below the field to guide the user in + providing the correct input. + + + Optional label: inputs that are not mandatory can be marked with an "Optional" tag to + set clear expectations. + + + + ), + }, + { + title: "Common input states", + content: ( + <> + Most inputs can also present standard interactive or informative states: + + + Disabled: this state prevents users from interacting with the field. It's typically + used when a value is not applicable or editable under certain conditions or roles. + + + Error: when a user enters invalid or incomplete data, the input shows an error state, + often accompanied by a helpful message to guide corrections. + + + Read-only: the input is visible, focusable, and hoverable, but not editable. This is + ideal for fields with auto-calculated values. Unlike disabled fields, read-only inputs can still be + submitted with the form and are part of the form data. + + + + ), + }, + ], + }, + { + title: "Using text inputs", + content: ( + + Text inputs, in particular, are commonly found in forms, search bars, and interactive fields that require text + user input. Our text input component is highly configurable, allowing designers and developers to adapt it to + different use cases while maintaining usability and accessibility. In this section, we will cover some key + characteristics of our text input, so you can learn about its particularities and behavior. + + ), + subSections: [ + { + title: "Actions", + subSections: [ + { + title: "Clearing content", + content: ( + <> + + Clearing content is one of the key actions of the text input. It allows users to{" "} + remove the content of the input without having to do it manually through a keyboard, + which is particularly useful when large data has been introduced. + +
+ States for the clear content button +
+ + ), + }, + { + title: "Custom actions", + content: ( + <> + + On top of the clear content action, our text input supports another custom action, such as copying the + data introduced or triggering a tooltip with helper text. This added flexibility allows teams to + tailor the input's behavior to their specific use case, enabling more{" "} + dynamic interactions directly from the input field. + + + + ), + }, + ], + }, + { + title: "Prefix and suffix", + content: ( + <> + + Halstack inputs also support the use of prefixes and suffixes, which are visual elements that help users + quickly understand the type of data expected in the field. These cues provide additional + context and improve clarity during data entry. + + + + ), + }, + + { + title: "Autosuggest", + content: ( + <> + + The autosuggest feature in our text input provides users with{" "} + real-time suggestions as they type, based on a predefined list of options. As the user + enters characters, the input field dynamically filters and displays matching values in a dropdown, + allowing for quick and efficient selection. + + + This feature is particularly useful for reducing input errors, speeding up data entry, and guiding users + toward valid or commonly used values, especially in cases where the list of possibilities is large but + predictable, such as country names, email domains, or product codes. It enhances usability by minimizing + typing effort and improving overall form completion accuracy. + +
+ Autosuggest states of the text input +
+ + ), + }, + ], + }, + { + title: "Best practices", + subSections: [ + { + title: "General", + content: ( + + + Always use clear labels: ensure every text input has a visible, descriptive label that + doesn't disappear as users begin typing. Avoid relying solely on placeholder text. + + + Use placeholders as hints only: placeholders should provide examples or expected formats + (e.g., "e.g., johndoe@email.com"), not serve as the primary field descriptor. + + + Clarify field requirements: use an "Optional" tag next to labels to indicate when a field + isn't mandatory, reducing user uncertainty. + + + Provide helper text when needed: include contextual guidance below the input to help + users provide the correct information, especially for complex or specific inputs. + + + Support various states consistently: reflect focus, disabled, error, and read-only states + with distinct, accessible visual cues. + + + ), + }, + { + title: "Actions", + content: ( + + + Provide a way to clear content: allow users to easily clear the input with a clear icon + or button, especially useful for fields like search or filters. + + + Use custom action icons appropriately: if adding custom icons inside the input (e.g., a + calendar icon for date inputs or a search icon), ensure they're meaningful, accessible, and do not + interfere with user input. + + + Avoid distracting behaviors: don't introduce actions that reset, redirect, or submit + forms unexpectedly from within a text field. + + + ), + }, + { + title: "Prefix/suffix", + content: ( + + + Use prefixes and suffixes to add clarity: add visual cues like currency symbols (€), + units (kg), or domain suffixes (.com) to help users understand the context of their input. + + + Do not confuse with input content: ensure prefixes/suffixes are visually distinct and not + editable to avoid confusion with the actual value being typed. + + + Keep it minimal and functional: avoid decorative or unnecessary additions. Prefixes and + suffixes should always serve a clear purpose. + + + ), + }, + { + title: "Autosuggest", + content: ( + + + Use autosuggest for known data sets: ideal when users need to search or select from a + large, predefined list (e.g., city names, users, tags). It enhances speed and reduces errors. + + + Ensure accessibility: suggestions should be fully navigable using a keyboard and readable + by screen readers. Users must be able to select options using arrow keys and Enter. + + + Prioritize relevance in suggestions: filter and order suggestions logically based on the + user's input to avoid overwhelming them with too many or unrelated options. + + + Allow free input if appropriate: when the field accepts both suggested and custom + entries, clearly indicate this behavior and validate accordingly. + + + ), + }, + ], + }, +]; + +const TextInputOverviewPage = () => ( + + + + + + +); + +export default TextInputOverviewPage; diff --git a/apps/website/screens/components/text-input/usage/examples/helperText.ts b/apps/website/screens/components/text-input/overview/examples/customAction.ts similarity index 57% rename from apps/website/screens/components/text-input/usage/examples/helperText.ts rename to apps/website/screens/components/text-input/overview/examples/customAction.ts index 828c891532..c66111b579 100644 --- a/apps/website/screens/components/text-input/usage/examples/helperText.ts +++ b/apps/website/screens/components/text-input/overview/examples/customAction.ts @@ -1,14 +1,23 @@ import { DxcTextInput, DxcInset, DxcFlex } from "@dxc-technology/halstack-react"; const code = `() => { + const copyAction = { + onClick: () => { + console.log("Copied."); + }, + icon: "Content_Copy", + title: "Copy", + }; + return ( diff --git a/apps/website/screens/components/text-input/usage/examples/prefixSuffix.ts b/apps/website/screens/components/text-input/overview/examples/prefixSuffix.ts similarity index 100% rename from apps/website/screens/components/text-input/usage/examples/prefixSuffix.ts rename to apps/website/screens/components/text-input/overview/examples/prefixSuffix.ts diff --git a/apps/website/screens/components/text-input/overview/images/text_input_anatomy.png b/apps/website/screens/components/text-input/overview/images/text_input_anatomy.png new file mode 100644 index 0000000000..254170acad Binary files /dev/null and b/apps/website/screens/components/text-input/overview/images/text_input_anatomy.png differ diff --git a/apps/website/screens/components/text-input/overview/images/text_input_autosuggest.png b/apps/website/screens/components/text-input/overview/images/text_input_autosuggest.png new file mode 100644 index 0000000000..95b8bda7d6 Binary files /dev/null and b/apps/website/screens/components/text-input/overview/images/text_input_autosuggest.png differ diff --git a/apps/website/screens/components/text-input/overview/images/text_input_clear_content.png b/apps/website/screens/components/text-input/overview/images/text_input_clear_content.png new file mode 100644 index 0000000000..ac02d50833 Binary files /dev/null and b/apps/website/screens/components/text-input/overview/images/text_input_clear_content.png differ diff --git a/apps/website/screens/components/text-input/specs/TextInputSpecsPage.tsx b/apps/website/screens/components/text-input/specs/TextInputSpecsPage.tsx deleted file mode 100644 index c4b83cb7c0..0000000000 --- a/apps/website/screens/components/text-input/specs/TextInputSpecsPage.tsx +++ /dev/null @@ -1,1438 +0,0 @@ -import { DxcParagraph, DxcTable, DxcLink, DxcBulletedList, DxcFlex } from "@dxc-technology/halstack-react"; -import QuickNavContainer from "@/common/QuickNavContainer"; -import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; -import DocFooter from "@/common/DocFooter"; -import Figure from "@/common/Figure"; -import Code from "@/common/Code"; -import Image from "@/common/Image"; -import inputStates from "./images/input_states.png"; -import inputAnatomy from "./images/input_anatomy.png"; -import inputSpecs from "./images/input_specs.png"; -import autosuggestStatesListItem from "./images/autosuggest_states_listItem.png"; -import autosuggestAnatomy from "./images/autosuggest_anatomy.png"; -import autosuggestSpecs from "./images/autosuggest_specs.png"; - -const sections = [ - { - title: "Specifications", - content: ( - <> -
- Text input design specifications -
-
- Autosuggest text input design specifications -
- - ), - }, - { - title: "States", - content: ( - <> - - Text input states: enabled, hover, focus,{" "} - error and disabled. - -
- Text input states -
- - List option states: enabled, hover, active and{" "} - system. - -
- List option states -
- - ), - }, - { - title: "Anatomy", - content: ( - <> - Text input anatomy - - Label text - - Helper text (Optional) - - Error indicator - - Clear action (Optional) - - - Input action (Optional) - - Input container - Placeholder text - Error message - Prefix - - Autosuggest anatomy - - List dialog - Text input - List option - List option value - - - ), - }, - { - title: "Design tokens", - subSections: [ - { - title: "Color", - subSections: [ - { - title: "Base", - content: ( - - - - Component token - Element - Core token - Value - - - - - - labelFontColor - - Label - - color-black - - #000000 - - - - valueFontColor - - Value - - color-black - - #000000 - - - - helperTextFontColor - - Helper text - - color-black - - #000000 - - - - placeholderFontColor - - Placeholder - - color-grey-600 - - #808080 - - - - enabledBorderColor - - Border:enabled - - color-black - - #000000 - - - - actionIconColor - - Action icon - - color-black - - #000000 - - - - actionBackgroundColor - - Action - - color-transparent - - transparent - - - - suffixColor - - Suffix - - color-grey-700 - - #666666 - - - - prefixColor - - Prefix - - color-grey-700 - - #666666 - - - - listOptionFontColor - - List option value - - color-black - - #000000 - - - - listOptionDividerColor - - List option divider - - color-grey-200 - - #e6e6e6 - - - - listDialogBorderColor - - List dialog - - color-grey-400 - - #bfbfbf - - - - listDialogBackgroundColor - - List dialog - - color-white - - #ffffff - - - - systemMessageFontColor - - System message - - color-grey-700 - - #666666 - - - - ), - }, - { - title: "Interactive", - content: ( - - - - Component token - Element - Core token - Value - - - - - - hoverBorderColor - - Border:hover - - color-purple-500 - - #a46ede - - - - focusBorderColor - - Border:focus - - color-blue-600 - - #0095ff - - - - errorBorderColor - - Border:error - - color-red-700 - - #d0011b - - - - hoverErrorBorderColor - - Border:error:hover - - color-red-600 - - #fe0123 - - - - disabledBorderColor - - Border:disabled - - color-grey-500 - - #999999 - - - - readOnlyBorderColor - - Border:readonly - - color-grey-500 - - #999999 - - - - hoverReadOnlyBorderColor - - Border:readonly:hover - - color-grey-600 - - #808080 - - - - errorMessageColor - - Error message - - color-red-700 - - #d0011b - - - - disabledContainerFillColor - - Input container:disabled - - color-grey-100 - - #f2f2f2 - - - - disabledLabelFontColor - - Label:disabled - - color-grey-500 - - #999999 - - - - disabledValueFontColor - - Value:disabled - - color-grey-500 - - #999999 - - - - disabledHelperTextFontColor - - Helper text:disabled - - color-grey-500 - - #999999 - - - - disabledPlaceholderFontColor - - Placeholder:disabled - - color-grey-500 - - #999999 - - - - hoverActionBackgroundColor - - Action:hover - - color-grey-100 - - #f2f2f2 - - - - focusActionBorderColor - - Action:focus - - color-blue-600 - - #0095ff - - - - activeActionBackgroundColor - - Action:active - - color-grey-300 - - #cccccc - - - - disabledActionBackgroundColor - - Action:disabled - - color-transparent - - transparent - - - - hoverActionIconColor - - Action icon:hover - - color-black - - #000000 - - - - focusActionIconColor - - Action icon:focus - - color-black - - #000000 - - - - activeActionIconColor - - Action icon:active - - color-black - - #000000 - - - - disabledActionIconColor - - Action icon:disabled - - color-grey-500 - - #999999 - - - - disabledSuffixColor - - Suffix:disabled - - color-grey-400 - - #bfbfbf - - - - disabledPrefixColor - - Prefix:disabled - - color-grey-400 - - #bfbfbf - - - - hoverListOptionBackgroundColor - - List option:hover - - color-grey-100 - - #f2f2f2 - - - - focusListOptionBorderColor - - List option:focus - - color-blue-600 - - #0095ff - - - - activeListOptionBackgroundColor - - List option:active - - color-grey-200 - - #e6e6e6 - - - - errorListDialogFontColor - - List dialog error - - color-black - - #000000 - - - - errorListDialogBackgroundColor - - List dialog error - - color-red-50 - - #fff5f6 - - - - errorListDialogBorderColor - - List dialog error - - color-red-700 - - #d0011b - - - - ), - }, - ], - }, - { - title: "Typography", - content: ( - <> - - - - Component token - Element - Core token - Value - - - - - - fontFamily - - All - - font-family-sans - - Open Sans - - - - labelFontSize - - Label - - font-scale-02 - - 0.875rem / 14px - - - - labelFontWeight - - Label - - font-weight-bold - - 600 - - - - labelFontStyle - - Label - - font-style-normal - - normal - - - - labelLineHeight - - Label - - font-leading-loose-01 - - 1.715em - - - - valueFontSize - - Value - - font-scale-03 - - 1rem / 16px - - - - valueFontWeight - - Value - - font-weight-regular - - 400 - - - - valueFontStyle - - Value - - font-style-normal - - normal - - - - helperTextFontSize - - Helper text - - font-scale-01 - - 12px - - - - helperTextFontWeight - - Helper text - - font-weight-regular - - 400 - - - - helperTextFontStyle - - Helper text - - font-style-normal - - normal - - - - helperTextLineHeight - - Helper text - - font-leading-normal - - 1.5em - - - - optionalLabelFontWeight - - Optional indicator - - font-weight-regular - - 400 - - - - listOptionFontSize - - List option - - font-scale-02 - - 0.875rem / 14px - - - - listOptionFontWeight - - List option - - font-weight-regular - - 400 - - - - listOptionFontStyle - - List option - - font-style-normal - - normal - - - - - - - Property - Element - Core token - Value - - - - - - font-size - - Error message - - font-scale-01 - - 0.75rem / 12px - - - - font-weight - - Error message - - font-weight-regular - - 400 - - - - line-height - - Value - - font-leading-normal - - 1.5em - - - - line-height - - Error message - - font-leading-normal - - 1.5em - - - - font-size - - Placeholder - - font-scale-03 - - 1rem / 16px - - - - font-weight - - Placeholder - - font-regular - - 400 - - - - font-weight - - List option typed - - font-bold - - 600 - - - - font-size - - System message - - font-scale-02 - - 0.875 / 14px - - - - font-weight - - System message - - font-regular - - 400 - - - - - ), - }, - { - title: "Spacing", - content: ( - <> - - - - Component token - Element - Core token - Value - - - - - - inputMarginTop - - Input container - - spacing-4 - - 0.25rem / 4px - - - - inputMarginBottom - - Input container - - spacing-4 - - 0.25rem / 4px - - - - prefixDividerPaddingRight - - Prefix - - spacing-8 - - 0.5rem / 8px - - - - suffixDividerPaddingLeft - - Suffix - - spacing-8 - - 0.5rem / 8px - - - - - - - Property - Element - Core token - Value - - - - - - margin-left - - Error icon - - spacing-4 - - 0.25rem / 4px - - - - margin-left - - Action - - spacing-4 - - 0.25rem / 4px - - - - margin-left - - Prefix - - spacing-4 - - 0.25rem / 4px - - - - padding-right - - Prefix - - spacing-8 - - 0.5rem / 8px - - - - padding-left - - Suffix - - spacing-8 - - 0.5rem / 8px - - - - margin-left - - Suffix - - spacing-4 - - 0.25rem / 4px - - - - margin-right - - Suffix - - spacing-4 - - 0.25rem / 4px - - - - padding-left - - Input - - spacing-8 - - 0.5rem / 8px - - - - padding-right - - Input - - spacing-8 - - 0.5rem / 8px - - - - padding-left - - Input container - - spacing-8 - - 0.5rem / 8px - - - - padding-right - - Input container - - spacing-8 - - 0.5rem / 8px - - - - padding-top - - List dialog - - spacing-4 - - 0.25rem / 4px - - - - padding-bottom - - List dialog - - spacing-4 - - 0.25rem / 4px - - - - padding-left - - List option - - spacing-8 - - 0.5rem / 8px - - - - padding-right - - List option - - spacing-8 - - 0.5rem / 8px - - - - padding-top - - List option - - spacing-2 - - 0.125rem / 2px - - - - padding-bottom - - List option - - spacing-2 - - 0.125rem / 2px - - - - padding-left - - List option value - - spacing-8 - - 0.5rem / 8px - - - - padding-right - - List option value - - spacing-8 - - 0.5rem / 8px - - - - - ), - }, - { - title: "Border", - content: ( - <> - - - - Property - Element - Core token - Value - - - - - - prefixDividerBorderWidth - - Prefix - - - 1px - - - - prefixDividerBorderStyle - - Prefix - - border-style-solid - - solid - - - - suffixDividerBorderWidth - - Suffix - - - 1px - - - - suffixDividerBorderStyle - - Suffix - - border-style-solid - - solid - - - - - - - Property - Element - Core token - Value - - - - - - border - - Input container - - border-width-1 - - 1px - - - - border - - Input container - - border-style-solid - - solid - - - - border - - Input container:focus - - border-width-1 - - 1px - - - - border - - Input container:focus - - border-style-solid - - solid - - - - box-shadow - - Input container:focus - - - 0 0 0 2px - - - - box-shadow - - Input container:error - - - 0 0 0 2px - - - - border - - List dialog - - border-width-1 - - 1px - - - - border - - List dialog - - border-style-solid - - solid - - - - border - - List dialog - - border-radius-medium - - 0.25rem / 4px - - - - border - - List option divider - - border-width-1 - - 1px - - - - border - - List option divider - - border-style-solid - - solid - - - - box-shadow - - List dialog - - shadow-default - - 0 8px 14px -2px rgba(0,0,0,0.1) - - - - - ), - }, - { - title: "Width", - content: ( - - - - Width - Value - - - - - - small - - 240px - - - - medium - - 360px - - - - large - - 480px - - - - fillParent - - 100% - - - - ), - }, - { - title: "Margin", - content: ( - <> - - - - Margin - Value - - - - - - xxsmall - - 6px - - - - xsmall - - 16px - - - - small - - 24px - - - - medium - - 36px - - - - large - - 48px - - - - xlarge - - 64px - - - - xxlarge - - 100px - - - - - And also apply different values to each side of the component: top, bottom,{" "} - left and right. - - - ), - }, - ], - }, - { - title: "Accessibility", - subSections: [ - { - title: "WCAG 2.2", - content: ( - - - Understanding WCAG 2.2 -{" "} - - 1.3.1: Information and Relationships - - - - Understanding WCAG 2.2 -{" "} - - 3.3.1: Error Identification - - - - Understanding WCAG 2.2 -{" "} - - 3.3.2: Labels and Instructions - - - - Understanding WCAG 2.2 -{" "} - - 3.3.3: Error Suggestion - - - - Understanding WCAG 2.2 -{" "} - - 4.1.2: Name, Role, Value - - - - ), - }, - ], - }, -]; - -const TextInputSpecsPage = () => { - return ( - - - - - - - ); -}; - -export default TextInputSpecsPage; diff --git a/apps/website/screens/components/text-input/specs/images/autosuggest_anatomy.png b/apps/website/screens/components/text-input/specs/images/autosuggest_anatomy.png deleted file mode 100644 index 36ff25791c..0000000000 Binary files a/apps/website/screens/components/text-input/specs/images/autosuggest_anatomy.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/specs/images/autosuggest_specs.png b/apps/website/screens/components/text-input/specs/images/autosuggest_specs.png deleted file mode 100644 index 19a2374201..0000000000 Binary files a/apps/website/screens/components/text-input/specs/images/autosuggest_specs.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/specs/images/autosuggest_states_listItem.png b/apps/website/screens/components/text-input/specs/images/autosuggest_states_listItem.png deleted file mode 100644 index 93bf4abbcd..0000000000 Binary files a/apps/website/screens/components/text-input/specs/images/autosuggest_states_listItem.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/specs/images/input_anatomy.png b/apps/website/screens/components/text-input/specs/images/input_anatomy.png deleted file mode 100644 index b779f12fb7..0000000000 Binary files a/apps/website/screens/components/text-input/specs/images/input_anatomy.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/specs/images/input_specs.png b/apps/website/screens/components/text-input/specs/images/input_specs.png deleted file mode 100644 index 6f824a567c..0000000000 Binary files a/apps/website/screens/components/text-input/specs/images/input_specs.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/specs/images/input_states.png b/apps/website/screens/components/text-input/specs/images/input_states.png deleted file mode 100644 index c46c1a9b4c..0000000000 Binary files a/apps/website/screens/components/text-input/specs/images/input_states.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/usage/TextInputUsagePage.tsx b/apps/website/screens/components/text-input/usage/TextInputUsagePage.tsx deleted file mode 100644 index db8f92ab97..0000000000 --- a/apps/website/screens/components/text-input/usage/TextInputUsagePage.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { DxcParagraph, DxcBulletedList, DxcFlex, DxcLink } from "@dxc-technology/halstack-react"; -import QuickNavContainer from "@/common/QuickNavContainer"; -import QuickNavContainerLayout from "@/common/QuickNavContainerLayout"; -import Figure from "@/common/Figure"; -import DocFooter from "@/common/DocFooter"; -import Image from "@/common/Image"; -import inputActionsClearImage from "./images/input_actions_clear.png"; -import inputActionsCustom from "./images/input_actions_custom.png"; -import prefixSuffix from "./examples/prefixSuffix"; -import Example from "@/common/example/Example"; -import helperText from "./examples/helperText"; -import Link from "next/link"; -import autosuggest from "./examples/autosuggest"; - -const sections = [ - { - title: "Usage", - content: ( - - Use text inputs in forms to help people enter, select and search for text. Common text input types include: - usernames, descriptions, URLs, phone numbers, credit cards, emails, addresses or plain text searches. - - ), - subSections: [ - { - title: "Do's", - content: ( - - - Do use fixed-width inputs for content that has a specific, known length (e.g. postcode, phone number). - - - Do use sentence for any input text case with standard, local grammar and punctuation rules. - - - Do use helpful and clear text for labels, error messages and helper texts. - - - ), - }, - { - title: "Don'ts", - content: ( - - - Do not use text input for text longer than a single line (e.g. name, phone number). Use the textarea - instead. - - Do not disable copy and paste. - Do not display a pop-up error message after validating. - Avoid masking label, keep it always visible. - - ), - }, - ], - }, - { - title: "Content", - subSections: [ - { - title: "Actions", - subSections: [ - { - title: "Clearing content", - content: ( - <> - Clear actions allow user to remove the content of the text input. -
- Text input with a clear content action button -
- - ), - }, - { - title: "Custom actions", - content: ( - <> - Text inputs can have an additional custom action. -
- Text input with an additional action -
- - ), - }, - ], - }, - { - title: "Prefixes and suffixes", - content: ( - <> - - Prefixes and suffixes help the user to understand the purpose of the text input. - - - - ), - }, - ], - }, - { - title: "Helper text", - content: ( - <> - - Helper text can be used as additional instructions to the user when filling in the form. It should be always - visible even in a focus state. - - - - ), - subSections: [ - { - title: "Usage", - content: ( - <> - Do: - - Keep helper text as short and specific as possible. - - Only use helper text when truly necessary to avoid overloading the user. - - Should give an example or an explanation of the field. - - Don't: - - Helper text should not run longer than the input area. - - - ), - }, - ], - }, - { - title: "Autosuggest", - content: ( - <> - - Suggests a list of options to fill a text input. A user can either select a suggestion or enter their own - answer. - - - - ), - subSections: [ - { - title: "Usage", - content: ( - <> - - - Use the suggestions to help users select from a list of standard responses when needed. - - - If the value for the textbox must be chosen from a predefined set of allowed values, use the{" "} - - select - {" "} - component instead. - - Keep suggestions simple and avoid scroll. - - - ), - }, - ], - }, -]; - -const TextInputUsagePage = () => { - return ( - - - - - - - ); -}; - -export default TextInputUsagePage; diff --git a/apps/website/screens/components/text-input/usage/examples/autosuggest.ts b/apps/website/screens/components/text-input/usage/examples/autosuggest.ts deleted file mode 100644 index 8d5b063bc2..0000000000 --- a/apps/website/screens/components/text-input/usage/examples/autosuggest.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { DxcTextInput, DxcInset, DxcFlex } from "@dxc-technology/halstack-react"; - -const code = `() => { - const countries = [ - "Afghanistan", - "Albania", - "Andorra", - "Antigua and Barbuda", - "Bahrain", - "Bangladesh", - "Barbados", - "Cameroon", - "Canada", - "Central African Republic", - "Chad", - "Democratic Republic of the Congo", - "Dominica", - "Denmark", - "Djibouti", - ]; - - return ( - - - - - - ); -}`; - -const scope = { - DxcTextInput, - DxcInset, - DxcFlex, -}; - -export default { code, scope }; diff --git a/apps/website/screens/components/text-input/usage/images/input_actions_clear.png b/apps/website/screens/components/text-input/usage/images/input_actions_clear.png deleted file mode 100644 index d35b387462..0000000000 Binary files a/apps/website/screens/components/text-input/usage/images/input_actions_clear.png and /dev/null differ diff --git a/apps/website/screens/components/text-input/usage/images/input_actions_custom.png b/apps/website/screens/components/text-input/usage/images/input_actions_custom.png deleted file mode 100644 index b525de6850..0000000000 Binary files a/apps/website/screens/components/text-input/usage/images/input_actions_custom.png and /dev/null differ diff --git a/packages/lib/src/number-input/NumberInput.tsx b/packages/lib/src/number-input/NumberInput.tsx index efd093a35f..da454cd5f6 100644 --- a/packages/lib/src/number-input/NumberInput.tsx +++ b/packages/lib/src/number-input/NumberInput.tsx @@ -4,32 +4,48 @@ import DxcTextInput from "../text-input/TextInput"; import NumberInputPropsType, { RefType } from "./types"; import NumberInputContext from "./NumberInputContext"; +const NumberInputContainer = styled.div<{ size: NumberInputPropsType["size"] }>` + ${({ size }) => size === "fillParent" && "width: 100%;"} + + // Chrome, Safari, Edge, Opera + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + // Firefox + input[type="number"] { + -moz-appearance: textfield; + } +`; + const DxcNumberInput = forwardRef( ( { - label, - name, + ariaLabel = "Number input", + autocomplete, defaultValue, - value, - helperText, - placeholder, disabled, - optional, - readOnly, - prefix, - suffix, - min, - max, - step = 1, - onChange, - onBlur, error, - autocomplete, + helperText, + label, margin, + max, + min, + name, + onBlur, + onChange, + optional, + placeholder, + prefix, + readOnly, + showControls = true, size, + step = 1, + suffix, tabIndex, - ariaLabel = "Number input", - showControls = true, + value, }, ref ) => { @@ -88,19 +104,4 @@ const DxcNumberInput = forwardRef( } ); -const NumberInputContainer = styled.div<{ size: NumberInputPropsType["size"] }>` - ${(props) => props.size === "fillParent" && "width: 100%;"} - // Chrome, Safari, Edge, Opera - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; - } - - // Firefox - input[type="number"] { - -moz-appearance: textfield; - } -`; - export default DxcNumberInput; diff --git a/packages/lib/src/password-input/PasswordInput.tsx b/packages/lib/src/password-input/PasswordInput.tsx index 3c5bad0b94..f75e2f7146 100644 --- a/packages/lib/src/password-input/PasswordInput.tsx +++ b/packages/lib/src/password-input/PasswordInput.tsx @@ -13,6 +13,13 @@ const setAriaAttributes = (ariaExpanded: "true" | "false", element: HTMLDivEleme buttonElement?.setAttribute("aria-expanded", ariaExpanded); }; +const PasswordInput = styled.div<{ size: PasswordInputPropsType["size"] }>` + ${(props) => props.size === "fillParent" && "width: 100%;"} + & ::-ms-reveal { + display: none; + } +`; + const DxcPasswordInput = forwardRef( ( { @@ -56,7 +63,7 @@ const DxcPasswordInput = forwardRef( }, [isPasswordVisible, passwordInput]); return ( - + ( } ); -const PasswordInput = styled.div<{ size: PasswordInputPropsType["size"] }>` - ${(props) => props.size === "fillParent" && "width: 100%;"} - & ::-ms-reveal { - display: none; - } -`; - export default DxcPasswordInput; diff --git a/packages/lib/src/select/ListOption.tsx b/packages/lib/src/select/ListOption.tsx index 8bb2d66af4..a81200d5fd 100644 --- a/packages/lib/src/select/ListOption.tsx +++ b/packages/lib/src/select/ListOption.tsx @@ -12,10 +12,7 @@ const OptionItem = styled.li<{ padding: var(--spacing-padding-none) var(--spacing-padding-xs); cursor: pointer; ${({ selected }) => selected && "background-color: var(--color-bg-secondary-lighter);"}; - &:hover { - background-color: ${({ selected }) => - selected ? "var(--color-bg-secondary-medium)" : "var(--color-bg-neutral-light)"}; - } + &:hover, &:active { background-color: ${({ selected }) => selected ? "var(--color-bg-secondary-medium)" : "var(--color-bg-neutral-light)"}; diff --git a/packages/lib/src/styles/forms/ErrorMessage.tsx b/packages/lib/src/styles/forms/ErrorMessage.tsx index 9dbe45fb29..f4540da534 100644 --- a/packages/lib/src/styles/forms/ErrorMessage.tsx +++ b/packages/lib/src/styles/forms/ErrorMessage.tsx @@ -9,7 +9,7 @@ const ErrorMessageContainer = styled.div` font-size: var(--typography-helper-text-s); font-weight: var(--typography-helper-text-regular); margin-top: var(--spacing-gap-xs); - + /* Error icon */ > span[role="img"] { font-size: var(--height-xxs); diff --git a/packages/lib/src/text-input/Suggestion.tsx b/packages/lib/src/text-input/Suggestion.tsx index 97336517f0..c9cea450c8 100644 --- a/packages/lib/src/text-input/Suggestion.tsx +++ b/packages/lib/src/text-input/Suggestion.tsx @@ -26,6 +26,11 @@ const StyledSuggestion = styled.span` overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + + /* Highlighted text */ + > span { + font-weight: var(--typography-label-semibold); + } `; const Suggestion = ({ highlighted, id, isLast, onClick, suggestion, value, visuallyFocused }: SuggestionProps) => { @@ -48,7 +53,7 @@ const Suggestion = ({ highlighted, id, isLast, onClick, suggestion, value, visua {highlighted ? ( <> - {matchedSuggestion.matchedWords} + {matchedSuggestion.matchedWords} {matchedSuggestion.noMatchedWords} ) : ( diff --git a/packages/lib/src/text-input/Suggestions.tsx b/packages/lib/src/text-input/Suggestions.tsx index a4b4eacd66..74dca76a91 100644 --- a/packages/lib/src/text-input/Suggestions.tsx +++ b/packages/lib/src/text-input/Suggestions.tsx @@ -7,19 +7,19 @@ import DxcIcon from "../icon/Icon"; import { scrollbarStyles } from "../styles/scroll"; const SuggestionsContainer = styled.div` + box-sizing: border-box; + max-height: 304px; + padding: var(--spacing-padding-xxs) var(--spacing-padding-none); background-color: var(--color-bg-neutral-lightest); border: var(--border-width-s) var(--border-style-default) var(--border-color-neutral-medium); border-radius: var(--border-radius-s); box-shadow: var(--shadow-mid-x-position) var(--shadow-mid-y-position) var(--shadow-mid-blur) var(--shadow-mid-spread) var(--shadow-light); - box-sizing: border-box; - max-height: 304px; - padding: var(--spacing-padding-xxs) var(--spacing-padding-none); color: var(--color-fg-neutral-dark); font-family: var(--typography-font-family); font-size: var(--typography-label-m); font-weight: var(--typography-label-regular); - overflow: auto; + overflow-y: auto; ${scrollbarStyles} `; diff --git a/packages/lib/src/text-input/TextInput.tsx b/packages/lib/src/text-input/TextInput.tsx index 5cdf8d88df..6fb6de21ac 100644 --- a/packages/lib/src/text-input/TextInput.tsx +++ b/packages/lib/src/text-input/TextInput.tsx @@ -441,7 +441,7 @@ const DxcTextInput = forwardRef( {label} {optional && {translatedLabels.formFields.optionalLabel}} )} - {helperText && {helperText}} + {helperText && {helperText}} (