From 71f888c964f14b3e3cd4639a684f9cc57055f572 Mon Sep 17 00:00:00 2001 From: zecuria Date: Thu, 21 Oct 2021 14:18:54 +1100 Subject: [PATCH] Added data prop to Text, Input and Frequency (#270) --- package-lock.json | 2 +- src/components/Frequency.js | 7 +++++-- src/components/Frequency.test.js | 16 ++++++++++++++++ src/components/Input.js | 7 +++++-- src/components/Input.test.js | 13 +++++++++++++ src/components/Text.js | 24 ++++++++++++++++++++++-- src/components/Text.test.js | 12 ++++++++++++ src/components/internal/InternalInput.js | 6 ++++++ src/utils/getDataAttributes.js | 4 ++++ 9 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 src/utils/getDataAttributes.js diff --git a/package-lock.json b/package-lock.json index 2bdad6b4..44f27296 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "basis", - "version": "1.69.3", + "version": "1.70.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/components/Frequency.js b/src/components/Frequency.js index 069a130d..9d0acbcb 100644 --- a/src/components/Frequency.js +++ b/src/components/Frequency.js @@ -100,6 +100,7 @@ function Frequency(props) { name, mode, label, + data, annually, quarterly, monthly, @@ -154,7 +155,7 @@ function Frequency(props) { }, [isInputEmpty, isFrequencyEmpty] ); - const data = useMemo( + const validationData = useMemo( () => ({ isInputEmpty, isFrequencyEmpty, @@ -176,13 +177,14 @@ function Frequency(props) { disabled, optional, validate, - data, + data: validationData, }); const inputComponent = ( { }); }); + it("with data attributes", () => { + render( + + ); + + const amountInput = screen.getByPlaceholderText("0.00"); + + expect(amountInput).toHaveAttribute("data-some-id", "true"); + + expect(amountInput).toHaveAttribute("data-other-id", "other-value"); + }); + it("with testId", () => { const { container } = render( diff --git a/src/components/Input.js b/src/components/Input.js index 86e1f5c2..d80375c9 100644 --- a/src/components/Input.js +++ b/src/components/Input.js @@ -60,6 +60,7 @@ function Input(props) { name, type, variant, + data = {}, prefix, suffix, maxLength, @@ -79,7 +80,7 @@ function Input(props) { const [inputId] = useState(() => `input-${nanoid()}`); const [auxId] = useState(() => `input-aux-${nanoid()}`); const isEmpty = useCallback((value) => value.trim() === "", []); - const data = useMemo( + const validationData = useMemo( () => ({ isEmpty, variant, @@ -99,7 +100,7 @@ function Input(props) { disabled, optional, validate, - data, + data: validationData, }); const onChange = useCallback( (event) => { @@ -124,6 +125,7 @@ function Input(props) { id={label ? inputId : null} name={name} type={type} + data={data} variant={variant} prefix={prefix} suffix={suffix} @@ -149,6 +151,7 @@ Input.propTypes = { name: PropTypes.string.isRequired, type: PropTypes.oneOf(TYPES), variant: PropTypes.oneOf(VARIANTS), + data: PropTypes.object, prefix: PropTypes.string, suffix: PropTypes.string, maxLength: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), diff --git a/src/components/Input.test.js b/src/components/Input.test.js index fd1f3c9d..cc83af5f 100644 --- a/src/components/Input.test.js +++ b/src/components/Input.test.js @@ -269,6 +269,19 @@ describe("Input", () => { }); }); + it("with data attributes", () => { + render( + + ); + + const input = screen.getByLabelText("First name"); + expect(input).toHaveAttribute("data-some-id", "false"); + expect(input).toHaveAttribute("data-other-id", "other-value"); + }); + it("with testId", () => { const { container } = render( diff --git a/src/components/Text.js b/src/components/Text.js index b6d45eb1..c1b2a001 100644 --- a/src/components/Text.js +++ b/src/components/Text.js @@ -12,6 +12,7 @@ import { mergeProps } from "../utils/component"; import { hasOwnProperty } from "../utils/core"; import { TEXT_STYLES, TEXT_ALIGNS } from "../utils/constants"; import { formatArray } from "../utils/array"; +import { getDataAttributes } from "../utils/getDataAttributes"; const AS = ["h1", "h2", "h3", "h4", "h5", "h6", "p"]; const COLORS = [ @@ -95,7 +96,16 @@ function Text(props) { align: (align) => ALIGNS.includes(align), wrap: (wrap) => typeof wrap === "boolean", }); - const { id, as, align, wrap, role, children, testId } = mergedProps; + const { + id, + as, + align, + wrap, + role, + children, + testId, + data = {}, + } = mergedProps; const css = useResponsivePropsCSS(mergedProps, DEFAULT_PROPS, { color: (_, theme, bp) => { const color = @@ -112,10 +122,19 @@ function Text(props) { margin: responsiveMargin, textStyle: responsiveTextStyle, }); + + const dataAttrs = getDataAttributes(data); + const Component = as; return ( - + {children} ); @@ -140,6 +159,7 @@ Text.propTypes = { } }); }, + data: PropTypes.object, align: PropTypes.oneOf(ALIGNS), wrap: PropTypes.bool, role: PropTypes.string, diff --git a/src/components/Text.test.js b/src/components/Text.test.js index 01f4019e..801a363c 100644 --- a/src/components/Text.test.js +++ b/src/components/Text.test.js @@ -157,6 +157,18 @@ describe("Text", () => { expect(node).toHaveAttribute("role", "alert"); }); + it("with dataAttributes", () => { + render( + + Hello World + + ); + + const node = screen.getByText("Hello World"); + expect(node).toHaveAttribute("data-some-id", "false"); + expect(node).toHaveAttribute("data-other-id", "other-value"); + }); + it("with testId", () => { const { container } = render(Hello World); diff --git a/src/components/internal/InternalInput.js b/src/components/internal/InternalInput.js index a1fe2c81..5720cb30 100644 --- a/src/components/internal/InternalInput.js +++ b/src/components/internal/InternalInput.js @@ -4,6 +4,7 @@ import useTheme from "../../hooks/useTheme"; import useBackground from "../../hooks/useBackground"; import useResponsivePropsCSS from "../../hooks/useResponsivePropsCSS"; import { mergeProps } from "../../utils/component"; +import { getDataAttributes } from "../../utils/getDataAttributes"; const TYPES = ["text", "password", "email", "tel"]; const VARIANTS = ["text", "numeric", "decimal"]; @@ -52,6 +53,7 @@ function InternalInput(props) { name, parentName, id, + data = {}, type, placeholder, variant, @@ -94,6 +96,8 @@ function InternalInput(props) { }, [pasteAllowed] ); + const dataAttrs = getDataAttributes(data); + const variantProps = variant === "numeric" ? { @@ -120,6 +124,7 @@ function InternalInput(props) { css={inputCSS} id={id} name={name} + {...dataAttrs} data-parent-name={parentName} aria-label={ariaLabel} placeholder={placeholder} @@ -155,6 +160,7 @@ InternalInput.propTypes = { suffix: PropTypes.string, maxLength: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), autoComplete: PropTypes.string, + data: PropTypes.object, color: PropTypes.oneOf(COLORS), disabled: PropTypes.bool, pasteAllowed: PropTypes.bool, diff --git a/src/utils/getDataAttributes.js b/src/utils/getDataAttributes.js new file mode 100644 index 00000000..ad85126c --- /dev/null +++ b/src/utils/getDataAttributes.js @@ -0,0 +1,4 @@ +export const getDataAttributes = (data) => + Object.fromEntries( + Object.entries(data).map(([key, value]) => [`data-${key}`, value]) + );