Skip to content

[docs-infra] Let a headless host edit through its controller alone - #1785

Draft
brijeshb42 wants to merge 1 commit into
di-migration-live-demo-providerfrom
di-migration-controller-code
Draft

[docs-infra] Let a headless host edit through its controller alone#1785
brijeshb42 wants to merge 1 commit into
di-migration-live-demo-providerfrom
di-migration-controller-code

Conversation

@brijeshb42

Copy link
Copy Markdown
Contributor

Eleventh in the docs-infra migration stack, on top of #1784. It closes the two gaps Material UI hit while adopting the headless API for live editing.

A headless host had no way to receive edits. LiveDemoProvider installs a CodeControllerContext and nothing else, but useCode read both the reader's edits and its setCode from CodeHighlighterContext, which only CodeHighlighter publishes. A host that renders the source panel itself got a controller its edits never reached, and had to hand-assemble a highlighter context to work around it — using an unexported internal.

useCode now falls back to the controller for both. The controlled code holds only the variants that were edited, so it is merged over the build-time map rather than replacing it; otherwise the first edit would drop every untouched variant. A highlighter context still wins where one exists, since it does this merging itself.

A projected edit needed bookkeeping every host would repeat. While a block is collapsed, a headless host's editor holds only the projected slice. Sending that slice as the source produces a file with no imports — it does not run — and, once patched, the projection's offsets are stale for the next edit.

setProjectedSource(slice) does what CodeEditor already does for the internal editor: patches the slice back into the complete source with its hidden indentation restored, and moves the projection's end to match. It falls back to replacing the whole file when there is no projection.

Both were found by wiring Material UI's experiment fixture to live editing, where the symptoms were ReferenceError: Stack is not defined on the first preview edit and a second edit splicing at the wrong offset.

Gate: 51 browser tests across chromium, firefox, and webkit — 6 new, covering editing with a controller and no highlighter, and two successive projected edits landing correctly — plus a clean typecheck, lint, and docs:validate. The 41 user.spec.ts failures are the pre-existing ones.

