Skip to content

Commit a20f0b7

Browse files
authored
Merge pull request #3759 from udecode/feat/40b
Add scrollRef
2 parents 4196a48 + 0546073 commit a20f0b7

File tree

25 files changed

+339
-214
lines changed

25 files changed

+339
-214
lines changed

.changeset/dirty-mangos-cover.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@udecode/plate-heading': patch
3+
---
4+
5+
- Use `useEditorScrollRef` instead of `useEditorContainerRef`

.changeset/sour-files-drum.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@udecode/plate-core': patch
3+
---
4+
5+
- Add `scrollRef` in Plate store
6+
- Add `useEditorScrollRef` to get the scroll container ref, that can be used in plugins to control the scroll position

apps/www/content/docs/api/core.mdx

+26
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,32 @@ a
160160
A new `PlatePlugin` with precise type control.
161161
</APIReturns>
162162

163+
### useEditorContainerRef
164+
165+
Get the editor container DOM reference.
166+
167+
<APIParameters>
168+
<APIItem name="id" type="string" optional>
169+
The ID of the plate editor. Default is using the closest editor id.
170+
</APIItem>
171+
</APIParameters>
172+
<APIReturns>
173+
A React ref object containing the editor container DOM element.
174+
</APIReturns>
175+
176+
### useEditorScrollRef
177+
178+
Get the editor scroll container reference. Returns the scroll ref if it exists, otherwise returns the container ref.
179+
180+
<APIParameters>
181+
<APIItem name="id" type="string" optional>
182+
The ID of the plate editor. Default is using the closest editor id.
183+
</APIItem>
184+
</APIParameters>
185+
<APIReturns>
186+
A React ref object containing either the scroll container or the editor container DOM element.
187+
</APIReturns>
188+
163189
### useEditorPlugin
164190

165191
Get editor and plugin context.

