From bb41157b6ff2c9561e71bb9fb8a57d3207a722f0 Mon Sep 17 00:00:00 2001 From: lilyvc <45168453+lilyvc@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:48:32 +0000 Subject: [PATCH] Checkbox and Radio Button Icon Alignment (#2694) Co-authored-by: Josh Wooding <12938082+joshwooding@users.noreply.github.com> --- .changeset/ten-mayflies-grow.md | 6 ++ packages/core/src/checkbox/Checkbox.css | 7 +- packages/core/src/checkbox/CheckboxGroup.css | 6 ++ .../core/src/radio-button/RadioButton.css | 10 +- .../src/radio-button/RadioButtonGroup.css | 6 ++ .../stories/checkbox/checkbox.qa.stories.tsx | 26 ++++- .../stories/form-field/form-field.stories.tsx | 97 +++++++++++++++++++ .../radio-button/radio-button.qa.stories.tsx | 18 ++++ 8 files changed, 170 insertions(+), 6 deletions(-) create mode 100644 .changeset/ten-mayflies-grow.md diff --git a/.changeset/ten-mayflies-grow.md b/.changeset/ten-mayflies-grow.md new file mode 100644 index 00000000000..bb62434ed45 --- /dev/null +++ b/.changeset/ten-mayflies-grow.md @@ -0,0 +1,6 @@ +--- +"@salt-ds/core": patch +--- + +Fixed alignment for Checkbox and Radio Button. They are now correctly aligned to their labels. +Fixed alignment for Checkbox Group and Radio Button Group when in a Form Field with label left. The Form Field label is now inline with the groups. diff --git a/packages/core/src/checkbox/Checkbox.css b/packages/core/src/checkbox/Checkbox.css index c664524b6ff..1f19b1536e7 100644 --- a/packages/core/src/checkbox/Checkbox.css +++ b/packages/core/src/checkbox/Checkbox.css @@ -23,6 +23,11 @@ cursor: var(--salt-selectable-cursor-readonly); } +.saltCheckbox-input, +.saltCheckboxIcon { + margin-top: calc((var(--salt-text-lineHeight) - var(--salt-size-selectable)) / 2); +} + .saltCheckboxIcon > svg { /* ensures svg is centered in all browsers */ transform: translate(0px, 0px); @@ -55,11 +60,9 @@ /* Styles applied to input element */ .saltCheckbox-input { cursor: inherit; - left: 0; margin: 0; opacity: 0; padding: 0; position: absolute; - top: 0; z-index: var(--salt-zIndex-default); } diff --git a/packages/core/src/checkbox/CheckboxGroup.css b/packages/core/src/checkbox/CheckboxGroup.css index 76c59ae7469..380252ab77d 100644 --- a/packages/core/src/checkbox/CheckboxGroup.css +++ b/packages/core/src/checkbox/CheckboxGroup.css @@ -27,3 +27,9 @@ .saltCheckboxGroup-noWrap .saltCheckbox { white-space: break-spaces; } + +/* Styles applied when checkbox button group is inside a form field with label left or right */ +.saltFormField-labelLeft .saltCheckboxGroup, +.saltFormField-labelRight .saltCheckboxGroup { + padding-top: var(--salt-spacing-100); +} diff --git a/packages/core/src/radio-button/RadioButton.css b/packages/core/src/radio-button/RadioButton.css index 68c65eedc71..7881805a4cf 100644 --- a/packages/core/src/radio-button/RadioButton.css +++ b/packages/core/src/radio-button/RadioButton.css @@ -9,6 +9,8 @@ line-height: var(--salt-text-lineHeight); font-family: var(--salt-text-fontFamily); font-weight: var(--salt-text-fontWeight); + + --radioButton-icon-marginTop: calc((var(--salt-text-lineHeight) - var(--salt-size-selectable)) / 2); } /* Styles applied when RadioButton is disabled */ @@ -29,14 +31,16 @@ position: absolute; height: var(--salt-size-selectable); opacity: 0; - top: 0; - left: 0; - margin: 0; + margin: var(--radioButton-icon-marginTop) 0 0 0; padding: 0; width: var(--salt-size-selectable); z-index: var(--salt-zIndex-default); } +.saltRadioButtonIcon { + margin-top: var(--radioButton-icon-marginTop); +} + .saltRadioButtonIcon > svg { /* ensures svg is centered in all browsers */ transform: translate(0px, 0px); diff --git a/packages/core/src/radio-button/RadioButtonGroup.css b/packages/core/src/radio-button/RadioButtonGroup.css index 21725f2b07b..ad03c9f3b62 100644 --- a/packages/core/src/radio-button/RadioButtonGroup.css +++ b/packages/core/src/radio-button/RadioButtonGroup.css @@ -26,3 +26,9 @@ .saltRadioButtonGroup-noWrap .saltRadioButton { white-space: break-spaces; } + +/* Styles applied when radio button group is inside a form field with label left or right */ +.saltFormField-labelLeft .saltRadioButtonGroup, +.saltFormField-labelRight .saltRadioButtonGroup { + padding-top: var(--salt-spacing-100); +} diff --git a/packages/core/stories/checkbox/checkbox.qa.stories.tsx b/packages/core/stories/checkbox/checkbox.qa.stories.tsx index 571dd91a924..5b0bb476fba 100644 --- a/packages/core/stories/checkbox/checkbox.qa.stories.tsx +++ b/packages/core/stories/checkbox/checkbox.qa.stories.tsx @@ -1,5 +1,12 @@ import { Meta, StoryFn } from "@storybook/react"; -import { Checkbox, CheckboxGroup, CheckboxGroupProps } from "@salt-ds/core"; +import { + Checkbox, + CheckboxGroup, + CheckboxGroupProps, + FormField, + FormFieldLabel, + FormFieldHelperText, +} from "@salt-ds/core"; import { QAContainer, QAContainerProps } from "docs/components"; export default { @@ -38,11 +45,28 @@ const CheckboxGroupExample = ({ ); }; +const CheckboxInFormFieldExample = () => { + return ( + + Assignment + + + + + + + + Select all appropriate + + ); +}; + export const AllExamplesGrid: StoryFn = (props) => { return ( + ); }; diff --git a/packages/core/stories/form-field/form-field.stories.tsx b/packages/core/stories/form-field/form-field.stories.tsx index 48bbedbaffe..8eb07687725 100644 --- a/packages/core/stories/form-field/form-field.stories.tsx +++ b/packages/core/stories/form-field/form-field.stories.tsx @@ -135,6 +135,103 @@ export const LabelLeft: StoryFn = (props) => { ); }; +export const LabelLeftWithControls: StoryFn = (props) => { + const [isRadioError, setIsRadioError] = useState(true); + + const [radioGroupValue, setRadioGroupValue] = useState(""); + const [checkboxGroupValue, setCheckboxGroupValue] = useState([]); + + const handleRadioChange: ChangeEventHandler = (event) => { + const { value } = event.target; + setRadioGroupValue(value); + props.onChange?.(event); + isRadioError && setIsRadioError(false); + }; + + const handleCheckboxChange: ChangeEventHandler = ( + event + ) => { + const { value } = event.target; + if (checkboxGroupValue.indexOf(value) === -1) { + setCheckboxGroupValue((prevControlledValues) => [ + ...prevControlledValues, + value, + ]); + } else { + setCheckboxGroupValue((prevControlledValues) => + prevControlledValues.filter( + (controlledValue) => controlledValue !== value + ) + ); + } + props.onChange?.(event); + }; + + const isCheckboxError = checkboxGroupValue.length === 0; + + return ( + + + Client directed request + + + + + + + Assignment + + + + + + + + Select all appropriate + + + Deal owner + + {radioData.map((radio) => { + return ( + + ); + })} + + {`${ + isRadioError ? "Must select one option. " : "" + }Is this deal for the ultimate parent or a subsidiary?`} + + + Fee type + + {checkboxesData.map((data) => ( + + ))} + + {`${ + isCheckboxError ? "Must select at least one option. " : "" + }`} + + + ); +}; + export const LabelQuestion: StoryFn = (props) => { return ( diff --git a/packages/core/stories/radio-button/radio-button.qa.stories.tsx b/packages/core/stories/radio-button/radio-button.qa.stories.tsx index 533e9fa4cbd..73cfade3c39 100644 --- a/packages/core/stories/radio-button/radio-button.qa.stories.tsx +++ b/packages/core/stories/radio-button/radio-button.qa.stories.tsx @@ -1,4 +1,6 @@ import { + FormField, + FormFieldLabel, RadioButton, RadioButtonGroup, RadioButtonGroupProps, @@ -38,11 +40,27 @@ const RadioButtonGroupExample = ({ ); }; +const RadioButtonInFormFieldExample = () => { + return ( + + Assignment + + + + + + + + + ); +}; + export const AllExamplesGrid: StoryFn = (props) => { return ( + ); };