Skip to content

Conversation

@marcysutton
Copy link
Member

@marcysutton marcysutton commented Nov 26, 2025

Summary:

This PR migrates the Date Picker from frontend to Wonder Blocks. Upgrades react-day-picker, removes Moment in favor of Temporal (with polyfill).

Addresses WB-1112, WB-1099, WB-1220, WB-2016

Issue: WB-1112

Not included:

  • Anything needed to publish a new package with Trusted Publishing. I plan to hold onto this feature branch before releasing it, so we have a little time for the tool in Wonder Stuff to land
  • Upgrading moment locales to react-day-picker/date-fns
  • Testing for MaybeNativeDatePicker on various devices to see if we still need/want it, and if so, establishing better UX than window.alert for validation errors
  • Accessibility issues from the audit
  • An overview page for the new Date Picker docs
  • Replacing Popper/focus-manager with WB Floating

Test plan:

  1. Ensure tests pass
  2. Review the migration code to ensure there isn't anything broken/unnecessary/confusing
  3. Check out the new stories! (note: these are likely to change) /?path=/docs/packages-date-picker-datepicker--docs

@changeset-bot
Copy link

changeset-bot bot commented Nov 26, 2025

🦋 Changeset detected

Latest commit: 4dbb09e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@khanacademy/wonder-blocks-date-picker Minor
@khanacademy/wb-dev-build-settings Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Dec 3, 2025

Size Change: +4.86 kB (+4.46%)

Total Size: 114 kB

Filename Size Change
packages/wonder-blocks-core/dist/es/index.js 2.59 kB +115 B (+4.64%) 🔍
packages/wonder-blocks-date-picker/dist/es/index.js 4.75 kB +4.75 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size
packages/wonder-blocks-accordion/dist/es/index.js 3 kB
packages/wonder-blocks-announcer/dist/es/index.js 1.74 kB
packages/wonder-blocks-badge/dist/es/index.js 2.02 kB
packages/wonder-blocks-banner/dist/es/index.js 2.01 kB
packages/wonder-blocks-birthday-picker/dist/es/index.js 1.92 kB
packages/wonder-blocks-breadcrumbs/dist/es/index.js 755 B
packages/wonder-blocks-button/dist/es/index.js 4.25 kB
packages/wonder-blocks-card/dist/es/index.js 1.06 kB
packages/wonder-blocks-cell/dist/es/index.js 2.18 kB
packages/wonder-blocks-clickable/dist/es/index.js 2.66 kB
packages/wonder-blocks-data/dist/es/index.js 5.48 kB
packages/wonder-blocks-dropdown/dist/es/index.js 19.4 kB
packages/wonder-blocks-form/dist/es/index.js 6.2 kB
packages/wonder-blocks-grid/dist/es/index.js 1.24 kB
packages/wonder-blocks-icon-button/dist/es/index.js 3.2 kB
packages/wonder-blocks-icon/dist/es/index.js 1.91 kB
packages/wonder-blocks-labeled-field/dist/es/index.js 3.48 kB
packages/wonder-blocks-layout/dist/es/index.js 1.63 kB
packages/wonder-blocks-link/dist/es/index.js 1.52 kB
packages/wonder-blocks-modal/dist/es/index.js 7.06 kB
packages/wonder-blocks-pill/dist/es/index.js 1.31 kB
packages/wonder-blocks-popover/dist/es/index.js 4.3 kB
packages/wonder-blocks-progress-spinner/dist/es/index.js 1.48 kB
packages/wonder-blocks-search-field/dist/es/index.js 1.1 kB
packages/wonder-blocks-styles/dist/es/index.js 464 B
packages/wonder-blocks-switch/dist/es/index.js 1.55 kB
packages/wonder-blocks-tabs/dist/es/index.js 3.71 kB
packages/wonder-blocks-testing-core/dist/es/index.js 3.25 kB
packages/wonder-blocks-testing/dist/es/index.js 978 B
packages/wonder-blocks-theming/dist/es/index.js 384 B
packages/wonder-blocks-timing/dist/es/index.js 1.37 kB
packages/wonder-blocks-tokens/dist/es/index.js 5.01 kB
packages/wonder-blocks-toolbar/dist/es/index.js 906 B
packages/wonder-blocks-tooltip/dist/es/index.js 6.4 kB
packages/wonder-blocks-typography/dist/es/index.js 1.57 kB

