Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfeng33 authored Nov 7, 2024
1 parent e609e51 commit b51b963
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 7 deletions.
2 changes: 1 addition & 1 deletion apps/www/public/r/styles/default/block-context-menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
},
"files": [
{
"content": "'use client';\n\nimport { useCallback, useState } from 'react';\n\nimport { AIChatPlugin } from '@udecode/plate-ai/react';\nimport { BlockquotePlugin } from '@udecode/plate-block-quote/react';\nimport { unsetNodes } from '@udecode/plate-common';\nimport {\n ParagraphPlugin,\n focusEditor,\n useEditorPlugin,\n} from '@udecode/plate-common/react';\nimport { HEADING_KEYS } from '@udecode/plate-heading';\nimport { IndentListPlugin } from '@udecode/plate-indent-list/react';\nimport {\n BLOCK_CONTEXT_MENU_ID,\n BlockMenuPlugin,\n BlockSelectionPlugin,\n} from '@udecode/plate-selection/react';\n\nimport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from './context-menu';\n\ntype Value = 'askAI' | null;\n\nexport function BlockContextMenu({ children }: { children: React.ReactNode }) {\n const { api, editor } = useEditorPlugin(BlockMenuPlugin);\n const [value, setValue] = useState<Value>(null);\n\n const handleTurnInto = useCallback(\n (type: string) => {\n editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes()\n .forEach(([node, path]) => {\n if (node[IndentListPlugin.key]) {\n unsetNodes(editor, [IndentListPlugin.key, 'indent'], { at: path });\n }\n\n editor.tf.toggle.block({ type }, { at: path });\n });\n },\n [editor]\n );\n\n const handleAlign = useCallback(\n (align: 'center' | 'left' | 'right') => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setNodes({ align });\n },\n [editor]\n );\n\n return (\n <ContextMenu modal={false}>\n <ContextMenuTrigger\n asChild\n onContextMenu={(event) => {\n const dataset = (event.target as HTMLElement).dataset;\n\n const disabled = dataset?.slateEditor === 'true';\n\n if (disabled) return event.preventDefault();\n\n api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {\n x: event.clientX,\n y: event.clientY,\n });\n }}\n >\n <div className=\"w-full\">{children}</div>\n </ContextMenuTrigger>\n <ContextMenuContent\n className=\"w-64\"\n onCloseAutoFocus={(e) => {\n e.preventDefault();\n\n if (value === 'askAI') {\n editor.getApi(AIChatPlugin).aiChat.show();\n }\n\n setValue(null);\n }}\n >\n <ContextMenuGroup>\n <ContextMenuItem\n onClick={() => {\n setValue('askAI');\n }}\n >\n Ask AI\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.removeNodes();\n focusEditor(editor);\n }}\n >\n Delete\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.duplicate(\n editor.getApi(BlockSelectionPlugin).blockSelection.getNodes()\n );\n }}\n >\n Duplicate\n {/* <ContextMenuShortcut>⌘ + D</ContextMenuShortcut> */}\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger>Turn into</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-48\">\n <ContextMenuItem\n onClick={() => handleTurnInto(ParagraphPlugin.key)}\n >\n Paragraph\n </ContextMenuItem>\n\n <ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h1)}>\n Heading 1\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h2)}>\n Heading 2\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h3)}>\n Heading 3\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => handleTurnInto(BlockquotePlugin.key)}\n >\n Blockquote\n </ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n </ContextMenuGroup>\n\n <ContextMenuGroup>\n <ContextMenuItem\n onClick={() =>\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setIndent(1)\n }\n >\n Indent\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() =>\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setIndent(-1)\n }\n >\n Outdent\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger>Align</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-48\">\n <ContextMenuItem onClick={() => handleAlign('left')}>\n Left\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleAlign('center')}>\n Center\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleAlign('right')}>\n Right\n </ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n </ContextMenuGroup>\n </ContextMenuContent>\n </ContextMenu>\n );\n}\n",
"content": "'use client';\n\nimport { useCallback, useState } from 'react';\n\nimport { AIChatPlugin } from '@udecode/plate-ai/react';\nimport { BlockquotePlugin } from '@udecode/plate-block-quote/react';\nimport { unsetNodes } from '@udecode/plate-common';\nimport {\n ParagraphPlugin,\n focusEditor,\n useEditorPlugin,\n} from '@udecode/plate-common/react';\nimport { HEADING_KEYS } from '@udecode/plate-heading';\nimport { IndentListPlugin } from '@udecode/plate-indent-list/react';\nimport {\n BLOCK_CONTEXT_MENU_ID,\n BlockMenuPlugin,\n BlockSelectionPlugin,\n} from '@udecode/plate-selection/react';\n\nimport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from './context-menu';\n\ntype Value = 'askAI' | null;\n\nexport function BlockContextMenu({ children }: { children: React.ReactNode }) {\n const { api, editor } = useEditorPlugin(BlockMenuPlugin);\n const [value, setValue] = useState<Value>(null);\n\n const handleTurnInto = useCallback(\n (type: string) => {\n editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes()\n .forEach(([node, path]) => {\n if (node[IndentListPlugin.key]) {\n unsetNodes(editor, [IndentListPlugin.key, 'indent'], { at: path });\n }\n\n editor.tf.toggle.block({ type }, { at: path });\n });\n },\n [editor]\n );\n\n const handleAlign = useCallback(\n (align: 'center' | 'left' | 'right') => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setNodes({ align });\n },\n [editor]\n );\n\n return (\n <ContextMenu\n onOpenChange={(open) => {\n if (!open) {\n // prevent unselect the block selection\n setTimeout(() => {\n api.blockMenu.hide();\n }, 0);\n }\n }}\n modal={false}\n >\n <ContextMenuTrigger\n asChild\n onContextMenu={(event) => {\n const dataset = (event.target as HTMLElement).dataset;\n\n const disabled = dataset?.slateEditor === 'true';\n\n if (disabled) return event.preventDefault();\n\n api.blockMenu.show(BLOCK_CONTEXT_MENU_ID, {\n x: event.clientX,\n y: event.clientY,\n });\n }}\n >\n <div className=\"w-full\">{children}</div>\n </ContextMenuTrigger>\n <ContextMenuContent\n className=\"w-64\"\n onCloseAutoFocus={(e) => {\n e.preventDefault();\n editor.getApi(BlockSelectionPlugin).blockSelection.focus();\n\n if (value === 'askAI') {\n editor.getApi(AIChatPlugin).aiChat.show();\n }\n\n setValue(null);\n }}\n >\n <ContextMenuGroup>\n <ContextMenuItem\n onClick={() => {\n setValue('askAI');\n }}\n >\n Ask AI\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.removeNodes();\n focusEditor(editor);\n }}\n >\n Delete\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.duplicate(\n editor.getApi(BlockSelectionPlugin).blockSelection.getNodes()\n );\n }}\n >\n Duplicate\n {/* <ContextMenuShortcut>⌘ + D</ContextMenuShortcut> */}\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger>Turn into</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-48\">\n <ContextMenuItem\n onClick={() => handleTurnInto(ParagraphPlugin.key)}\n >\n Paragraph\n </ContextMenuItem>\n\n <ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h1)}>\n Heading 1\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h2)}>\n Heading 2\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleTurnInto(HEADING_KEYS.h3)}>\n Heading 3\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() => handleTurnInto(BlockquotePlugin.key)}\n >\n Blockquote\n </ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n </ContextMenuGroup>\n\n <ContextMenuGroup>\n <ContextMenuItem\n onClick={() =>\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setIndent(1)\n }\n >\n Indent\n </ContextMenuItem>\n <ContextMenuItem\n onClick={() =>\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.setIndent(-1)\n }\n >\n Outdent\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger>Align</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-48\">\n <ContextMenuItem onClick={() => handleAlign('left')}>\n Left\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleAlign('center')}>\n Center\n </ContextMenuItem>\n <ContextMenuItem onClick={() => handleAlign('right')}>\n Right\n </ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n </ContextMenuGroup>\n </ContextMenuContent>\n </ContextMenu>\n );\n}\n",
"path": "plate-ui/block-context-menu.tsx",
"target": "components/plate-ui/block-context-menu.tsx",
"type": "registry:ui"
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 options: {\n areaOptions: {\n behaviour: {\n scrolling: {\n speedDivider: 1.5,\n },\n startThreshold: 10,\n },\n boundaries: '#scroll_container',\n container: '#scroll_container',\n selectables: '#scroll_container .slate-selectable',\n selectionAreaClass: 'slate-selection-area',\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 options: {\n areaOptions: {\n behaviour: {\n scrolling: {\n speedDivider: 1.5,\n },\n startThreshold: 4,\n },\n boundaries: '#scroll_container',\n container: '#scroll_container',\n selectables: '#scroll_container .slate-selectable',\n selectionAreaClass: 'slate-selection-area',\n },\n enableContextMenu: true,\n },\n }),\n] as const;\n",
"path": "components/editor/plugins/block-selection-plugins.ts",
"target": "components/editor/plugins/block-selection-plugins.ts",
"type": "registry:component"
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/styles/default/editor.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"files": [
{
"content": "'use client';\n\nimport React from 'react';\n\nimport type { PlateContentProps } from '@udecode/plate-common/react';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@udecode/cn';\nimport { PlateContent } from '@udecode/plate-common/react';\nimport { cva } from 'class-variance-authority';\n\nconst editorContainerVariants = cva(\n 'relative flex cursor-text [&_.slate-selection-area]:border [&_.slate-selection-area]:border-brand/25 [&_.slate-selection-area]:bg-brand/15',\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: 'w-full',\n demo: 'h-[650px] w-full overflow-y-auto',\n },\n },\n }\n);\n\nexport const EditorContainer = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<'div'> &\n VariantProps<typeof editorContainerVariants>\n>(({ className, variant, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\n 'ignore-click-outside/toolbar',\n editorContainerVariants({ variant }),\n className\n )}\n role=\"button\"\n {...props}\n />\n );\n});\n\nEditorContainer.displayName = 'EditorContainer';\n\nconst editorVariants = cva(\n cn(\n 'group/editor',\n 'relative w-full whitespace-pre-wrap break-words',\n 'rounded-md ring-offset-background placeholder:text-muted-foreground/80 focus-visible:outline-none',\n '[&_[data-slate-placeholder]]:text-muted-foreground/80 [&_[data-slate-placeholder]]:!opacity-100',\n '[&_[data-slate-placeholder]]:top-[auto_!important]',\n '[&_strong]:font-bold'\n ),\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n disabled: {\n true: 'cursor-not-allowed opacity-50',\n },\n focused: {\n true: 'ring-2 ring-ring ring-offset-2',\n },\n variant: {\n ai: 'w-full px-0 text-sm',\n aiChat:\n 'max-h-[min(70vh,320px)] w-full max-w-[700px] overflow-y-auto px-3 py-2 text-sm',\n default:\n 'min-h-full w-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n demo: 'min-h-full w-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n fullWidth: 'min-h-full w-full px-16 pb-72 pt-4 text-base sm:px-24',\n },\n },\n }\n);\n\nexport type EditorProps = PlateContentProps &\n VariantProps<typeof editorVariants>;\n\nexport const Editor = React.forwardRef<HTMLDivElement, EditorProps>(\n ({ className, disabled, focused, variant, ...props }, ref) => {\n return (\n <PlateContent\n ref={ref}\n className={cn(\n editorVariants({\n disabled,\n focused,\n variant,\n }),\n className\n )}\n disabled={disabled}\n disableDefaultStyles\n {...props}\n />\n );\n }\n);\n\nEditor.displayName = 'Editor';\n",
"content": "'use client';\n\nimport React from 'react';\n\nimport type { PlateContentProps } from '@udecode/plate-common/react';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@udecode/cn';\nimport { PlateContent } from '@udecode/plate-common/react';\nimport { cva } from 'class-variance-authority';\n\nconst editorContainerVariants = cva(\n 'relative flex cursor-text [&_.slate-selection-area]:border [&_.slate-selection-area]:border-brand/25 [&_.slate-selection-area]:bg-brand/15',\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: 'w-full',\n demo: 'h-[650px] w-full overflow-y-auto',\n },\n },\n }\n);\n\nexport const EditorContainer = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<'div'> &\n VariantProps<typeof editorContainerVariants>\n>(({ className, variant, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\n 'ignore-click-outside/toolbar',\n editorContainerVariants({ variant }),\n className\n )}\n role=\"button\"\n {...props}\n />\n );\n});\n\nEditorContainer.displayName = 'EditorContainer';\n\nconst editorVariants = cva(\n cn(\n 'group/editor',\n 'relative w-full overflow-x-hidden whitespace-pre-wrap break-words',\n 'rounded-md ring-offset-background placeholder:text-muted-foreground/80 focus-visible:outline-none',\n '[&_[data-slate-placeholder]]:text-muted-foreground/80 [&_[data-slate-placeholder]]:!opacity-100',\n '[&_[data-slate-placeholder]]:top-[auto_!important]',\n '[&_strong]:font-bold'\n ),\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n disabled: {\n true: 'cursor-not-allowed opacity-50',\n },\n focused: {\n true: 'ring-2 ring-ring ring-offset-2',\n },\n variant: {\n ai: 'w-full px-0 text-sm',\n aiChat:\n 'max-h-[min(70vh,320px)] w-full max-w-[700px] overflow-y-auto px-3 py-2 text-sm',\n default:\n 'min-h-full w-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n demo: 'min-h-full w-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n fullWidth: 'min-h-full w-full px-16 pb-72 pt-4 text-base sm:px-24',\n },\n },\n }\n);\n\nexport type EditorProps = PlateContentProps &\n VariantProps<typeof editorVariants>;\n\nexport const Editor = React.forwardRef<HTMLDivElement, EditorProps>(\n ({ className, disabled, focused, variant, ...props }, ref) => {\n return (\n <PlateContent\n ref={ref}\n className={cn(\n editorVariants({\n disabled,\n focused,\n variant,\n }),\n className\n )}\n disabled={disabled}\n disableDefaultStyles\n {...props}\n />\n );\n }\n);\n\nEditor.displayName = 'Editor';\n",
"path": "plate-ui/editor.tsx",
"target": "components/plate-ui/editor.tsx",
"type": "registry:ui"
Expand Down
Loading

0 comments on commit b51b963

Please sign in to comment.