Skip to content

Commit

Permalink
Merge pull request #3759 from udecode/feat/40b
Browse files Browse the repository at this point in the history
Add scrollRef
  • Loading branch information
zbeyens authored Nov 13, 2024
2 parents 4196a48 + 0546073 commit a20f0b7
Show file tree
Hide file tree
Showing 25 changed files with 339 additions and 214 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-mangos-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@udecode/plate-heading': patch
---

- Use `useEditorScrollRef` instead of `useEditorContainerRef`
6 changes: 6 additions & 0 deletions .changeset/sour-files-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@udecode/plate-core': patch
---

- Add `scrollRef` in Plate store
- Add `useEditorScrollRef` to get the scroll container ref, that can be used in plugins to control the scroll position
26 changes: 26 additions & 0 deletions apps/www/content/docs/api/core.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,32 @@ a
A new `PlatePlugin` with precise type control.
</APIReturns>

### useEditorContainerRef

Get the editor container DOM reference.

<APIParameters>
<APIItem name="id" type="string" optional>
The ID of the plate editor. Default is using the closest editor id.
</APIItem>
</APIParameters>
<APIReturns>
A React ref object containing the editor container DOM element.
</APIReturns>

### useEditorScrollRef

Get the editor scroll container reference. Returns the scroll ref if it exists, otherwise returns the container ref.

<APIParameters>
<APIItem name="id" type="string" optional>
The ID of the plate editor. Default is using the closest editor id.
</APIItem>
</APIParameters>
<APIReturns>
A React ref object containing either the scroll container or the editor container DOM element.
</APIReturns>

### useEditorPlugin

Get editor and plugin context.
Expand Down
2 changes: 1 addition & 1 deletion apps/www/content/docs/block-selection.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ BlockSelectionPlugin.configure({

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

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


```ts
Expand Down
4 changes: 4 additions & 0 deletions apps/www/content/docs/components/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Use the [CLI](https://platejs.org/docs/components/cli) to install the latest ver

## November 2024 #16

### November 13 #16.6

- `resizable`: hide `ResizeHandle` when read-only

### November 8 #16.5

- Add this to your tailwind config:
Expand Down
7 changes: 4 additions & 3 deletions apps/www/public/r/styles/default/ai-plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
"@udecode/plate-heading",
"@udecode/plate-horizontal-rule",
"@udecode/plate-link",
"@udecode/plate-markdown",
"@udecode/plate-selection"
"@udecode/plate-markdown"
],
"files": [
{
"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",
"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",
"path": "components/editor/plugins/ai-plugins.tsx",
"target": "components/editor/plugins/ai-plugins.tsx",
"type": "registry:component"
Expand All @@ -21,6 +20,8 @@
"name": "ai-plugins",
"registryDependencies": [
"basic-nodes-plugins",
"block-selection-plugins",
"cursor-overlay-plugin",
"indent-list-plugins",
"link-plugin",
"ai-menu",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
],
"files": [
{
"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",
"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",
"path": "components/editor/plugins/block-selection-plugins.ts",
"target": "components/editor/plugins/block-selection-plugins.ts",
"type": "registry:component"
Expand Down
18 changes: 18 additions & 0 deletions apps/www/public/r/styles/default/cursor-overlay-plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"dependencies": [
"@udecode/plate-selection"
],
"files": [
{
"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",
"path": "components/editor/plugins/cursor-overlay-plugin.tsx",
"target": "components/editor/plugins/cursor-overlay-plugin.tsx",
"type": "registry:component"
}
],
"name": "cursor-overlay-plugin",
"registryDependencies": [
"cursor-overlay"
],
"type": "registry:component"
}
Loading

0 comments on commit a20f0b7

Please sign in to comment.