# Contributing to react-live Thanks for contributing! This guide covers the local dev workflow and how releases work. ## Setup npm workspaces, Node LTS -- `nvm use` picks it up from `.nvmrc`. ```sh npm install npm run build:lib # build the library once -- the docs site resolves react-live to dist ``` Skip the build and `npm run check:types` and `npm run start:docs` will fail with `Cannot find module 'react-live'`. Nothing builds implicitly; there is no `prepare` hook. | Path | What it is | | -------------------------------------------- | ----------------------------------------------------- | | [`packages/react-live`](packages/react-live) | The published package. The only thing released. | | [`website`](website) | The Docusaurus docs site, deployed to Vercel. | | [`docs`](docs) | Markdown, rendered by the website from the repo root. | ## Commands All from the repo root. ```sh npm run check # lint + format + types + tests -- run this before opening a PR npm run format # auto-fix: prettier + oxlint --fix npm test # unit tests (vitest, jsdom) npm run stories # dev server: browse component scenarios by hand npm run stories:test # the same stories + interaction tests, in real Chromium npm run build # library, then docs site npm run start:docs # run the docs site locally ``` Inside `packages/react-live` there are also `test:watch`, `test:coverage`, and `build:watch`. ## Tests Unit tests are colocated with the source under [`packages/react-live/src`](packages/react-live/src). Files containing JSX use a `.jsx` extension — Vite will not parse JSX in a `.js` file. `npm run stories:test` runs the real-browser suite and needs a Chromium binary once: ```sh npx playwright install chromium ``` It covers what jsdom structurally cannot — typing, caret position, `tabMode` — because jsdom has no contentEditable editing model. It is not part of `npm run check`. Two things to know when writing tests: - **Await the settle.** `LiveProvider` transpiles in an effect, so assert after an `await screen.findBy*` query, not on the first paint. React `act()` warnings fail the run. - **Assert caret position behaviourally** — type a character and check where it lands. Prism splits lines into many token spans, so raw `Selection` offsets are not what you expect. ## Stories Stories live in [`packages/react-live/stories`](packages/react-live/stories) as `*.stories.tsx`. A story names a component and the props to render it with: ```tsx export const title = "Live"; export const Inline = story(LiveProvider, { args: { code: "Hello World!" }, }); ``` `args` is typed as that component's props, so a renamed, missing, or mistyped prop fails `npm run typecheck` instead of surfacing during a manual browse. Pass `render` only when a scenario needs more than a single element — local state, sibling markup, a different composition: ```tsx export const TabFocus = story(Editor, { args: { code: "// press Tab to leave", language: "javascript", tabMode: "focus", }, render: (args) => ( <> ), }); ``` Add a file matching `*.stories.tsx` and it appears in the sidebar automatically. The dev server aliases `react-live` to source, so library edits hot-reload with no build step. `npm run stories:test` smoke-renders every story through the same loader, so a broken story fails CI. A story that throws on purpose sets `expectsError: true`. Two modules back the harness, kept apart deliberately: `story.ts` defines a story and `load.ts` discovers them. Merging them makes the eager glob import the story files while `story()` is still initialising, which fails at import time — where no type-check would have caught it. ## Changesets If your change affects published behaviour, add a changeset and commit it with your PR: ```sh npm run changeset ``` Pick a bump type (`patch` for fixes, `minor` for backwards-compatible features, `major` for breaking changes) and write the summary for a changelog reader. PRs with no user-facing change — docs, CI, tests, refactors — don't need one. ## Releasing Automated. Merging PRs with changesets to `master` opens (or updates) a **"Version Packages"** PR; merging that publishes to npm over GitHub OIDC ([trusted publishing](https://docs.npmjs.com/trusted-publishers/)), so no npm token is stored and provenance is attached automatically. The publish job requires approval in the `Production` environment. The docs site deploys to Vercel from `website`, building with `npm run build:prod`. To inspect the tarball locally, use `npm pack` — not `npm pack --dry-run`. The build runs publint and attw, which pack the package themselves, and the nested pack inherits the `--dry-run` flag and finds no tarball. The release path is unaffected. ## Code of Conduct See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).