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 (
+
);
};