From 7a5215a0fbf1e4a7097eea73d9a5f2aedfca5fd5 Mon Sep 17 00:00:00 2001 From: Zhihao Cui <5257855+origami-z@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:55:26 +0100 Subject: [PATCH] Fix data attributes error on pass through props (#4039) --- .changeset/good-fishes-shout.md | 12 ++++++++++++ .../src/__tests__/__e2e__/checkbox/Checkbox.cy.tsx | 7 +++++++ .../core/src/__tests__/__e2e__/input/Input.cy.tsx | 7 +++++++ .../__e2e__/multiline-input/MultilineInput.cy.tsx | 10 ++++++++++ .../__e2e__/radio-button/RadioButton.cy.tsx | 10 ++++++++++ .../core/src/__tests__/__e2e__/switch/Switch.cy.tsx | 5 +++++ packages/core/src/checkbox/Checkbox.tsx | 3 ++- packages/core/src/index.ts | 1 + packages/core/src/input/Input.tsx | 3 ++- .../core/src/multiline-input/MultilineInput.tsx | 4 +++- packages/core/src/pill-input/PillInput.tsx | 3 ++- packages/core/src/radio-button/RadioButton.tsx | 11 ++++++----- packages/core/src/switch/Switch.tsx | 13 +++++++------ packages/core/src/types.ts | 8 ++++++++ 14 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 .changeset/good-fishes-shout.md create mode 100644 packages/core/src/types.ts diff --git a/.changeset/good-fishes-shout.md b/.changeset/good-fishes-shout.md new file mode 100644 index 00000000000..ab7e4c694c5 --- /dev/null +++ b/.changeset/good-fishes-shout.md @@ -0,0 +1,12 @@ +--- +"@salt-ds/core": patch +--- + +Fixed data-\* attributes not allowed on pass through props. Closes #3797. + +- `Checkbox.inputProps` +- `Input.inputProps` +- `MultilineInput.textAreaProps` +- `PillInput.inputProps` +- `RadioButton.inputProps` +- `Switch.inputProps` diff --git a/packages/core/src/__tests__/__e2e__/checkbox/Checkbox.cy.tsx b/packages/core/src/__tests__/__e2e__/checkbox/Checkbox.cy.tsx index 969608bd3e9..51770ed72a5 100644 --- a/packages/core/src/__tests__/__e2e__/checkbox/Checkbox.cy.tsx +++ b/packages/core/src/__tests__/__e2e__/checkbox/Checkbox.cy.tsx @@ -1,6 +1,13 @@ import { Checkbox } from "@salt-ds/core"; describe("GIVEN a Checkbox", () => { + it("SHOULD support data attribute on inputProps", () => { + cy.mount( + , + ); + cy.findByTestId("customInput").should("be.checked"); + }); + describe("WHEN in an indeterminate state", () => { it("THEN should have indeterminate set to true", () => { cy.mount(); diff --git a/packages/core/src/__tests__/__e2e__/input/Input.cy.tsx b/packages/core/src/__tests__/__e2e__/input/Input.cy.tsx index 770cc5dbed1..41c08b90ce9 100644 --- a/packages/core/src/__tests__/__e2e__/input/Input.cy.tsx +++ b/packages/core/src/__tests__/__e2e__/input/Input.cy.tsx @@ -7,6 +7,13 @@ describe("GIVEN an Input", () => { cy.checkAxeComponent(); }); + it("SHOULD support data attribute on inputProps", () => { + cy.mount( + , + ); + cy.findByTestId("customInput").should("have.value", "value"); + }); + describe("WHEN cy.mounted as an uncontrolled component", () => { it("THEN it should cy.mount with the specified defaultValue", () => { cy.mount(); diff --git a/packages/core/src/__tests__/__e2e__/multiline-input/MultilineInput.cy.tsx b/packages/core/src/__tests__/__e2e__/multiline-input/MultilineInput.cy.tsx index 8e8b832d74d..9231f943ef7 100644 --- a/packages/core/src/__tests__/__e2e__/multiline-input/MultilineInput.cy.tsx +++ b/packages/core/src/__tests__/__e2e__/multiline-input/MultilineInput.cy.tsx @@ -11,6 +11,16 @@ const { } = composeStories(multilineInputStories); describe("GIVEN an MultilineInput", () => { + it("SHOULD support data attribute on textAreaProps", () => { + cy.mount( + , + ); + cy.findByTestId("customInput").should("have.value", "value"); + }); + it("should allow a default value to be set", () => { const changeSpy = cy.stub().as("changeSpy"); const handleChange = (event: ChangeEvent) => { diff --git a/packages/core/src/__tests__/__e2e__/radio-button/RadioButton.cy.tsx b/packages/core/src/__tests__/__e2e__/radio-button/RadioButton.cy.tsx index 8b51b952360..041cd9d85f9 100644 --- a/packages/core/src/__tests__/__e2e__/radio-button/RadioButton.cy.tsx +++ b/packages/core/src/__tests__/__e2e__/radio-button/RadioButton.cy.tsx @@ -1,6 +1,16 @@ import { RadioButton } from "@salt-ds/core"; describe("GIVEN a RadioButton component", () => { + it("SHOULD support data attribute on inputProps", () => { + cy.mount( + , + ); + cy.findByTestId("customInput").should("have.value", "value"); + }); + describe("WHEN RadioButton is given a value", () => { it("SHOULD render with the specified value", () => { cy.mount(); diff --git a/packages/core/src/__tests__/__e2e__/switch/Switch.cy.tsx b/packages/core/src/__tests__/__e2e__/switch/Switch.cy.tsx index cbd8aabd2f1..daf240ae30e 100644 --- a/packages/core/src/__tests__/__e2e__/switch/Switch.cy.tsx +++ b/packages/core/src/__tests__/__e2e__/switch/Switch.cy.tsx @@ -14,6 +14,11 @@ function ControlledSwitch({ onChange, disabled }: SwitchProps) { } describe("GIVEN a Switch", () => { + it("SHOULD support data attribute on inputProps", () => { + cy.mount(); + cy.findByTestId("customInput").should("be.checked"); + }); + describe("WHEN using Tab to navigate", () => { it("THEN should be focusable", () => { cy.mount(); diff --git a/packages/core/src/checkbox/Checkbox.tsx b/packages/core/src/checkbox/Checkbox.tsx index 9b5fc89e8da..426810ff2ee 100644 --- a/packages/core/src/checkbox/Checkbox.tsx +++ b/packages/core/src/checkbox/Checkbox.tsx @@ -11,6 +11,7 @@ import { } from "react"; import { useFormFieldProps } from "../form-field-context"; import type { AdornmentValidationStatus } from "../status-adornment"; +import type { DataAttributes } from "../types"; import { makePrefixer, useControlled, @@ -52,7 +53,7 @@ export interface CheckboxProps /** * Properties applied to the input element. */ - inputProps?: Partial>; + inputProps?: Partial> & DataAttributes; /** * The label to be shown next to the checkbox. */ diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 43ce1577a44..21518f52394 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -61,3 +61,4 @@ export * from "./toggle-button-group"; export * from "./tooltip"; export * from "./utils"; export * from "./viewport"; +export * from "./types"; diff --git a/packages/core/src/input/Input.tsx b/packages/core/src/input/Input.tsx index fec8d327788..df4bf5ad83d 100644 --- a/packages/core/src/input/Input.tsx +++ b/packages/core/src/input/Input.tsx @@ -13,6 +13,7 @@ import { } from "react"; import { useFormFieldProps } from "../form-field-context"; import { StatusAdornment } from "../status-adornment"; +import type { DataAttributes } from "../types"; import { makePrefixer, useControlled } from "../utils"; import inputCss from "./Input.css"; @@ -37,7 +38,7 @@ export interface InputProps /** * [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes) applied to the `input` element. */ - inputProps?: InputHTMLAttributes; + inputProps?: Partial> & DataAttributes; /** * Optional ref for the input component */ diff --git a/packages/core/src/multiline-input/MultilineInput.tsx b/packages/core/src/multiline-input/MultilineInput.tsx index ad114b19e49..d013e7ee45c 100644 --- a/packages/core/src/multiline-input/MultilineInput.tsx +++ b/packages/core/src/multiline-input/MultilineInput.tsx @@ -16,6 +16,7 @@ import { } from "react"; import { useFormFieldProps } from "../form-field-context"; import { StatusAdornment } from "../status-adornment"; +import type { DataAttributes } from "../types"; import { makePrefixer, useControlled, useForkRef } from "../utils"; import multilineInputCss from "./MultilineInput.css"; @@ -51,7 +52,8 @@ export interface MultilineInputProps /** * [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#Attributes) applied to the `textarea` element. */ - textAreaProps?: TextareaHTMLAttributes; + textAreaProps?: Partial> & + DataAttributes; /** * Optional ref for the textarea component */ diff --git a/packages/core/src/pill-input/PillInput.tsx b/packages/core/src/pill-input/PillInput.tsx index 42e89c4a0d1..d2a9213935a 100644 --- a/packages/core/src/pill-input/PillInput.tsx +++ b/packages/core/src/pill-input/PillInput.tsx @@ -20,6 +20,7 @@ import { import { useFormFieldProps } from "../form-field-context"; import { Pill } from "../pill"; import { StatusAdornment } from "../status-adornment"; +import type { DataAttributes } from "../types"; import { makePrefixer, useControlled, useForkRef, useId } from "../utils"; import { useTruncatePills } from "./useTruncatePills"; @@ -45,7 +46,7 @@ export interface PillInputProps /** * [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes) applied to the `input` element. */ - inputProps?: InputHTMLAttributes; + inputProps?: Partial> & DataAttributes; /** * Optional ref for the input component */ diff --git a/packages/core/src/radio-button/RadioButton.tsx b/packages/core/src/radio-button/RadioButton.tsx index 133e121301a..7103a92e55b 100644 --- a/packages/core/src/radio-button/RadioButton.tsx +++ b/packages/core/src/radio-button/RadioButton.tsx @@ -1,3 +1,5 @@ +import { useComponentCssInjection } from "@salt-ds/styles"; +import { useWindow } from "@salt-ds/window"; import { clsx } from "clsx"; import { type ChangeEventHandler, @@ -7,14 +9,13 @@ import { type ReactNode, forwardRef, } from "react"; +import { useFormFieldProps } from "../form-field-context"; +import type { AdornmentValidationStatus } from "../status-adornment"; +import type { DataAttributes } from "../types"; import { makePrefixer, useControlled } from "../utils"; import { RadioButtonIcon } from "./RadioButtonIcon"; import { useRadioGroup } from "./internal/useRadioGroup"; -import { useComponentCssInjection } from "@salt-ds/styles"; -import { useWindow } from "@salt-ds/window"; -import { useFormFieldProps } from "../form-field-context"; -import type { AdornmentValidationStatus } from "../status-adornment"; import radioButtonCss from "./RadioButton.css"; const withBaseName = makePrefixer("saltRadioButton"); @@ -40,7 +41,7 @@ export interface RadioButtonProps /** * Props to be passed to the radio input */ - inputProps?: Partial>; + inputProps?: Partial> & DataAttributes; /** * The label to be shown next to the radio icon */ diff --git a/packages/core/src/switch/Switch.tsx b/packages/core/src/switch/Switch.tsx index 9b55e3a24f4..901deb6d68b 100644 --- a/packages/core/src/switch/Switch.tsx +++ b/packages/core/src/switch/Switch.tsx @@ -1,3 +1,8 @@ +import { + type IconProps, + SuccessSmallSolidIcon, + SuccessSolidIcon, +} from "@salt-ds/icons"; import { useComponentCssInjection } from "@salt-ds/styles"; import { useWindow } from "@salt-ds/window"; import { clsx } from "clsx"; @@ -10,13 +15,9 @@ import { } from "react"; import { useFormFieldProps } from "../form-field-context"; import { useDensity } from "../salt-provider"; +import type { DataAttributes } from "../types"; import { makePrefixer, useControlled } from "../utils"; -import { - type IconProps, - SuccessSmallSolidIcon, - SuccessSolidIcon, -} from "@salt-ds/icons"; import switchCss from "./Switch.css"; export interface SwitchProps @@ -40,7 +41,7 @@ export interface SwitchProps /** * Properties applied to the input element. */ - inputProps?: Partial>; + inputProps?: Partial> & DataAttributes; /** * The label to be shown next to the checkbox. */ diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts new file mode 100644 index 00000000000..bd9b3852e46 --- /dev/null +++ b/packages/core/src/types.ts @@ -0,0 +1,8 @@ +/** + * Support data-* attributes for pass through props, e.g. `Input.inputProps`. + * + * https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-%2A + */ +export type DataAttributes = { + [dataAttribute: `data-${string}`]: string; +};