From 66a5e9d4465410b2ecea3350737bc9e7bdfc0a93 Mon Sep 17 00:00:00 2001 From: TeerapatChan Date: Fri, 14 Nov 2025 09:49:53 +0700 Subject: [PATCH 1/5] fix: disabled --- .../compound/editor/components/rich-text-editor.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/react/v2/components/compound/editor/components/rich-text-editor.tsx b/packages/react/v2/components/compound/editor/components/rich-text-editor.tsx index 90c3ad59..e4f1f914 100644 --- a/packages/react/v2/components/compound/editor/components/rich-text-editor.tsx +++ b/packages/react/v2/components/compound/editor/components/rich-text-editor.tsx @@ -37,8 +37,12 @@ export const RichTextEditor = (props: RichTextEditorProps) => { if (props.value !== undefined && !isDeepEqual(editor.getJSON(), props.value)) { editor.commands.setContent(props.value) } + }, [editor, props.value]) + + useEffect(() => { + if (!editor) return editor.setEditable(!props.isDisabled) - }, [editor, props.value, props.isDisabled]) + }, [editor, props.isDisabled]) return (
From 3a9c7527eb96435f4109b8cc4b163b34a161b704 Mon Sep 17 00:00:00 2001 From: TeerapatChan Date: Fri, 14 Nov 2025 09:50:00 +0700 Subject: [PATCH 2/5] fix: z index --- .../v2/components/compound/editor/components/editor-bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/v2/components/compound/editor/components/editor-bar.tsx b/packages/react/v2/components/compound/editor/components/editor-bar.tsx index 3f5b5b66..f709658d 100644 --- a/packages/react/v2/components/compound/editor/components/editor-bar.tsx +++ b/packages/react/v2/components/compound/editor/components/editor-bar.tsx @@ -19,7 +19,7 @@ export const EditorBar: React.FC<{ className?: string; children?: React.ReactNod return (
From 0db7932f1ac83b467d2726721f6b7c5a5d5e29a2 Mon Sep 17 00:00:00 2001 From: Benz <105777142+TeerapatChan@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:54:55 +0700 Subject: [PATCH 3/5] Create flat-goats-confess.md --- .changeset/flat-goats-confess.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/flat-goats-confess.md diff --git a/.changeset/flat-goats-confess.md b/.changeset/flat-goats-confess.md new file mode 100644 index 00000000..2804bf04 --- /dev/null +++ b/.changeset/flat-goats-confess.md @@ -0,0 +1,5 @@ +--- +"@genseki/react": patch +--- + +feat: rich text bug useEffect and z index From 9b0fac02f12f07e586fa543c5f68b1c2ca4b5621 Mon Sep 17 00:00:00 2001 From: TeerapatChan Date: Fri, 14 Nov 2025 10:56:46 +0700 Subject: [PATCH 4/5] fix: custom link --- .../src/components/slot-before.tsx | 3 +- .../compound/editor/components/index.ts | 1 + .../editor/components/link-button.tsx | 50 +++++++++ .../editor/components/mark-button.tsx | 21 +--- .../extensions/custom-link-extension.ts | 105 ++---------------- 5 files changed, 67 insertions(+), 113 deletions(-) create mode 100644 packages/react/v2/components/compound/editor/components/link-button.tsx diff --git a/examples/ui-playground/src/components/slot-before.tsx b/examples/ui-playground/src/components/slot-before.tsx index 74ac9bdf..29c3f786 100644 --- a/examples/ui-playground/src/components/slot-before.tsx +++ b/examples/ui-playground/src/components/slot-before.tsx @@ -19,6 +19,7 @@ import { EditorBar, EditorBgColorPicker, EditorTextColorPicker, + LinkButton, MarkButton, RedoButton, SelectionExtension, @@ -37,7 +38,7 @@ export const EditorSlotBefore = () => { - + diff --git a/packages/react/v2/components/compound/editor/components/index.ts b/packages/react/v2/components/compound/editor/components/index.ts index 01cd1311..0561b084 100644 --- a/packages/react/v2/components/compound/editor/components/index.ts +++ b/packages/react/v2/components/compound/editor/components/index.ts @@ -1,5 +1,6 @@ export * from './editor-bar' export * from './editor-color-picker' +export * from './link-button' export * from './mark-button' export * from './redo-undo-buttons' export * from './rich-text-editor' diff --git a/packages/react/v2/components/compound/editor/components/link-button.tsx b/packages/react/v2/components/compound/editor/components/link-button.tsx new file mode 100644 index 00000000..6c4231af --- /dev/null +++ b/packages/react/v2/components/compound/editor/components/link-button.tsx @@ -0,0 +1,50 @@ +import { useCallback } from 'react' + +import { LinkIcon } from '@phosphor-icons/react' +import { useCurrentEditor } from '@tiptap/react' + +import { ToolbarItem } from '@genseki/react' + +export const LinkButton = () => { + const { editor } = useCurrentEditor() + const isLinkActive = editor?.isActive('link') ?? false + + const handleLinkToggle = useCallback(() => { + if (!editor) return + + if (isLinkActive) { + editor.chain().focus().unsetLink().run() + return + } + + const { from, to } = editor.state.selection + const selectedText = editor.state.doc.textBetween(from, to, '') + + if (!selectedText) { + alert('Please select text first') + return + } + + const url = prompt('Enter URL:', '') + + if (!url) return + + editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run() + }, [editor, isLinkActive]) + + if (!editor) return null + + return ( + + + + ) +} diff --git a/packages/react/v2/components/compound/editor/components/mark-button.tsx b/packages/react/v2/components/compound/editor/components/mark-button.tsx index 8bc6f5d8..b1798a7e 100644 --- a/packages/react/v2/components/compound/editor/components/mark-button.tsx +++ b/packages/react/v2/components/compound/editor/components/mark-button.tsx @@ -2,7 +2,6 @@ import { type Icon, - LinkIcon, ListBulletsIcon, TextBolderIcon, TextItalicIcon, @@ -13,7 +12,7 @@ import { useCurrentEditor } from '@tiptap/react' import { ToolbarItem } from '../../../../../src/react/components/primitives/toolbar' -type MarkType = 'bold' | 'italic' | 'underline' | 'strike' | 'bulletList' | 'link' +type MarkType = 'bold' | 'italic' | 'underline' | 'strike' | 'bulletList' type MarkOptions = Record< MarkType, @@ -66,22 +65,6 @@ const useMark = (type: MarkType) => { editor.chain().focus().toggleBulletList().run() }, }, - link: { - label: 'Link', - icon: LinkIcon, - isSelected: editor.isActive('link'), - onClick() { - if (!editor.isActive('link')) { - const { state } = editor - const { from, to } = state.selection - const url = state.doc.textBetween(from, to, '') - - editor.chain().focus().insertContent(`[](${url})`).run() - return - } - editor.chain().focus().unsetMark('link').run() - }, - }, } return options[type] @@ -97,7 +80,7 @@ export const MarkButton = (props: { type: MarkType }) => { diff --git a/packages/react/v2/components/compound/editor/extensions/custom-link-extension.ts b/packages/react/v2/components/compound/editor/extensions/custom-link-extension.ts index 01b790c6..6a3927d2 100644 --- a/packages/react/v2/components/compound/editor/extensions/custom-link-extension.ts +++ b/packages/react/v2/components/compound/editor/extensions/custom-link-extension.ts @@ -1,96 +1,15 @@ -import { InputRule, markInputRule, markPasteRule, PasteRule } from '@tiptap/core' -import type { LinkOptions } from '@tiptap/extension-link' -import { Link } from '@tiptap/extension-link' +import Link from '@tiptap/extension-link' -const inputRegex = /(?:^|\s)\[([^\]]*)?\]\((\S+)(?: ["“](.+)["”])?\)$/i - -const pasteRegex = /(?:^|\s)\[([^\]]*)?\]\((\S+)(?: ["“](.+)["”])?\)/gi - -function linkInputRule(config: Parameters[0]) { - const defaultMarkInputRule = markInputRule(config) - - return new InputRule({ - find: config.find, - handler(props) { - const { tr } = props.state - - defaultMarkInputRule.handler(props) - tr.setMeta('preventAutolink', true) - }, - }) -} - -function linkPasteRule(config: Parameters[0]) { - const defaultMarkPasteRule = markPasteRule(config) - - return new PasteRule({ - find: config.find, - handler(props) { - const { tr } = props.state - - defaultMarkPasteRule.handler(props) - tr.setMeta('preventAutolink', true) - }, - }) -} - -type CustomLinkExtensionOptions = LinkOptions - -const CustomLinkExtension = Link.extend({ +export const CustomLinkExtension = Link.extend({ inclusive: false, - addOptions() { - return { - ...this.parent?.(), - openOnClick: 'whenNotEditable', - } - }, - addAttributes() { - return { - ...this.parent?.(), - title: { - default: null, - }, - } - }, - - addInputRules() { - return [ - linkInputRule({ - find: inputRegex, - type: this.type, - - // We need to use `pop()` to remove the last capture groups from the match to - // satisfy Tiptap's `markPasteRule` expectation of having the content as the last - // capture group in the match (this makes the attribute order important) - getAttributes(match) { - return { - title: match.pop()?.trim(), - href: match.pop()?.trim(), - } - }, - }), - ] - }, - addPasteRules() { - return [ - linkPasteRule({ - find: pasteRegex, - type: this.type, - - // We need to use `pop()` to remove the last capture groups from the match to - // satisfy Tiptap's `markInputRule` expectation of having the content as the last - // capture group in the match (this makes the attribute order important) - getAttributes(match) { - return { - title: match.pop()?.trim(), - href: match.pop()?.trim(), - } - }, - }), - ] - }, +}).configure({ + openOnClick: false, + HTMLAttributes: { + class: 'custom-link', + rel: 'noopener noreferrer', + target: '_blank', + }, + protocols: ['http', 'https', 'mailto', 'tel'], + autolink: true, + linkOnPaste: true, }) - -export { CustomLinkExtension } - -export type { CustomLinkExtensionOptions } From 4bbecdad38e6a98b268ceff45dd927f7a8737ddc Mon Sep 17 00:00:00 2001 From: Benz <105777142+TeerapatChan@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:11:51 +0700 Subject: [PATCH 5/5] Fix rich text bug and update link handling --- .changeset/flat-goats-confess.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.changeset/flat-goats-confess.md b/.changeset/flat-goats-confess.md index 2804bf04..5306e821 100644 --- a/.changeset/flat-goats-confess.md +++ b/.changeset/flat-goats-confess.md @@ -2,4 +2,5 @@ "@genseki/react": patch --- -feat: rich text bug useEffect and z index +fix: rich text bug useEffect and z index +fix: rich text link to use prompt instead of markdown