Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SWED-2336 radio buttons UI #975

Merged
merged 11 commits into from
Apr 24, 2024
8 changes: 8 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

- labels line-height increased & mobile values adjusted, so values are in sync with `h4` typography style

- Radio inputs

- minor non-breaking UI change to the default input radio
- minor UI changes to checkmark variant
- some non-breaking UI changes (colors, width, ...)
- Now the checkmark icon is achieved via span.checkmark-icon instead of an actual icon element loading an svg.
- It is now possible to add a subtext inside the checkmark variant (use span.subtext)

- Buttons
- minor non-breaking UI updates (height for size large, unify hover state, modify active & focus-visible UI, and more)
- add Danish MitId button style (you can use either `i.bank-id-dk` OR `i.mitid-dk`, both are supported)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ exports[`Component: RadioButton DeveloperDocumentation renders 1`] = `
className="d-flex justify-content-center"
>
<div
className="radio"
className="radio "
>


Expand Down Expand Up @@ -229,7 +229,7 @@ exports[`Component: RadioButton DeveloperDocumentation renders 1`] = `
className="code-view-code"
>
<pre>
&lt;div class="radio"&gt;
&lt;div class="radio "&gt;


&lt;input type="radio" id="radio-example-10" name="radio-example" disabled checked&gt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const options = [
},
{
id: "radio-example-2",
label: "Label",
label: "Longer label",
},
];

Expand All @@ -18,7 +18,7 @@ export const radiobuttonShowCase = {
tabsId: "radioShowcaseTabs",
elements: [
{
tab: "Primary",
tab: "Default",
component: (
<Radio
groupTitle="Group legend"
Expand Down Expand Up @@ -98,6 +98,14 @@ export const radiobuttonShowCase = {
hintTextId: "hint-text-radio-example",
},
},
{
id: "label_subtext",
name: "Label subtext",
value: {
hasLabelSubtext: true,
size: "large",
},
},
],
},
],
Expand Down Expand Up @@ -126,6 +134,24 @@ export const radiobuttonShowCase = {
},
],
},
{
id: "size_radio",
title: "Size modifiers",
values: [
{
name: "Small",
value: {
size: "small",
},
},
{
name: "Large",
value: {
size: "large",
},
},
],
},
],
},
title: "Checkmark buttons",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// @ts-check
const { test, expect } = require("@playwright/test");

/**
*
* @param {import("@playwright/test").Page} page
* @returns boolean
*/
const checkIfOptionsDisplayed = async (page) =>
await (
await page.locator(".showcase-panel-advanced").getAttribute("class")
).includes("options-active");

const openOptions = async (page) => {
const areOptionsDisplayed = await checkIfOptionsDisplayed(page);

if (!areOptionsDisplayed) {
await page.getByRole("button", { name: "Open options menu" }).click();
}
};

const closeOptions = async (page) => {
const areOptionsDisplayed = await checkIfOptionsDisplayed(page);

if (areOptionsDisplayed) {
await page.getByRole("button", { name: "Close options menu" }).click();
}
};

test("Radio buttons page exist", async ({ page }) => {
await page.goto("http://localhost:3000/");
await page
.getByRole("link", {
name: "Components Find all currently available components here",
})
.click();
await expect(page.getByRole("link", { name: "Radio button" })).toHaveCount(
page.viewportSize().width < 991 ? 1 : 2,
);
await page
.getByLabel("components overview")
.getByRole("link", { name: "Radio button" })
.click();
await expect(page).toHaveTitle(/Radio button/);
await expect(
page.getByRole("heading", { name: "Radio button", exact: true, level: 1 }),
).toBeVisible();
});
test.describe(`radio button visual regressions`, () => {
/**
* @type string
*/
let brand;
/**
* @type {import("@playwright/test").Locator}
*/
let previewContainer;

test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:3000/components/radio-button");

brand = (await page.title()).includes("Swedbank") ? "SwedbankPay" : "PayEx";
previewContainer = await page.locator(".component-preview-content > form");
});

