From 843df96f907288e9dc016f4e94d98365d2be31b0 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 15 Jan 2025 11:08:36 +0100 Subject: [PATCH 1/9] docs --- apps/www/content/docs/en/typescript.mdx | 191 ++++++++++++++++++++++++ apps/www/src/config/docs-plugins.ts | 10 +- apps/www/src/config/docs.ts | 5 + 3 files changed, 197 insertions(+), 9 deletions(-) create mode 100644 apps/www/content/docs/en/typescript.mdx diff --git a/apps/www/content/docs/en/typescript.mdx b/apps/www/content/docs/en/typescript.mdx new file mode 100644 index 0000000000..2b948d3410 --- /dev/null +++ b/apps/www/content/docs/en/typescript.mdx @@ -0,0 +1,191 @@ +--- +title: TypeScript +description: Configure TypeScript (tsconfig) for using Plate, including module resolution solutions. +--- + +Plate provides ESM packages, which require certain TypeScript (and bundler) configurations to ensure compatibility, especially when importing subpath modules like `@udecode/plate/react`. Below are several solutions and workarounds to make TypeScript happy. + +## Quick Summary + +1. **Recommended (Easiest):** Set `"moduleResolution": "bundler"` in your `tsconfig.json`. +2. **Alternate (Node resolution):** Keep `"moduleResolution": "node"` and map paths to `dist/react` (and potentially alias them in your bundler config). +3. **Up-to-date Packages:** Ensure all `@udecode/plate-*` dependencies share the same major/minor version. + +## Why Import Error Happens + +Plate packages provide multiple exports, including a `react` folder in each package for React-specific code. When TypeScript's older or default module resolution strategy encounters these subpath imports (e.g., `@udecode/plate-something/react`), it may fail to find the corresponding type declarations unless: + +1. You switch to a resolution mode that's aware of ESM exports and subpaths, or +2. You manually alias or map these subpaths back to the correct `dist/react/index.d.ts`. + +## Recommended: `"moduleResolution": "bundler"` + +The simplest approach for modern bundlers (Vite, Next.js 14, etc.) is to enable the new TypeScript "bundler" resolution mode. Example: + +```jsonc +// tsconfig.json +{ + "compilerOptions": { + // ... + "module": "esnext", + "moduleResolution": "bundler", + // ... + } +} +``` + +This aligns TypeScript's resolution logic more closely with modern bundlers and ESM packages. Below is a working excerpt from [Plate template](https://github.com/udecode/plate-template): + +```jsonc +{ + "compilerOptions": { + "strict": false, + "strictNullChecks": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": false, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": false, + "noPropertyAccessFromIndexSignature": false, + "noUncheckedIndexedAccess": false, + "noUnusedLocals": false, + "noUnusedParameters": false, + + "isolatedModules": true, + + "allowJs": true, + "checkJs": false, + + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + + "lib": ["dom", "dom.iterable", "esnext"], + "jsx": "preserve", + "module": "esnext", + "target": "es2022", + "moduleResolution": "bundler", + "moduleDetection": "force", + "resolveJsonModule": true, + "noEmit": true, + "incremental": true, + "sourceMap": true, + + "baseUrl": "src", + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + ".next/types/**/*.ts", + "src/**/*.ts", + "src/**/*.tsx" + ], + "exclude": ["node_modules"] +} +``` + +**Why `moduleResolution = bundler`?** +- It properly handles subpath imports in ESM packages. +- It's the recommended solution moving forward as bundlers evolve. + +## Workaround: Keep `"moduleResolution": "node"` + Path Aliases + +If switching to `"moduleResolution": "bundler"` is not possible in a large codebase (or conflicts with older dependencies), you can manually map the subpath imports to their actual locations. For example: + +```jsonc +// tsconfig.json +{ + "compilerOptions": { + "moduleResolution": "node", + "paths": { + "@udecode/plate/react": [ + "./node_modules/@udecode/plate/dist/react/index.d.ts" + ], + "@udecode/plate-core/react": [ + "./node_modules/@udecode/plate-core/dist/react/index.d.ts" + ], + "@udecode/plate-list/react": [ + "./node_modules/@udecode/plate-list/dist/react/index.d.ts" + ] + // ...repeat for all @udecode/plate-*/react packages in use + } + } +} +``` + +Additionally, in your bundler config (e.g. `vite.config.ts`), create aliases so that runtime imports resolve to the correct directories: + +```ts +import { defineConfig } from 'vite'; +import path from 'path'; + +export default defineConfig({ + resolve: { + alias: { + '@udecode/plate/react': path.resolve( + __dirname, + 'node_modules/@udecode/plate/dist/react' + ), + '@udecode/plate-core/react': path.resolve( + __dirname, + 'node_modules/@udecode/plate-core/dist/react' + ), + '@udecode/plate-list/react': path.resolve( + __dirname, + 'node_modules/@udecode/plate-list/dist/react' + ), + + // Non-/react base aliases: + '@udecode/plate': path.resolve( + __dirname, + 'node_modules/@udecode/plate' + ), + '@udecode/plate-core': path.resolve( + __dirname, + 'node_modules/@udecode/plate-core' + ), + '@udecode/plate-list': path.resolve( + __dirname, + 'node_modules/@udecode/plate-list' + ) + + // ...repeat for your actual set of Plate packages + } + } +}); +``` + +### Notes & Caveats +- You must replicate this pattern for **every** Plate package that you import with `@udecode/plate-xyz/react`. +- You may also need to configure Jest or other testing environments with the same aliases. +- This approach is more verbose and can become fragile if the packages or file structures change. + +## Ensure Matching Plate Versions + +Say you're upgrading one package to `42.0.3`, double-check that all your `@udecode/plate-*` packages are on the **latest version up to 42.0.3** (one package could stay at `42.0.2` if it has no `42.0.3` release). Mixing versions often leads to mismatches. + +## FAQ + +**Q**: "I updated `moduleResolution` to `bundler` but it broke my older imports." +**A**: If your codebase has older TS usage or relies on the older Node resolution, you might try partial migration or switch to the path alias approach until all dependencies can handle ESM properly. + +**Q**: "I want to keep `moduleResolution` as `node`. Are there official type definitions for the `/react` subpaths?" +**A**: All subpaths do have `.d.ts` files in `dist/react`. The path alias approach above is the recommended manual fix if you cannot do `bundler`. + +**Q**: "Do I have to alias each `@udecode/plate-*` package, or can I do a wildcard?" +**A**: Typically, you must do them individually because each has a unique `dist/react` folder. A wildcard might work in some bundler configurations, but it's trickier in TS's `paths` since each subpath needs an explicit mapping. + +**Q**: "What if I use an older Next.js version or a custom Webpack config?" +**A**: The principle is the same—add webpack aliases or switch your TS `moduleResolution`. If you have any custom Next config, you can alias the subpaths under `webpack.resolve.alias`. + +**Q**: "I still get type errors in Jest." +**A**: You'll need to replicate the same alias or resolution changes in your Jest config. For example, using `moduleNameMapper` in `jest.config.js`: + ```js + moduleNameMapper: { + '^@udecode/plate/react$': '/node_modules/@udecode/plate/dist/react', + // ... + } + ``` diff --git a/apps/www/src/config/docs-plugins.ts b/apps/www/src/config/docs-plugins.ts index b2cd1587c2..8c59d9a2ca 100644 --- a/apps/www/src/config/docs-plugins.ts +++ b/apps/www/src/config/docs-plugins.ts @@ -41,7 +41,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ { description: 'Provides quick access to block-specific actions.', href: '/docs/block-menu', - label: 'New', title: 'Block Menu', }, { @@ -52,7 +51,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ { description: 'Highlight important information or add special notes.', href: '/docs/callout', - label: 'New', title: 'Callout', }, { @@ -85,7 +83,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ { description: 'A visual overlay for cursors and selections.', href: '/docs/cursor-overlay', - label: 'New', title: 'Cursor Overlay', }, { @@ -109,7 +106,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ description: 'Enables the insertion and rendering of LaTeX equations in your editor.', href: '/docs/equation', - label: 'New', title: 'Equation', }, { @@ -182,7 +178,7 @@ export const pluginsNavItems: SidebarNavItem[] = [ { description: 'Embed medias like videos or tweets into your document.', href: '/docs/media', - label: ['Element', 'New'], + label: ['Element'], title: 'Media', }, { @@ -200,7 +196,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ { description: 'Automatically assign unique IDs to nodes in the document.', href: '/docs/node-id', - label: 'New', title: 'Node ID', }, { @@ -239,7 +234,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ description: 'Slash command menu for quick insertion of various content types.', href: '/docs/slash-command', - label: 'New', title: 'Slash Command', }, { @@ -264,7 +258,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ description: 'Renders a table of contents element with clickable links to headings in the document.', href: '/docs/toc', - label: 'New', title: 'Table of Contents', }, { @@ -276,7 +269,6 @@ export const pluginsNavItems: SidebarNavItem[] = [ { description: 'Ensure a trailing block is always present in the document.', href: '/docs/trailing-block', - label: 'New', title: 'Trailing Block', }, ]; diff --git a/apps/www/src/config/docs.ts b/apps/www/src/config/docs.ts index e35e630594..b49c520e72 100644 --- a/apps/www/src/config/docs.ts +++ b/apps/www/src/config/docs.ts @@ -98,6 +98,11 @@ export const guidesNavItems: SidebarNavItem[] = [ label: 'New', title: 'Serializing HTML', }, + { + href: '/docs/typescript', + label: 'New', + title: 'TypeScript', + }, { href: '/docs/debugging', title: 'Debugging', From c070094e9e85d381522e71a2e9e40c79a58a629d Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 15 Jan 2025 11:26:33 +0100 Subject: [PATCH 2/9] docs --- apps/www/content/docs/en/getting-started.mdx | 20 ++++- apps/www/content/docs/en/typescript.mdx | 86 ++++++++++++-------- 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/apps/www/content/docs/en/getting-started.mdx b/apps/www/content/docs/en/getting-started.mdx index 6a2b5101a7..d7560702e2 100644 --- a/apps/www/content/docs/en/getting-started.mdx +++ b/apps/www/content/docs/en/getting-started.mdx @@ -22,7 +22,7 @@ For an existing React project, jump to the next step. First, install the core dependencies: ```bash -npm install @udecode/plate slate-react slate-history +npm install @udecode/plate ``` For the examples in this guide, we'll also use these plugins: @@ -36,6 +36,24 @@ npm install @udecode/plate-basic-marks @udecode/plate-heading @udecode/plate-blo - `@udecode/plate-block-quote` adds blockquote support. - `@udecode/cn` helps with component styling (optional). +### TypeScript Requirements + +Ensure your `tsconfig.json` is properly configured. The recommended setup for Plate requires TypeScript 5.0+ with the `"bundler"` module resolution: + +```jsonc +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + // ... other options + } +} +``` + + + **Note**: If you can't use TypeScript 5.0+ or "bundler" resolution, see the [TypeScript](/docs/typescript) page for alternative solutions using path aliases. + + ### Basic Editor Let's start with a minimal editor setup. diff --git a/apps/www/content/docs/en/typescript.mdx b/apps/www/content/docs/en/typescript.mdx index 2b948d3410..65e5e2a3de 100644 --- a/apps/www/content/docs/en/typescript.mdx +++ b/apps/www/content/docs/en/typescript.mdx @@ -7,16 +7,10 @@ Plate provides ESM packages, which require certain TypeScript (and bundler) conf ## Quick Summary -1. **Recommended (Easiest):** Set `"moduleResolution": "bundler"` in your `tsconfig.json`. +1. **Recommended (Easiest):** Use TypeScript **5.0+** and set `"moduleResolution": "bundler"` in your `tsconfig.json`. 2. **Alternate (Node resolution):** Keep `"moduleResolution": "node"` and map paths to `dist/react` (and potentially alias them in your bundler config). 3. **Up-to-date Packages:** Ensure all `@udecode/plate-*` dependencies share the same major/minor version. -## Why Import Error Happens - -Plate packages provide multiple exports, including a `react` folder in each package for React-specific code. When TypeScript's older or default module resolution strategy encounters these subpath imports (e.g., `@udecode/plate-something/react`), it may fail to find the corresponding type declarations unless: - -1. You switch to a resolution mode that's aware of ESM exports and subpaths, or -2. You manually alias or map these subpaths back to the correct `dist/react/index.d.ts`. ## Recommended: `"moduleResolution": "bundler"` @@ -56,7 +50,6 @@ This aligns TypeScript's resolution logic more closely with modern bundlers and "allowJs": true, "checkJs": false, - "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, @@ -87,16 +80,31 @@ This aligns TypeScript's resolution logic more closely with modern bundlers and } ``` -**Why `moduleResolution = bundler`?** -- It properly handles subpath imports in ESM packages. -- It's the recommended solution moving forward as bundlers evolve. +- **`"moduleResolution": "bundler"`** was introduced in TypeScript 5.0. +- If your TS version is older than 5.0, you **must** upgrade or stick to `"moduleResolution": "node"` plus manual path aliases. + +```jsonc +// package.json +{ + "devDependencies": { + "typescript": "^5.0.0" + } +} +``` + +If you see an error like `TS5023: Unknown compiler option 'moduleResolution'` (for `bundler`), it likely means your TypeScript version is below 5.0. + +## Workaround: `"moduleResolution": "node"` + Path Aliases -## Workaround: Keep `"moduleResolution": "node"` + Path Aliases +If upgrading your entire project to TS 5.0 or changing the resolution mode is not possible: -If switching to `"moduleResolution": "bundler"` is not possible in a large codebase (or conflicts with older dependencies), you can manually map the subpath imports to their actual locations. For example: +1. Keep `"moduleResolution": "node"`. +2. Map each Plate subpath import to its `dist/react` types in `tsconfig.json` using `paths`. +3. Alias these paths in your bundler config. + +### Example `tsconfig.json` ```jsonc -// tsconfig.json { "compilerOptions": { "moduleResolution": "node", @@ -110,13 +118,13 @@ If switching to `"moduleResolution": "bundler"` is not possible in a large codeb "@udecode/plate-list/react": [ "./node_modules/@udecode/plate-list/dist/react/index.d.ts" ] - // ...repeat for all @udecode/plate-*/react packages in use + // ...repeat for all @udecode/plate-*/react packages } } } ``` -Additionally, in your bundler config (e.g. `vite.config.ts`), create aliases so that runtime imports resolve to the correct directories: +### Example `vite.config.ts` ```ts import { defineConfig } from 'vite'; @@ -151,17 +159,14 @@ export default defineConfig({ __dirname, 'node_modules/@udecode/plate-list' ) - - // ...repeat for your actual set of Plate packages } } }); ``` -### Notes & Caveats -- You must replicate this pattern for **every** Plate package that you import with `@udecode/plate-xyz/react`. -- You may also need to configure Jest or other testing environments with the same aliases. -- This approach is more verbose and can become fragile if the packages or file structures change. +**Note:** +- You must do this for every `@udecode/plate-*/react` import you use. +- For testing/Jest, replicate these aliases via `moduleNameMapper` or similar. ## Ensure Matching Plate Versions @@ -169,23 +174,36 @@ Say you're upgrading one package to `42.0.3`, double-check that all your `@udeco ## FAQ -**Q**: "I updated `moduleResolution` to `bundler` but it broke my older imports." -**A**: If your codebase has older TS usage or relies on the older Node resolution, you might try partial migration or switch to the path alias approach until all dependencies can handle ESM properly. +> I updated `moduleResolution` to `bundler` but it broke my older imports." + +If your codebase has older TS usage or relies on `node` resolution, try the path alias approach or fully migrate to a TS 5+ / ESM environment. + +> "I'm seeing `TS2305` about missing exports. Is that a resolution error or a real missing export?" -**Q**: "I want to keep `moduleResolution` as `node`. Are there official type definitions for the `/react` subpaths?" -**A**: All subpaths do have `.d.ts` files in `dist/react`. The path alias approach above is the recommended manual fix if you cannot do `bundler`. +It can be either: +- If the entire package is "not found," it's likely a resolution issue. +- If it's specifically "no exported member," double-check that you spelled the import correctly (no typos) and that your installed version actually has that export. -**Q**: "Do I have to alias each `@udecode/plate-*` package, or can I do a wildcard?" -**A**: Typically, you must do them individually because each has a unique `dist/react` folder. A wildcard might work in some bundler configurations, but it's trickier in TS's `paths` since each subpath needs an explicit mapping. +> "Which minimum TS version do I need for `moduleResolution: bundler`?" -**Q**: "What if I use an older Next.js version or a custom Webpack config?" -**A**: The principle is the same—add webpack aliases or switch your TS `moduleResolution`. If you have any custom Next config, you can alias the subpaths under `webpack.resolve.alias`. +TypeScript 5.0 or higher. -**Q**: "I still get type errors in Jest." -**A**: You'll need to replicate the same alias or resolution changes in your Jest config. For example, using `moduleNameMapper` in `jest.config.js`: - ```js +> "We switched to bundler resolution, but some older libraries in our project break." + +If your older libraries aren't ESM-friendly, you might stick to `node` resolution and do manual path aliases. Some large codebases gradually upgrade or create separate build pipelines for legacy code. + +> "We see the error in Jest but not in Vite." + +You'll need to replicate your alias/resolution changes for Jest. For example: + +```js +// jest.config.js +module.exports = { + // ... moduleNameMapper: { '^@udecode/plate/react$': '/node_modules/@udecode/plate/dist/react', + '^@udecode/plate-core/react$': '/node_modules/@udecode/plate-core/dist/react', // ... } - ``` +}; +``` From 8f3b92525f257a869f691d969cdba136cb1be27d Mon Sep 17 00:00:00 2001 From: zbeyens Date: Wed, 15 Jan 2025 21:13:52 +0100 Subject: [PATCH 3/9] docs --- apps/www/content/docs/en/form.mdx | 246 ++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 apps/www/content/docs/en/form.mdx diff --git a/apps/www/content/docs/en/form.mdx b/apps/www/content/docs/en/form.mdx new file mode 100644 index 0000000000..a5bb38240f --- /dev/null +++ b/apps/www/content/docs/en/form.mdx @@ -0,0 +1,246 @@ +--- +title: Form +description: How to integrate Plate editor with react-hook-form. +--- + +While Plate is typically used as an **uncontrolled** input, there are valid scenarios where you want to integrate the editor within a form library like [**react-hook-form**](https://www.react-hook-form.com) or the [**Form**](https://ui.shadcn.com/docs/components/form) component from **shadcn/ui**. This guide walks through best practices and common pitfalls. + +## When to Integrate Plate with a Form + +- **Form Submission**: You want the editor’s content to be included along with other fields (e.g., ``, ``, ``, `