compressed-size-action

@github-actions
Copy link
Contributor

github-actions bot commented Dec 3, 2025

A new build was pushed to Chromatic! 🚀

https://5e1bf4b385e3fb0020b7073c-fpqbiczclm.chromatic.com/

Chromatic results:

Metric Total
Captured snapshots 1
Tests with visual changes 1
Total stories 750
Inherited (not captured) snapshots [TurboSnap] 448
Tests on the build 449

@marcysutton marcysutton changed the title [DRAFT] WB Date Picker: initial migration WB Date Picker: initial migration Dec 3, 2025
@marcysutton marcysutton marked this pull request as ready for review December 3, 2025 21:10
@khan-actions-bot khan-actions-bot requested a review from a team December 3, 2025 21:10
@khan-actions-bot
Copy link
Contributor

khan-actions-bot commented Dec 3, 2025

Gerald

Required Reviewers
  • @Khan/wonder-blocks for changes to package.json, pnpm-lock.yaml, pnpm-workspace.yaml, tsconfig-build.json, .changeset/odd-scissors-suffer.md, build-settings/rollup.config.mjs, consistency-tests/tsconfig.json, __docs__/wonder-blocks-date-picker/_overview_.mdx, __docs__/wonder-blocks-date-picker/date-picker.argtypes.tsx, __docs__/wonder-blocks-date-picker/date-picker.stories.tsx, __docs__/wonder-blocks-date-picker/temporal-api.mdx, config/jest/css.mock.js, config/jest/test.config.js, packages/wonder-blocks-card/.npmignore, packages/wonder-blocks-date-picker/.npmignore, packages/wonder-blocks-date-picker/CHANGELOG.md, packages/wonder-blocks-date-picker/package.json, packages/wonder-blocks-date-picker/tsconfig-build.json, packages/wonder-blocks-core/src/index.ts, packages/wonder-blocks-date-picker/src/index.ts, packages/wonder-blocks-date-picker/src/components/date-picker-input.tsx, packages/wonder-blocks-date-picker/src/components/date-picker-overlay.tsx, packages/wonder-blocks-date-picker/src/components/date-picker.tsx, packages/wonder-blocks-date-picker/src/components/focus-manager.tsx, packages/wonder-blocks-date-picker/src/util/temporal-locale-utils.ts, packages/wonder-blocks-date-picker/src/util/types.ts, packages/wonder-blocks-date-picker/src/components/__tests__/date-picker-input.test.tsx, packages/wonder-blocks-date-picker/src/components/__tests__/date-picker-overlay.test.tsx, packages/wonder-blocks-date-picker/src/components/__tests__/date-picker.test.tsx, packages/wonder-blocks-date-picker/src/components/styles/react-day-picker.css, packages/wonder-blocks-date-picker/src/util/__tests__/temporal-locale-utils.test.ts

Don't want to be involved in this pull request? Comment #removeme and we won't notify you of further changes.

@marcysutton marcysutton changed the base branch from feature/datepicker to main December 4, 2025 17:22
@marcysutton marcysutton changed the base branch from main to feature/datepicker December 4, 2025 17:23
Copy link
Member

@beaesguerra beaesguerra left a comment

Choose a reason for hiding this comment

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

Exciting we're bringing the date picker to WB! Doing a first pass and left some questions! I haven't reviewed the UI components too deeply yet since a lot of it is moved over from frontend (let me know though if there are specific areas to pay more attention to!). I also haven't done some manual testing yet!

const extensions = [".js", ".jsx", ".ts", ".tsx"];

