From 6f2370a377b487e67bd4dde1ed87dbf9f0aaa079 Mon Sep 17 00:00:00 2001 From: zbeyens Date: Tue, 26 Nov 2024 15:07:57 +0100 Subject: [PATCH] docs --- apps/www/public/r/index.json | 7 ++++++- apps/www/public/r/styles/default/editor-select.json | 3 +-- apps/www/public/r/styles/default/select-editor.json | 7 ++++++- apps/www/public/r/styles/default/tag-element.json | 2 +- .../src/__registry__/default/block/editor-select/page.tsx | 2 ++ apps/www/src/config/docs-icons.tsx | 1 + 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/apps/www/public/r/index.json b/apps/www/public/r/index.json index bd32bf637e..d7fa2dbde4 100644 --- a/apps/www/public/r/index.json +++ b/apps/www/public/r/index.json @@ -1026,7 +1026,7 @@ "description": "A tag element component with selection states and styling.", "docs": [ { - "route": "/docs/tag" + "route": "/docs/multi-select" } ], "examples": [ @@ -1944,6 +1944,11 @@ ], "doc": { "description": "An editor to select tags.", + "docs": [ + { + "route": "/docs/multi-select" + } + ], "examples": [ "select-editor-demo" ], diff --git a/apps/www/public/r/styles/default/editor-select.json b/apps/www/public/r/styles/default/editor-select.json index 40a1aea780..af6609a658 100644 --- a/apps/www/public/r/styles/default/editor-select.json +++ b/apps/www/public/r/styles/default/editor-select.json @@ -1,9 +1,8 @@ { "description": "A select editor", - "descriptionSrc": "/docs/multi-select", "files": [ { - "content": "import EditorSelectForm from '@/registry/default/example/select-editor-demo';\n\nexport default function Page() {\n return (\n
\n \n
\n );\n}\n", + "content": "import EditorSelectForm from '@/registry/default/example/select-editor-demo';\nexport const descriptionSrc = '/docs/multi-select';\n\nexport default function Page() {\n return (\n
\n \n
\n );\n}\n", "path": "block/editor-select/page.tsx", "target": "app/editor/page.tsx", "type": "registry:page" diff --git a/apps/www/public/r/styles/default/select-editor.json b/apps/www/public/r/styles/default/select-editor.json index a30810ab22..413074d532 100644 --- a/apps/www/public/r/styles/default/select-editor.json +++ b/apps/www/public/r/styles/default/select-editor.json @@ -6,6 +6,11 @@ ], "doc": { "description": "An editor to select tags.", + "docs": [ + { + "route": "/docs/multi-select" + } + ], "examples": [ "select-editor-demo" ], @@ -13,7 +18,7 @@ }, "files": [ { - "content": "'use client';\n\nimport React from 'react';\n\nimport { useCommandActions } from '@udecode/cmdk';\nimport {\n getEditorString,\n isHotkey,\n removeEditorText,\n replaceNodeChildren,\n} from '@udecode/plate-common';\nimport {\n Plate,\n useEditorContainerRef,\n useEditorRef,\n usePlateEditor,\n} from '@udecode/plate-common/react';\nimport { isEqualTags } from '@udecode/plate-tag';\nimport {\n MultiSelectPlugin,\n TagPlugin,\n useSelectEditorCombobox,\n useSelectableItems,\n} from '@udecode/plate-tag/react';\nimport { Fzf } from 'fzf';\nimport { PlusIcon } from 'lucide-react';\n\nimport { Command, CommandGroup, CommandItem, CommandList } from './command';\nimport { Editor, EditorContainer } from './editor';\nimport { Popover, PopoverAnchor, PopoverContent } from './popover';\nimport { TagElement } from './tag-element';\n\nexport type SelectItem = {\n value: string;\n isNew?: boolean;\n};\n\ntype SelectEditorContextValue = {\n items: SelectItem[];\n open: boolean;\n setOpen: (open: boolean) => void;\n defaultValue?: SelectItem[];\n value?: SelectItem[];\n onValueChange?: (items: SelectItem[]) => void;\n};\n\nconst SelectEditorContext = React.createContext<\n SelectEditorContextValue | undefined\n>(undefined);\n\nconst useSelectEditorContext = () => {\n const context = React.useContext(SelectEditorContext);\n\n if (!context) {\n throw new Error('useSelectEditor must be used within SelectEditor');\n }\n\n return context;\n};\n\nexport function SelectEditor({\n children,\n defaultValue,\n items = [],\n value,\n onValueChange,\n}: {\n children: React.ReactNode;\n defaultValue?: SelectItem[];\n items?: SelectItem[];\n value?: SelectItem[];\n onValueChange?: (items: SelectItem[]) => void;\n}) {\n const [open, setOpen] = React.useState(false);\n const [internalValue] = React.useState(defaultValue);\n\n return (\n \n \n {children}\n \n \n );\n}\n\nexport function SelectEditorContent({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const { value } = useSelectEditorContext();\n const { setSearch } = useCommandActions();\n\n const editor = usePlateEditor(\n {\n plugins: [\n MultiSelectPlugin.configure({\n node: {\n component: TagElement,\n },\n }),\n ],\n value: createEditorValue(value),\n },\n []\n );\n\n React.useEffect(() => {\n if (!isEqualTags(editor, value)) {\n replaceNodeChildren(editor, {\n at: [],\n nodes: createEditorValue(value),\n });\n }\n }, [editor, value]);\n\n return (\n {\n setSearch(getEditorString(editor, []));\n }}\n editor={editor}\n >\n {children}\n \n );\n}\n\nexport const SelectEditorInput = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n const editor = useEditorRef();\n const { setOpen } = useSelectEditorContext();\n const { selectCurrentItem, selectFirstItem } = useCommandActions();\n\n return (\n setOpen(false)}\n onFocusCapture={() => {\n setOpen(true);\n selectFirstItem();\n }}\n onKeyDown={(e) => {\n if (isHotkey('enter', e)) {\n e.preventDefault();\n selectCurrentItem();\n removeEditorText(editor);\n }\n if (isHotkey('escape', e) || isHotkey('mod+enter', e)) {\n e.preventDefault();\n e.currentTarget.blur();\n }\n }}\n autoFocusOnEditable\n {...props}\n />\n );\n});\n\nexport function SelectEditorCombobox() {\n const editor = useEditorRef();\n const containerRef = useEditorContainerRef();\n const { items, open, onValueChange } = useSelectEditorContext();\n const selectableItems = useSelectableItems({\n filter: fzfFilter,\n items,\n });\n const { selectFirstItem } = useCommandActions();\n\n useSelectEditorCombobox({ open, selectFirstItem, onValueChange });\n\n if (!open || selectableItems.length === 0) return null;\n\n return (\n \n \n e.preventDefault()}\n onOpenAutoFocus={(e) => e.preventDefault()}\n align=\"start\"\n alignOffset={-4}\n animate={false}\n sideOffset={8}\n >\n \n \n {selectableItems.map((item) => (\n e.preventDefault()}\n onSelect={() => {\n editor.getTransforms(TagPlugin).insert.tag(item);\n }}\n >\n {item.isNew ? (\n
\n \n Create new label:\n \"{item.value}\"\n
\n ) : (\n item.value\n )}\n \n ))}\n
\n
\n \n
\n );\n}\n\nconst createEditorValue = (value?: SelectItem[]) => [\n {\n children: [\n { text: '' },\n ...(value?.flatMap((item) => [\n {\n children: [{ text: '' }],\n type: TagPlugin.key,\n ...item,\n },\n {\n text: '',\n },\n ]) ?? []),\n ],\n type: 'p',\n },\n];\n\nconst fzfFilter = (value: string, search: string): boolean => {\n if (!search) return true;\n\n const fzf = new Fzf([value], {\n casing: 'case-insensitive',\n selector: (v: string) => v,\n });\n\n return fzf.find(search).length > 0;\n};\n", + "content": "'use client';\n\nimport React from 'react';\n\nimport { useCommandActions } from '@udecode/cmdk';\nimport {\n getEditorString,\n isHotkey,\n removeEditorText,\n replaceNodeChildren,\n} from '@udecode/plate-common';\nimport {\n Plate,\n useEditorContainerRef,\n useEditorRef,\n usePlateEditor,\n} from '@udecode/plate-common/react';\nimport { isEqualTags } from '@udecode/plate-tag';\nimport {\n MultiSelectPlugin,\n TagPlugin,\n useSelectEditorCombobox,\n useSelectableItems,\n} from '@udecode/plate-tag/react';\nimport { Fzf } from 'fzf';\nimport { PlusIcon } from 'lucide-react';\n\nimport { Command, CommandGroup, CommandItem, CommandList } from './command';\nimport { Editor, EditorContainer } from './editor';\nimport { Popover, PopoverAnchor, PopoverContent } from './popover';\nimport { TagElement } from './tag-element';\n\nexport type SelectItem = {\n value: string;\n isNew?: boolean;\n};\n\ntype SelectEditorContextValue = {\n items: SelectItem[];\n open: boolean;\n setOpen: (open: boolean) => void;\n defaultValue?: SelectItem[];\n value?: SelectItem[];\n onValueChange?: (items: SelectItem[]) => void;\n};\n\nconst SelectEditorContext = React.createContext<\n SelectEditorContextValue | undefined\n>(undefined);\n\nconst useSelectEditorContext = () => {\n const context = React.useContext(SelectEditorContext);\n\n if (!context) {\n throw new Error('useSelectEditor must be used within SelectEditor');\n }\n\n return context;\n};\n\nexport function SelectEditor({\n children,\n defaultValue,\n items = [],\n value,\n onValueChange,\n}: {\n children: React.ReactNode;\n defaultValue?: SelectItem[];\n items?: SelectItem[];\n value?: SelectItem[];\n onValueChange?: (items: SelectItem[]) => void;\n}) {\n const [open, setOpen] = React.useState(false);\n const [internalValue] = React.useState(defaultValue);\n\n return (\n \n \n {children}\n \n \n );\n}\n\nexport function SelectEditorContent({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const { value } = useSelectEditorContext();\n const { setSearch } = useCommandActions();\n\n const editor = usePlateEditor(\n {\n plugins: [MultiSelectPlugin.withComponent(TagElement)],\n value: createEditorValue(value),\n },\n []\n );\n\n React.useEffect(() => {\n if (!isEqualTags(editor, value)) {\n replaceNodeChildren(editor, {\n at: [],\n nodes: createEditorValue(value),\n });\n }\n }, [editor, value]);\n\n return (\n {\n setSearch(getEditorString(editor, []));\n }}\n editor={editor}\n >\n {children}\n \n );\n}\n\nexport const SelectEditorInput = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n const editor = useEditorRef();\n const { setOpen } = useSelectEditorContext();\n const { selectCurrentItem, selectFirstItem } = useCommandActions();\n\n return (\n setOpen(false)}\n onFocusCapture={() => {\n setOpen(true);\n selectFirstItem();\n }}\n onKeyDown={(e) => {\n if (isHotkey('enter', e)) {\n e.preventDefault();\n selectCurrentItem();\n removeEditorText(editor);\n }\n if (isHotkey('escape', e) || isHotkey('mod+enter', e)) {\n e.preventDefault();\n e.currentTarget.blur();\n }\n }}\n autoFocusOnEditable\n {...props}\n />\n );\n});\n\nexport function SelectEditorCombobox() {\n const editor = useEditorRef();\n const containerRef = useEditorContainerRef();\n const { items, open, onValueChange } = useSelectEditorContext();\n const selectableItems = useSelectableItems({\n filter: fzfFilter,\n items,\n });\n const { selectFirstItem } = useCommandActions();\n\n useSelectEditorCombobox({ open, selectFirstItem, onValueChange });\n\n if (!open || selectableItems.length === 0) return null;\n\n return (\n \n \n e.preventDefault()}\n onOpenAutoFocus={(e) => e.preventDefault()}\n align=\"start\"\n alignOffset={-4}\n animate={false}\n sideOffset={8}\n >\n \n \n {selectableItems.map((item) => (\n e.preventDefault()}\n onSelect={() => {\n editor.getTransforms(TagPlugin).insert.tag(item);\n }}\n >\n {item.isNew ? (\n
\n \n Create new label:\n \"{item.value}\"\n
\n ) : (\n item.value\n )}\n \n ))}\n
\n
\n \n
\n );\n}\n\nconst createEditorValue = (value?: SelectItem[]) => [\n {\n children: [\n { text: '' },\n ...(value?.flatMap((item) => [\n {\n children: [{ text: '' }],\n type: TagPlugin.key,\n ...item,\n },\n {\n text: '',\n },\n ]) ?? []),\n ],\n type: 'p',\n },\n];\n\nconst fzfFilter = (value: string, search: string): boolean => {\n if (!search) return true;\n\n const fzf = new Fzf([value], {\n casing: 'case-insensitive',\n selector: (v: string) => v,\n });\n\n return fzf.find(search).length > 0;\n};\n", "path": "plate-ui/select-editor.tsx", "target": "components/plate-ui/select-editor.tsx", "type": "registry:ui" diff --git a/apps/www/public/r/styles/default/tag-element.json b/apps/www/public/r/styles/default/tag-element.json index dc5b330760..ee6d260d76 100644 --- a/apps/www/public/r/styles/default/tag-element.json +++ b/apps/www/public/r/styles/default/tag-element.json @@ -4,7 +4,7 @@ "description": "A tag element component with selection states and styling.", "docs": [ { - "route": "/docs/tag" + "route": "/docs/multi-select" } ], "examples": [ diff --git a/apps/www/src/__registry__/default/block/editor-select/page.tsx b/apps/www/src/__registry__/default/block/editor-select/page.tsx index a1621b8251..59af9d8599 100644 --- a/apps/www/src/__registry__/default/block/editor-select/page.tsx +++ b/apps/www/src/__registry__/default/block/editor-select/page.tsx @@ -2,6 +2,8 @@ import EditorSelectForm from '@/registry/default/example/select-editor-demo'; export const description = 'A select editor'; +export const descriptionSrc = '/docs/multi-select'; + export const iframeHeight = '650px'; export const containerClassName = 'w-full h-full'; diff --git a/apps/www/src/config/docs-icons.tsx b/apps/www/src/config/docs-icons.tsx index 693bda2c67..02d1c512d1 100644 --- a/apps/www/src/config/docs-icons.tsx +++ b/apps/www/src/config/docs-icons.tsx @@ -237,6 +237,7 @@ export const DocIcons = { resizable: ProportionsIcon, 'search-highlight-leaf': HighlighterIcon, select: KeyboardIcon, + 'select-editor': TagsIcon, separator: SeparatorHorizontalIcon, 'server-side': ServerIcon, 'single-line': RectangleHorizontalIcon,