@tiptap/extension-ruby-text 3.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,174 @@
1
+ import { Mark, mergeAttributes } from '@tiptap/core'
2
+
3
+ import type { RubyTextAnnotationEditorProps } from './ruby-text-decoration-plugin.js'
4
+ import { RubyTextDecorationPlugin } from './ruby-text-decoration-plugin.js'
5
+
6
+ export type { RubyTextAnnotationEditorProps }
7
+
8
+ export interface RubyTextOptions {
9
+ /**
10
+ * HTML attributes to add to the ruby element.
11
+ * @default {}
12
+ */
13
+ HTMLAttributes: Record<string, any>
14
+ /**
15
+ * Whether clicking an annotation opens an inline editor.
16
+ * @default true
17
+ */
18
+ allowClickToEdit: boolean
19
+ /**
20
+ * Renders a custom element used as the inline annotation editor.
21
+ * The returned element is mounted inside the `rt` element. A descendant
22
+ * with the `autofocus` attribute is focused, otherwise the element itself.
23
+ * When not set, a plain text input is rendered.
24
+ * @default undefined
25
+ */
26
+ renderAnnotationEditor?: (props: RubyTextAnnotationEditorProps) => HTMLElement
27
+ }
28
+
29
+ export interface RubyTextAttributes {
30
+ /**
31
+ * The ruby text annotation rendered in the HTML `rt` element.
32
+ */
33
+ rt: string | null
34
+ }
35
+
36
+ declare module '@tiptap/core' {
37
+ interface Commands<ReturnType> {
38
+ rubyText: {
39
+ /**
40
+ * Set a ruby text mark with an annotation on the current selection.
41
+ * @example editor.commands.setRubyText({ rt: 'かんじ' })
42
+ */
43
+ setRubyText: (attributes: RubyTextAttributes) => ReturnType
44
+ /**
45
+ * Toggle a ruby text mark on the current selection.
46
+ * @example editor.commands.toggleRubyText({ rt: 'かんじ' })
47
+ */
48
+ toggleRubyText: (attributes: RubyTextAttributes) => ReturnType
49
+ /**
50
+ * Remove the ruby text mark from the current selection.
51
+ * @example editor.commands.unsetRubyText()
52
+ */
53
+ unsetRubyText: () => ReturnType
54
+ }
55
+ }
56
+ }
57
+
58
+ /**
59
+ * This extension adds support for HTML ruby text annotations.
60
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby
61
+ */
62
+ export const RubyText = Mark.create<RubyTextOptions>({
63
+ name: 'rubyText',
64
+
65
+ inclusive: false,
66
+
67
+ addOptions() {
68
+ return {
69
+ HTMLAttributes: {},
70
+ allowClickToEdit: true,
71
+ renderAnnotationEditor: undefined,
72
+ }
73
+ },
74
+
75
+ addAttributes() {
76
+ return {
77
+ rt: {
78
+ default: null,
79
+ },
80
+ }
81
+ },
82
+
83
+ parseHTML() {
84
+ return [
85
+ {
86
+ tag: 'ruby',
87
+ contentElement: (node: HTMLElement) => {
88
+ const rb = node.querySelector('rb')
89
+
90
+ if (rb) {
91
+ return rb
92
+ }
93
+
94
+ const surrogate = document.createElement('span')
95
+
96
+ Array.from(node.childNodes).forEach(child => {
97
+ if (child.nodeName !== 'RT' && child.nodeName !== 'RP') {
98
+ surrogate.appendChild(child.cloneNode(true))
99
+ }
100
+ })
101
+
102
+ return surrogate
103
+ },
104
+ getAttrs: (node: HTMLElement) => {
105
+ const rt = node.querySelector('rt')
106
+
107
+ if (!rt) {
108
+ return false
109
+ }
110
+
111
+ return { rt: rt.textContent ?? '' }
112
+ },
113
+ },
114
+ ]
115
+ },
116
+
117
+ renderHTML({ HTMLAttributes, mark }) {
118
+ return [
119
+ 'ruby',
120
+ mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
121
+ ['rb', 0],
122
+ ...(mark.attrs.rt == null ? [] : [['rt', { contenteditable: 'false' }, mark.attrs.rt]]),
123
+ ]
124
+ },
125
+
126
+ addCommands() {
127
+ return {
128
+ setRubyText:
129
+ attributes =>
130
+ ({ commands }) => {
131
+ return commands.setMark(this.name, attributes)
132
+ },
133
+ toggleRubyText:
134
+ attributes =>
135
+ ({ commands }) => {
136
+ return commands.toggleMark(this.name, attributes, { extendEmptyMarkRange: true })
137
+ },
138
+ unsetRubyText:
139
+ () =>
140
+ ({ commands }) => {
141
+ return commands.unsetMark(this.name, { extendEmptyMarkRange: true })
142
+ },
143
+ }
144
+ },
145
+
146
+ addProseMirrorPlugins() {
147
+ return [
148
+ RubyTextDecorationPlugin(this.type, {
149
+ editor: this.editor,
150
+ allowClickToEdit: this.options.allowClickToEdit,
151
+ renderAnnotationEditor: this.options.renderAnnotationEditor,
152
+ }),
153
+ ]
154
+ },
155
+
156
+ addMarkView() {
157
+ return ({ HTMLAttributes }) => {
158
+ const ruby = document.createElement('ruby')
159
+
160
+ Object.entries(mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)).forEach(
161
+ ([key, value]) => {
162
+ if (value != null) {
163
+ ruby.setAttribute(key, String(value))
164
+ }
165
+ },
166
+ )
167
+
168
+ return {
169
+ dom: ruby,
170
+ contentDOM: ruby,
171
+ }
172
+ }
173
+ },
174
+ })