// radio input default
test(`visual regresion radio input default`, async ({ page }) => {
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-default.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).hover();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-default-hovered.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).click();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-default-checked-changed.png`,
);
});
// radio input - checkmark - small
test(`visual regresion radio input checkmark small`, async ({ page }) => {
page.getByRole("link", { name: "Checkmark" }).click();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-small.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).hover();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-small-hovered.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).click();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-small-checked-changed.png`,
);
});
// radio input - checkmark - large
test(`visual regresion radio input checkmark large`, async ({ page }) => {
page.getByRole("link", { name: "Checkmark" }).click();

await openOptions(page);
await page.getByLabel("Large").click({ force: true });
await closeOptions(page);

await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-large.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).hover();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-large-hovered.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).click();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-large-checked-changed.png`,
);
});
// radio input - checkmark - subtext
test(`visual regresion radio input checkmark with subtext`, async ({
page,
}) => {
page.getByRole("link", { name: "Checkmark" }).click();

await openOptions(page);
await page.getByLabel("Label subtext").click({ force: true });
await closeOptions(page);

await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-subtext.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).hover();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-subtext-hovered.png`,
);
await previewContainer.getByText("Longer label", { exact: true }).click();
await expect(previewContainer).toHaveScreenshot(
`${brand}-radio-input-checkmark-subtext-checked-changed.png`,
);
});
});

test.describe(`radio input options behave correctly`, () => {
// TODO:
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ exports[`Forms: index renders 1`] = `
Don't
</span>
<div
className="radio"
className="radio "
>


Expand Down Expand Up @@ -1151,7 +1151,7 @@ exports[`Forms: index renders 1`] = `
</div>
</div>
<div
className="radio"
className="radio "
>


Expand Down
35 changes: 26 additions & 9 deletions src/App/components/FormComponents/Radio.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const Radio = ({
style,
helpBlock,
errorMessage,
size = "small",
hasLabelSubtext = false,
}) => {
const attrs = {
type: "radio",
Expand Down Expand Up @@ -42,18 +44,29 @@ const Radio = ({
{style === "checkmark" ? (
<div className="radio-row">
{options.map(({ label, id, checked }, i) => (
<div className={`radio${style ? ` ${style}` : ""}`} key={i}>
<div
className={`radio${style ? ` ${style}` : ""} ${size === "large" ? "large" : ""}`}
key={i}
>
{"\n"}
<input {...attrs} id={id} defaultChecked={checked} />
{"\n"}
<label htmlFor={id}>
{style === "checkmark" && (
<i
className="swepay-icon-check-circle-filled-customizable bg-blend-exclusion small"
aria-hidden="true"
></i>
)}{" "}
{label}
{!hasLabelSubtext ? (
<>
{"\n"}
{label}
</>
) : (
<>
<span>{label}</span>
{"\n"}
<span className="subtext">100 kr extra/mån</span>
</>
)}
{"\n"}
<span className="checkmark-icon"></span>
{"\n"}
</label>
{"\n"}
</div>
Expand Down Expand Up @@ -97,7 +110,9 @@ const Radio = ({
</form>
) : (
<>
<div className={`radio${style ? ` ${style}` : ""}`}>
<div
className={`radio${style ? ` ${style}` : ""} ${size === "large" ? "large" : ""}`}
>
{"\n"}
<input {...attrs} />
{"\n"}
Expand Down Expand Up @@ -130,6 +145,8 @@ Radio.propTypes = {
className: PropTypes.string,
style: PropTypes.string,
helpBlock: PropTypes.string,
size: PropTypes.oneOf(["small", "large"]),
hasLabelSubtext: PropTypes.bool,
};

export default Radio;
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ exports[`Component: Radio - renders checkbox group with groupTitle 1`] = `

exports[`Component: Radio - renders checked 1`] = `
<div
className="radio"
className="radio "
>


Expand All @@ -140,7 +140,7 @@ exports[`Component: Radio - renders checked 1`] = `

exports[`Component: Radio - renders disabled 1`] = `
<div
className="radio"
className="radio "
>


Expand Down Expand Up @@ -217,7 +217,7 @@ exports[`Component: Radio - renders radio group 1`] = `

exports[`Component: Radio - renders with id and label 1`] = `
<div
className="radio"
className="radio "
>


Expand All @@ -244,7 +244,7 @@ exports[`Component: Radio - renders with id and label 1`] = `

exports[`Component: Radio - renders with name 1`] = `
<div
className="radio"
className="radio "
>


Expand All @@ -263,7 +263,7 @@ exports[`Component: Radio - renders with name 1`] = `

exports[`Component: Radio - renders without label 1`] = `
<div
className="radio"
className="radio "
>


Expand Down
Loading
Loading