mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-13 10:53:06 +00:00
Add emoji text node
Signed-off-by: Anton Alexeyev <alexeyev.anton@gmail.com>
This commit is contained in:
parent
76a425ba98
commit
4d1b2a436d
@ -19,6 +19,7 @@
|
|||||||
import NodeContent from './NodeContent.svelte'
|
import NodeContent from './NodeContent.svelte'
|
||||||
|
|
||||||
export let node: MarkupNode
|
export let node: MarkupNode
|
||||||
|
export let single = true
|
||||||
export let preview = false
|
export let preview = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -27,9 +28,9 @@
|
|||||||
|
|
||||||
{#if marks.length > 0}
|
{#if marks.length > 0}
|
||||||
<NodeMarks {marks}>
|
<NodeMarks {marks}>
|
||||||
<NodeContent {node} {preview} />
|
<NodeContent {node} {single} {preview} />
|
||||||
</NodeMarks>
|
</NodeMarks>
|
||||||
{:else}
|
{:else}
|
||||||
<NodeContent {node} {preview} />
|
<NodeContent {node} {single} {preview} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
import Node from './Node.svelte'
|
import Node from './Node.svelte'
|
||||||
|
|
||||||
export let node: MarkupNode
|
export let node: MarkupNode
|
||||||
|
export let single = true
|
||||||
export let preview = false
|
export let preview = false
|
||||||
|
|
||||||
function toRef (objectId: string): Ref<Doc> {
|
function toRef (objectId: string): Ref<Doc> {
|
||||||
@ -78,11 +79,13 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{:else if node.type === MarkupNodeType.text}
|
{:else if node.type === MarkupNodeType.text}
|
||||||
{node.text}
|
{node.text}
|
||||||
|
{:else if node.type === MarkupNodeType.emoji}
|
||||||
|
<span class="emoji" class:emojiOnly={single}>{node.attrs?.emoji}</span>
|
||||||
{:else if node.type === MarkupNodeType.paragraph}
|
{:else if node.type === MarkupNodeType.paragraph}
|
||||||
<p class="p-inline contrast" class:overflow-label={preview} class:emojiOnly={checkEmoji(nodes)}>
|
<p class="p-inline contrast" class:overflow-label={preview} class:emojiOnly={checkEmoji(nodes)}>
|
||||||
{#if nodes.length > 0}
|
{#if nodes.length > 0}
|
||||||
{#each nodes as node}
|
{#each nodes as node}
|
||||||
<Node {node} {preview} />
|
<Node {node} {preview} single={nodes.length === 1} />
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
|
@ -25,6 +25,7 @@ export enum MarkupNodeType {
|
|||||||
image = 'image',
|
image = 'image',
|
||||||
file = 'file',
|
file = 'file',
|
||||||
reference = 'reference',
|
reference = 'reference',
|
||||||
|
emoji = 'emoji',
|
||||||
hard_break = 'hardBreak',
|
hard_break = 'hardBreak',
|
||||||
ordered_list = 'orderedList',
|
ordered_list = 'orderedList',
|
||||||
bullet_list = 'bulletList',
|
bullet_list = 'bulletList',
|
||||||
|
@ -91,6 +91,7 @@ const nonEmptyNodes = [
|
|||||||
MarkupNodeType.horizontal_rule,
|
MarkupNodeType.horizontal_rule,
|
||||||
MarkupNodeType.image,
|
MarkupNodeType.image,
|
||||||
MarkupNodeType.reference,
|
MarkupNodeType.reference,
|
||||||
|
MarkupNodeType.emoji,
|
||||||
MarkupNodeType.subLink,
|
MarkupNodeType.subLink,
|
||||||
MarkupNodeType.table
|
MarkupNodeType.table
|
||||||
]
|
]
|
||||||
|
@ -37,6 +37,7 @@ import { ImageNode, ImageOptions } from '../nodes/image'
|
|||||||
import { MarkdownNode } from '../nodes/markdown'
|
import { MarkdownNode } from '../nodes/markdown'
|
||||||
import { MermaidExtension, mermaidOptions } from '../nodes/mermaid'
|
import { MermaidExtension, mermaidOptions } from '../nodes/mermaid'
|
||||||
import { ReferenceNode } from '../nodes/reference'
|
import { ReferenceNode } from '../nodes/reference'
|
||||||
|
import { EmojiNode } from '../nodes/emoji'
|
||||||
import { TodoItemNode, TodoListNode } from '../nodes/todo'
|
import { TodoItemNode, TodoListNode } from '../nodes/todo'
|
||||||
|
|
||||||
import { DefaultKit, DefaultKitOptions } from './default-kit'
|
import { DefaultKit, DefaultKitOptions } from './default-kit'
|
||||||
@ -103,6 +104,7 @@ export const ServerKit = Extension.create<ServerKitOptions>({
|
|||||||
TodoItemNode,
|
TodoItemNode,
|
||||||
TodoListNode,
|
TodoListNode,
|
||||||
ReferenceNode,
|
ReferenceNode,
|
||||||
|
EmojiNode,
|
||||||
CommentNode,
|
CommentNode,
|
||||||
MarkdownNode,
|
MarkdownNode,
|
||||||
NodeUuid,
|
NodeUuid,
|
||||||
|
79
packages/text/src/nodes/emoji.ts
Normal file
79
packages/text/src/nodes/emoji.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2025 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import { Node, mergeAttributes } from '@tiptap/core'
|
||||||
|
|
||||||
|
declare module '@tiptap/core' {
|
||||||
|
interface Commands<ReturnType> {
|
||||||
|
emoji: {
|
||||||
|
insertEmoji: (emoji: string) => ReturnType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EmojiNodeOptions {
|
||||||
|
emoji: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EmojiNode = Node.create<EmojiNodeOptions>({
|
||||||
|
name: 'emoji',
|
||||||
|
group: 'inline',
|
||||||
|
inline: true,
|
||||||
|
atom: true,
|
||||||
|
selectable: false,
|
||||||
|
|
||||||
|
addAttributes () {
|
||||||
|
return {
|
||||||
|
emoji: {
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands () {
|
||||||
|
return {
|
||||||
|
insertEmoji:
|
||||||
|
(emoji: string) =>
|
||||||
|
({ commands }) => {
|
||||||
|
return commands.insertContent({
|
||||||
|
type: this.name,
|
||||||
|
attrs: { emoji }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
parseHTML () {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: `span[data-type="${this.name}"]`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML ({ node, HTMLAttributes }) {
|
||||||
|
return [
|
||||||
|
'span',
|
||||||
|
mergeAttributes(
|
||||||
|
{
|
||||||
|
'data-type': this.name,
|
||||||
|
class: 'emoji'
|
||||||
|
},
|
||||||
|
HTMLAttributes
|
||||||
|
),
|
||||||
|
node.attrs.emoji
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
export * from './image'
|
export * from './image'
|
||||||
export * from './reference'
|
export * from './reference'
|
||||||
|
export * from './emoji'
|
||||||
export * from './todo'
|
export * from './todo'
|
||||||
export * from './file'
|
export * from './file'
|
||||||
export * from './codeblock'
|
export * from './codeblock'
|
||||||
|
@ -77,6 +77,9 @@
|
|||||||
insertText: (text) => {
|
insertText: (text) => {
|
||||||
editor?.insertText(text)
|
editor?.insertText(text)
|
||||||
},
|
},
|
||||||
|
insertEmoji: (emoji) => {
|
||||||
|
editor?.insertEmoji(emoji)
|
||||||
|
},
|
||||||
insertMarkup: (markup) => {
|
insertMarkup: (markup) => {
|
||||||
editor?.insertMarkup(markup)
|
editor?.insertMarkup(markup)
|
||||||
},
|
},
|
||||||
|
@ -178,6 +178,9 @@
|
|||||||
insertText: (text) => {
|
insertText: (text) => {
|
||||||
editor?.commands.insertContent(text)
|
editor?.commands.insertContent(text)
|
||||||
},
|
},
|
||||||
|
insertEmoji: (emoji) => {
|
||||||
|
editor?.commands.insertEmoji(emoji)
|
||||||
|
},
|
||||||
insertMarkup: (markup) => {
|
insertMarkup: (markup) => {
|
||||||
editor?.commands.insertContent(markupToJSON(markup))
|
editor?.commands.insertContent(markupToJSON(markup))
|
||||||
},
|
},
|
||||||
|
@ -84,6 +84,9 @@
|
|||||||
insertText: (text) => {
|
insertText: (text) => {
|
||||||
editor?.insertText(text)
|
editor?.insertText(text)
|
||||||
},
|
},
|
||||||
|
insertEmoji: (emoji) => {
|
||||||
|
editor?.insertEmoji(emoji)
|
||||||
|
},
|
||||||
insertMarkup: (markup) => {
|
insertMarkup: (markup) => {
|
||||||
editor?.insertMarkup(markup)
|
editor?.insertMarkup(markup)
|
||||||
},
|
},
|
||||||
|
@ -79,6 +79,9 @@
|
|||||||
insertText: (text) => {
|
insertText: (text) => {
|
||||||
editor?.insertText(text)
|
editor?.insertText(text)
|
||||||
},
|
},
|
||||||
|
insertEmoji: (emoji) => {
|
||||||
|
editor?.insertEmoji(emoji)
|
||||||
|
},
|
||||||
insertMarkup: (markup) => {
|
insertMarkup: (markup) => {
|
||||||
editor?.insertMarkup(markup)
|
editor?.insertMarkup(markup)
|
||||||
},
|
},
|
||||||
|
@ -96,6 +96,10 @@
|
|||||||
return editor
|
return editor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function insertEmoji (emoji: string): void {
|
||||||
|
editor?.commands.insertEmoji(emoji)
|
||||||
|
}
|
||||||
|
|
||||||
export function insertText (text: string): void {
|
export function insertText (text: string): void {
|
||||||
editor?.commands.insertContent(text)
|
editor?.commands.insertContent(text)
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,7 @@ export const defaultRefActions: RefAction[] = [
|
|||||||
if (emoji === null || emoji === undefined) {
|
if (emoji === null || emoji === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
editorHandler.insertEmoji(emoji.emoji)
|
||||||
editorHandler.insertText(emoji.emoji)
|
|
||||||
editorHandler.focus()
|
editorHandler.focus()
|
||||||
},
|
},
|
||||||
() => {}
|
() => {}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Extension } from '@tiptap/core'
|
import { EmojiNode, type EmojiNodeOptions } from '@hcengineering/text'
|
||||||
import { type ResolvedPos } from '@tiptap/pm/model'
|
import { type ResolvedPos } from '@tiptap/pm/model'
|
||||||
|
|
||||||
const emojiReplaceDict = {
|
const emojiReplaceDict = {
|
||||||
@ -63,7 +63,7 @@ function isValidEmojiPosition ($pos: ResolvedPos): boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmojiExtension = Extension.create({
|
export const EmojiExtension = EmojiNode.extend<EmojiNodeOptions>({
|
||||||
addInputRules () {
|
addInputRules () {
|
||||||
return Object.keys(emojiReplaceDict).map((pattern) => {
|
return Object.keys(emojiReplaceDict).map((pattern) => {
|
||||||
return {
|
return {
|
||||||
|
@ -16,6 +16,7 @@ export type CollaboratorType = 'local' | 'cloud'
|
|||||||
*/
|
*/
|
||||||
export interface TextEditorHandler {
|
export interface TextEditorHandler {
|
||||||
insertText: (html: string) => void
|
insertText: (html: string) => void
|
||||||
|
insertEmoji: (emoji: string) => void
|
||||||
insertMarkup: (markup: Markup) => void
|
insertMarkup: (markup: Markup) => void
|
||||||
insertTemplate: (name: string, markup: string) => void
|
insertTemplate: (name: string, markup: string) => void
|
||||||
insertTable: (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) => void
|
insertTable: (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) => void
|
||||||
|
Loading…
Reference in New Issue
Block a user