@brijeshb42 brijeshb42 added the scope: docs-infra Involves the docs-infra product (https://www.notion.so/mui-org/b9f676062eb94747b6768209f7751305). label Aug 14, 2026
@code-infra-dashboard

code-infra-dashboard Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy preview

https://deploy-preview-1785--mui-internal.netlify.app/
QR code for https://deploy-preview-1785--mui-internal.netlify.app/

Bundle size

Total Size Change: 🔺+1.25KB(+0.04%) - Total Gzip Change: 🔺+545B(+0.06%)
Files: 73 total (1 added, 0 removed, 4 changed)

Show details for 73 more bundles

@mui/internal-docs-infra/useCodeparsed: 🔺+572B(+0.52%) gzip: 🔺+186B(+0.51%)
@mui/internal-docs-infra/useDemoparsed: 🔺+568B(+0.44%) gzip: 🔺+208B(+0.49%)
createEditableSourceProjectionparsed: 🔺+275B(new) gzip: 🔺+213B(new)
CodeEditorparsed: ▼-165B(-3.82%) gzip: ▼-59B(-3.08%)
CodeContextparsed: ▼-3B(-3.45%) gzip: ▼-3B(-3.06%)
@mui/internal-docs-infra/abstractCreateDemoparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateDemoClientparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateStreamparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateTypesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/ChunkProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/cliparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeControllerContextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeExternalsContextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighterparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter/errorsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CoordinatedLazyparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CoordinatedLazy/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createDemoDataparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createDemoData/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createSitemapparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createSitemap/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/LiveDemoProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCodeWindowparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCoordinatedparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCopierparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCrossTabStateparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useDemoControllerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useErrorsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useLocalStorageStateparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/usePreferenceparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useScrollAnchorparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useSearchparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useSearch/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useStreamparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useStream/typesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useTypeparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useTypesparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useUrlHashStateparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/withDocsInfraparsed: 0B(0.00%) gzip: 0B(0.00%)
addLineGuttersparsed: 0B(0.00%) gzip: 0B(0.00%)
BuildEngineparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeHighlighterChunkparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeHighlighterClientparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeInitialSourceLoaderparsed: 0B(0.00%) gzip: 0B(0.00%)
CodeSourceLoaderparsed: 0B(0.00%) gzip: 0B(0.00%)
compileCssWithPostcssparsed: 0B(0.00%) gzip: 0B(0.00%)
createFrameparsed: 0B(0.00%) gzip: 0B(0.00%)
createParseSourceWorkerClientparsed: 0B(0.00%) gzip: 0B(0.00%)
EditingEngineparsed: 0B(0.00%) gzip: 0B(0.00%)
embedTransformsparsed: 0B(0.00%) gzip: 0B(0.00%)
enhanceCodeEmphasisparsed: 0B(0.00%) gzip: 0B(0.00%)
findExpandingRangesparsed: 0B(0.00%) gzip: 0B(0.00%)
getHastTextContentparsed: 0B(0.00%) gzip: 0B(0.00%)
grammarLoadersparsed: 0B(0.00%) gzip: 0B(0.00%)
grammarsparsed: 0B(0.00%) gzip: 0B(0.00%)
isFrameSpanparsed: 0B(0.00%) gzip: 0B(0.00%)
loadIsomorphicCodeVariantparsed: 0B(0.00%) gzip: 0B(0.00%)
parseSourceparsed: 0B(0.00%) gzip: 0B(0.00%)
rolldown-runtimeparsed: 0B(0.00%) gzip: 0B(0.00%)
source.cssparsed: 0B(0.00%) gzip: 0B(0.00%)
source.jsparsed: 0B(0.00%) gzip: 0B(0.00%)
source.jsonparsed: 0B(0.00%) gzip: 0B(0.00%)
source.mdxparsed: 0B(0.00%) gzip: 0B(0.00%)
source.shellparsed: 0B(0.00%) gzip: 0B(0.00%)
source.tsparsed: 0B(0.00%) gzip: 0B(0.00%)
source.tsxparsed: 0B(0.00%) gzip: 0B(0.00%)
source.yamlparsed: 0B(0.00%) gzip: 0B(0.00%)
text.html.basicparsed: 0B(0.00%) gzip: 0B(0.00%)
text.mdparsed: 0B(0.00%) gzip: 0B(0.00%)
TransformEngineparsed: 0B(0.00%) gzip: 0B(0.00%)
transpileSourceparsed: 0B(0.00%) gzip: 0B(0.00%)

Details of bundle changes

Performance

Total duration: 20.53 ms 🔺+3.68 ms(+21.8%) | Renders: 5 (+0) | Paint: 76.43 ms 🔺+15.37 ms(+25.2%)

Test Duration Renders
HeavyList mount 11.26 ms 🔺+3.22 ms(+40.0%) 1 (+0)

6 tests within noise — details

Metric alarms

Test Metric Change
HeavyList mount bench:paint 🔺 +14.32 ms

Check out the code infra dashboard for more information about this PR.

A headless host wires editing through `LiveDemoProvider`, which installs a
`CodeControllerContext` and nothing else. `useCode` read the reader's edits
and its `setCode` from the `CodeHighlighterContext` instead, which only
`CodeHighlighter` publishes — so a host that renders the source itself got a
controller its edits never reached, and had to hand-assemble a highlighter
context to work around it.

`useCode` now falls back to the controller for both. The controlled code
holds only the variants that were edited, so it is merged over the
build-time map rather than replacing it; otherwise the first edit would drop
every untouched variant. A highlighter context still wins where one exists,
since it does this merging itself.
@brijeshb42
brijeshb42 force-pushed the di-migration-live-demo-provider branch from 5ed9f0e to c19fef3 Compare August 14, 2026 18:44
@brijeshb42
brijeshb42 force-pushed the di-migration-controller-code branch from dd7ba7f to 52efcfa Compare August 14, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: docs-infra Involves the docs-infra product (https://www.notion.so/mui-org/b9f676062eb94747b6768209f7751305).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant