Skip to content

[Radio] Refactor multiple choice indicator (logic and UI updates) #2687

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

Merged
merged 11 commits into from
Jul 11, 2025

Conversation

mark-fitzgerald
Copy link
Contributor

@mark-fitzgerald mark-fitzgerald commented Jul 8, 2025

Summary:

This PR refactors the logic, HTML, and CSS for the choice icon, now called choice-indicator. It replaces the code from choice-icon.* and focus-ring.tsx.

To account for product theming and dark mode styling, CSS variables from Wonder Blocks is used throughout. CSS tokens are used instead of Wonder Blocks components since the multiple choice indicator use case doesn't fit the intended use cases of the components available.

Issue: LEMS-3173

Test plan:

  1. Launch Storybook locally
  2. Navigate to Perseus => Widgets => Radio => Indicator => All Settings
  3. Visually, the different states match the new specs.
  4. Upon inspection, notice that CSS variables are used in appropriate places.

…ton with basic styling.

Initial Storybook file for testing.
Add icon for review mode (aka correctness).
Prevent button execution when in review mode.
Adjust styling for various states (i.e. hover, review mode).
Add stories.
Add unit tests.
…dard HTML button instead of WB Button.

Style button to use WB tokens (CSS variables).
Update unit tests accordingly.
Fix handleClick function to send correct state value for isChecked.
…tor multiple choice indicator (logic and UI updates)
Update snapshots for multiple choice widget to account for proper handling of CSS Modules imports.
Copy link
Contributor

github-actions bot commented Jul 8, 2025

Size Change: 0 B

Total Size: 481 kB

ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 20.7 kB
packages/keypad-context/dist/es/index.js 1 kB
packages/kmath/dist/es/index.js 5.98 kB
packages/math-input/dist/es/index.js 98.6 kB
packages/math-input/dist/es/strings.js 1.61 kB
packages/perseus-core/dist/es/index.js 21.2 kB
packages/perseus-editor/dist/es/index.js 91.3 kB
packages/perseus-linter/dist/es/index.js 7.14 kB
packages/perseus-score/dist/es/index.js 9.25 kB
packages/perseus-utils/dist/es/index.js 403 B
packages/perseus/dist/es/index.js 208 kB
packages/perseus/dist/es/strings.js 7.56 kB
packages/pure-markdown/dist/es/index.js 1.22 kB
packages/simple-markdown/dist/es/index.js 6.72 kB

compressed-size-action

Copy link
Contributor

github-actions bot commented Jul 8, 2025

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (387c5c2) and published it to npm. You
can install it using the tag PR2687.

Example:

pnpm add @khanacademy/perseus@PR2687

If you are working in Khan Academy's frontend, you can run the below command.

./tools/bump_perseus_version.ts -t PR2687

If you are working in Khan Academy's webapp, you can run the below command.

./dev/tools/bump_perseus_version.js -t PR2687

Change name to "choice-indicator" (removing "multiple").
@@ -75,7 +76,7 @@ module.exports = {
...pkgMap,
...vendorMap,
// Load a .js file with no exports whenever a .css file is requested.
"\\.(css)$": "<rootDir>/config/test/style-mock.js",
"(?<!\\.module)\\.css$": "<rootDir>/config/test/style-mock.js",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adjusted this entry to only be applied on regular CSS files, but to not apply to CSS Module files (otherwise, it would conflict with the transform instructions on line 57).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Snapshots that used components that referenced CSS Module files were updated due to the Jest configuration change.

Copy link
Contributor

@ivyolamit ivyolamit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mark-fitzgerald here's my first round of review comments. I'll do a second round shortly after my meetings 🙏🏼

border: solid 0.2rem var(--wb-semanticColor-core-border-neutral-strong);
color: var(--wb-semanticColor-core-foreground-neutral-default);
cursor: pointer;
font-family: var(--wb-font-family-sans);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this something we want to define here? and not in global?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preferably, this would be set somewhere higher up. I'm not sure that we can rely upon a proper ancestor setting, though. Probably something that I need to check with the team.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think of adding todo comment here for now so we won't forget that it would be preferable to have this on higher level instead of here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to declare this higher up, but it is probably easier to do a full css pass as we integrate the new design, and after we have the individual components all hooked up. We have a lot of very specific css rules floating around in Perseus that it might be simpler to do it holistically

line-height: var(--wb-font-heading-lineHeight-small);
outline: 0 solid var(--wb-semanticColor-core-background-instructive-default);
outline-offset: 0;
padding: 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
padding: 0;
padding: var(--wb-sizing-size_0);

background-color: var(
--wb-semanticColor-core-background-instructive-default
);
border-width: 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment with 0 above


/* icon inside the button when showing correctness */
.base [role="img"] {
margin-inline-end: 0.4rem;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
margin-inline-end: 0.4rem;
margin-inline-end: var(--wb-sizing-size_040);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to 1/3 of an em. The space between the icon and the choice letter should scale visually with the font-size. Even though the checkbox is an icon, it is acting like text (i.e. similar to unicode icons). The space between the icon and the letter should be proportional to their size. By setting the margin to an em measurement, we don't have to worry about adjusting this space if we change the font size of the letter, and it will scale with any user-based font-size changes.

@ivyolamit ivyolamit added the project: new radio widget Pull requests that is related to the Radio Widget project that will build the new radio widget label Jul 9, 2025
…more from Wonder Blocks (mostly for sizing).

Move icon sizing to CSS file.
Adjust styling to account for container context (i.e. flex shrinking, additional hover detection).
Add reference handling so that container can "click" the indicator without having to require the user to click the indicator button itself.
Make sure that only one click event is registered when clicking the container.
Update story and unit test files, accordingly.
flex-shrink: 0;
font-family: var(--wb-font-family-sans);
font-size: var(--wb-font-heading-size-small);
height: var(--wb-c-button-root-sizing-height-small);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can't seem to find this in the docs, is this something available for us to use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not in the docs. In fact, they cautioned against using it. However, they also didn't provide an alternative to our needs. I suppose setting our own size here would be more appropriate, since the size of this button isn't tied to anything in Wonder Blocks. I'll update accordingly.

Copy link
Contributor

@ivyolamit ivyolamit Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mark-fitzgerald just saw this in

node_modules/.pnpm/@khanacademy+wonder-blocks-button@10.2.11_@phosphor-icons+core@2.0.2_aphrodite@1.2.5_re_f6b95c8f1f4f35b85908aaae53936269/node_modules/@khanacademy/wonder-blocks-button/dist/css/vars.css

has --wb-c-button-root-sizing-height-small: var(--wb-sizing-size_320); ?

if we can't use --wb-sizing-size_320 please add a comment on it so no-one will copy it

Copy link
Contributor

@SonicScrewdriver SonicScrewdriver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me! Thanks for the amazing comments and explanations for the unique CSS applications

border: solid 0.2rem var(--wb-semanticColor-core-border-neutral-strong);
color: var(--wb-semanticColor-core-foreground-neutral-default);
cursor: pointer;
font-family: var(--wb-font-family-sans);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to declare this higher up, but it is probably easier to do a full css pass as we integrate the new design, and after we have the individual components all hooked up. We have a lot of very specific css rules floating around in Perseus that it might be simpler to do it holistically

.is-correct[aria-pressed="true"] {
background-color: var(--wb-semanticColor-core-background-success-strong);
color: var(
--wb-semanticColor-action-primary-progressive-default-foreground
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing that I'm not the biggest fan of is how long these tokens can get.

);
width: calc(
1.5em + var(--wb-c-button-root-sizing-height-small)
); /* adding 1.5em accounts for the checkmark icon */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greatly appreciate the explanation here!

If we change the font size of the letter, we want the icon to scale proportionally.
The space between the icon and the letter should also be proportional to their size.
By setting the width, height, and margin to an em unit,
we don't have to worry about adjusting these if we change the font size of the letter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a nitpick, please properly aligning any multi-line comments

Copy link
Contributor

@ivyolamit ivyolamit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mark-fitzgerald overall PR looks good. I have few comments, but i'll leave it up to you.
And also i think one of the file was missed in renaming multiple-choice-indicator.test.tsx --> choice-indicator.test.tsx

@mark-fitzgerald mark-fitzgerald merged commit 611da42 into main Jul 11, 2025
8 checks passed
@mark-fitzgerald mark-fitzgerald deleted the LEMS-3137-modernize-option-indicator branch July 11, 2025 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
olc-5.0.d08c8 project: new radio widget Pull requests that is related to the Radio Widget project that will build the new radio widget
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants