mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-11 01:40:32 +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'
|
||||
|
||||
export let node: MarkupNode
|
||||
export let single = true
|
||||
export let preview = false
|
||||
</script>
|
||||
|
||||
@ -27,9 +28,9 @@
|
||||
|
||||
{#if marks.length > 0}
|
||||
<NodeMarks {marks}>
|
||||
<NodeContent {node} {preview} />
|
||||
<NodeContent {node} {single} {preview} />
|
||||
</NodeMarks>
|
||||
{:else}
|
||||
<NodeContent {node} {preview} />
|
||||
<NodeContent {node} {single} {preview} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -22,6 +22,7 @@
|
||||
import Node from './Node.svelte'
|
||||
|
||||
export let node: MarkupNode
|
||||
export let single = true
|
||||
export let preview = false
|
||||
|
||||
function toRef (objectId: string): Ref<Doc> {
|
||||
@ -78,11 +79,13 @@
|
||||
{/if}
|
||||
{:else if node.type === MarkupNodeType.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}
|
||||
<p class="p-inline contrast" class:overflow-label={preview} class:emojiOnly={checkEmoji(nodes)}>
|
||||
{#if nodes.length > 0}
|
||||
{#each nodes as node}
|
||||
<Node {node} {preview} />
|
||||
<Node {node} {preview} single={nodes.length === 1} />
|
||||
{/each}
|
||||
{/if}
|
||||
</p>
|
||||
|
@ -25,6 +25,7 @@ export enum MarkupNodeType {
|
||||
image = 'image',
|
||||
file = 'file',
|
||||
reference = 'reference',
|
||||
emoji = 'emoji',
|
||||
hard_break = 'hardBreak',
|
||||
ordered_list = 'orderedList',
|
||||
bullet_list = 'bulletList',
|
||||
|
@ -91,6 +91,7 @@ const nonEmptyNodes = [
|
||||
MarkupNodeType.horizontal_rule,
|
||||
MarkupNodeType.image,
|
||||
MarkupNodeType.reference,
|
||||
MarkupNodeType.emoji,
|
||||
MarkupNodeType.subLink,
|
||||
MarkupNodeType.table
|
||||
]
|
||||
|
@ -37,6 +37,7 @@ import { ImageNode, ImageOptions } from '../nodes/image'
|
||||
import { MarkdownNode } from '../nodes/markdown'
|
||||
import { MermaidExtension, mermaidOptions } from '../nodes/mermaid'
|
||||
import { ReferenceNode } from '../nodes/reference'
|
||||
import { EmojiNode } from '../nodes/emoji'
|
||||
import { TodoItemNode, TodoListNode } from '../nodes/todo'
|
||||
|
||||
import { DefaultKit, DefaultKitOptions } from './default-kit'
|
||||
@ -103,6 +104,7 @@ export const ServerKit = Extension.create<ServerKitOptions>({
|
||||
TodoItemNode,
|
||||
TodoListNode,
|
||||
ReferenceNode,
|
||||
EmojiNode,
|
||||
CommentNode,
|
||||
MarkdownNode,
|
||||
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 './reference'
|
||||
export * from './emoji'
|
||||
export * from './todo'
|
||||
export * from './file'
|
||||
export * from './codeblock'
|
||||
|
@ -77,6 +77,9 @@
|
||||
insertText: (text) => {
|
||||
editor?.insertText(text)
|
||||
},
|
||||
insertEmoji: (emoji) => {
|
||||
editor?.insertEmoji(emoji)
|
||||
},
|
||||
insertMarkup: (markup) => {
|
||||
editor?.insertMarkup(markup)
|
||||
},
|
||||
|
@ -178,6 +178,9 @@
|
||||
insertText: (text) => {
|
||||
editor?.commands.insertContent(text)
|
||||
},
|
||||
insertEmoji: (emoji) => {
|
||||
editor?.commands.insertEmoji(emoji)
|
||||
},
|
||||
insertMarkup: (markup) => {
|
||||
editor?.commands.insertContent(markupToJSON(markup))
|
||||
},
|
||||
|
@ -84,6 +84,9 @@
|
||||
insertText: (text) => {
|
||||
editor?.insertText(text)
|
||||
},
|
||||
insertEmoji: (emoji) => {
|
||||
editor?.insertEmoji(emoji)
|
||||
},
|
||||
insertMarkup: (markup) => {
|
||||
editor?.insertMarkup(markup)
|
||||
},
|
||||
|
@ -79,6 +79,9 @@
|
||||
insertText: (text) => {
|
||||
editor?.insertText(text)
|
||||
},
|
||||
insertEmoji: (emoji) => {
|
||||
editor?.insertEmoji(emoji)
|
||||
},
|
||||
insertMarkup: (markup) => {
|
||||
editor?.insertMarkup(markup)
|
||||
},
|
||||
|
@ -96,6 +96,10 @@
|
||||
return editor
|
||||
}
|
||||
|
||||
export function insertEmoji (emoji: string): void {
|
||||
editor?.commands.insertEmoji(emoji)
|
||||
}
|
||||
|
||||
export function insertText (text: string): void {
|
||||
editor?.commands.insertContent(text)
|
||||
}
|
||||
|
@ -27,8 +27,7 @@ export const defaultRefActions: RefAction[] = [
|
||||
if (emoji === null || emoji === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
editorHandler.insertText(emoji.emoji)
|
||||
editorHandler.insertEmoji(emoji.emoji)
|
||||
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'
|
||||
|
||||
const emojiReplaceDict = {
|
||||
@ -63,7 +63,7 @@ function isValidEmojiPosition ($pos: ResolvedPos): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
export const EmojiExtension = Extension.create({
|
||||
export const EmojiExtension = EmojiNode.extend<EmojiNodeOptions>({
|
||||
addInputRules () {
|
||||
return Object.keys(emojiReplaceDict).map((pattern) => {
|
||||
return {
|
||||
|
@ -16,6 +16,7 @@ export type CollaboratorType = 'local' | 'cloud'
|
||||
*/
|
||||
export interface TextEditorHandler {
|
||||
insertText: (html: string) => void
|
||||
insertEmoji: (emoji: string) => void
|
||||
insertMarkup: (markup: Markup) => void
|
||||
insertTemplate: (name: string, markup: string) => void
|
||||
insertTable: (options: { rows?: number, cols?: number, withHeaderRow?: boolean }) => void
|
||||
|
Loading…
Reference in New Issue
Block a user