return {
external: (id) => id.endsWith(".css"),
Copy link
Member

Choose a reason for hiding this comment

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

I'm not too familiar with rollup so I was curious about this! I asked an LLM and it said: This tells Rollup: "Don't bundle CSS files into the output."

We don't currently include css from third parties in WB, so I'm wondering how that css will get consumed in frontend

I'm also curious about how it would fit in with the upcoming CSS modules work (cc: @jandrade in case he has thoughts on this!)

Copy link
Member Author

Choose a reason for hiding this comment

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

There might be a better way to do this, but the purpose was to get the date picker package to build. It was breaking on the CSS import for customization.

moduleNameMapper: {
"^@khanacademy/wonder-blocks-(.*)$":
"<rootDir>/packages/wonder-blocks-$1/src/index.ts",
"\\.(css|less|scss|sass)$": "<rootDir>/config/jest/css.mock.js",
Copy link
Member

Choose a reason for hiding this comment

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

Would consumers also need to set this up for things that use the date picker? I think maybe no since perseus and frontend uses css files already (?)

Copy link
Member Author

Choose a reason for hiding this comment

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

I assume because frontend already has this setup and it doesn't break testing or bundling, it should be fine?

Copy link
Member Author

Choose a reason for hiding this comment

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

This might not be applicable for consumers anymore because the CSS is bundled. But it was definitely needed for our tests!

Comment on lines +164 to +165
"react-day-picker": "catalog:",
"temporal-polyfill": "catalog:"
Copy link
Member

Choose a reason for hiding this comment

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

Should these be dependencies at the wonder-blocks-date-picker package level, rather than root?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point...maybe BirthdayPicker and DatePicker could each handle them instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually we do need these dependencies at the root, or our stories fail!

Comment on lines 9 to 14
MaybeNativeDatePicker,
DatePickerOverlay,
DatePickerInput,
DatePicker,
TemporalLocaleUtils,
type CustomModifiers,
Copy link
Member

Choose a reason for hiding this comment

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

Are there some exports that could be internal to WB only and don't need to be exported? For example, I see only the DatePicker uses the DatePickerOverlay component in frontend, so we could choose not to export it!

Less exports would mean less external facing APIs to maintain and we have more flexibility with internal breaking changes!

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we can get rid of DatePickerOverlay and its stories, which required the import. That one will be replaced by WB Floating and isn't really serving a purpose!

I'm not so sure about TemporalLocaleUtils and CustomModifiers, though. I started to move the locale utils into wonder-blocks-core before realizing it imports CustomModifiers, which imports a type from react-day-picker. So I think I'll opt to leave them be for now.

* Utility functions for working with Temporal dates in react-day-picker.
* These replace the MomentLocaleUtils that were previously used.
*
* Question: Should we move this to a separate package?
Copy link
Member

Choose a reason for hiding this comment

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

Good idea 💡 I think it would be useful to have date utilities, probably in a different package so consumers can use the date utilities without needing a dep on react-day-picker!

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a comment elsewhere in the PR discussion, but the CustomModifiers complicates things with an import from react-day-picker. That wrinkle makes me think it should live here.

import calendarIcon from "@phosphor-icons/core/bold/calendar-blank-bold.svg";
import type {CustomModifiers} from "../util/types";

interface Props {
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious if the DatePickerInput should also had a readonly state, similar to other form field components!

Copy link
Member Author

Choose a reason for hiding this comment

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

Ooh yes, probably! I will file an issue for a follow-up.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to use wb css variables for the line height and font size values?


const validateAndUpdate = React.useCallback(
(newDate?: Temporal.PlainDate | null) => {
// TODO: do we need to allow other locales/formats?
Copy link
Member

Choose a reason for hiding this comment

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

I would think we'd need to account for the locale!

Copy link
Member Author

Choose a reason for hiding this comment

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

Cool, that will be part of this ticket! https://khanacademy.atlassian.net/browse/FEI-7342

) {
/* eslint-disable-next-line no-alert
--
We really should have a different UX for this but this
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can use LabeledField for displaying error messages!

@khan-actions-bot khan-actions-bot requested a review from a team December 4, 2025 23:10
},
"references": [
{"path": "../packages/wonder-blocks-accordion/tsconfig-build.json"},
{"path": "../packages/wonder-blocks-birthday-picker/tsconfig-build.json"},
Copy link
Member Author

Choose a reason for hiding this comment

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

These packages were missing before, so I added them while I was in there.

@@ -0,0 +1,6 @@
*.tsbuildinfo
Copy link
Member Author

Choose a reason for hiding this comment

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

This too -- Card had missed some of the boilerplate files other packages have.

],
input: `packages/${pkgName}/src/index.ts`,
plugins: [
postcss({
Copy link
Member Author

Choose a reason for hiding this comment

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

I changed the logic to bundle the CSS, so consumers won't have to deal with it too! I verified we need the CSS import from react-day-picker to get a properly styled calendar, but the custom @layer styles were outdated so I removed them.

Copy link
Member

Choose a reason for hiding this comment

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

This would affect all the other packages, so I'm not sure if there is another approach we could take for this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it did break the the pnpm run dev script too. I restored the logic I had originally and added docs on how to include the stylesheet as a consumer!

@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (5036747) to head (2dd7f84).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##   feature/datepicker   #2876   +/-   ##
==========================================
==========================================

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5036747...2dd7f84. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@jandrade jandrade left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! I left multiple comments to simplify this PR and keep only the things we need for now. I think that after determining if we want/need to include the native input, then we should add that in a separate PR.

Copy link
Member

Choose a reason for hiding this comment

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

suggestion: I don't think we need to expose the package internals as we only expect devs to use DatePicker directly. These stories can be removed. Same with DatePickerOverlay and probably with MaybeNativeDatePicker (still TBD).

Copy link
Member Author

Choose a reason for hiding this comment

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

Good call. I removed them!

Copy link
Member

Choose a reason for hiding this comment

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

suggestion: As mentioned in other stories, I'm not sure if we are going to use this approach, or if we are going to use the picker directly in all devices. We should talk about this offline. For now, I think it's fine not to include this in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cool, I stored it in a branch to potentially revisit later!

],
input: `packages/${pkgName}/src/index.ts`,
plugins: [
postcss({
Copy link
Member

Choose a reason for hiding this comment

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

This would affect all the other packages, so I'm not sure if there is another approach we could take for this.

plugins: [
postcss({
// Extract CSS to a separate file
extract: path.resolve(`packages/${pkgName}/dist/index.css`),
Copy link
Member

Choose a reason for hiding this comment

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

hmmmm this might conflict with the CSS variables build setup (specially the wb-tokens package). Did you find any issues with the build? specially when used in frontend?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, so I changed it back to not bundle together!

Comment on lines 51 to 54
"react-router": "catalog:",
"react-router-dom": "catalog:",
"react-router-dom-v5-compat": "catalog:",
"react-window": "catalog:",
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: I don't think these deps are required by this package.

Copy link
Member

Choose a reason for hiding this comment

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

thought: As mentioned before, we might not need this logic anymore as we could end up using DatePicker directly. My hesitation about including this in the codebase is that we should experiment first if we are going to keep this approach or if we are going to allow using DatePicker directly (my initial inclination is the latter).

Depending on the approach we choose, it feels safer to just include DatePicker in this PR, then later include the rest of the implementation if we decide to include this Maybe.. wrapper.

Copy link
Member

Choose a reason for hiding this comment

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

suggestion: As the file comment says, DatePicker was unusable on iOS, but this was tested years ago. With v9, we might not need to use this wrapper anymore.

Comment on lines 9 to 11
DatePickerInput,
DatePicker,
TemporalLocaleUtils,
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: we should probably only expose DatePicker and TemporalLocaleUtils if these are going to be needed by consumers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants