Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWXTUM9dpnCS2wtFkx4
4.3 KiB
Port @kuhyx/web-ui from React to Astro + vanilla TS
what
kuhy chose one framework for every web UI: Astro, with no React islands. This
package is the first blocker. RangeSlider is its only React export. It
becomes RangeSlider.astro plus a <range-slider> custom element. The
pure-TS helpers and the CSS stay as they are. Every repo's
TODO-astro-migration.md waits for the tag this produces.
steps
- Keep these as they are:
quantile.ts(nth,clamp01,quantileValue,valueQuantile,fractionFromPointer),stepped-value.ts(keyTarget,steppedValue),text.ts(fuzzyMatch),tokens.css,range-slider.css. - Write
src/range-slider-element.ts, aRangeSliderElement extends HTMLElementregistered asrange-slider. Inputs: avaluesproperty (number[]),loandhiattributes, alabelattribute, and aformatproperty (a function). Output: a bubblingchangeCustomEvent with{ lo, hi }. Keep the current DOM: two<button role="slider">thumbs witharia-valuemin,aria-valuemaxandaria-valuenow, grab-the-nearer-thumb on pointer, and the keyboard map in README.md. All of the logic stays in the existing pure helpers. - Write
src/RangeSlider.astro. It server-renders the same markup (track, thumbs, optional head) inside<range-slider>. Its<script>imports the element module, so including the component registers the element. - Order: element and its tests first, then the
.astrowrapper, then exports and packaging, then README, then the tag. - Packaging. tsc cannot emit
.astro, so ship the.astrosource as it is. Astro compiles.astrofiles from dependencies. Add toexports:"./RangeSlider.astro": "./src/RangeSlider.astro"and"./range-slider": "./dist/range-slider-element.js". Addsrc/*.astrotofiles. Keepdist/committed for the.tsoutput. The.astroscript imports../dist/range-slider-element.js, never the.tssource. - Consumers import it like this:
import RangeSlider from "@kuhyx/web-ui/RangeSlider.astro";in frontmatter. Scripts useimport "@kuhyx/web-ui/range-slider";and listen forchange. Tokens stayimport "@kuhyx/web-ui/tokens.css";in the shared layout. - Dependencies, all exact pins via pnpm: drop
peerDependencies.react,react,react-dom,@types/react,@types/react-domand@testing-library/react. Addastro@7.4.4as a devDependency (for the Container API andastro check),@astrojs/check@0.9.12and@testing-library/domat its newest stable. AddpeerDependencies.astro: ">=7.4.0". - Tests.
range-slider.test.tsxbecomesrange-slider-element.test.ts, which covers the custom element in jsdom: pointer, keyboard, thechangeevent and the ARIA attributes. AddRangeSlider.astro.test.ts, which usesexperimental_AstroContainerto check the server markup. Keep coverage at 100% forsrc/**/*.ts. Exclude.astrofrom coverage, since its script holds only the import. - Rewrite README.md's Install and "What's here" sections for the Astro API.
Then tag
web_ui-v0.5.0. Before tagging, runpnpm build.
done
Run from ~/src/utils/web_ui:
pnpm install --frozen-lockfile && pnpm lint && pnpm coverage && pnpm build && ! grep -q '"react"' package.json && ! find src -name '*.tsx' | grep -q . && git tag -l web_ui-v0.5.0 | grep -q .
This exits 0.
verify
Do it in the first consumer migrated, awesome-mcp-explorer, because it uses
RangeSlider. Check that the slider drags and that arrow keys and Home/End
step. Use a headless chromium at 4K and at a mobile viewport. The filter must
update and there must be no console errors.
read first
~/src/utils/web_ui/README.md: keyboard map, why&path:/web_ui, release steps.~/src/utils/web_ui/src/range-slider.tsxandrange-slider.test.tsx.- The consumers and their tags:
- control-panel/web: v0.3.2
- signal-bot/web: v0.3.1
- dufs-cloud/web: v0.3.1
- awesome-mcp-explorer: v0.3.1
- foss-audit: v0.4.0
- Astro docs: "Publish to NPM" (shipping
.astro), andreference/container-reference.
order
Migration order across kuhy's repos:
web_uifirst (this file), because every other repo waits for its tag.- Content sites next (public sites, e.g. teatr-pw's Astro version).
- Small apps after.
control-panelandsteam-backlog-enforcerlast, after every other repo.
REMOVE ME AFTER FINISH