From 9e71786d8406265c74793914c0ec85aaa6d908e0 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 12:44:51 +0700 Subject: [PATCH 01/14] [BOOKINGSG-9221][GZ] rename style filename --- .../{radio-button.styles.tsx => radio-button.styles.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/radio-button/{radio-button.styles.tsx => radio-button.styles.ts} (100%) diff --git a/src/radio-button/radio-button.styles.tsx b/src/radio-button/radio-button.styles.ts similarity index 100% rename from src/radio-button/radio-button.styles.tsx rename to src/radio-button/radio-button.styles.ts From 06d233a6e91e68cf74998d51efd2681c1df5e10f Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 12:46:20 +0700 Subject: [PATCH 02/14] [BOOKINGSG-9221][GZ] migrate tokens --- src/radio-button/radio-button.styles.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index 6cf39e73b..f45d93411 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -1,7 +1,7 @@ import { CircleDotIcon, CircleIcon } from "@lifesg/react-icons"; import styled, { css } from "styled-components"; -import { V3_Colour, V3_Motion } from "../v3_theme"; +import { Colour, Motion } from "../theme"; import type { RadioButtonSize } from "./types"; // ============================================================================= @@ -47,9 +47,9 @@ export const StyledUnCheckedIcon = styled(CircleIcon)` width: 100%; color: ${(props) => props.$disabled - ? V3_Colour["icon-disabled-subtle"](props) - : V3_Colour["icon-subtle"](props)}; - transition: ${V3_Motion["duration-150"]} ${V3_Motion["ease-default"]}; + ? Colour["icon-disabled-subtle"] + : Colour["icon-subtle"]}; + transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; `; export const StyledCheckedIcon = styled(CircleDotIcon)` @@ -57,10 +57,10 @@ export const StyledCheckedIcon = styled(CircleDotIcon)` width: 100%; color: ${(props) => props.$disabled - ? V3_Colour["icon-selected-disabled"](props) - : V3_Colour["icon-selected"](props)}; + ? Colour["icon-selected-disabled"] + : Colour["icon-selected"]}; - transition: ${V3_Motion["duration-150"]} ${V3_Motion["ease-default"]}; + transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; `; export const Input = styled.input` @@ -76,8 +76,7 @@ export const Input = styled.input` &:hover + ${StyledUnCheckedIcon}, &:hover + ${StyledCheckedIcon} { @media (pointer: fine) { - color: ${(props) => - !props.$disabledVisual && V3_Colour["icon-hover"](props)}; + color: ${(props) => !props.$disabledVisual && Colour["icon-hover"]}; } } `; From 0e7aad42b879c57587d6d3d2e3bee247b9a9ca6a Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 13:08:41 +0700 Subject: [PATCH 03/14] [BOOKINGSG-9221][GZ] convert styled interpolation to semantic data attributes --- src/radio-button/radio-button.styles.ts | 80 ++++++++++--------------- src/radio-button/radio-button.tsx | 16 ++--- 2 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index f45d93411..d7f3561f1 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -1,82 +1,66 @@ import { CircleDotIcon, CircleIcon } from "@lifesg/react-icons"; -import styled, { css } from "styled-components"; +import styled from "styled-components"; import { Colour, Motion } from "../theme"; -import type { RadioButtonSize } from "./types"; -// ============================================================================= -// STYLE INTERFACE, transient props are denoted with $ -// See more https://styled-components.com/docs/api#transient-props -// ============================================================================= -interface StyleProps { - $selected?: boolean; - $disabled?: boolean; - $displaySize?: RadioButtonSize | undefined; -} - -interface InputStyleProps { - $disabledVisual?: boolean | undefined; -} - -// ============================================================================= -// STYLING -// ============================================================================= - -export const Container = styled.div` +export const Container = styled.div` display: flex; justify-content: center; align-items: center; - ${(props) => { - if (props.$displaySize === "small") { - return css` - height: 1.5rem; - width: 1.5rem; - `; - } else { - return css` - height: 2rem; - width: 2rem; - `; - } - }} position: relative; + + &[data-display-size="small"] { + height: 1.5rem; + width: 1.5rem; + } + + &[data-display-size="default"] { + height: 2rem; + width: 2rem; + } `; -export const StyledUnCheckedIcon = styled(CircleIcon)` +export const StyledUnCheckedIcon = styled(CircleIcon)` height: 100%; width: 100%; - color: ${(props) => - props.$disabled - ? Colour["icon-disabled-subtle"] - : Colour["icon-subtle"]}; + color: ${Colour["icon-subtle"]}; transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; + + &[data-disabled="true"] { + color: ${Colour["icon-disabled-subtle"]}; + } `; -export const StyledCheckedIcon = styled(CircleDotIcon)` +export const StyledCheckedIcon = styled(CircleDotIcon)` height: 100%; width: 100%; - color: ${(props) => - props.$disabled - ? Colour["icon-selected-disabled"] - : Colour["icon-selected"]}; + color: ${Colour["icon-selected"]}; transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; + + &[data-disabled="true"] { + color: ${Colour["icon-selected-disabled"]}; + } `; -export const Input = styled.input` +export const Input = styled.input` position: absolute; height: 100%; width: 100%; - cursor: ${(props) => (props.$disabledVisual ? "not-allowed" : "pointer")}; + cursor: pointer; z-index: 1; appearance: none; background: transparent; border: none; - &:hover + ${StyledUnCheckedIcon}, &:hover + ${StyledCheckedIcon} { + &[data-disabled-visual="true"] { + cursor: not-allowed; + } + + &:not([data-disabled-visual="true"]):hover + [data-radio-icon] { @media (pointer: fine) { - color: ${(props) => !props.$disabledVisual && Colour["icon-hover"]}; + color: ${Colour["icon-hover"]}; } } `; diff --git a/src/radio-button/radio-button.tsx b/src/radio-button/radio-button.tsx index af842992c..1d61d59dd 100644 --- a/src/radio-button/radio-button.tsx +++ b/src/radio-button/radio-button.tsx @@ -1,4 +1,4 @@ -import type React from "react"; +import type { ChangeEvent } from "react"; import { Container, @@ -27,7 +27,7 @@ export const RadioButton = ({ // ============================================================================= // EVENT HANDLERS // ============================================================================= - const handleOnChange = (event: React.ChangeEvent) => { + const handleOnChange = (event: ChangeEvent) => { if (disabled) { event.preventDefault(); return; @@ -43,13 +43,15 @@ export const RadioButton = ({ return checked ? ( ) : ( ); @@ -57,10 +59,8 @@ export const RadioButton = ({ return ( {renderIcon()} From c6a9755a239863fefb901998abe58a2e66abd969 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 13:10:57 +0700 Subject: [PATCH 04/14] [BOOKINGSG-9221][GZ] convert styled comopnents to linaria css --- src/radio-button/radio-button.styles.ts | 11 +++++------ src/radio-button/radio-button.tsx | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index d7f3561f1..3ae110537 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -1,9 +1,8 @@ -import { CircleDotIcon, CircleIcon } from "@lifesg/react-icons"; -import styled from "styled-components"; +import { css } from "@linaria/core"; import { Colour, Motion } from "../theme"; -export const Container = styled.div` +export const container = css` display: flex; justify-content: center; align-items: center; @@ -20,7 +19,7 @@ export const Container = styled.div` } `; -export const StyledUnCheckedIcon = styled(CircleIcon)` +export const uncheckedIcon = css` height: 100%; width: 100%; color: ${Colour["icon-subtle"]}; @@ -31,7 +30,7 @@ export const StyledUnCheckedIcon = styled(CircleIcon)` } `; -export const StyledCheckedIcon = styled(CircleDotIcon)` +export const checkedIcon = css` height: 100%; width: 100%; color: ${Colour["icon-selected"]}; @@ -43,7 +42,7 @@ export const StyledCheckedIcon = styled(CircleDotIcon)` } `; -export const Input = styled.input` +export const input = css` position: absolute; height: 100%; width: 100%; diff --git a/src/radio-button/radio-button.tsx b/src/radio-button/radio-button.tsx index 1d61d59dd..068bc830d 100644 --- a/src/radio-button/radio-button.tsx +++ b/src/radio-button/radio-button.tsx @@ -1,11 +1,8 @@ +import { CircleDotIcon, CircleIcon } from "@lifesg/react-icons"; +import clsx from "clsx"; import type { ChangeEvent } from "react"; -import { - Container, - Input, - StyledCheckedIcon, - StyledUnCheckedIcon, -} from "./radio-button.styles"; +import * as styles from "./radio-button.styles"; import type { RadioButtonProps } from "./types"; export const RadioButton = ({ @@ -41,29 +38,31 @@ export const RadioButton = ({ // ============================================================================= const renderIcon = () => { return checked ? ( - ) : ( - ); }; return ( - - {renderIcon()} - + ); }; From 96b57d24313aaa89909d1f5e576ceb10127994e1 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 13:16:53 +0700 Subject: [PATCH 05/14] [BOOKINGSG-9221][GZ] add unit test --- tests/radio-button/radio-button.spec.tsx | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/radio-button/radio-button.spec.tsx diff --git a/tests/radio-button/radio-button.spec.tsx b/tests/radio-button/radio-button.spec.tsx new file mode 100644 index 000000000..47bf6353b --- /dev/null +++ b/tests/radio-button/radio-button.spec.tsx @@ -0,0 +1,37 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { RadioButton } from "src/radio-button"; + +describe("RadioButton", () => { + it("should fire onChange when enabled", () => { + const onChange = jest.fn(); + render(); + + fireEvent.click(screen.getByTestId("radio-input")); + + expect(onChange).toHaveBeenCalledTimes(1); + }); + + it("should not fire onChange when disabled", () => { + const onChange = jest.fn(); + render(); + + fireEvent.click(screen.getByTestId("radio-input")); + + expect(onChange).not.toHaveBeenCalled(); + }); + + it("should remain focusable when disabled and focusableWhenDisabled is true", () => { + const onChange = jest.fn(); + render( + + ); + + const input = screen.getByTestId("radio-input"); + fireEvent.click(input); + + expect(input).not.toBeDisabled(); + expect(input).toHaveAttribute("aria-disabled", "true"); + expect(input).toHaveAttribute("tabIndex", "0"); + expect(onChange).not.toHaveBeenCalled(); + }); +}); From f40c6695cbfbcb99ad6a9fb2a9f6a958e605fbbe Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 15:36:04 +0700 Subject: [PATCH 06/14] [BOOKINGSG-9221][GZ] cleanup selectors --- src/radio-button/radio-button.styles.ts | 14 ++++++++++---- src/radio-button/radio-button.tsx | 22 ++++++++++++++-------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index 3ae110537..c056efc5b 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -2,6 +2,12 @@ import { css } from "@linaria/core"; import { Colour, Motion } from "../theme"; +export const classes = { + icon: "radioButtonIcon", + iconDisabled: "radioButtonIconDisabled", + inputDisabledVisual: "radioButtonInputDisabledVisual", +} as const; + export const container = css` display: flex; justify-content: center; @@ -25,7 +31,7 @@ export const uncheckedIcon = css` color: ${Colour["icon-subtle"]}; transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; - &[data-disabled="true"] { + &.${classes.iconDisabled} { color: ${Colour["icon-disabled-subtle"]}; } `; @@ -37,7 +43,7 @@ export const checkedIcon = css` transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; - &[data-disabled="true"] { + &.${classes.iconDisabled} { color: ${Colour["icon-selected-disabled"]}; } `; @@ -53,11 +59,11 @@ export const input = css` background: transparent; border: none; - &[data-disabled-visual="true"] { + &.${classes.inputDisabledVisual} { cursor: not-allowed; } - &:not([data-disabled-visual="true"]):hover + [data-radio-icon] { + &:not(.${classes.inputDisabledVisual}):hover + .${classes.icon} { @media (pointer: fine) { color: ${Colour["icon-hover"]}; } diff --git a/src/radio-button/radio-button.tsx b/src/radio-button/radio-button.tsx index 068bc830d..637a18ae2 100644 --- a/src/radio-button/radio-button.tsx +++ b/src/radio-button/radio-button.tsx @@ -40,17 +40,21 @@ export const RadioButton = ({ return checked ? ( ) : ( ); @@ -70,8 +74,10 @@ export const RadioButton = ({ disabled={isNativeDisabled} aria-disabled={isFocusableWhenDisabled} tabIndex={isFocusableWhenDisabled ? 0 : tabIndex} - data-disabled-visual={disabled ? "true" : "false"} - className={styles.input} + className={clsx( + styles.input, + disabled && styles.classes.inputDisabledVisual + )} {...otherProps} /> {renderIcon()} From 828b76e4cf6e6ac02d4e1e7d04e92c7bb3970eb9 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Thu, 16 Apr 2026 15:59:04 +0700 Subject: [PATCH 07/14] [BOOKINGSG-9221][GZ] add visual test --- .../focusable-when-disabled.e2e.tsx | 23 +++ .../radio-button/keyboard-navigation.e2e.tsx | 25 +++ .../components/radio-button/variants.e2e.tsx | 46 +++++ .../RadioButton-Variants--hover-disabled.png | Bin 0 -> 1111 bytes .../RadioButton-Variants--hover-enabled.png | Bin 0 -> 1226 bytes .../chromium/RadioButton-Variants--mount.png | Bin 0 -> 5048 bytes .../radio-button/radio-button.e2e.spec.ts | 168 ++++++++++++++++++ 7 files changed, 262 insertions(+) create mode 100644 e2e/nextjs-app/src/app/components/radio-button/focusable-when-disabled.e2e.tsx create mode 100644 e2e/nextjs-app/src/app/components/radio-button/keyboard-navigation.e2e.tsx create mode 100644 e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx create mode 100644 e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-disabled.png create mode 100644 e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-enabled.png create mode 100644 e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--mount.png create mode 100644 e2e/tests/components/radio-button/radio-button.e2e.spec.ts diff --git a/e2e/nextjs-app/src/app/components/radio-button/focusable-when-disabled.e2e.tsx b/e2e/nextjs-app/src/app/components/radio-button/focusable-when-disabled.e2e.tsx new file mode 100644 index 000000000..b401d41d0 --- /dev/null +++ b/e2e/nextjs-app/src/app/components/radio-button/focusable-when-disabled.e2e.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { RadioButton } from "@lifesg/react-design-system/radio-button"; +import { useState } from "react"; + +export default function Story() { + const [changeCount, setChangeCount] = useState(0); + + return ( +
+ + + setChangeCount((value) => value + 1)} + /> + + {changeCount} +
+ ); +} diff --git a/e2e/nextjs-app/src/app/components/radio-button/keyboard-navigation.e2e.tsx b/e2e/nextjs-app/src/app/components/radio-button/keyboard-navigation.e2e.tsx new file mode 100644 index 000000000..031fa72d1 --- /dev/null +++ b/e2e/nextjs-app/src/app/components/radio-button/keyboard-navigation.e2e.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { RadioButton } from "@lifesg/react-design-system/radio-button"; +import { useState } from "react"; + +export default function Story() { + const [checked, setChecked] = useState(false); + const [changeCount, setChangeCount] = useState(0); + + return ( +
+ + + { + setChecked(true); + setChangeCount((value) => value + 1); + }} + /> + + {changeCount} +
+ ); +} diff --git a/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx b/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx new file mode 100644 index 000000000..322ce2210 --- /dev/null +++ b/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { RadioButton } from "@lifesg/react-design-system/radio-button"; + +export default function Story() { + return ( + <> +
+ + + + +
+
+ + + + +
+ + ); +} diff --git a/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-disabled.png b/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..0c20e3b69b9e9c22249bd0610b499597ed9141ef GIT binary patch literal 1111 zcmV-d1gQIoP)+9>gyF0uF1_p+Ngd`>=Mn^}JYcMHiCGYR=i;Ig33k$cmw||`w6cm(~mzSTP z@8#u1N>C(saBwgb0`3)^4NVs&+OY-}vaLxtS@{QShk z1O{faxuBpRD=Q01vYT^rbF;Lx1ieDRcr7k2h6+g%(&Vt;`1m*m;o;%+_4QDUlgZFu zS67$NVo6B}PMKsNXAS%N`+^w`v8k!aIWy9ZyScg9YPDiKHZ}%hpl>4g_V(7_-;Y6X zaBxFIgP)%tN6O#dzp=4VoIAv^2(ckSZgzH7IE%Wvx`2QHz91&o*4AQxdp$Qd#~0+1 zgK5HXV33)ai8CchL`6lVrKOQ(vV1G&l7qE9Jw0KNlaoVA$j;8j6N~UIk4tWMcNb6C z8FWBOh>MH!_V&gA;e;u|C5Pxl+UbxgOeT}C2eA|fTyo+nNZkWR;F^6vx z0Vq#uK9?MF4f?G=WeA-)#=3ujOHKrXv$Hc&1+*^2b>oT+T$@WuO2YH;@e$b@DdF(& z@cH@KwiE|ka`Ex;K0ZDetgNh%5|)>j@x&tVDNGSAIoPuBqHAkw=jZ1n3Fv!cV}m4p zxI}C%EG)EGK5ewSyBp`r7rei}@9pg+O>M~k_<|DTe0_b(%F0MfBs)4fn7;Jt>Z-G| zQ`}RCV-aFQI@z3_o}QVRAx#a~EF&Ys$>jC*^^uX0mzNiei;9Y%dy;`lnvV1YnWGq^ zI6#_?T1z-W0q6;_7+2@yUj2X<;@;bb)2t+uPx^b@w&5wzfhs zB2lvgYT(q=)YsS7ot+(o0W>1$e*ozq)PoE~cVAY7=;`U%-rlaLs6YZju3>d`6$hG} zoLo~=BfcQvLpKr!N?Okkq(ym4OjlA~UJm1(nwoN*9Bu%#g$2bc6276KAzNPz84b#S z%F0TdI59I}RGKL%DKG^HlM8@290xWQodeV&$h+)1c6h}{p~znV00960Twk+n00006 dNkl_uv#9_8002ovPDHLkV1m{(1t|ak literal 0 HcmV?d00001 diff --git a/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-enabled.png b/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-enabled.png new file mode 100644 index 0000000000000000000000000000000000000000..c88ddc0fb17c52cd4fdf3ee2af125db50d3d63e3 GIT binary patch literal 1226 zcmV;*1U37KP)0M41!|#ywm>T%4%`^lCCHT4F~DZVY%v-%ngyL%GDR+&W=7ownHRb- zXZ*NWT%rjkE^(|PI-8ow-~yH{1KMqrg_Z%OUt1~At`z7V+GHUsW9OWATb8B2i<75s zpXa>)oUi9OFB6GG(8CIY9%2&WXi12pB_WQMgg9Cf;%Ir)#q|w)PMx2yyJj8NgYZ+H z&R58UwHtCZPe~CwIMh{1cwy$GXz(h z%{2>cMPVkQC5g)^Q!K9sn{yU31XtWtG;e076YPU{@}#NIPTnEi#Y2|(7ZzE49^i5~ zME$i*=QZI zUq^)WTRp#ZkD}-qj=w7ia_hd=%2Rm^EV-BW8)1I&10nIh+G+v=#{QEXW%z*v;?hzd z`|kZsV2pX@Ui`Gn?!r1tN1d}!GQ~>yBfB<1CkPv|>K?NG7q71e1M0J9KIr)Mzbk7v z!@dTG@;xUkSEu1;>zfsC)f6HUXv*}%CoL^U`(m{PTn=C@)^5mInLNfl0l1I-&~@qT zh!;iI>!Bvi9(@TSg#Lo_c3b!8iY!@}Ez*|D=NA_LH#=88SII@knyVk&1t-Q`uZB4p z{Jq=Db~ltTNn}~;9*Dces+a05>vNtfdK|HXllat6NkSYgkEpm{Fz9eNd_Eu85{X1E zm-G3oiuibF#Mx}No}M0;%XQmxnM_tyRi#ua(LI9fC<%o^Mx$|fc$mlIDHMv#DDd3t z^}5||yWJiRhl`7gwOTDWAl49w3j_k~?d^WQA6{QmQamx zg`g_w?Cb<(8jYsDzJApg3j_kaUSC;R32p|10kH;G+`z!V`1rU=rGizpwr6#9bwNP^ zI1dgIe6wLCuD7?BVHllGhvN)xTrL+v5IeBM!7#wV0ZR=g4#!_86spx~Sb`9USa1^n o0RR7vC0IlN000I_L_t&o04NUB-Na09#{d8T07*qoM6N<$g5wrDGXMYp literal 0 HcmV?d00001 diff --git a/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--mount.png b/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--mount.png new file mode 100644 index 0000000000000000000000000000000000000000..6b74aa8dbcec20affa25aa88869b6d02db47cb3d GIT binary patch literal 5048 zcmcIodpOho+ut{&gGizyqH-uygqXwkD^dxiP{v4;Q*+4qFiS#3#$?KADW_7#9A=nN z$(gV$=d&?pp_yU!`>cM?)$e+)>-pokuIKsZbHD%kykGb0KE3YuldBe{yLKGh0Rn+` zUAky&1p)~HN6^h}TY&HJJMEbu&~DHr<9}`hXUq?I`dp`FHZGc?UCf#=@!{khir@D? zKBFLH^lA*FVm{D}$<1{)A~3XuGKccaUDZo_?zvVBF9fD}mSl1L;Xv5yfbwrf{2PAaa!qg?lJLR;Gv@$Hfp?8P;x zE%Tx&uV5qXc3fw9x)!b&cgtBaX*Zmz*x&mL@z|^MjEubp7dhc6DJhbYl2K7n+Kj{( zFK*h{RNQSpNP?dF=zY(5X`iWsAvl~!^8T48t)4tV#%nT}1loaJy5bRCfr!^|eZF(M zZPJ8BF&GRL8ukH)v*e^@WMrhJd6f3SATsl_v)eZ>+3aJId7Ja|_rxvo53Z9JTerHV znsV$C@2Yi_oU>}jtBPfLN_&JdEjh}0vPk!assXrs#%so!@j&P=_6Ezg*D-6BJDx}= z!ag~je(z9Sk&|OAC6>=Ruz!ESyLV{Tgd52!-w`i3vHQ_L|b+BwtWIn!=UY+%_q*m!{Tq=Lo2sZQ_f5m0Nq|Hi6s zU-19~9JKIU=+iCT)~fMM?s^J+9HRDT{JfzB83qeoL`d2&9D<{YF-{5 zOTl^;`5K0X$Q4jv;c(4Ywq<8;>zAd&t(%QhSpS~8O!9Z<4T`CH0)^!-7BB5N!<|tN zTX-MIu`&4rzvfywvFr2aN9a5>8Xd^!KmMuP{=&=lX-niEHau z?Tt3zFj@UsG!$W5HiZ1MKTUOeO!barB`C9ok{?U1ExtvvE_ffStTn#an}3$e06xCjM%xZ`-oQuKck=n-6;;-+$}wmcNml>p*BkPAu%xrU{B|67h4UxU-#SCu5O;wN~Gx zH`WO3RpA!dkacJBRn`8YPIKzf!dh=Kcjd}?n9I$;Z9Ts!&x)3LkZF;>?H>A=XO#Rg z9UYwuZ+K^hrl;>__jj#9Iqro0wqW%0qxi)2_K_?sf!75nPCu%4wUuc#l|SR-HtU0VDdkex(deK;Kc>C>lD)WO4t=jrqvMT)Ab z=5A#&d|qC-W($vIXUlPjZe8-(5AlTJE4Pfw6C!wAlKZ8_`lIHNg!PD5I~mmTPIvLV z@=I_8G~2Gs0egu0re=sOz*>RgVo!!$_r(AEZ@xy-DeH30uU~(qtUl)!j{o#qTYQ`U ziW;nQEeJ6jgkRI)vKuLK|CJBsGk<+|E_uwRKb5=g@#M0@wOo;Oaxj>cMSJMKY`;~l zy-aW*Gji;*^v&P&DC&e*c!%K!81)tE_R0V58augCZiU}Y7)FUbj`tGrBZfeolKVT`w%;Z>^6c`TucSA{5lo z-u?{5rrLUXco<)NS6Dcezmb%YaX7m_=HukCWZv-$WIbQ5YB^TLY<*gQ(0+Cjg012X zgRLGqV!;b&tc~B`+5p_BoS#4rmbY(@4F!$p_avI9Yf0|idj(=?Wb{yBjz2>mgh+*g zdT0HC({JxD^ zTCS>8Ymq~BZ;?aTMCc@{SW=3QLhNW}8vH2<%IvW;)Hg85dj7o3wNob9y$IDIDket$ z@o^_G5b+9}rlY7PAdx--Bx_n`{EX);T{n-d<%m~Lh0aK)zj#m7JHl)BfuK`wpt0uy zP%}UkBq(;4L0JlEBCfSzK}+)G>32>7$l~MU^_JT-?(1u%GqPi4(yC;zoz$+buD(9y zPw>z>ivH{TB3i5C=F*_0AU`OtW3y{&>>mN6LG8?$#qox?H*emUo0|&>3Hd$o;BvXA zNI%gV&l&3r)u%KxuDg9cjO)B&aqh;@kfB~gWrb_lrKj!Tsx2*p>7;Yn_nwqflAfnz zyuw<2su|Q@8oh4au^`^JIhHjJ-g$OlO!-%OsK2y?pxQ|4xvfNXb#)l_t>&=%9MC5B z@ZtQB%Q*ouYmur~OKqK4q9`jK;m1Qj=Dyo~=k(PGQWvBBkr$M}n*=jdM!_=Nv#e8`GuBSHv z5pjJ5Bf0WZ8E5Q4qU-m5t!4+u;a$q0inYrxKblr}WJE;$$4xSB5)X0#&2m0glsL37 zDxThsNlm3Kb6_N2`r_o|q%=6NY4G^R*&BCwR4k4>sIf!5z2&F zcbg^RHb+-AFe1wYXh&|pyZoc{yMNsj)Urb7Hava0TbO6k$sMrnF_*hhM|)BOn!j3DXB|Z`yZy{}Qo} z@BfeDwM?W=29^Ke17F1nLS@oZQe3psO;&+GTAyWstM%l6SdC~3RZxz-*+#yY>76sp z*U1mWG~ru{duH`QmSC=~w6clW+1W$dUiNs{lWnM@0VK=KMXUCyNcTqDDMkH7Dgo|r zd*7J&+vR7J8h&OKg9;G4(9}5umqqQw8e$U@M}5v&ZJAum%E~G#Dw>|222{rQ_&9u^ zqFK}k%>6XM+nDo12Iu#9Bn;p`LNnmXZDmap`}$+)_EC-Wu-F<2WU1Ojvv3?tI6LzX zN}==CAQ>5%&35mIiNI=?pZ!$E~$>Pt;$4?Z(7F`1Z{0BV=PV4Soq+WW4#u9l{#iEmr~&K12is@ZtRYyQrq z(|SIxRjzI9P`G7o4{5zfCDWo{U()ik(cdH`K9YF=v}T|&r>Z%GGD+-?;hr%c|G+>k zZEZybg}X4=wtxuMg}Ks3h`}|?N>nUH*)*+M-*Pj1R*@IP3Gyzt)fL9jj-4Rrdqcf& z#Bs8;ZV%=v{o)?FF+IF9OCMrwtr;-9xw)x5629E_QiH`}sW0T^<|-5PJ;A5=E~=ak z6+iK^9;SJJeTCsSt5QA73e_<#INC}cL2}T|1*zqZQ%$u!(z0AaPbbzbWX=e?L0}uV ze(}ck^HN2pa3ehXq^?)V=PCNL^MGq97Fl{a0mDE8A%(G9looa*mTVAdSz+v(E!efUzl5Lx0dr{42^amf?WI!ayX zMJ13=4TUx$PzEDDMevIirDzEQqJo2Hl0fthAX@Irfk8pCy8dp?&dwgP9Bcl1a&21m z#0e|I-#+TeZ5>@%2^6oS1umRlT3(J4IB(N6iNUf}9N&i{R&KVMn^jBHHt(~jP-d97 zZe$i_cx4;qbOiO+SX*0bGqiMcZb2Z0Wy?!TkLV%%a&sEn?i)6lEr&!{_a34deD)}R zS{Kn^6m7vS*hUFR!7(dDJ1C{Y0Sx}?Gg_BuLJ!YxKY6lFg9XT>ZXYP0hnvASNU}|| z<#tl3TCw$*{OXlDQ20!Qr8*n8CU%( z6=xD5Dk9Q`cs#%m6&1O4VYF+c7m8bAb!?ftqEA&VSKejIe2jdh3N6_Eb~#ha+s3B% zihgNnsb74jT0B@d_o?0{fc#$+#Oje|QGuMRK$M=0*srQ6qH| zAJg~!yHadZq)}!l>p2J{aGU=Y5WUMR`TCw`!X5tpLRqt_z`8}*hiPmiof1_1JUdmd zSIz4h!4wV~TKnfI9AMg|soZ!>;Q&1&t$o^$)}h?_v!AhoLd@UU8g(0pcR*u;bjus^ zeJJswjg42cS>&~m?`Jkv6?Z%gGLF^t zhIQBqW=*FoR}C$^mgg0sdb+zOw9TBW={rz@v4frs&S81Qh z4UL2TV4GZS$?N5d4!HLVUP^W~O2el=ShDNB-yz=%9)m$*R3ms3o>qIF8I}J>8@`ag zgwO%R70^VI>s1U4A{w4b;*T8IM>|!QfI>Oe1ees-Lba@{tbpw`mr?uqgDt5VdE>Z% z54yQ{z36?Inbr8jhNdO+1@meEm1$WX_9eWb4>N*5l(%rP`A;aE3m(6V=CnWEaXGktX{3Dr?3^?$qF?SwTOIhmf?bKn2S$8_VUsma-|MiV@@NV zfy#aI2Xpj4QJ}+ zcgiYR(GI=+RsN&r&0BxJ8U0OpD!~sh=rid5;YsL!|1kB42Pgy{4;79m13+!%7n=Ym WZqsHOGeZ>T({ + story: async ({ page }, runStory) => { + const story = new StoryPage(page); + await runStory(story); + }, +}); + +test.describe("RadioButton", () => { + test.describe(() => { + test.beforeEach(async ({ story }) => { + await story.init("variants"); + }); + + test("Variants", async ({ story }) => { + await compareScreenshot(story, "mount"); + + await expect( + story.getContainer( + story.locators.components.radioUncheckedDefault + ) + ).toMatchAriaSnapshot(` + - radio + `); + + await expect( + story.getContainer( + story.locators.components.radioCheckedDefault + ) + ).toMatchAriaSnapshot(` + - radio [checked] + `); + + await expect( + story.getContainer( + story.locators.components.radioCheckedDisabled + ) + ).toMatchAriaSnapshot(` + - radio [disabled] [checked] + `); + + await story.locators.components.radioUncheckedDefault.hover(); + await compareScreenshot(story, "hover-enabled", { + locator: story.getContainer( + story.locators.components.radioUncheckedDefault + ), + }); + + await story.locators.components.radioUncheckedDisabled.hover(); + await compareScreenshot(story, "hover-disabled", { + locator: story.getContainer( + story.locators.components.radioUncheckedDisabled + ), + }); + }); + }); + + test.describe(() => { + test.beforeEach(async ({ story }) => { + await story.init("focusable-when-disabled"); + }); + + test("Focusable when disabled", async ({ story }) => { + await test.step("Remains disabled", async () => { + await expect(story.locators.components.radio).toHaveAttribute( + "aria-disabled", + "true" + ); + + await expect(story.locators.components.radio).toBeDisabled(); + }); + + await test.step("Can receive focus", async () => { + await story.locators.focusStart.focus(); + await story.page.keyboard.press("Tab"); + + await expect(story.locators.components.radio).toBeFocused(); + }); + + await test.step("Do not trigger onChange", async () => { + await expect(story.locators.changeCount).toHaveText("0"); + + await story.locators.components.radio.click({ + force: true, + }); + + await story.page.keyboard.press("Space"); + + await expect(story.locators.changeCount).toHaveText("0"); + }); + }); + }); + + test.describe(() => { + test.beforeEach(async ({ story }) => { + await story.init("keyboard-navigation"); + }); + + test("Keyboard navigation", async ({ story }) => { + await test.step("Radio can receive focus", async () => { + await story.locators.focusStart.focus(); + await story.page.keyboard.press("Tab"); + + await expect(story.locators.components.radio).toBeFocused(); + }); + + await test.step("Space key checks radio and fires onChange", async () => { + await expect(story.locators.changeCount).toHaveText("0"); + + await story.page.keyboard.press("Space"); + + await expect(story.locators.components.radio).toBeChecked(); + await expect(story.locators.changeCount).toHaveText("1"); + }); + }); + }); +}); From fce0a112992011eacf7f7ccc8232d2804eec3d87 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Fri, 17 Apr 2026 10:54:09 +0700 Subject: [PATCH 08/14] [BOOKINGSG-9221][GZ] remove unused locators --- e2e/tests/components/radio-button/radio-button.e2e.spec.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/e2e/tests/components/radio-button/radio-button.e2e.spec.ts b/e2e/tests/components/radio-button/radio-button.e2e.spec.ts index 38c871115..3ec91f6a2 100644 --- a/e2e/tests/components/radio-button/radio-button.e2e.spec.ts +++ b/e2e/tests/components/radio-button/radio-button.e2e.spec.ts @@ -12,8 +12,6 @@ class StoryPage extends AbstractStoryPage { radioCheckedDefault: Locator; radioUncheckedDisabled: Locator; radioCheckedDisabled: Locator; - - radioFocusableDisabled: Locator; }; focusStart: Locator; changeCount: Locator; @@ -36,9 +34,6 @@ class StoryPage extends AbstractStoryPage { radioCheckedDisabled: page.getByTestId( "radio-checked-disabled" ), - radioFocusableDisabled: page.getByTestId( - "radio-focusable-disabled" - ), }, focusStart: page.getByTestId("focus-start"), changeCount: page.getByTestId("change-count"), From 33dfcee4a12b087c0509748d2973f952c0b5cbe8 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Fri, 17 Apr 2026 10:56:02 +0700 Subject: [PATCH 09/14] [BOOKINGSG-9221][GZ] add aria snapshot for radio button unchecked disabled --- e2e/tests/components/radio-button/radio-button.e2e.spec.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/e2e/tests/components/radio-button/radio-button.e2e.spec.ts b/e2e/tests/components/radio-button/radio-button.e2e.spec.ts index 3ec91f6a2..b93f08916 100644 --- a/e2e/tests/components/radio-button/radio-button.e2e.spec.ts +++ b/e2e/tests/components/radio-button/radio-button.e2e.spec.ts @@ -92,6 +92,13 @@ test.describe("RadioButton", () => { ), }); + await expect( + story.getContainer( + story.locators.components.radioUncheckedDisabled + ) + ).toMatchAriaSnapshot(` + - radio [disabled] + `); await story.locators.components.radioUncheckedDisabled.hover(); await compareScreenshot(story, "hover-disabled", { locator: story.getContainer( From 60228a92f2e84e11ac2d5c9aec91b6e25ef16381 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Fri, 17 Apr 2026 11:11:20 +0700 Subject: [PATCH 10/14] [BOOKINGSG-9221][GZ] refactor input classes --- src/radio-button/radio-button.styles.ts | 12 +++++------- src/radio-button/radio-button.tsx | 7 +------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index c056efc5b..5d6a091a8 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -3,9 +3,7 @@ import { css } from "@linaria/core"; import { Colour, Motion } from "../theme"; export const classes = { - icon: "radioButtonIcon", iconDisabled: "radioButtonIconDisabled", - inputDisabledVisual: "radioButtonInputDisabledVisual", } as const; export const container = css` @@ -52,18 +50,18 @@ export const input = css` position: absolute; height: 100%; width: 100%; - cursor: pointer; + cursor: not-allowed; z-index: 1; appearance: none; background: transparent; border: none; +`; - &.${classes.inputDisabledVisual} { - cursor: not-allowed; - } +export const inputActive = css` + cursor: pointer; - &:not(.${classes.inputDisabledVisual}):hover + .${classes.icon} { + &:hover + svg { @media (pointer: fine) { color: ${Colour["icon-hover"]}; } diff --git a/src/radio-button/radio-button.tsx b/src/radio-button/radio-button.tsx index 637a18ae2..1cfbdf5ac 100644 --- a/src/radio-button/radio-button.tsx +++ b/src/radio-button/radio-button.tsx @@ -42,7 +42,6 @@ export const RadioButton = ({ data-testid="radio-checked" className={clsx( styles.checkedIcon, - styles.classes.icon, disabled && styles.classes.iconDisabled )} aria-hidden @@ -52,7 +51,6 @@ export const RadioButton = ({ data-testid="radio-unchecked" className={clsx( styles.uncheckedIcon, - styles.classes.icon, disabled && styles.classes.iconDisabled )} aria-hidden @@ -74,10 +72,7 @@ export const RadioButton = ({ disabled={isNativeDisabled} aria-disabled={isFocusableWhenDisabled} tabIndex={isFocusableWhenDisabled ? 0 : tabIndex} - className={clsx( - styles.input, - disabled && styles.classes.inputDisabledVisual - )} + className={clsx(styles.input, !disabled && styles.inputActive)} {...otherProps} /> {renderIcon()} From 11c6c6d87ea256710cb9d7fd4e303f3a35909e6a Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Fri, 17 Apr 2026 11:14:14 +0700 Subject: [PATCH 11/14] [BOOKINGSG-9221][GZ] extract out common icon styles --- src/radio-button/radio-button.styles.ts | 11 +++++------ src/radio-button/radio-button.tsx | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index 5d6a091a8..fa3992c43 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -23,11 +23,14 @@ export const container = css` } `; -export const uncheckedIcon = css` +export const icon = css` height: 100%; width: 100%; - color: ${Colour["icon-subtle"]}; transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; +`; + +export const uncheckedIcon = css` + color: ${Colour["icon-subtle"]}; &.${classes.iconDisabled} { color: ${Colour["icon-disabled-subtle"]}; @@ -35,12 +38,8 @@ export const uncheckedIcon = css` `; export const checkedIcon = css` - height: 100%; - width: 100%; color: ${Colour["icon-selected"]}; - transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; - &.${classes.iconDisabled} { color: ${Colour["icon-selected-disabled"]}; } diff --git a/src/radio-button/radio-button.tsx b/src/radio-button/radio-button.tsx index 1cfbdf5ac..5f1e3c4d1 100644 --- a/src/radio-button/radio-button.tsx +++ b/src/radio-button/radio-button.tsx @@ -41,6 +41,7 @@ export const RadioButton = ({ Date: Fri, 17 Apr 2026 11:16:32 +0700 Subject: [PATCH 12/14] [BOOKINGSG-9221][GZ] remove nested icon classes --- src/radio-button/radio-button.styles.ts | 16 +++++++--------- src/radio-button/radio-button.tsx | 8 ++++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/radio-button/radio-button.styles.ts b/src/radio-button/radio-button.styles.ts index fa3992c43..51dcb9fc2 100644 --- a/src/radio-button/radio-button.styles.ts +++ b/src/radio-button/radio-button.styles.ts @@ -2,9 +2,7 @@ import { css } from "@linaria/core"; import { Colour, Motion } from "../theme"; -export const classes = { - iconDisabled: "radioButtonIconDisabled", -} as const; +export const classes = {} as const; export const container = css` display: flex; @@ -31,18 +29,18 @@ export const icon = css` export const uncheckedIcon = css` color: ${Colour["icon-subtle"]}; +`; - &.${classes.iconDisabled} { - color: ${Colour["icon-disabled-subtle"]}; - } +export const uncheckedIconDisabled = css` + color: ${Colour["icon-disabled-subtle"]}; `; export const checkedIcon = css` color: ${Colour["icon-selected"]}; +`; - &.${classes.iconDisabled} { - color: ${Colour["icon-selected-disabled"]}; - } +export const checkedIconDisabled = css` + color: ${Colour["icon-selected-disabled"]}; `; export const input = css` diff --git a/src/radio-button/radio-button.tsx b/src/radio-button/radio-button.tsx index 5f1e3c4d1..b147130cb 100644 --- a/src/radio-button/radio-button.tsx +++ b/src/radio-button/radio-button.tsx @@ -42,8 +42,7 @@ export const RadioButton = ({ data-testid="radio-checked" className={clsx( styles.icon, - styles.checkedIcon, - disabled && styles.classes.iconDisabled + disabled ? styles.checkedIconDisabled : styles.checkedIcon )} aria-hidden /> @@ -52,8 +51,9 @@ export const RadioButton = ({ data-testid="radio-unchecked" className={clsx( styles.icon, - styles.uncheckedIcon, - disabled && styles.classes.iconDisabled + disabled + ? styles.uncheckedIconDisabled + : styles.uncheckedIcon )} aria-hidden /> From 9d5e49daef43d096962e33d1d312357924b20e8e Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Fri, 17 Apr 2026 11:19:44 +0700 Subject: [PATCH 13/14] [BOOKINGSG-9221][GZ] flatten locators & add spacing to the story --- .../components/radio-button/variants.e2e.tsx | 4 +- .../RadioButton-Variants--hover-disabled.png | Bin 1111 -> 840 bytes .../RadioButton-Variants--hover-enabled.png | Bin 1226 -> 996 bytes .../chromium/RadioButton-Variants--mount.png | Bin 5048 -> 5188 bytes .../radio-button/radio-button.e2e.spec.ts | 73 +++++++----------- 5 files changed, 30 insertions(+), 47 deletions(-) diff --git a/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx b/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx index 322ce2210..93c4c1cd1 100644 --- a/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx +++ b/e2e/nextjs-app/src/app/components/radio-button/variants.e2e.tsx @@ -4,7 +4,7 @@ import { RadioButton } from "@lifesg/react-design-system/radio-button"; export default function Story() { return ( - <> +
- +
); } diff --git a/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-disabled.png b/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-disabled.png index 0c20e3b69b9e9c22249bd0610b499597ed9141ef..7989890bae67a9f6fa39a6ddf10a4f1e921c138b 100644 GIT binary patch delta 818 zcmV-21I_%`2*?JIBYy(@Nklg8Uz2EyAuE_0PJ2P=bF2B#>$NA};@ynSrGv{b*wOZ7# z7^#oZ#i^o;Q$-i2iY`tSU7RZaySPLm5s5_d`FyEV!t2Du#DDbk^!obx($W%r4})@5 z(rh+89*^7YE*6V_956XKd2n!Wcz8H4FhEKuii^c!A0HptY*xI^&dx3@EX>Tzz{ZD} zOs4%6qIh|ExxBng@~DV&xm;GO6~^G;;L*|1&dv^k^xK$1q2Tp;5my8lucxP{2q8%# zEe^kDu~=Zt&410^+}t2AT?Qk5&(F^yif3nMSY?tyE*qlJs8EJQyuZKiu8g$het3A8 zpPz?qHk*+Q^pC_f8jZKNHyBe>Q@6Lbqobo7ud%VQySqEF?r_H>#707#!{HEz#r5^| z`1m;A5reO;u3%taJDpCxBUcDM_-pxPQ30xk*~e^0S;P4%t?%R$=Vz z?U53@ySsQ|5`N}!#f8IRJdtOJ0V%PvvNAL@1OwLz(}gPzw-afrL#h}I29Xb9Dh^z6 zVk=1PgU?`_leR6GP^P2T5(l9Gal&1Ut&>b9Ny}H1!TbCBB#C;1^Zx$cxw7bP z*4Eb0F`$0w{2ayb#l=PM8XUowts!EG^vCw>b!*s3KQ`4pK>s606+9>gyF0uF27d;IgoGp}CPqg`lWQ<3 zXC?3N?~99z3kwUkx3_EDc`07Q!ongVB0@t$ zF~-M>iwoOd&|-CUb!==b$wP(Q{QUgH!~_Orv$>$4AS){iO0t`Cb91w_v;@6E!FVk$ zE`|z864Khqw&|g5wW+ zCX=uSu@nbfa^fmT-2+G9nv-@dnDgZVzl-ewC{JoWmmG2p`mH}@2%R~`x_^O7P6UIq zvolf!w0|zdb>oT+T$@WuO2YH;@e$b@DdF(&@cH@KwiE|ka`Ex;K0ZDetgNh%5|)>j z@x&tVDNGSAIoPuBqHAkw=jZ1n3Fv!cV}m4pxI}C%EG)EGK5ewSyBp`r7rei}@9pg+ zO>M~k_<|DTe0_b(%F0MfBs)4fn7;Jt>Z-G|Q-9o3h+`3ALps@ z!^!0J_4SdFk(ZYjjEjnjpnH;mN}7)J1ev24qc}jCj#^7NLILOru^3n91_r*KEUKG?galL!$X~vGM>1ShRpq_{M?kkUgf3zJxSsAV4Zp$@i)uH( zXn*9W!XT%LKja=B9*&NVMC$;~DJCWc^)P)uob3Ba4&Hona`N=_)J`liG7>R|pMJ?g zcVAOqU*G2DCgL$XlT`!$Mh^>FE4&xNVtRVIY{1q9s@LJ+VcmUAZEbD%DJ?B^?0q2B z866$n+S-CsZE0y?Hb-=UW!u}^;k0%4HGj9Zwn8x?QL_VT;MCOA*VosbogIV$G$QDK z0O=sqgA7G?UsiFL?t-ma*qKmtOpVRdyC2b!FmTvJmcz98X4HxdU*TF(!pMR`k1 zS5jVH4&$AgnsS{SZUD4}1;r~8zM-KZTVD(r4a$JZ%1WF#F*9LQnkgwMFa-#c3p{{0 z90xWQodeV&$h+)1c6h}{p~znV00960Twk+n00006Nkl_uv#9_8002ov JPDHLkV1i9g2EqUU diff --git a/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-enabled.png b/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-enabled.png index c88ddc0fb17c52cd4fdf3ee2af125db50d3d63e3..11744dc8737259ccc51527f044732534d348ca65 100644 GIT binary patch delta 975 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 literal 5048 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 WZqsHOGeZ>T { await compareScreenshot(story, "mount"); await expect( - story.getContainer( - story.locators.components.radioUncheckedDefault - ) + story.getContainer(story.locators.radioUncheckedDefault) ).toMatchAriaSnapshot(` - radio `); - await expect( - story.getContainer( - story.locators.components.radioCheckedDefault - ) - ).toMatchAriaSnapshot(` + await expect(story.getContainer(story.locators.radioCheckedDefault)) + .toMatchAriaSnapshot(` - radio [checked] `); await expect( - story.getContainer( - story.locators.components.radioCheckedDisabled - ) + story.getContainer(story.locators.radioCheckedDisabled) ).toMatchAriaSnapshot(` - radio [disabled] [checked] `); - await story.locators.components.radioUncheckedDefault.hover(); + await story.locators.radioUncheckedDefault.hover(); await compareScreenshot(story, "hover-enabled", { locator: story.getContainer( - story.locators.components.radioUncheckedDefault + story.locators.radioUncheckedDefault ), }); await expect( - story.getContainer( - story.locators.components.radioUncheckedDisabled - ) + story.getContainer(story.locators.radioUncheckedDisabled) ).toMatchAriaSnapshot(` - radio [disabled] `); - await story.locators.components.radioUncheckedDisabled.hover(); + await story.locators.radioUncheckedDisabled.hover(); await compareScreenshot(story, "hover-disabled", { locator: story.getContainer( - story.locators.components.radioUncheckedDisabled + story.locators.radioUncheckedDisabled ), }); }); @@ -115,25 +98,25 @@ test.describe("RadioButton", () => { test("Focusable when disabled", async ({ story }) => { await test.step("Remains disabled", async () => { - await expect(story.locators.components.radio).toHaveAttribute( + await expect(story.locators.radio).toHaveAttribute( "aria-disabled", "true" ); - await expect(story.locators.components.radio).toBeDisabled(); + await expect(story.locators.radio).toBeDisabled(); }); await test.step("Can receive focus", async () => { await story.locators.focusStart.focus(); await story.page.keyboard.press("Tab"); - await expect(story.locators.components.radio).toBeFocused(); + await expect(story.locators.radio).toBeFocused(); }); await test.step("Do not trigger onChange", async () => { await expect(story.locators.changeCount).toHaveText("0"); - await story.locators.components.radio.click({ + await story.locators.radio.click({ force: true, }); @@ -154,7 +137,7 @@ test.describe("RadioButton", () => { await story.locators.focusStart.focus(); await story.page.keyboard.press("Tab"); - await expect(story.locators.components.radio).toBeFocused(); + await expect(story.locators.radio).toBeFocused(); }); await test.step("Space key checks radio and fires onChange", async () => { @@ -162,7 +145,7 @@ test.describe("RadioButton", () => { await story.page.keyboard.press("Space"); - await expect(story.locators.components.radio).toBeChecked(); + await expect(story.locators.radio).toBeChecked(); await expect(story.locators.changeCount).toHaveText("1"); }); }); From f383b7d3a3bbecf1fb8a22cf9a2011dca594b269 Mon Sep 17 00:00:00 2001 From: Ghazwan Date: Fri, 17 Apr 2026 11:23:59 +0700 Subject: [PATCH 14/14] [BOOKINGSG-9221][GZ] group aria snapshot & add checked hover cases --- ...utton-Variants--hover-checked-disabled.png | Bin 0 -> 1012 bytes ...Button-Variants--hover-checked-enabled.png | Bin 0 -> 1225 bytes .../radio-button/radio-button.e2e.spec.ts | 31 ++++++++---------- 3 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-checked-disabled.png create mode 100644 e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-checked-enabled.png diff --git a/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-checked-disabled.png b/e2e/tests/components/radio-button/__screenshots__/chromium/RadioButton-Variants--hover-checked-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..35595d016572ea9aa46a5da2e225eeb2a482397e GIT binary patch literal 1012 zcmVOw@t3bBKt3w5Wsuz(BkX9@0ft4k5Yf})5WMFbZL_J*mX=Y8Da z%^RNPzL|L;1i9ZLoO|v}=F905b2uC(@d`7EV;JOAVUSaWK~5D0IaL_sRPocvJv}|$ z-rm~nc9+YA$Bc}O?Ck7{ii+amV)B15DNiM#Q0Vyh_~_`!>2!X(ATu+wrKP2{wKX9j zfha+d-2MIi>gwv}=O=y4&CM++D9FjlfehvQ`#XCDD-I72mz0zcd8m*(JUram+Jcan zm}s?H8yXs5q`%fU9FCKd6WA37#$#`9FHA@zAx#eFZEkKt$ji$c9UX;XbQZ&YOG``C zihX^3@G_BsTr}L>-BD(6;`sQuJ~N`ZdtzcDKR+Mx#>NJMfyh9@a=~D5etsU|4^ESl zlj-T{?3Lf|zr4I;*;-duXEy(-18%o_ad8oj&dSP~nVCT_2%acGZg+QgZ*LF6^z<|= z$MjGh92|fj)1;)NST!)s^Yb(KLFnx4?C9taJ5boI_zfr=5bEped1gC1J0Q(71H4}E z_VzaPOjA@;R8vz!w2&1yhbTEj8;*p~)YQb3*Votk`}>i$z@k{d9vd4QDR1$}6D4+9=GE-fuhN=kx&c0!^{4&8}p-eH=@$45lE{w`$C>+36( zO(s)eVIljfXp*Cu$Y&_)0s8p(_+T=v)sfoWSI9MfK9&VLCcg#7BQg*rhw4Rs+m8YT zR%9a@36tseue~l3MBPf80Sh1i6A|y_Z-J_7u~?`K6TZB>u&;_Hxys5)e0n?{lvAec z@9)>&H83#1V`F^#!nAyKbw#vNES?q;y%j#4 zo0|&+0vIZ%rlwGk*((ffa5q8<2U|4oxr}nSu&{s%0^85d&hi_hMh>{RxWE7m0aMV( z$cRX2+ibSwrt_N1?^hv7o!VyREH_$UtRG$9RIt zk;=FnU`$5>(n3f9526<%b!ckC*BFDFo12Lw)Gs(ID=U1LL?D)zmm~Nvzwmn0>cPRm z*j;ca{&_WoEs?Mov0{BSKMTIBS#emIaL_sRAG=)g+Wdg202yy0ssL2|MM?D ikN^Mx21!IgR09BaKESybIOn$j0000p{K_?ln}v1f-gOIE?(dJA?|k=s z=lt$D=X;zh^m@H$zCwuRF*tH;!I5JNjvQNXfcGMIl1| z-j^1=QIHxR6?#h_)3E*cdHvC|TBpmy=b^(}^7d?a3^4>_axkB!vKfT5_=pP!R>Se~ z)4A)$c;Uf%YJtnP=EE+ddq?g{$H0nx7h%mZ6JKzMznn$GOKldbztwb7XYM(xgbzixq#!I~v% zdC~F(Ae5cc!BB_{q~zeVS?x{`b`&ne%I|*dDLwti?Mz^qYZ^_sxqYqA5C-{0H-rL9 z?ow+XJfkEbxhen0eOQ3EDjNM;?fP=I!_stxMC40Im)iPJV97ytLNmLAHI1Fa1J+6Z zR@cprYuzK1Ea3ANCq^P)2%JEHB}e5=x`!HWjFTAZd&jV>lKWzHui1gfz%22*+_Ps{ zC?NVU4=oz-c|61fq~xI1Kr;~wYf@C6JHr93KU6?ZU(H?S>V|IQ3&p806e0tI+&W^LdU*3` zhtr)DBW^nK0=*=Gs<_2yX*F74;+$l8c9L8um}LNNl&7hMm=`Vz`nU3BnK+nmMrI{b z)sKeF-52e?*|Y4mXOj^zm{s?X^-Es$)f7;lE#7tZ z { test("Variants", async ({ story }) => { await compareScreenshot(story, "mount"); - await expect( - story.getContainer(story.locators.radioUncheckedDefault) - ).toMatchAriaSnapshot(` + await expect(story.layout).toMatchAriaSnapshot(` - radio - `); - - await expect(story.getContainer(story.locators.radioCheckedDefault)) - .toMatchAriaSnapshot(` - radio [checked] - `); - - await expect( - story.getContainer(story.locators.radioCheckedDisabled) - ).toMatchAriaSnapshot(` - radio [disabled] [checked] + - radio [disabled] `); await story.locators.radioUncheckedDefault.hover(); @@ -77,17 +67,24 @@ test.describe("RadioButton", () => { ), }); - await expect( - story.getContainer(story.locators.radioUncheckedDisabled) - ).toMatchAriaSnapshot(` - - radio [disabled] - `); + await story.locators.radioCheckedDefault.hover(); + await compareScreenshot(story, "hover-checked-enabled", { + locator: story.getContainer(story.locators.radioCheckedDefault), + }); + await story.locators.radioUncheckedDisabled.hover(); await compareScreenshot(story, "hover-disabled", { locator: story.getContainer( story.locators.radioUncheckedDisabled ), }); + + await story.locators.radioCheckedDisabled.hover(); + await compareScreenshot(story, "hover-checked-disabled", { + locator: story.getContainer( + story.locators.radioCheckedDisabled + ), + }); }); });