apps/www/content/docs/block-selection.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ BlockSelectionPlugin.configure({
9292

9393
useing `options.areaOptions.behaviour.scrolling.speedDivider` to set the scroll speed.
9494

95-
The value of `1.5` is our recommended speed.Since it's same with the default speed of the browser.
95+
The value of `1.5` is our recommended speed since it's near the browser-native speed.
9696

9797

9898
```ts

apps/www/content/docs/components/changelog.mdx

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Use the [CLI](https://platejs.org/docs/components/cli) to install the latest ver
1111

1212
## November 2024 #16
1313

14+
### November 13 #16.6
15+
16+
- `resizable`: hide `ResizeHandle` when read-only
17+
1418
### November 8 #16.5
1519

1620
- Add this to your tailwind config:

apps/www/public/r/styles/default/ai-plugins.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77
"@udecode/plate-heading",
88
"@udecode/plate-horizontal-rule",
99
"@udecode/plate-link",
10-
"@udecode/plate-markdown",
11-
"@udecode/plate-selection"
10+
"@udecode/plate-markdown"
1211
],
1312
"files": [
1413
{
15-
"content": "'use client';\n\nimport React from 'react';\n\nimport { withProps } from '@udecode/cn';\nimport { AIChatPlugin, AIPlugin } from '@udecode/plate-ai/react';\nimport {\n BoldPlugin,\n CodePlugin,\n ItalicPlugin,\n StrikethroughPlugin,\n UnderlinePlugin,\n} from '@udecode/plate-basic-marks/react';\nimport { BlockquotePlugin } from '@udecode/plate-block-quote/react';\nimport {\n CodeBlockPlugin,\n CodeLinePlugin,\n CodeSyntaxPlugin,\n} from '@udecode/plate-code-block/react';\nimport {\n ParagraphPlugin,\n PlateLeaf,\n createPlateEditor,\n} from '@udecode/plate-common/react';\nimport { HEADING_KEYS } from '@udecode/plate-heading';\nimport { HorizontalRulePlugin } from '@udecode/plate-horizontal-rule/react';\nimport { LinkPlugin } from '@udecode/plate-link/react';\nimport { MarkdownPlugin } from '@udecode/plate-markdown';\nimport { BlockSelectionPlugin } from '@udecode/plate-selection/react';\n\nimport { AIMenu } from '@/components/plate-ui/ai-menu';\nimport { BlockquoteElement } from '@/components/plate-ui/blockquote-element';\nimport { CodeBlockElement } from '@/components/plate-ui/code-block-element';\nimport { CodeLeaf } from '@/components/plate-ui/code-leaf';\nimport { CodeLineElement } from '@/components/plate-ui/code-line-element';\nimport { CodeSyntaxLeaf } from '@/components/plate-ui/code-syntax-leaf';\nimport { HeadingElement } from '@/components/plate-ui/heading-element';\nimport { HrElement } from '@/components/plate-ui/hr-element';\nimport { LinkElement } from '@/components/plate-ui/link-element';\nimport { ParagraphElement } from '@/components/plate-ui/paragraph-element';\n\nimport { basicNodesPlugins } from './basic-nodes-plugins';\nimport { indentListPlugins } from './indent-list-plugins';\nimport { linkPlugin } from './link-plugin';\n\nconst createAIEditor = () => {\n const editor = createPlateEditor({\n id: 'ai',\n override: {\n components: {\n [BlockquotePlugin.key]: BlockquoteElement,\n [BoldPlugin.key]: withProps(PlateLeaf, { as: 'strong' }),\n [CodeBlockPlugin.key]: CodeBlockElement,\n [CodeLinePlugin.key]: CodeLineElement,\n [CodePlugin.key]: CodeLeaf,\n [CodeSyntaxPlugin.key]: CodeSyntaxLeaf,\n [HEADING_KEYS.h1]: withProps(HeadingElement, { variant: 'h1' }),\n [HEADING_KEYS.h2]: withProps(HeadingElement, { variant: 'h2' }),\n [HEADING_KEYS.h3]: withProps(HeadingElement, { variant: 'h3' }),\n [HorizontalRulePlugin.key]: HrElement,\n [ItalicPlugin.key]: withProps(PlateLeaf, { as: 'em' }),\n [LinkPlugin.key]: LinkElement,\n [ParagraphPlugin.key]: ParagraphElement,\n [StrikethroughPlugin.key]: withProps(PlateLeaf, { as: 's' }),\n [UnderlinePlugin.key]: withProps(PlateLeaf, { as: 'u' }),\n },\n },\n plugins: [\n ParagraphPlugin,\n ...basicNodesPlugins,\n HorizontalRulePlugin,\n linkPlugin,\n ...indentListPlugins,\n MarkdownPlugin.configure({ options: { indentList: true } }),\n // FIXME\n BlockSelectionPlugin.configure({\n api: {},\n extendEditor: null,\n options: {},\n render: {},\n useHooks: null,\n handlers: {},\n }),\n ],\n value: [{ children: [{ text: '' }], type: 'p' }],\n });\n\n return editor;\n};\n\nconst systemCommon = `\\\nYou are an advanced AI-powered note-taking assistant, designed to enhance productivity and creativity in note management.\nRespond directly to user prompts with clear, concise, and relevant content. Maintain a neutral, helpful tone.\n\nRules:\n- <Document> is the entire note the user is working on.\n- <Reminder> is a reminder of how you should reply to INSTRUCTIONS. It does not apply to questions.\n- Anything else is the user prompt.\n- Your response should be tailored to the user's prompt, providing precise assistance to optimize note management.\n- For INSTRUCTIONS: Follow the <Reminder> exactly. Provide ONLY the content to be inserted or replaced. No explanations or comments.\n- For QUESTIONS: Provide a helpful and concise answer. You may include brief explanations if necessary.\n- CRITICAL: Distinguish between INSTRUCTIONS and QUESTIONS. Instructions typically ask you to modify or add content. Questions ask for information or clarification.\n`;\n\nconst systemDefault = `\\\n${systemCommon}\n- <Block> is the current block of text the user is working on.\n- Ensure your output can seamlessly fit into the existing <Block> structure.\n- CRITICAL: Provide only a single block of text. DO NOT create multiple paragraphs or separate blocks.\n<Block>\n{block}\n</Block>\n`;\n\nconst systemSelecting = `\\\n${systemCommon}\n- <Block> is the block of text containing the user's selection, providing context.\n- Ensure your output can seamlessly fit into the existing <Block> structure.\n- <Selection> is the specific text the user has selected in the block and wants to modify or ask about.\n- Consider the context provided by <Block>, but only modify <Selection>. Your response should be a direct replacement for <Selection>.\n<Block>\n{block}\n</Block>\n<Selection>\n{selection}\n</Selection>\n`;\n\nconst systemBlockSelecting = `\\\n${systemCommon}\n- <Selection> represents the full blocks of text the user has selected and wants to modify or ask about.\n- Your response should be a direct replacement for the entire <Selection>.\n- Maintain the overall structure and formatting of the selected blocks, unless explicitly instructed otherwise.\n- CRITICAL: Provide only the content to replace <Selection>. Do not add additional blocks or change the block structure unless specifically requested.\n<Selection>\n{block}\n</Selection>\n`;\n\nconst userDefault = `<Reminder>\nCRITICAL: DO NOT use block formatting. You can only use inline formatting.\nCRITICAL: DO NOT start new lines or paragraphs.\nNEVER write <Block>.\n</Reminder>\n{prompt}`;\n\nconst userSelecting = `<Reminder>\nIf this is a question, provide a helpful and concise answer about <Selection>.\nIf this is an instruction, provide ONLY the text to replace <Selection>. No explanations.\nEnsure it fits seamlessly within <Block>. If <Block> is empty, write ONE random sentence.\nNEVER write <Block> or <Selection>.\n</Reminder>\n{prompt} about <Selection>`;\n\nconst userBlockSelecting = `<Reminder>\nIf this is a question, provide a helpful and concise answer about <Selection>.\nIf this is an instruction, provide ONLY the content to replace the entire <Selection>. No explanations.\nMaintain the overall structure unless instructed otherwise.\nNEVER write <Block> or <Selection>.\n</Reminder>\n{prompt} about <Selection>`;\n\nexport const PROMPT_TEMPLATES = {\n systemBlockSelecting,\n systemDefault,\n systemSelecting,\n userBlockSelecting,\n userDefault,\n userSelecting,\n};\n\nexport const aiPlugins = [\n MarkdownPlugin.configure({ options: { indentList: true } }),\n AIPlugin,\n AIChatPlugin.configure({\n options: {\n createAIEditor,\n promptTemplate: ({ isBlockSelecting, isSelecting }) => {\n return isBlockSelecting\n ? PROMPT_TEMPLATES.userBlockSelecting\n : isSelecting\n ? PROMPT_TEMPLATES.userSelecting\n : PROMPT_TEMPLATES.userDefault;\n },\n systemTemplate: ({ isBlockSelecting, isSelecting }) => {\n return isBlockSelecting\n ? PROMPT_TEMPLATES.systemBlockSelecting\n : isSelecting\n ? PROMPT_TEMPLATES.systemSelecting\n : PROMPT_TEMPLATES.systemDefault;\n },\n },\n render: { afterEditable: () => <AIMenu /> },\n }),\n] as const;\n",
14+
"content": "'use client';\n\nimport React from 'react';\n\nimport { withProps } from '@udecode/cn';\nimport { AIChatPlugin, AIPlugin } from '@udecode/plate-ai/react';\nimport {\n BoldPlugin,\n CodePlugin,\n ItalicPlugin,\n StrikethroughPlugin,\n UnderlinePlugin,\n} from '@udecode/plate-basic-marks/react';\nimport { BlockquotePlugin } from '@udecode/plate-block-quote/react';\nimport {\n CodeBlockPlugin,\n CodeLinePlugin,\n CodeSyntaxPlugin,\n} from '@udecode/plate-code-block/react';\nimport {\n ParagraphPlugin,\n PlateLeaf,\n createPlateEditor,\n} from '@udecode/plate-common/react';\nimport { HEADING_KEYS } from '@udecode/plate-heading';\nimport { HorizontalRulePlugin } from '@udecode/plate-horizontal-rule/react';\nimport { LinkPlugin } from '@udecode/plate-link/react';\nimport { MarkdownPlugin } from '@udecode/plate-markdown';\n\nimport { cursorOverlayPlugin } from '@/components/editor/plugins/cursor-overlay-plugin';\nimport { AIMenu } from '@/components/plate-ui/ai-menu';\nimport { BlockquoteElement } from '@/components/plate-ui/blockquote-element';\nimport { CodeBlockElement } from '@/components/plate-ui/code-block-element';\nimport { CodeLeaf } from '@/components/plate-ui/code-leaf';\nimport { CodeLineElement } from '@/components/plate-ui/code-line-element';\nimport { CodeSyntaxLeaf } from '@/components/plate-ui/code-syntax-leaf';\nimport { HeadingElement } from '@/components/plate-ui/heading-element';\nimport { HrElement } from '@/components/plate-ui/hr-element';\nimport { LinkElement } from '@/components/plate-ui/link-element';\nimport { ParagraphElement } from '@/components/plate-ui/paragraph-element';\n\nimport { basicNodesPlugins } from './basic-nodes-plugins';\nimport { blockSelectionReadOnlyPlugin } from './block-selection-plugins';\nimport { indentListPlugins } from './indent-list-plugins';\nimport { linkPlugin } from './link-plugin';\n\nconst createAIEditor = () => {\n const editor = createPlateEditor({\n id: 'ai',\n override: {\n components: {\n [BlockquotePlugin.key]: BlockquoteElement,\n [BoldPlugin.key]: withProps(PlateLeaf, { as: 'strong' }),\n [CodeBlockPlugin.key]: CodeBlockElement,\n [CodeLinePlugin.key]: CodeLineElement,\n [CodePlugin.key]: CodeLeaf,\n [CodeSyntaxPlugin.key]: CodeSyntaxLeaf,\n [HEADING_KEYS.h1]: withProps(HeadingElement, { variant: 'h1' }),\n [HEADING_KEYS.h2]: withProps(HeadingElement, { variant: 'h2' }),\n [HEADING_KEYS.h3]: withProps(HeadingElement, { variant: 'h3' }),\n [HorizontalRulePlugin.key]: HrElement,\n [ItalicPlugin.key]: withProps(PlateLeaf, { as: 'em' }),\n [LinkPlugin.key]: LinkElement,\n [ParagraphPlugin.key]: ParagraphElement,\n [StrikethroughPlugin.key]: withProps(PlateLeaf, { as: 's' }),\n [UnderlinePlugin.key]: withProps(PlateLeaf, { as: 'u' }),\n },\n },\n plugins: [\n ...basicNodesPlugins,\n ...indentListPlugins,\n HorizontalRulePlugin,\n linkPlugin,\n MarkdownPlugin.configure({ options: { indentList: true } }),\n blockSelectionReadOnlyPlugin,\n ],\n });\n\n return editor;\n};\n\nconst systemCommon = `\\\nYou are an advanced AI-powered note-taking assistant, designed to enhance productivity and creativity in note management.\nRespond directly to user prompts with clear, concise, and relevant content. Maintain a neutral, helpful tone.\n\nRules:\n- <Document> is the entire note the user is working on.\n- <Reminder> is a reminder of how you should reply to INSTRUCTIONS. It does not apply to questions.\n- Anything else is the user prompt.\n- Your response should be tailored to the user's prompt, providing precise assistance to optimize note management.\n- For INSTRUCTIONS: Follow the <Reminder> exactly. Provide ONLY the content to be inserted or replaced. No explanations or comments.\n- For QUESTIONS: Provide a helpful and concise answer. You may include brief explanations if necessary.\n- CRITICAL: Distinguish between INSTRUCTIONS and QUESTIONS. Instructions typically ask you to modify or add content. Questions ask for information or clarification.\n`;\n\nconst systemDefault = `\\\n${systemCommon}\n- <Block> is the current block of text the user is working on.\n- Ensure your output can seamlessly fit into the existing <Block> structure.\n- CRITICAL: Provide only a single block of text. DO NOT create multiple paragraphs or separate blocks.\n<Block>\n{block}\n</Block>\n`;\n\nconst systemSelecting = `\\\n${systemCommon}\n- <Block> is the block of text containing the user's selection, providing context.\n- Ensure your output can seamlessly fit into the existing <Block> structure.\n- <Selection> is the specific text the user has selected in the block and wants to modify or ask about.\n- Consider the context provided by <Block>, but only modify <Selection>. Your response should be a direct replacement for <Selection>.\n<Block>\n{block}\n</Block>\n<Selection>\n{selection}\n</Selection>\n`;\n\nconst systemBlockSelecting = `\\\n${systemCommon}\n- <Selection> represents the full blocks of text the user has selected and wants to modify or ask about.\n- Your response should be a direct replacement for the entire <Selection>.\n- Maintain the overall structure and formatting of the selected blocks, unless explicitly instructed otherwise.\n- CRITICAL: Provide only the content to replace <Selection>. Do not add additional blocks or change the block structure unless specifically requested.\n<Selection>\n{block}\n</Selection>\n`;\n\nconst userDefault = `<Reminder>\nCRITICAL: DO NOT use block formatting. You can only use inline formatting.\nCRITICAL: DO NOT start new lines or paragraphs.\nNEVER write <Block>.\n</Reminder>\n{prompt}`;\n\nconst userSelecting = `<Reminder>\nIf this is a question, provide a helpful and concise answer about <Selection>.\nIf this is an instruction, provide ONLY the text to replace <Selection>. No explanations.\nEnsure it fits seamlessly within <Block>. If <Block> is empty, write ONE random sentence.\nNEVER write <Block> or <Selection>.\n</Reminder>\n{prompt} about <Selection>`;\n\nconst userBlockSelecting = `<Reminder>\nIf this is a question, provide a helpful and concise answer about <Selection>.\nIf this is an instruction, provide ONLY the content to replace the entire <Selection>. No explanations.\nMaintain the overall structure unless instructed otherwise.\nNEVER write <Block> or <Selection>.\n</Reminder>\n{prompt} about <Selection>`;\n\nexport const PROMPT_TEMPLATES = {\n systemBlockSelecting,\n systemDefault,\n systemSelecting,\n userBlockSelecting,\n userDefault,\n userSelecting,\n};\n\nexport const aiPlugins = [\n cursorOverlayPlugin,\n MarkdownPlugin.configure({ options: { indentList: true } }),\n AIPlugin,\n AIChatPlugin.configure({\n options: {\n createAIEditor,\n promptTemplate: ({ isBlockSelecting, isSelecting }) => {\n return isBlockSelecting\n ? PROMPT_TEMPLATES.userBlockSelecting\n : isSelecting\n ? PROMPT_TEMPLATES.userSelecting\n : PROMPT_TEMPLATES.userDefault;\n },\n systemTemplate: ({ isBlockSelecting, isSelecting }) => {\n return isBlockSelecting\n ? PROMPT_TEMPLATES.systemBlockSelecting\n : isSelecting\n ? PROMPT_TEMPLATES.systemSelecting\n : PROMPT_TEMPLATES.systemDefault;\n },\n },\n render: { afterEditable: () => <AIMenu /> },\n }),\n] as const;\n",
1615
"path": "components/editor/plugins/ai-plugins.tsx",
1716
"target": "components/editor/plugins/ai-plugins.tsx",
1817
"type": "registry:component"
@@ -21,6 +20,8 @@
2120
"name": "ai-plugins",
2221
"registryDependencies": [
2322
"basic-nodes-plugins",
23+
"block-selection-plugins",
24+
"cursor-overlay-plugin",
2425
"indent-list-plugins",
2526
"link-plugin",
2627
"ai-menu",

apps/www/public/r/styles/default/block-selection-plugins.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
],
55
"files": [
66
{
7-
"content": "'use client';\n\nimport { BlockSelectionPlugin } from '@udecode/plate-selection/react';\n\nexport const blockSelectionPlugins = [\n BlockSelectionPlugin.configure({\n inject: {\n excludeBelowPlugins: ['tr'],\n excludePlugins: ['table', 'code_line', 'column_group', 'column'],\n },\n options: {\n areaOptions: {\n behaviour: {\n scrolling: {\n speedDivider: 1.5,\n },\n startThreshold: 4,\n },\n },\n enableContextMenu: true,\n },\n }),\n] as const;\n",
7+
"content": "'use client';\n\nimport { BlockSelectionPlugin } from '@udecode/plate-selection/react';\n\nexport const blockSelectionPlugins = [\n BlockSelectionPlugin.configure({\n inject: {\n excludeBelowPlugins: ['tr'],\n excludePlugins: ['table', 'code_line', 'column_group', 'column'],\n },\n options: {\n areaOptions: {\n behaviour: {\n scrolling: {\n speedDivider: 1.5,\n },\n startThreshold: 4,\n },\n },\n enableContextMenu: true,\n },\n }),\n] as const;\n\nexport const blockSelectionReadOnlyPlugin = BlockSelectionPlugin.configure({\n api: {},\n extendEditor: null,\n options: {},\n render: {},\n useHooks: null,\n handlers: {},\n});\n",
88
"path": "components/editor/plugins/block-selection-plugins.ts",
99
"target": "components/editor/plugins/block-selection-plugins.ts",
1010
"type": "registry:component"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"dependencies": [
3+
"@udecode/plate-selection"
4+
],
5+
"files": [
6+
{
7+
"content": "'use client';\n\nimport { CursorOverlayPlugin } from '@udecode/plate-selection/react';\n\nimport { CursorOverlay } from '@/components/plate-ui/cursor-overlay';\n\nexport const cursorOverlayPlugin = CursorOverlayPlugin.configure({\n render: {\n afterEditable: () => <CursorOverlay />,\n },\n});\n",
8+
"path": "components/editor/plugins/cursor-overlay-plugin.tsx",
9+
"target": "components/editor/plugins/cursor-overlay-plugin.tsx",
10+
"type": "registry:component"
11+
}
12+
],
13+
"name": "cursor-overlay-plugin",
14+
"registryDependencies": [
15+
"cursor-overlay"
16+
],
17+
"type": "registry:component"
18+
}

0 commit comments

Comments
 (0)