@tiptap/extension-invisible-characters 3.23.6 → 3.24.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.
- package/dist/index.cjs +13 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/package.json +21 -22
- package/src/plugin/InvisibleCharacter.ts +3 -1
- package/src/plugin/InvisibleCharactersPlugin.ts +14 -3
package/dist/index.cjs
CHANGED
|
@@ -140,11 +140,19 @@ var InvisibleCharactersPlugin = (state, options) => {
|
|
|
140
140
|
}
|
|
141
141
|
return {
|
|
142
142
|
visible: options.visible,
|
|
143
|
-
decorations: addDecorationsBetweenPositions(
|
|
143
|
+
decorations: addDecorationsBetweenPositions(
|
|
144
|
+
$from.pos,
|
|
145
|
+
$to.pos,
|
|
146
|
+
state,
|
|
147
|
+
import_view.DecorationSet.empty
|
|
148
|
+
)
|
|
144
149
|
};
|
|
145
150
|
},
|
|
146
151
|
apply: (tr, pluginState, _, currentState) => {
|
|
147
|
-
const newPluginState = stateReducer(
|
|
152
|
+
const newPluginState = stateReducer(
|
|
153
|
+
pluginState,
|
|
154
|
+
tr.getMeta("setInvisibleCharactersVisible")
|
|
155
|
+
);
|
|
148
156
|
const decorations = getUpdatedRanges(tr).reduce(
|
|
149
157
|
(nextDecorations, [from, to]) => {
|
|
150
158
|
return addDecorationsBetweenPositions(from, to, currentState, nextDecorations);
|
|
@@ -265,7 +273,9 @@ var InvisibleCharacter = class {
|
|
|
265
273
|
const textContent = textBetween(from, to, doc);
|
|
266
274
|
return textContent.reduce((oldDecorations, currentPosition) => {
|
|
267
275
|
return currentPosition.text.split("").reduce((innerDecorations, char, i) => {
|
|
268
|
-
return this.test(char) ? innerDecorations.add(doc, [
|
|
276
|
+
return this.test(char) ? innerDecorations.add(doc, [
|
|
277
|
+
createDecorationWidget(currentPosition.pos + i, this.type, this.content)
|
|
278
|
+
]) : innerDecorations;
|
|
269
279
|
}, oldDecorations);
|
|
270
280
|
}, decorations);
|
|
271
281
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/invisible-characters.ts","../src/plugin/InvisibleCharactersPlugin.ts","../src/plugin/reducers.ts","../src/plugin/style.ts","../src/plugin/utils/create-style-tag.ts","../src/plugin/utils/get-updated-ranges.ts","../src/plugin/utils/create-decoration-widget.ts","../src/plugin/InvisibleNode.ts","../src/plugin/invisible-characters/hardBreak.ts","../src/plugin/invisible-characters/paragraph.ts","../src/plugin/utils/text-between.ts","../src/plugin/InvisibleCharacter.ts","../src/plugin/invisible-characters/space.ts"],"sourcesContent":["import { InvisibleCharacters } from './invisible-characters.js'\n\nexport * from './invisible-characters.js'\nexport * from './plugin/invisible-characters/hardBreak.js'\nexport * from './plugin/invisible-characters/paragraph.js'\nexport * from './plugin/invisible-characters/space.js'\nexport * from './plugin/InvisibleCharacter.js'\nexport * from './plugin/InvisibleNode.js'\nexport * from './types.js'\n\nexport default InvisibleCharacters\n","import { Extension } from '@tiptap/core'\n\nimport { InvisibleCharactersPlugin, InvisibleCharactersPluginKey } from './plugin/index.js'\nimport { HardBreakNode } from './plugin/invisible-characters/hardBreak.js'\nimport { ParagraphNode } from './plugin/invisible-characters/paragraph.js'\nimport { SpaceCharacter } from './plugin/invisible-characters/space.js'\nimport type { InvisibleCharactersOptions } from './types.js'\n\nexport { HardBreakNode, ParagraphNode, SpaceCharacter }\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n invisibleCharacters: {\n /**\n * Show invisible characters\n */\n showInvisibleCharacters: (show?: boolean) => ReturnType\n\n /**\n * Hide invisible characters\n */\n hideInvisibleCharacters: () => ReturnType\n\n /**\n * Toggle invisible characters\n */\n toggleInvisibleCharacters: () => ReturnType\n }\n }\n}\n\nexport const InvisibleCharacters = Extension.create<InvisibleCharactersOptions>({\n name: 'invisibleCharacters',\n\n addOptions() {\n return {\n visible: true,\n builders: [new SpaceCharacter(), new ParagraphNode(), new HardBreakNode()],\n injectCSS: true,\n injectNonce: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [InvisibleCharactersPlugin(this.editor.state, this.options)]\n },\n\n addStorage() {\n return {\n visibility: () => this.options.visible,\n }\n },\n\n onBeforeCreate() {\n this.storage.visibility = () => {\n return InvisibleCharactersPluginKey.getState(this.editor.state)?.visible\n }\n },\n\n addCommands() {\n return {\n showInvisibleCharacters:\n (visibility = true) =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n hideInvisibleCharacters:\n () =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', false)\n }\n\n return true\n },\n toggleInvisibleCharacters:\n () =>\n ({ dispatch, tr, state }) => {\n const visibility = !InvisibleCharactersPluginKey.getState(state)?.visible\n\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n }\n },\n})\n\nexport default InvisibleCharacters\n","import type { EditorState } from '@tiptap/pm/state'\nimport { AllSelection, Plugin, PluginKey } from '@tiptap/pm/state'\nimport { DecorationSet } from '@tiptap/pm/view'\n\nimport type { InvisibleCharactersOptions, PluginState } from '../types.js'\nimport { stateReducer } from './reducers.js'\nimport { style } from './style.js'\nimport { createStyleTag } from './utils/create-style-tag.js'\nimport { getUpdatedRanges } from './utils/get-updated-ranges.js'\n\nexport const InvisibleCharactersPluginKey = new PluginKey<PluginState>('invisibleCharacters')\n\nexport const InvisibleCharactersPlugin = (state: EditorState, options: InvisibleCharactersOptions) => {\n const key = InvisibleCharactersPluginKey\n const emptyDecorationSet = DecorationSet.create(state.doc, [])\n\n const addDecorationsBetweenPositions = (\n from: number,\n to: number,\n editorState: EditorState,\n decorations: DecorationSet,\n ) => {\n return options.builders\n .sort((builderA, builderB) => {\n if (builderA.priority > builderB.priority) {\n return 1\n }\n\n return -1\n })\n .reduce((newDecos, builder) => {\n return builder.createDecoration(from, to, editorState.doc, newDecos)\n }, decorations)\n }\n\n return new Plugin({\n key,\n\n state: {\n init: () => {\n const { $from, $to } = new AllSelection(state.doc)\n\n if (options.injectCSS && document) {\n createStyleTag(style, options.injectNonce)\n }\n\n return {\n visible: options.visible,\n decorations: addDecorationsBetweenPositions($from.pos, $to.pos, state, DecorationSet.empty),\n }\n },\n apply: (tr, pluginState, _, currentState) => {\n const newPluginState = stateReducer(pluginState, tr.getMeta('setInvisibleCharactersVisible'))\n\n const decorations = getUpdatedRanges(tr).reduce(\n (nextDecorations, [from, to]) => {\n return addDecorationsBetweenPositions(from, to, currentState, nextDecorations)\n },\n newPluginState.decorations.map(tr.mapping, tr.doc),\n )\n\n return {\n ...newPluginState,\n decorations,\n }\n },\n },\n\n props: {\n decorations(editorState) {\n const pluginState = this.getState(editorState)\n\n const visible = pluginState?.visible\n const decorations = pluginState?.decorations\n\n return visible ? decorations : emptyDecorationSet\n },\n },\n })\n}\n\nexport default InvisibleCharactersPlugin\n","import type { PluginState } from '../types.js'\n\nexport const stateReducer = (state: PluginState, visible: boolean): PluginState => {\n if (visible === undefined) {\n return state\n }\n\n return { ...state, visible }\n}\n\nexport default stateReducer\n","export const style = `.tiptap-invisible-character {\n height: 0;\n padding: 0;\n pointer-events: none;\n user-select: none;\n width: 0;\n}\n\n.tiptap-invisible-character::before {\n caret-color: inherit;\n color: #aaa;\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n line-height: 1em;\n width: 0;\n}\n\n.tiptap-invisible-character--space::before {\n content: '·'\n}\n\n.tiptap-invisible-character--break::before {\n content: '¬'\n}\n\n.tiptap-invisible-character--paragraph::before {\n content: '¶'\n}\n\n.tiptap-invisible-character + img.ProseMirror-separator {\n height: 0 !important;\n pointer-events: none;\n user-select: none;\n width: 0 !important;\n}\n\n.is-empty[data-placeholder].has-focus > .tiptap-invisible-character {\n display: none;\n}\n`\n\nexport default style\n","export const createStyleTag = (style: string, nonce?: string): HTMLStyleElement => {\n const tiptapStyleTag = <HTMLStyleElement>(\n document.querySelector('style[data-tiptap-extension-invisible-characters-style]')\n )\n\n if (tiptapStyleTag !== null) {\n return tiptapStyleTag\n }\n\n const styleNode = document.createElement('style')\n\n if (nonce) {\n styleNode.setAttribute('nonce', nonce)\n }\n\n styleNode.setAttribute('data-tiptap-extension-invisible-characters-style', '')\n styleNode.innerHTML = style\n document.getElementsByTagName('head')[0].appendChild(styleNode)\n\n return styleNode\n}\n\nexport default createStyleTag\n","import type { Transaction } from '@tiptap/pm/state'\n\ntype StepRange = [from: number, to: number]\n\nexport const getUpdatedRanges = ({ mapping }: Transaction): StepRange[] => {\n const ranges: StepRange[] = []\n\n mapping.maps.forEach((stepMap, i) => {\n stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {\n ranges.push([mapping.slice(i + 1).map(newStart), mapping.slice(i + 1).map(newEnd)])\n })\n })\n\n return ranges\n}\n\nexport default getUpdatedRanges\n","import { Decoration } from '@tiptap/pm/view'\n\nexport const createDecorationWidget = (pos: number, type: string, content?: string) => {\n const createElement = () => {\n const newElement = document.createElement('span')\n\n newElement.classList.add('tiptap-invisible-character')\n newElement.classList.add(`tiptap-invisible-character--${type}`)\n\n if (content) {\n newElement.textContent = content\n }\n\n return newElement\n }\n\n return Decoration.widget(pos, createElement, {\n key: type,\n marks: [],\n side: 1000,\n })\n}\n\nexport default createDecorationWidget\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\n\nexport interface InvisibleNodeOptions {\n content?: string\n position?: (node: Node, pos: number) => number\n predicate: (value: Node) => boolean\n priority?: number\n type: string\n}\n\n/** Default position for nodes is always at the end of the node */\nconst defaultPosition = (node: Node, pos: number) => pos + node.nodeSize - 1\n\nexport class InvisibleNode {\n predicate: (value: Node) => boolean\n\n position: (node: Node, pos: number) => number\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleNodeOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.position = options.position || defaultPosition\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n let newDecorations = decorations\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (this.test(node)) {\n const decorationPosition = this.position(node, pos)\n const oldDecorations = newDecorations.find(\n decorationPosition,\n decorationPosition,\n spec => spec.key === this.type,\n )\n\n newDecorations = newDecorations\n .remove(oldDecorations)\n .add(doc, [createDecorationWidget(decorationPosition, this.type, this.content)])\n }\n })\n return newDecorations\n }\n\n test(value: Node) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class HardBreakNode extends InvisibleNode {\n constructor() {\n super({\n type: 'break',\n predicate: node => node.type === node.type.schema.nodes.hardBreak,\n })\n }\n}\n\nexport default HardBreakNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class ParagraphNode extends InvisibleNode {\n constructor() {\n super({\n type: 'paragraph',\n predicate: node => node.type === node.type.schema.nodes.paragraph,\n })\n }\n}\n\nexport default ParagraphNode\n","import type { Node } from '@tiptap/pm/model'\n\nimport type { Position } from '../../types.js'\n\nexport const textBetween = (from: number, to: number, doc: Node) => {\n const positions: Position[] = []\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (node.isText) {\n const offset = Math.max(from, pos) - pos\n\n positions.push({\n pos: pos + offset,\n text: node.text?.slice(offset, to - pos) || '',\n })\n }\n })\n\n return positions\n}\n\nexport default textBetween\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\nimport { textBetween } from './utils/text-between.js'\n\nexport interface InvisibleCharacterOptions {\n type: string\n predicate: (value: string) => boolean\n priority?: number\n content?: string\n}\n\nexport class InvisibleCharacter {\n predicate: (value: string) => boolean\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleCharacterOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n const textContent = textBetween(from, to, doc)\n\n return textContent.reduce((oldDecorations, currentPosition) => {\n return currentPosition.text.split('').reduce((innerDecorations, char, i) => {\n return this.test(char)\n ? innerDecorations.add(doc, [createDecorationWidget(currentPosition.pos + i, this.type, this.content)])\n : innerDecorations\n }, oldDecorations)\n }, decorations)\n }\n\n test(value: string) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleCharacter\n","import { InvisibleCharacter } from '../InvisibleCharacter.js'\n\nexport class SpaceCharacter extends InvisibleCharacter {\n constructor() {\n super({\n type: 'space',\n predicate: (char: string) => char === ' ',\n })\n }\n}\n\nexport default SpaceCharacter\n"],"mappings":"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","names":["style","import_view"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/invisible-characters.ts","../src/plugin/InvisibleCharactersPlugin.ts","../src/plugin/reducers.ts","../src/plugin/style.ts","../src/plugin/utils/create-style-tag.ts","../src/plugin/utils/get-updated-ranges.ts","../src/plugin/utils/create-decoration-widget.ts","../src/plugin/InvisibleNode.ts","../src/plugin/invisible-characters/hardBreak.ts","../src/plugin/invisible-characters/paragraph.ts","../src/plugin/utils/text-between.ts","../src/plugin/InvisibleCharacter.ts","../src/plugin/invisible-characters/space.ts"],"sourcesContent":["import { InvisibleCharacters } from './invisible-characters.js'\n\nexport * from './invisible-characters.js'\nexport * from './plugin/invisible-characters/hardBreak.js'\nexport * from './plugin/invisible-characters/paragraph.js'\nexport * from './plugin/invisible-characters/space.js'\nexport * from './plugin/InvisibleCharacter.js'\nexport * from './plugin/InvisibleNode.js'\nexport * from './types.js'\n\nexport default InvisibleCharacters\n","import { Extension } from '@tiptap/core'\n\nimport { InvisibleCharactersPlugin, InvisibleCharactersPluginKey } from './plugin/index.js'\nimport { HardBreakNode } from './plugin/invisible-characters/hardBreak.js'\nimport { ParagraphNode } from './plugin/invisible-characters/paragraph.js'\nimport { SpaceCharacter } from './plugin/invisible-characters/space.js'\nimport type { InvisibleCharactersOptions } from './types.js'\n\nexport { HardBreakNode, ParagraphNode, SpaceCharacter }\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n invisibleCharacters: {\n /**\n * Show invisible characters\n */\n showInvisibleCharacters: (show?: boolean) => ReturnType\n\n /**\n * Hide invisible characters\n */\n hideInvisibleCharacters: () => ReturnType\n\n /**\n * Toggle invisible characters\n */\n toggleInvisibleCharacters: () => ReturnType\n }\n }\n}\n\nexport const InvisibleCharacters = Extension.create<InvisibleCharactersOptions>({\n name: 'invisibleCharacters',\n\n addOptions() {\n return {\n visible: true,\n builders: [new SpaceCharacter(), new ParagraphNode(), new HardBreakNode()],\n injectCSS: true,\n injectNonce: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [InvisibleCharactersPlugin(this.editor.state, this.options)]\n },\n\n addStorage() {\n return {\n visibility: () => this.options.visible,\n }\n },\n\n onBeforeCreate() {\n this.storage.visibility = () => {\n return InvisibleCharactersPluginKey.getState(this.editor.state)?.visible\n }\n },\n\n addCommands() {\n return {\n showInvisibleCharacters:\n (visibility = true) =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n hideInvisibleCharacters:\n () =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', false)\n }\n\n return true\n },\n toggleInvisibleCharacters:\n () =>\n ({ dispatch, tr, state }) => {\n const visibility = !InvisibleCharactersPluginKey.getState(state)?.visible\n\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n }\n },\n})\n\nexport default InvisibleCharacters\n","import type { EditorState } from '@tiptap/pm/state'\nimport { AllSelection, Plugin, PluginKey } from '@tiptap/pm/state'\nimport { DecorationSet } from '@tiptap/pm/view'\n\nimport type { InvisibleCharactersOptions, PluginState } from '../types.js'\nimport { stateReducer } from './reducers.js'\nimport { style } from './style.js'\nimport { createStyleTag } from './utils/create-style-tag.js'\nimport { getUpdatedRanges } from './utils/get-updated-ranges.js'\n\nexport const InvisibleCharactersPluginKey = new PluginKey<PluginState>('invisibleCharacters')\n\nexport const InvisibleCharactersPlugin = (\n state: EditorState,\n options: InvisibleCharactersOptions,\n) => {\n const key = InvisibleCharactersPluginKey\n const emptyDecorationSet = DecorationSet.create(state.doc, [])\n\n const addDecorationsBetweenPositions = (\n from: number,\n to: number,\n editorState: EditorState,\n decorations: DecorationSet,\n ) => {\n return options.builders\n .sort((builderA, builderB) => {\n if (builderA.priority > builderB.priority) {\n return 1\n }\n\n return -1\n })\n .reduce((newDecos, builder) => {\n return builder.createDecoration(from, to, editorState.doc, newDecos)\n }, decorations)\n }\n\n return new Plugin({\n key,\n\n state: {\n init: () => {\n const { $from, $to } = new AllSelection(state.doc)\n\n if (options.injectCSS && document) {\n createStyleTag(style, options.injectNonce)\n }\n\n return {\n visible: options.visible,\n decorations: addDecorationsBetweenPositions(\n $from.pos,\n $to.pos,\n state,\n DecorationSet.empty,\n ),\n }\n },\n apply: (tr, pluginState, _, currentState) => {\n const newPluginState = stateReducer(\n pluginState,\n tr.getMeta('setInvisibleCharactersVisible'),\n )\n\n const decorations = getUpdatedRanges(tr).reduce(\n (nextDecorations, [from, to]) => {\n return addDecorationsBetweenPositions(from, to, currentState, nextDecorations)\n },\n newPluginState.decorations.map(tr.mapping, tr.doc),\n )\n\n return {\n ...newPluginState,\n decorations,\n }\n },\n },\n\n props: {\n decorations(editorState) {\n const pluginState = this.getState(editorState)\n\n const visible = pluginState?.visible\n const decorations = pluginState?.decorations\n\n return visible ? decorations : emptyDecorationSet\n },\n },\n })\n}\n\nexport default InvisibleCharactersPlugin\n","import type { PluginState } from '../types.js'\n\nexport const stateReducer = (state: PluginState, visible: boolean): PluginState => {\n if (visible === undefined) {\n return state\n }\n\n return { ...state, visible }\n}\n\nexport default stateReducer\n","export const style = `.tiptap-invisible-character {\n height: 0;\n padding: 0;\n pointer-events: none;\n user-select: none;\n width: 0;\n}\n\n.tiptap-invisible-character::before {\n caret-color: inherit;\n color: #aaa;\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n line-height: 1em;\n width: 0;\n}\n\n.tiptap-invisible-character--space::before {\n content: '·'\n}\n\n.tiptap-invisible-character--break::before {\n content: '¬'\n}\n\n.tiptap-invisible-character--paragraph::before {\n content: '¶'\n}\n\n.tiptap-invisible-character + img.ProseMirror-separator {\n height: 0 !important;\n pointer-events: none;\n user-select: none;\n width: 0 !important;\n}\n\n.is-empty[data-placeholder].has-focus > .tiptap-invisible-character {\n display: none;\n}\n`\n\nexport default style\n","export const createStyleTag = (style: string, nonce?: string): HTMLStyleElement => {\n const tiptapStyleTag = <HTMLStyleElement>(\n document.querySelector('style[data-tiptap-extension-invisible-characters-style]')\n )\n\n if (tiptapStyleTag !== null) {\n return tiptapStyleTag\n }\n\n const styleNode = document.createElement('style')\n\n if (nonce) {\n styleNode.setAttribute('nonce', nonce)\n }\n\n styleNode.setAttribute('data-tiptap-extension-invisible-characters-style', '')\n styleNode.innerHTML = style\n document.getElementsByTagName('head')[0].appendChild(styleNode)\n\n return styleNode\n}\n\nexport default createStyleTag\n","import type { Transaction } from '@tiptap/pm/state'\n\ntype StepRange = [from: number, to: number]\n\nexport const getUpdatedRanges = ({ mapping }: Transaction): StepRange[] => {\n const ranges: StepRange[] = []\n\n mapping.maps.forEach((stepMap, i) => {\n stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {\n ranges.push([mapping.slice(i + 1).map(newStart), mapping.slice(i + 1).map(newEnd)])\n })\n })\n\n return ranges\n}\n\nexport default getUpdatedRanges\n","import { Decoration } from '@tiptap/pm/view'\n\nexport const createDecorationWidget = (pos: number, type: string, content?: string) => {\n const createElement = () => {\n const newElement = document.createElement('span')\n\n newElement.classList.add('tiptap-invisible-character')\n newElement.classList.add(`tiptap-invisible-character--${type}`)\n\n if (content) {\n newElement.textContent = content\n }\n\n return newElement\n }\n\n return Decoration.widget(pos, createElement, {\n key: type,\n marks: [],\n side: 1000,\n })\n}\n\nexport default createDecorationWidget\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\n\nexport interface InvisibleNodeOptions {\n content?: string\n position?: (node: Node, pos: number) => number\n predicate: (value: Node) => boolean\n priority?: number\n type: string\n}\n\n/** Default position for nodes is always at the end of the node */\nconst defaultPosition = (node: Node, pos: number) => pos + node.nodeSize - 1\n\nexport class InvisibleNode {\n predicate: (value: Node) => boolean\n\n position: (node: Node, pos: number) => number\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleNodeOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.position = options.position || defaultPosition\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n let newDecorations = decorations\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (this.test(node)) {\n const decorationPosition = this.position(node, pos)\n const oldDecorations = newDecorations.find(\n decorationPosition,\n decorationPosition,\n spec => spec.key === this.type,\n )\n\n newDecorations = newDecorations\n .remove(oldDecorations)\n .add(doc, [createDecorationWidget(decorationPosition, this.type, this.content)])\n }\n })\n return newDecorations\n }\n\n test(value: Node) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class HardBreakNode extends InvisibleNode {\n constructor() {\n super({\n type: 'break',\n predicate: node => node.type === node.type.schema.nodes.hardBreak,\n })\n }\n}\n\nexport default HardBreakNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class ParagraphNode extends InvisibleNode {\n constructor() {\n super({\n type: 'paragraph',\n predicate: node => node.type === node.type.schema.nodes.paragraph,\n })\n }\n}\n\nexport default ParagraphNode\n","import type { Node } from '@tiptap/pm/model'\n\nimport type { Position } from '../../types.js'\n\nexport const textBetween = (from: number, to: number, doc: Node) => {\n const positions: Position[] = []\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (node.isText) {\n const offset = Math.max(from, pos) - pos\n\n positions.push({\n pos: pos + offset,\n text: node.text?.slice(offset, to - pos) || '',\n })\n }\n })\n\n return positions\n}\n\nexport default textBetween\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\nimport { textBetween } from './utils/text-between.js'\n\nexport interface InvisibleCharacterOptions {\n type: string\n predicate: (value: string) => boolean\n priority?: number\n content?: string\n}\n\nexport class InvisibleCharacter {\n predicate: (value: string) => boolean\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleCharacterOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n const textContent = textBetween(from, to, doc)\n\n return textContent.reduce((oldDecorations, currentPosition) => {\n return currentPosition.text.split('').reduce((innerDecorations, char, i) => {\n return this.test(char)\n ? innerDecorations.add(doc, [\n createDecorationWidget(currentPosition.pos + i, this.type, this.content),\n ])\n : innerDecorations\n }, oldDecorations)\n }, decorations)\n }\n\n test(value: string) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleCharacter\n","import { InvisibleCharacter } from '../InvisibleCharacter.js'\n\nexport class SpaceCharacter extends InvisibleCharacter {\n constructor() {\n super({\n type: 'space',\n predicate: (char: string) => char === ' ',\n })\n }\n}\n\nexport default SpaceCharacter\n"],"mappings":"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","names":["style","import_view"]}
|
package/dist/index.js
CHANGED
|
@@ -108,11 +108,19 @@ var InvisibleCharactersPlugin = (state, options) => {
|
|
|
108
108
|
}
|
|
109
109
|
return {
|
|
110
110
|
visible: options.visible,
|
|
111
|
-
decorations: addDecorationsBetweenPositions(
|
|
111
|
+
decorations: addDecorationsBetweenPositions(
|
|
112
|
+
$from.pos,
|
|
113
|
+
$to.pos,
|
|
114
|
+
state,
|
|
115
|
+
DecorationSet.empty
|
|
116
|
+
)
|
|
112
117
|
};
|
|
113
118
|
},
|
|
114
119
|
apply: (tr, pluginState, _, currentState) => {
|
|
115
|
-
const newPluginState = stateReducer(
|
|
120
|
+
const newPluginState = stateReducer(
|
|
121
|
+
pluginState,
|
|
122
|
+
tr.getMeta("setInvisibleCharactersVisible")
|
|
123
|
+
);
|
|
116
124
|
const decorations = getUpdatedRanges(tr).reduce(
|
|
117
125
|
(nextDecorations, [from, to]) => {
|
|
118
126
|
return addDecorationsBetweenPositions(from, to, currentState, nextDecorations);
|
|
@@ -233,7 +241,9 @@ var InvisibleCharacter = class {
|
|
|
233
241
|
const textContent = textBetween(from, to, doc);
|
|
234
242
|
return textContent.reduce((oldDecorations, currentPosition) => {
|
|
235
243
|
return currentPosition.text.split("").reduce((innerDecorations, char, i) => {
|
|
236
|
-
return this.test(char) ? innerDecorations.add(doc, [
|
|
244
|
+
return this.test(char) ? innerDecorations.add(doc, [
|
|
245
|
+
createDecorationWidget(currentPosition.pos + i, this.type, this.content)
|
|
246
|
+
]) : innerDecorations;
|
|
237
247
|
}, oldDecorations);
|
|
238
248
|
}, decorations);
|
|
239
249
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/invisible-characters.ts","../src/plugin/InvisibleCharactersPlugin.ts","../src/plugin/reducers.ts","../src/plugin/style.ts","../src/plugin/utils/create-style-tag.ts","../src/plugin/utils/get-updated-ranges.ts","../src/plugin/utils/create-decoration-widget.ts","../src/plugin/InvisibleNode.ts","../src/plugin/invisible-characters/hardBreak.ts","../src/plugin/invisible-characters/paragraph.ts","../src/plugin/utils/text-between.ts","../src/plugin/InvisibleCharacter.ts","../src/plugin/invisible-characters/space.ts","../src/index.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\n\nimport { InvisibleCharactersPlugin, InvisibleCharactersPluginKey } from './plugin/index.js'\nimport { HardBreakNode } from './plugin/invisible-characters/hardBreak.js'\nimport { ParagraphNode } from './plugin/invisible-characters/paragraph.js'\nimport { SpaceCharacter } from './plugin/invisible-characters/space.js'\nimport type { InvisibleCharactersOptions } from './types.js'\n\nexport { HardBreakNode, ParagraphNode, SpaceCharacter }\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n invisibleCharacters: {\n /**\n * Show invisible characters\n */\n showInvisibleCharacters: (show?: boolean) => ReturnType\n\n /**\n * Hide invisible characters\n */\n hideInvisibleCharacters: () => ReturnType\n\n /**\n * Toggle invisible characters\n */\n toggleInvisibleCharacters: () => ReturnType\n }\n }\n}\n\nexport const InvisibleCharacters = Extension.create<InvisibleCharactersOptions>({\n name: 'invisibleCharacters',\n\n addOptions() {\n return {\n visible: true,\n builders: [new SpaceCharacter(), new ParagraphNode(), new HardBreakNode()],\n injectCSS: true,\n injectNonce: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [InvisibleCharactersPlugin(this.editor.state, this.options)]\n },\n\n addStorage() {\n return {\n visibility: () => this.options.visible,\n }\n },\n\n onBeforeCreate() {\n this.storage.visibility = () => {\n return InvisibleCharactersPluginKey.getState(this.editor.state)?.visible\n }\n },\n\n addCommands() {\n return {\n showInvisibleCharacters:\n (visibility = true) =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n hideInvisibleCharacters:\n () =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', false)\n }\n\n return true\n },\n toggleInvisibleCharacters:\n () =>\n ({ dispatch, tr, state }) => {\n const visibility = !InvisibleCharactersPluginKey.getState(state)?.visible\n\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n }\n },\n})\n\nexport default InvisibleCharacters\n","import type { EditorState } from '@tiptap/pm/state'\nimport { AllSelection, Plugin, PluginKey } from '@tiptap/pm/state'\nimport { DecorationSet } from '@tiptap/pm/view'\n\nimport type { InvisibleCharactersOptions, PluginState } from '../types.js'\nimport { stateReducer } from './reducers.js'\nimport { style } from './style.js'\nimport { createStyleTag } from './utils/create-style-tag.js'\nimport { getUpdatedRanges } from './utils/get-updated-ranges.js'\n\nexport const InvisibleCharactersPluginKey = new PluginKey<PluginState>('invisibleCharacters')\n\nexport const InvisibleCharactersPlugin = (state: EditorState, options: InvisibleCharactersOptions) => {\n const key = InvisibleCharactersPluginKey\n const emptyDecorationSet = DecorationSet.create(state.doc, [])\n\n const addDecorationsBetweenPositions = (\n from: number,\n to: number,\n editorState: EditorState,\n decorations: DecorationSet,\n ) => {\n return options.builders\n .sort((builderA, builderB) => {\n if (builderA.priority > builderB.priority) {\n return 1\n }\n\n return -1\n })\n .reduce((newDecos, builder) => {\n return builder.createDecoration(from, to, editorState.doc, newDecos)\n }, decorations)\n }\n\n return new Plugin({\n key,\n\n state: {\n init: () => {\n const { $from, $to } = new AllSelection(state.doc)\n\n if (options.injectCSS && document) {\n createStyleTag(style, options.injectNonce)\n }\n\n return {\n visible: options.visible,\n decorations: addDecorationsBetweenPositions($from.pos, $to.pos, state, DecorationSet.empty),\n }\n },\n apply: (tr, pluginState, _, currentState) => {\n const newPluginState = stateReducer(pluginState, tr.getMeta('setInvisibleCharactersVisible'))\n\n const decorations = getUpdatedRanges(tr).reduce(\n (nextDecorations, [from, to]) => {\n return addDecorationsBetweenPositions(from, to, currentState, nextDecorations)\n },\n newPluginState.decorations.map(tr.mapping, tr.doc),\n )\n\n return {\n ...newPluginState,\n decorations,\n }\n },\n },\n\n props: {\n decorations(editorState) {\n const pluginState = this.getState(editorState)\n\n const visible = pluginState?.visible\n const decorations = pluginState?.decorations\n\n return visible ? decorations : emptyDecorationSet\n },\n },\n })\n}\n\nexport default InvisibleCharactersPlugin\n","import type { PluginState } from '../types.js'\n\nexport const stateReducer = (state: PluginState, visible: boolean): PluginState => {\n if (visible === undefined) {\n return state\n }\n\n return { ...state, visible }\n}\n\nexport default stateReducer\n","export const style = `.tiptap-invisible-character {\n height: 0;\n padding: 0;\n pointer-events: none;\n user-select: none;\n width: 0;\n}\n\n.tiptap-invisible-character::before {\n caret-color: inherit;\n color: #aaa;\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n line-height: 1em;\n width: 0;\n}\n\n.tiptap-invisible-character--space::before {\n content: '·'\n}\n\n.tiptap-invisible-character--break::before {\n content: '¬'\n}\n\n.tiptap-invisible-character--paragraph::before {\n content: '¶'\n}\n\n.tiptap-invisible-character + img.ProseMirror-separator {\n height: 0 !important;\n pointer-events: none;\n user-select: none;\n width: 0 !important;\n}\n\n.is-empty[data-placeholder].has-focus > .tiptap-invisible-character {\n display: none;\n}\n`\n\nexport default style\n","export const createStyleTag = (style: string, nonce?: string): HTMLStyleElement => {\n const tiptapStyleTag = <HTMLStyleElement>(\n document.querySelector('style[data-tiptap-extension-invisible-characters-style]')\n )\n\n if (tiptapStyleTag !== null) {\n return tiptapStyleTag\n }\n\n const styleNode = document.createElement('style')\n\n if (nonce) {\n styleNode.setAttribute('nonce', nonce)\n }\n\n styleNode.setAttribute('data-tiptap-extension-invisible-characters-style', '')\n styleNode.innerHTML = style\n document.getElementsByTagName('head')[0].appendChild(styleNode)\n\n return styleNode\n}\n\nexport default createStyleTag\n","import type { Transaction } from '@tiptap/pm/state'\n\ntype StepRange = [from: number, to: number]\n\nexport const getUpdatedRanges = ({ mapping }: Transaction): StepRange[] => {\n const ranges: StepRange[] = []\n\n mapping.maps.forEach((stepMap, i) => {\n stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {\n ranges.push([mapping.slice(i + 1).map(newStart), mapping.slice(i + 1).map(newEnd)])\n })\n })\n\n return ranges\n}\n\nexport default getUpdatedRanges\n","import { Decoration } from '@tiptap/pm/view'\n\nexport const createDecorationWidget = (pos: number, type: string, content?: string) => {\n const createElement = () => {\n const newElement = document.createElement('span')\n\n newElement.classList.add('tiptap-invisible-character')\n newElement.classList.add(`tiptap-invisible-character--${type}`)\n\n if (content) {\n newElement.textContent = content\n }\n\n return newElement\n }\n\n return Decoration.widget(pos, createElement, {\n key: type,\n marks: [],\n side: 1000,\n })\n}\n\nexport default createDecorationWidget\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\n\nexport interface InvisibleNodeOptions {\n content?: string\n position?: (node: Node, pos: number) => number\n predicate: (value: Node) => boolean\n priority?: number\n type: string\n}\n\n/** Default position for nodes is always at the end of the node */\nconst defaultPosition = (node: Node, pos: number) => pos + node.nodeSize - 1\n\nexport class InvisibleNode {\n predicate: (value: Node) => boolean\n\n position: (node: Node, pos: number) => number\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleNodeOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.position = options.position || defaultPosition\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n let newDecorations = decorations\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (this.test(node)) {\n const decorationPosition = this.position(node, pos)\n const oldDecorations = newDecorations.find(\n decorationPosition,\n decorationPosition,\n spec => spec.key === this.type,\n )\n\n newDecorations = newDecorations\n .remove(oldDecorations)\n .add(doc, [createDecorationWidget(decorationPosition, this.type, this.content)])\n }\n })\n return newDecorations\n }\n\n test(value: Node) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class HardBreakNode extends InvisibleNode {\n constructor() {\n super({\n type: 'break',\n predicate: node => node.type === node.type.schema.nodes.hardBreak,\n })\n }\n}\n\nexport default HardBreakNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class ParagraphNode extends InvisibleNode {\n constructor() {\n super({\n type: 'paragraph',\n predicate: node => node.type === node.type.schema.nodes.paragraph,\n })\n }\n}\n\nexport default ParagraphNode\n","import type { Node } from '@tiptap/pm/model'\n\nimport type { Position } from '../../types.js'\n\nexport const textBetween = (from: number, to: number, doc: Node) => {\n const positions: Position[] = []\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (node.isText) {\n const offset = Math.max(from, pos) - pos\n\n positions.push({\n pos: pos + offset,\n text: node.text?.slice(offset, to - pos) || '',\n })\n }\n })\n\n return positions\n}\n\nexport default textBetween\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\nimport { textBetween } from './utils/text-between.js'\n\nexport interface InvisibleCharacterOptions {\n type: string\n predicate: (value: string) => boolean\n priority?: number\n content?: string\n}\n\nexport class InvisibleCharacter {\n predicate: (value: string) => boolean\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleCharacterOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n const textContent = textBetween(from, to, doc)\n\n return textContent.reduce((oldDecorations, currentPosition) => {\n return currentPosition.text.split('').reduce((innerDecorations, char, i) => {\n return this.test(char)\n ? innerDecorations.add(doc, [createDecorationWidget(currentPosition.pos + i, this.type, this.content)])\n : innerDecorations\n }, oldDecorations)\n }, decorations)\n }\n\n test(value: string) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleCharacter\n","import { InvisibleCharacter } from '../InvisibleCharacter.js'\n\nexport class SpaceCharacter extends InvisibleCharacter {\n constructor() {\n super({\n type: 'space',\n predicate: (char: string) => char === ' ',\n })\n }\n}\n\nexport default SpaceCharacter\n","import { InvisibleCharacters } from './invisible-characters.js'\n\nexport * from './invisible-characters.js'\nexport * from './plugin/invisible-characters/hardBreak.js'\nexport * from './plugin/invisible-characters/paragraph.js'\nexport * from './plugin/invisible-characters/space.js'\nexport * from './plugin/InvisibleCharacter.js'\nexport * from './plugin/InvisibleNode.js'\nexport * from './types.js'\n\nexport default InvisibleCharacters\n"],"mappings":"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","names":["style"]}
|
|
1
|
+
{"version":3,"sources":["../src/invisible-characters.ts","../src/plugin/InvisibleCharactersPlugin.ts","../src/plugin/reducers.ts","../src/plugin/style.ts","../src/plugin/utils/create-style-tag.ts","../src/plugin/utils/get-updated-ranges.ts","../src/plugin/utils/create-decoration-widget.ts","../src/plugin/InvisibleNode.ts","../src/plugin/invisible-characters/hardBreak.ts","../src/plugin/invisible-characters/paragraph.ts","../src/plugin/utils/text-between.ts","../src/plugin/InvisibleCharacter.ts","../src/plugin/invisible-characters/space.ts","../src/index.ts"],"sourcesContent":["import { Extension } from '@tiptap/core'\n\nimport { InvisibleCharactersPlugin, InvisibleCharactersPluginKey } from './plugin/index.js'\nimport { HardBreakNode } from './plugin/invisible-characters/hardBreak.js'\nimport { ParagraphNode } from './plugin/invisible-characters/paragraph.js'\nimport { SpaceCharacter } from './plugin/invisible-characters/space.js'\nimport type { InvisibleCharactersOptions } from './types.js'\n\nexport { HardBreakNode, ParagraphNode, SpaceCharacter }\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n invisibleCharacters: {\n /**\n * Show invisible characters\n */\n showInvisibleCharacters: (show?: boolean) => ReturnType\n\n /**\n * Hide invisible characters\n */\n hideInvisibleCharacters: () => ReturnType\n\n /**\n * Toggle invisible characters\n */\n toggleInvisibleCharacters: () => ReturnType\n }\n }\n}\n\nexport const InvisibleCharacters = Extension.create<InvisibleCharactersOptions>({\n name: 'invisibleCharacters',\n\n addOptions() {\n return {\n visible: true,\n builders: [new SpaceCharacter(), new ParagraphNode(), new HardBreakNode()],\n injectCSS: true,\n injectNonce: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n return [InvisibleCharactersPlugin(this.editor.state, this.options)]\n },\n\n addStorage() {\n return {\n visibility: () => this.options.visible,\n }\n },\n\n onBeforeCreate() {\n this.storage.visibility = () => {\n return InvisibleCharactersPluginKey.getState(this.editor.state)?.visible\n }\n },\n\n addCommands() {\n return {\n showInvisibleCharacters:\n (visibility = true) =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n hideInvisibleCharacters:\n () =>\n ({ dispatch, tr }) => {\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', false)\n }\n\n return true\n },\n toggleInvisibleCharacters:\n () =>\n ({ dispatch, tr, state }) => {\n const visibility = !InvisibleCharactersPluginKey.getState(state)?.visible\n\n if (dispatch) {\n tr.setMeta('setInvisibleCharactersVisible', visibility)\n }\n\n return true\n },\n }\n },\n})\n\nexport default InvisibleCharacters\n","import type { EditorState } from '@tiptap/pm/state'\nimport { AllSelection, Plugin, PluginKey } from '@tiptap/pm/state'\nimport { DecorationSet } from '@tiptap/pm/view'\n\nimport type { InvisibleCharactersOptions, PluginState } from '../types.js'\nimport { stateReducer } from './reducers.js'\nimport { style } from './style.js'\nimport { createStyleTag } from './utils/create-style-tag.js'\nimport { getUpdatedRanges } from './utils/get-updated-ranges.js'\n\nexport const InvisibleCharactersPluginKey = new PluginKey<PluginState>('invisibleCharacters')\n\nexport const InvisibleCharactersPlugin = (\n state: EditorState,\n options: InvisibleCharactersOptions,\n) => {\n const key = InvisibleCharactersPluginKey\n const emptyDecorationSet = DecorationSet.create(state.doc, [])\n\n const addDecorationsBetweenPositions = (\n from: number,\n to: number,\n editorState: EditorState,\n decorations: DecorationSet,\n ) => {\n return options.builders\n .sort((builderA, builderB) => {\n if (builderA.priority > builderB.priority) {\n return 1\n }\n\n return -1\n })\n .reduce((newDecos, builder) => {\n return builder.createDecoration(from, to, editorState.doc, newDecos)\n }, decorations)\n }\n\n return new Plugin({\n key,\n\n state: {\n init: () => {\n const { $from, $to } = new AllSelection(state.doc)\n\n if (options.injectCSS && document) {\n createStyleTag(style, options.injectNonce)\n }\n\n return {\n visible: options.visible,\n decorations: addDecorationsBetweenPositions(\n $from.pos,\n $to.pos,\n state,\n DecorationSet.empty,\n ),\n }\n },\n apply: (tr, pluginState, _, currentState) => {\n const newPluginState = stateReducer(\n pluginState,\n tr.getMeta('setInvisibleCharactersVisible'),\n )\n\n const decorations = getUpdatedRanges(tr).reduce(\n (nextDecorations, [from, to]) => {\n return addDecorationsBetweenPositions(from, to, currentState, nextDecorations)\n },\n newPluginState.decorations.map(tr.mapping, tr.doc),\n )\n\n return {\n ...newPluginState,\n decorations,\n }\n },\n },\n\n props: {\n decorations(editorState) {\n const pluginState = this.getState(editorState)\n\n const visible = pluginState?.visible\n const decorations = pluginState?.decorations\n\n return visible ? decorations : emptyDecorationSet\n },\n },\n })\n}\n\nexport default InvisibleCharactersPlugin\n","import type { PluginState } from '../types.js'\n\nexport const stateReducer = (state: PluginState, visible: boolean): PluginState => {\n if (visible === undefined) {\n return state\n }\n\n return { ...state, visible }\n}\n\nexport default stateReducer\n","export const style = `.tiptap-invisible-character {\n height: 0;\n padding: 0;\n pointer-events: none;\n user-select: none;\n width: 0;\n}\n\n.tiptap-invisible-character::before {\n caret-color: inherit;\n color: #aaa;\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n line-height: 1em;\n width: 0;\n}\n\n.tiptap-invisible-character--space::before {\n content: '·'\n}\n\n.tiptap-invisible-character--break::before {\n content: '¬'\n}\n\n.tiptap-invisible-character--paragraph::before {\n content: '¶'\n}\n\n.tiptap-invisible-character + img.ProseMirror-separator {\n height: 0 !important;\n pointer-events: none;\n user-select: none;\n width: 0 !important;\n}\n\n.is-empty[data-placeholder].has-focus > .tiptap-invisible-character {\n display: none;\n}\n`\n\nexport default style\n","export const createStyleTag = (style: string, nonce?: string): HTMLStyleElement => {\n const tiptapStyleTag = <HTMLStyleElement>(\n document.querySelector('style[data-tiptap-extension-invisible-characters-style]')\n )\n\n if (tiptapStyleTag !== null) {\n return tiptapStyleTag\n }\n\n const styleNode = document.createElement('style')\n\n if (nonce) {\n styleNode.setAttribute('nonce', nonce)\n }\n\n styleNode.setAttribute('data-tiptap-extension-invisible-characters-style', '')\n styleNode.innerHTML = style\n document.getElementsByTagName('head')[0].appendChild(styleNode)\n\n return styleNode\n}\n\nexport default createStyleTag\n","import type { Transaction } from '@tiptap/pm/state'\n\ntype StepRange = [from: number, to: number]\n\nexport const getUpdatedRanges = ({ mapping }: Transaction): StepRange[] => {\n const ranges: StepRange[] = []\n\n mapping.maps.forEach((stepMap, i) => {\n stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {\n ranges.push([mapping.slice(i + 1).map(newStart), mapping.slice(i + 1).map(newEnd)])\n })\n })\n\n return ranges\n}\n\nexport default getUpdatedRanges\n","import { Decoration } from '@tiptap/pm/view'\n\nexport const createDecorationWidget = (pos: number, type: string, content?: string) => {\n const createElement = () => {\n const newElement = document.createElement('span')\n\n newElement.classList.add('tiptap-invisible-character')\n newElement.classList.add(`tiptap-invisible-character--${type}`)\n\n if (content) {\n newElement.textContent = content\n }\n\n return newElement\n }\n\n return Decoration.widget(pos, createElement, {\n key: type,\n marks: [],\n side: 1000,\n })\n}\n\nexport default createDecorationWidget\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\n\nexport interface InvisibleNodeOptions {\n content?: string\n position?: (node: Node, pos: number) => number\n predicate: (value: Node) => boolean\n priority?: number\n type: string\n}\n\n/** Default position for nodes is always at the end of the node */\nconst defaultPosition = (node: Node, pos: number) => pos + node.nodeSize - 1\n\nexport class InvisibleNode {\n predicate: (value: Node) => boolean\n\n position: (node: Node, pos: number) => number\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleNodeOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.position = options.position || defaultPosition\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n let newDecorations = decorations\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (this.test(node)) {\n const decorationPosition = this.position(node, pos)\n const oldDecorations = newDecorations.find(\n decorationPosition,\n decorationPosition,\n spec => spec.key === this.type,\n )\n\n newDecorations = newDecorations\n .remove(oldDecorations)\n .add(doc, [createDecorationWidget(decorationPosition, this.type, this.content)])\n }\n })\n return newDecorations\n }\n\n test(value: Node) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class HardBreakNode extends InvisibleNode {\n constructor() {\n super({\n type: 'break',\n predicate: node => node.type === node.type.schema.nodes.hardBreak,\n })\n }\n}\n\nexport default HardBreakNode\n","import { InvisibleNode } from '../InvisibleNode.js'\n\nexport class ParagraphNode extends InvisibleNode {\n constructor() {\n super({\n type: 'paragraph',\n predicate: node => node.type === node.type.schema.nodes.paragraph,\n })\n }\n}\n\nexport default ParagraphNode\n","import type { Node } from '@tiptap/pm/model'\n\nimport type { Position } from '../../types.js'\n\nexport const textBetween = (from: number, to: number, doc: Node) => {\n const positions: Position[] = []\n\n doc.nodesBetween(from, to, (node, pos) => {\n if (node.isText) {\n const offset = Math.max(from, pos) - pos\n\n positions.push({\n pos: pos + offset,\n text: node.text?.slice(offset, to - pos) || '',\n })\n }\n })\n\n return positions\n}\n\nexport default textBetween\n","import type { Node } from '@tiptap/pm/model'\nimport type { DecorationSet } from '@tiptap/pm/view'\n\nimport { createDecorationWidget } from './utils/create-decoration-widget.js'\nimport { textBetween } from './utils/text-between.js'\n\nexport interface InvisibleCharacterOptions {\n type: string\n predicate: (value: string) => boolean\n priority?: number\n content?: string\n}\n\nexport class InvisibleCharacter {\n predicate: (value: string) => boolean\n\n content?: string\n\n type: string\n\n priority: number\n\n constructor(options: InvisibleCharacterOptions) {\n this.predicate = options.predicate\n this.type = options.type\n this.content = options.content\n this.priority = options.priority || 100\n }\n\n createDecoration(from: number, to: number, doc: Node, decorations: DecorationSet) {\n const textContent = textBetween(from, to, doc)\n\n return textContent.reduce((oldDecorations, currentPosition) => {\n return currentPosition.text.split('').reduce((innerDecorations, char, i) => {\n return this.test(char)\n ? innerDecorations.add(doc, [\n createDecorationWidget(currentPosition.pos + i, this.type, this.content),\n ])\n : innerDecorations\n }, oldDecorations)\n }, decorations)\n }\n\n test(value: string) {\n return this.predicate(value)\n }\n}\n\nexport default InvisibleCharacter\n","import { InvisibleCharacter } from '../InvisibleCharacter.js'\n\nexport class SpaceCharacter extends InvisibleCharacter {\n constructor() {\n super({\n type: 'space',\n predicate: (char: string) => char === ' ',\n })\n }\n}\n\nexport default SpaceCharacter\n","import { InvisibleCharacters } from './invisible-characters.js'\n\nexport * from './invisible-characters.js'\nexport * from './plugin/invisible-characters/hardBreak.js'\nexport * from './plugin/invisible-characters/paragraph.js'\nexport * from './plugin/invisible-characters/space.js'\nexport * from './plugin/InvisibleCharacter.js'\nexport * from './plugin/InvisibleNode.js'\nexport * from './types.js'\n\nexport default InvisibleCharacters\n"],"mappings":"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","names":["style"]}
|
package/package.json
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/extension-invisible-characters",
|
|
3
|
+
"version": "3.24.0",
|
|
3
4
|
"description": "invisible characters extension for tiptap",
|
|
4
|
-
"version": "3.23.6",
|
|
5
|
-
"homepage": "https://tiptap.dev/docs/editor/extensions/functionality/invisiblecharacters",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"tiptap",
|
|
8
7
|
"tiptap extension"
|
|
9
8
|
],
|
|
9
|
+
"homepage": "https://tiptap.dev/docs/editor/extensions/functionality/invisiblecharacters",
|
|
10
10
|
"license": "MIT",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/ueberdosis/tiptap",
|
|
14
|
+
"directory": "packages/extension-invisible-characters"
|
|
15
|
+
},
|
|
11
16
|
"funding": {
|
|
12
17
|
"type": "github",
|
|
13
18
|
"url": "https://github.com/sponsors/ueberdosis"
|
|
14
19
|
},
|
|
20
|
+
"files": [
|
|
21
|
+
"src",
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
15
24
|
"type": "module",
|
|
25
|
+
"main": "dist/index.cjs",
|
|
26
|
+
"module": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
16
28
|
"exports": {
|
|
17
29
|
".": {
|
|
18
30
|
"types": {
|
|
@@ -23,30 +35,17 @@
|
|
|
23
35
|
"require": "./dist/index.cjs"
|
|
24
36
|
}
|
|
25
37
|
},
|
|
26
|
-
"main": "dist/index.cjs",
|
|
27
|
-
"module": "dist/index.js",
|
|
28
|
-
"types": "dist/index.d.ts",
|
|
29
|
-
"files": [
|
|
30
|
-
"src",
|
|
31
|
-
"dist"
|
|
32
|
-
],
|
|
33
38
|
"devDependencies": {
|
|
34
|
-
"@tiptap/core": "^3.
|
|
35
|
-
"@tiptap/
|
|
36
|
-
"@tiptap/
|
|
39
|
+
"@tiptap/core": "^3.24.0",
|
|
40
|
+
"@tiptap/pm": "^3.24.0",
|
|
41
|
+
"@tiptap/extension-text-style": "^3.24.0"
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
39
|
-
"@tiptap/
|
|
40
|
-
"@tiptap/
|
|
41
|
-
"@tiptap/pm": "3.
|
|
42
|
-
},
|
|
43
|
-
"repository": {
|
|
44
|
-
"type": "git",
|
|
45
|
-
"url": "https://github.com/ueberdosis/tiptap",
|
|
46
|
-
"directory": "packages/extension-invisible-characters"
|
|
44
|
+
"@tiptap/extension-text-style": "3.24.0",
|
|
45
|
+
"@tiptap/core": "3.24.0",
|
|
46
|
+
"@tiptap/pm": "3.24.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
|
-
"build": "tsup"
|
|
50
|
-
"lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
|
|
49
|
+
"build": "tsup"
|
|
51
50
|
}
|
|
52
51
|
}
|
|
@@ -33,7 +33,9 @@ export class InvisibleCharacter {
|
|
|
33
33
|
return textContent.reduce((oldDecorations, currentPosition) => {
|
|
34
34
|
return currentPosition.text.split('').reduce((innerDecorations, char, i) => {
|
|
35
35
|
return this.test(char)
|
|
36
|
-
? innerDecorations.add(doc, [
|
|
36
|
+
? innerDecorations.add(doc, [
|
|
37
|
+
createDecorationWidget(currentPosition.pos + i, this.type, this.content),
|
|
38
|
+
])
|
|
37
39
|
: innerDecorations
|
|
38
40
|
}, oldDecorations)
|
|
39
41
|
}, decorations)
|
|
@@ -10,7 +10,10 @@ import { getUpdatedRanges } from './utils/get-updated-ranges.js'
|
|
|
10
10
|
|
|
11
11
|
export const InvisibleCharactersPluginKey = new PluginKey<PluginState>('invisibleCharacters')
|
|
12
12
|
|
|
13
|
-
export const InvisibleCharactersPlugin = (
|
|
13
|
+
export const InvisibleCharactersPlugin = (
|
|
14
|
+
state: EditorState,
|
|
15
|
+
options: InvisibleCharactersOptions,
|
|
16
|
+
) => {
|
|
14
17
|
const key = InvisibleCharactersPluginKey
|
|
15
18
|
const emptyDecorationSet = DecorationSet.create(state.doc, [])
|
|
16
19
|
|
|
@@ -46,11 +49,19 @@ export const InvisibleCharactersPlugin = (state: EditorState, options: Invisible
|
|
|
46
49
|
|
|
47
50
|
return {
|
|
48
51
|
visible: options.visible,
|
|
49
|
-
decorations: addDecorationsBetweenPositions(
|
|
52
|
+
decorations: addDecorationsBetweenPositions(
|
|
53
|
+
$from.pos,
|
|
54
|
+
$to.pos,
|
|
55
|
+
state,
|
|
56
|
+
DecorationSet.empty,
|
|
57
|
+
),
|
|
50
58
|
}
|
|
51
59
|
},
|
|
52
60
|
apply: (tr, pluginState, _, currentState) => {
|
|
53
|
-
const newPluginState = stateReducer(
|
|
61
|
+
const newPluginState = stateReducer(
|
|
62
|
+
pluginState,
|
|
63
|
+
tr.getMeta('setInvisibleCharactersVisible'),
|
|
64
|
+
)
|
|
54
65
|
|
|
55
66
|
const decorations = getUpdatedRanges(tr).reduce(
|
|
56
67
|
(nextDecorations, [from, to]) => {
|