From 9fbbf841bcda38fef961213dd506771e2584276a Mon Sep 17 00:00:00 2001 From: dav-is Date: Thu, 19 Mar 2026 22:56:52 -0400 Subject: [PATCH 01/45] Integrate useEditable() and pass controller to abstractCreateDemoClient() --- .../demos/code-editor/CodeEditorContent.tsx | 13 +- .../demos/demo-live/DemoLive.tsx | 5 +- .../demos/demo-live/DemoLiveContent.tsx | 12 +- .../demos/demo-live/createDemoClient.ts | 3 +- .../demos/multi-file/MultiFileContent.tsx | 13 +- .../code-controller-context/page.mdx | 43 +-- .../abstract-create-demo-client/page.mdx | 18 +- docs/app/docs-infra/hooks/use-demo/page.mdx | 12 +- packages/docs-infra/package.json | 3 +- .../abstractCreateDemoClient.tsx | 62 ++-- packages/docs-infra/src/useCode/Pre.tsx | 32 ++ packages/docs-infra/src/useCode/useCode.ts | 29 +- .../src/useCode/useFileNavigation.test.ts | 6 +- .../src/useCode/useFileNavigation.tsx | 27 +- .../src/useCode/useSourceEditing.test.ts | 281 ++++++++++++++++++ .../src/useCode/useSourceEditing.ts | 114 +++++-- pnpm-lock.yaml | 3 + 17 files changed, 520 insertions(+), 156 deletions(-) create mode 100644 packages/docs-infra/src/useCode/useSourceEditing.test.ts diff --git a/docs/app/docs-infra/components/code-controller-context/demos/code-editor/CodeEditorContent.tsx b/docs/app/docs-infra/components/code-controller-context/demos/code-editor/CodeEditorContent.tsx index 2f9972650..3711b5f15 100644 --- a/docs/app/docs-infra/components/code-controller-context/demos/code-editor/CodeEditorContent.tsx +++ b/docs/app/docs-infra/components/code-controller-context/demos/code-editor/CodeEditorContent.tsx @@ -1,7 +1,6 @@ 'use client'; import * as React from 'react'; -import { useEditable } from 'use-editable'; import type { ContentProps } from '@mui/internal-docs-infra/CodeHighlighter/types'; import { useCode } from '@mui/internal-docs-infra/useCode'; import { LabeledSwitch } from '@/components/LabeledSwitch'; @@ -10,8 +9,7 @@ import styles from './CodeEditorContent.module.css'; import '@wooorm/starry-night/style/light'; // load the light theme for syntax highlighting export function CodeEditorContent(props: ContentProps) { - const preRef = React.useRef(null); - const code = useCode(props, { preClassName: styles.codeBlock, preRef }); + const code = useCode(props, { preClassName: styles.codeBlock }); const hasJsTransform = code.availableTransforms.includes('js'); const isJsSelected = code.selectedTransform === 'js'; @@ -23,15 +21,6 @@ export function CodeEditorContent(props: ContentProps) { [code], ); - const onInput = React.useCallback( - (text: string) => { - code.setSource?.(text); - }, - [code], - ); - - useEditable(preRef, onInput, { indentation: 2 }); - return (
diff --git a/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLive.tsx b/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLive.tsx index e634b8568..8352553a9 100644 --- a/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLive.tsx +++ b/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLive.tsx @@ -1,14 +1,11 @@ import * as React from 'react'; import { CodeProvider } from '@mui/internal-docs-infra/CodeProvider'; -import { DemoController } from './DemoController'; import { DemoCheckboxBasic } from './demo-basic'; export function DemoLive() { return ( - - - + ); } diff --git a/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLiveContent.tsx b/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLiveContent.tsx index 167c91925..f62adebd1 100644 --- a/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLiveContent.tsx +++ b/docs/app/docs-infra/components/code-controller-context/demos/demo-live/DemoLiveContent.tsx @@ -1,7 +1,6 @@ 'use client'; import * as React from 'react'; -import { useEditable } from 'use-editable'; import type { ContentProps } from '@mui/internal-docs-infra/CodeHighlighter/types'; import { useDemo } from '@mui/internal-docs-infra/useDemo'; import { LabeledSwitch } from '@/components/LabeledSwitch'; @@ -16,8 +15,7 @@ const variantNames: Record = { }; export function DemoLiveContent(props: ContentProps) { - const preRef = React.useRef(null); - const demo = useDemo(props, { preClassName: styles.codeBlock, preRef }); + const demo = useDemo(props, { preClassName: styles.codeBlock }); const hasJsTransform = demo.availableTransforms.includes('js'); const isJsSelected = demo.selectedTransform === 'js'; @@ -40,14 +38,6 @@ export function DemoLiveContent(props: ContentProps) { [demo.variants], ); - const onChange = React.useCallback( - (text: string) => { - demo.setSource?.(text); - }, - [demo], - ); - useEditable(preRef, onChange, { indentation: 2, disabled: !demo.setSource }); - return (
{demo.component}
diff --git a/docs/app/docs-infra/components/code-controller-context/demos/demo-live/createDemoClient.ts b/docs/app/docs-infra/components/code-controller-context/demos/demo-live/createDemoClient.ts index 74c12378e..a0761d9f9 100644 --- a/docs/app/docs-infra/components/code-controller-context/demos/demo-live/createDemoClient.ts +++ b/docs/app/docs-infra/components/code-controller-context/demos/demo-live/createDemoClient.ts @@ -1,6 +1,7 @@ 'use client'; import { createDemoClientFactory } from '@mui/internal-docs-infra/abstractCreateDemoClient'; +import { DemoController } from './DemoController'; /** * Creates a demo client copying dependencies in the client bundle for live editing. @@ -8,5 +9,5 @@ import { createDemoClientFactory } from '@mui/internal-docs-infra/abstractCreate * @param meta Additional meta and modules for the demo client. */ export const createDemoClient = createDemoClientFactory({ - live: true, + DemoController, }); diff --git a/docs/app/docs-infra/components/code-controller-context/demos/multi-file/MultiFileContent.tsx b/docs/app/docs-infra/components/code-controller-context/demos/multi-file/MultiFileContent.tsx index a447eebe9..f650db127 100644 --- a/docs/app/docs-infra/components/code-controller-context/demos/multi-file/MultiFileContent.tsx +++ b/docs/app/docs-infra/components/code-controller-context/demos/multi-file/MultiFileContent.tsx @@ -1,7 +1,6 @@ 'use client'; import * as React from 'react'; -import { useEditable } from 'use-editable'; import type { ContentProps } from '@mui/internal-docs-infra/CodeHighlighter/types'; import { useCode } from '@mui/internal-docs-infra/useCode'; import { Tabs } from '@/components/Tabs'; @@ -10,8 +9,7 @@ import styles from '../code-editor/CodeEditorContent.module.css'; import '@wooorm/starry-night/style/light'; export function MultiFileContent(props: ContentProps) { - const preRef = React.useRef(null); - const code = useCode(props, { preClassName: styles.codeBlock, preRef }); + const code = useCode(props, { preClassName: styles.codeBlock }); const tabs = React.useMemo(() => { return code.files.map(({ name }) => ({ @@ -20,15 +18,6 @@ export function MultiFileContent(props: ContentProps) { })); }, [code.files]); - const onInput = React.useCallback( - (text: string) => { - code.setSource?.(text); - }, - [code], - ); - - useEditable(preRef, onInput, { indentation: 2 }); - return (
diff --git a/docs/app/docs-infra/components/code-controller-context/page.mdx b/docs/app/docs-infra/components/code-controller-context/page.mdx index 317172eef..a5920b4cb 100644 --- a/docs/app/docs-infra/components/code-controller-context/page.mdx +++ b/docs/app/docs-infra/components/code-controller-context/page.mdx @@ -137,22 +137,10 @@ The [`useCode`](../use-code/page.mdx) hook automatically integrates with the Cod ```tsx 'use client'; -import { useEditable } from 'use-editable'; import { useCode } from '@mui/internal-docs-infra/useCode'; function EditorContent(props) { - const preRef = React.useRef(null); - const code = useCode(props, { preRef }); - - // code.setSource updates the controller automatically - const onInput = React.useCallback( - (text: string) => { - code.setSource?.(text); - }, - [code], - ); - - useEditable(preRef, onInput, { indentation: 2 }); + const code = useCode(props); return (
@@ -165,7 +153,8 @@ function EditorContent(props) { ## Working with useDemo Hook -The [`useDemo`](../use-demo/page.mdx) hook provides additional functionality for live component demos: +The [`useDemo`](../use-demo/page.mdx) hook provides additional functionality for live component demos. +Editing is handled automatically by the `Pre` component — just render `demo.selectedFile`: ```tsx 'use client'; @@ -175,19 +164,12 @@ import { useDemo } from '@mui/internal-docs-infra/useDemo'; function DemoContent(props) { const demo = useDemo(props); - const onInput = React.useCallback( - (text: string) => { - demo.setSource?.(text); - }, - [demo], - ); - return (
{/* Live component preview */}
{demo.component}
- {/* Editable source code */} + {/* Editable source code — editing is handled automatically */}
-