@limetech/lime-elements 38.11.0 → 38.12.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/CHANGELOG.md +16 -0
- package/dist/cjs/index.cjs.js +0 -9
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +209 -111
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
- package/dist/cjs/limel-snackbar.cjs.entry.js.map +1 -1
- package/dist/cjs/limel-text-editor.cjs.entry.js +7 -1
- package/dist/cjs/limel-text-editor.cjs.entry.js.map +1 -1
- package/dist/collection/components/snackbar/snackbar.js +1 -1
- package/dist/collection/components/snackbar/snackbar.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-items.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js +15 -54
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js +52 -44
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js +11 -13
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link-plugin.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/append-transaction-handler.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/detect-trigger-removal.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/get-trigger-event-detail.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/monitor-triggered-text.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/send-trigger-event.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/text-input-handler.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/inserter.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +54 -8
- package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js.map +1 -1
- package/dist/collection/components/text-editor/text-editor.js +38 -4
- package/dist/collection/components/text-editor/text-editor.js.map +1 -1
- package/dist/collection/components/text-editor/text-editor.types.js +1 -9
- package/dist/collection/components/text-editor/text-editor.types.js.map +1 -1
- package/dist/collection/components/text-editor/utils/metadata-utils.js +108 -0
- package/dist/collection/components/text-editor/utils/metadata-utils.js.map +1 -0
- package/dist/esm/index.js +0 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/limel-prosemirror-adapter.entry.js +209 -111
- package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
- package/dist/esm/limel-snackbar.entry.js.map +1 -1
- package/dist/esm/limel-text-editor.entry.js +7 -1
- package/dist/esm/limel-text-editor.entry.js.map +1 -1
- package/dist/lime-elements/index.esm.js +1 -1
- package/dist/lime-elements/index.esm.js.map +1 -1
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/p-3a87b175.entry.js.map +1 -1
- package/dist/lime-elements/p-7b039dab.entry.js +2 -0
- package/dist/lime-elements/p-7b039dab.entry.js.map +1 -0
- package/dist/lime-elements/{p-033fa919.entry.js → p-7f3045bd.entry.js} +2 -2
- package/dist/lime-elements/p-7f3045bd.entry.js.map +1 -0
- package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-items.d.ts +2 -2
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/inserter.d.ts +2 -7
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/node.d.ts +9 -0
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/link-plugin.d.ts +0 -4
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/append-transaction-handler.d.ts +1 -1
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/detect-trigger-removal.d.ts +1 -1
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/get-trigger-event-detail.d.ts +2 -2
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/monitor-triggered-text.d.ts +2 -2
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/send-trigger-event.d.ts +1 -1
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/text-input-handler.d.ts +1 -1
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory.d.ts +1 -1
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/inserter.d.ts +1 -1
- package/dist/types/components/text-editor/prosemirror-adapter/prosemirror-adapter.d.ts +10 -0
- package/dist/types/components/text-editor/text-editor.d.ts +10 -0
- package/dist/types/components/text-editor/text-editor.types.d.ts +32 -7
- package/dist/types/components/text-editor/utils/metadata-utils.d.ts +22 -0
- package/dist/types/components.d.ts +17 -4
- package/package.json +1 -1
- package/dist/cjs/text-editor.types-5e5567e2.js +0 -13
- package/dist/cjs/text-editor.types-5e5567e2.js.map +0 -1
- package/dist/esm/text-editor.types-e82469d1.js +0 -13
- package/dist/esm/text-editor.types-e82469d1.js.map +0 -1
- package/dist/lime-elements/p-033fa919.entry.js.map +0 -1
- package/dist/lime-elements/p-7006fafe.entry.js +0 -2
- package/dist/lime-elements/p-7006fafe.entry.js.map +0 -1
- package/dist/lime-elements/p-9ca516ed.js +0 -2
- package/dist/lime-elements/p-9ca516ed.js.map +0 -1
|
@@ -11,12 +11,12 @@ import { menuTranslationIDs, getTextEditorMenuItems } from './menu/menu-items';
|
|
|
11
11
|
import { MarkdownConverter } from '../utils/markdown-converter';
|
|
12
12
|
import { HTMLConverter } from '../utils/html-converter';
|
|
13
13
|
import { EditorMenuTypes, editorMenuTypesArray, } from './menu/types';
|
|
14
|
-
import translate from '
|
|
15
|
-
import { createRandomString } from '
|
|
16
|
-
import { isItem } from '
|
|
14
|
+
import translate from '../../../global/translations';
|
|
15
|
+
import { createRandomString } from '../../../util/random-string';
|
|
16
|
+
import { isItem } from '../../../components/action-bar/isItem';
|
|
17
17
|
import { cloneDeep, debounce } from 'lodash-es';
|
|
18
18
|
import { strikethrough } from './menu/menu-schema-extender';
|
|
19
|
-
import { createLinkPlugin
|
|
19
|
+
import { createLinkPlugin } from './plugins/link-plugin';
|
|
20
20
|
import { createImageInserterPlugin } from './plugins/image/inserter';
|
|
21
21
|
import { createImageViewPlugin } from './plugins/image/view';
|
|
22
22
|
import { createMenuStateTrackingPlugin } from './plugins/menu-state-tracking-plugin';
|
|
@@ -25,6 +25,7 @@ import { createNodeSpec } from '../utils/plugin-factory';
|
|
|
25
25
|
import { createTriggerPlugin } from './plugins/trigger/factory';
|
|
26
26
|
import { getTableNodes, getTableEditingPlugins } from './plugins/table-plugin';
|
|
27
27
|
import { getImageNode, imageCache } from './plugins/image/node';
|
|
28
|
+
import { getMetadataFromDoc, hasMetadataChanged, } from '../utils/metadata-utils';
|
|
28
29
|
const DEBOUNCE_TIMEOUT = 300;
|
|
29
30
|
/**
|
|
30
31
|
* The ProseMirror adapter offers a rich text editing experience with markdown support.
|
|
@@ -38,6 +39,7 @@ const DEBOUNCE_TIMEOUT = 300;
|
|
|
38
39
|
export class ProsemirrorAdapter {
|
|
39
40
|
constructor() {
|
|
40
41
|
this.changeWaiting = false;
|
|
42
|
+
this.metadata = { images: [], links: [] };
|
|
41
43
|
/**
|
|
42
44
|
* Used to stop change event emitting as result of getting updated value from consumer
|
|
43
45
|
*/
|
|
@@ -74,6 +76,8 @@ export class ProsemirrorAdapter {
|
|
|
74
76
|
if (content === this.lastEmittedValue) {
|
|
75
77
|
return;
|
|
76
78
|
}
|
|
79
|
+
const metadata = getMetadataFromDoc(newState.doc);
|
|
80
|
+
this.metadataEmitter(metadata);
|
|
77
81
|
this.lastEmittedValue = content;
|
|
78
82
|
this.changeWaiting = true;
|
|
79
83
|
this.changeEmitter(content);
|
|
@@ -265,7 +269,7 @@ export class ProsemirrorAdapter {
|
|
|
265
269
|
keymap(this.menuCommandFactory.buildKeymap()),
|
|
266
270
|
createTriggerPlugin(this.triggerCharacters, this.contentConverter),
|
|
267
271
|
createLinkPlugin(this.handleNewLinkSelection),
|
|
268
|
-
createImageInserterPlugin(this.imagePasted.emit
|
|
272
|
+
createImageInserterPlugin(this.imagePasted.emit),
|
|
269
273
|
createImageViewPlugin(this.language),
|
|
270
274
|
createMenuStateTrackingPlugin(editorMenuTypesArray, this.menuCommandFactory, this.updateActiveActionBarItems),
|
|
271
275
|
createActionBarInteractionPlugin(this.menuCommandFactory),
|
|
@@ -283,8 +287,24 @@ export class ProsemirrorAdapter {
|
|
|
283
287
|
const tr = this.view.state.tr;
|
|
284
288
|
tr.replaceWith(0, tr.doc.content.size, prosemirrorDoc.content);
|
|
285
289
|
this.view.dispatch(tr);
|
|
290
|
+
const metadata = getMetadataFromDoc(this.view.state.doc);
|
|
291
|
+
this.metadataEmitter(metadata);
|
|
286
292
|
this.suppressChangeEvent = false;
|
|
287
293
|
}
|
|
294
|
+
metadataEmitter(metadata) {
|
|
295
|
+
if (hasMetadataChanged(this.metadata, metadata)) {
|
|
296
|
+
this.removeImagesFromCache(this.metadata, metadata);
|
|
297
|
+
this.metadata = metadata;
|
|
298
|
+
this.metadataChange.emit(metadata);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
removeImagesFromCache(oldMetadata, newMetadata) {
|
|
302
|
+
const removedImages = oldMetadata.images.filter((oldImage) => !newMetadata.images.some((newImage) => newImage.fileInfoId === oldImage.fileInfoId));
|
|
303
|
+
removedImages.forEach((image) => {
|
|
304
|
+
imageCache.delete(image.fileInfoId);
|
|
305
|
+
this.imageRemoved.emit(image);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
288
308
|
static get is() { return "limel-prosemirror-adapter"; }
|
|
289
309
|
static get encapsulation() { return "shadow"; }
|
|
290
310
|
static get delegatesFocus() { return true; }
|
|
@@ -521,10 +541,36 @@ export class ProsemirrorAdapter {
|
|
|
521
541
|
"text": "Dispatched when a image is removed from the editor"
|
|
522
542
|
},
|
|
523
543
|
"complexType": {
|
|
524
|
-
"original": "
|
|
525
|
-
"resolved": "
|
|
544
|
+
"original": "EditorImage",
|
|
545
|
+
"resolved": "EditorImage",
|
|
546
|
+
"references": {
|
|
547
|
+
"EditorImage": {
|
|
548
|
+
"location": "import",
|
|
549
|
+
"path": "../text-editor.types"
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}, {
|
|
554
|
+
"method": "metadataChange",
|
|
555
|
+
"name": "metadataChange",
|
|
556
|
+
"bubbles": true,
|
|
557
|
+
"cancelable": true,
|
|
558
|
+
"composed": true,
|
|
559
|
+
"docs": {
|
|
560
|
+
"tags": [{
|
|
561
|
+
"name": "private",
|
|
562
|
+
"text": undefined
|
|
563
|
+
}, {
|
|
564
|
+
"name": "alpha",
|
|
565
|
+
"text": undefined
|
|
566
|
+
}],
|
|
567
|
+
"text": "Dispatched when the metadata of the editor changes (images and links)"
|
|
568
|
+
},
|
|
569
|
+
"complexType": {
|
|
570
|
+
"original": "EditorMetadata",
|
|
571
|
+
"resolved": "EditorMetadata",
|
|
526
572
|
"references": {
|
|
527
|
-
"
|
|
573
|
+
"EditorMetadata": {
|
|
528
574
|
"location": "import",
|
|
529
575
|
"path": "../text-editor.types"
|
|
530
576
|
}
|
package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prosemirror-adapter.js","sourceRoot":"","sources":["../../../../src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Element,\n Event,\n EventEmitter,\n Host,\n Prop,\n State,\n Watch,\n h,\n} from '@stencil/core';\nimport { EditorState, Transaction } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { Schema, DOMParser } from 'prosemirror-model';\nimport { schema } from 'prosemirror-schema-basic';\nimport { addListNodes } from 'prosemirror-schema-list';\nimport { exampleSetup } from 'prosemirror-example-setup';\nimport { keymap } from 'prosemirror-keymap';\nimport { ActionBarItem } from 'src/components/action-bar/action-bar.types';\nimport { ListSeparator } from 'src/components/list/list-item.types';\nimport { MenuCommandFactory } from './menu/menu-commands';\nimport { menuTranslationIDs, getTextEditorMenuItems } from './menu/menu-items';\nimport { ContentTypeConverter } from '../utils/content-type-converter';\nimport { MarkdownConverter } from '../utils/markdown-converter';\nimport { HTMLConverter } from '../utils/html-converter';\nimport {\n EditorMenuTypes,\n EditorTextLink,\n editorMenuTypesArray,\n} from './menu/types';\nimport translate from 'src/global/translations';\nimport { createRandomString } from 'src/util/random-string';\nimport { isItem } from 'src/components/action-bar/isItem';\nimport { cloneDeep, debounce } from 'lodash-es';\nimport { Languages } from '../../date-picker/date.types';\nimport { strikethrough } from './menu/menu-schema-extender';\nimport {\n EditorLinkMenuEventDetail,\n createLinkPlugin,\n} from './plugins/link-plugin';\nimport { createImageInserterPlugin } from './plugins/image/inserter';\nimport { createImageViewPlugin } from './plugins/image/view';\nimport { createMenuStateTrackingPlugin } from './plugins/menu-state-tracking-plugin';\nimport { createActionBarInteractionPlugin } from './plugins/menu-action-interaction-plugin';\nimport { CustomElementDefinition } from '../../../global/shared-types/custom-element.types';\nimport { createNodeSpec } from '../utils/plugin-factory';\nimport { createTriggerPlugin } from './plugins/trigger/factory';\nimport {\n TriggerCharacter,\n ImageInserter,\n ImageInfo,\n} from '../text-editor.types';\nimport { getTableNodes, getTableEditingPlugins } from './plugins/table-plugin';\nimport { getImageNode, imageCache } from './plugins/image/node';\nimport { EditorUiType } from '../types';\n\nconst DEBOUNCE_TIMEOUT = 300;\n\n/**\n * The ProseMirror adapter offers a rich text editing experience with markdown support.\n * [Read more...](https://prosemirror.net/)\n *\n * @exampleComponent limel-example-prosemirror-adapter-basic\n * @exampleComponent limel-example-prosemirror-adapter-with-custom-menu\n * @beta\n * @private\n */\n@Component({\n tag: 'limel-prosemirror-adapter',\n shadow: { delegatesFocus: true },\n styleUrl: 'prosemirror-adapter.scss',\n})\nexport class ProsemirrorAdapter {\n /**\n * The type of content that the editor should handle and emit, defaults to `markdown`\n *\n * Assumed to be set only once, so not reactive to changes\n */\n @Prop()\n public contentType: 'markdown' | 'html' = 'markdown';\n\n /**\n * The value of the editor, expected to be markdown\n */\n @Prop()\n public value: string;\n\n /**\n * Defines the language for translations.\n */\n @Prop({ reflect: true })\n public language: Languages;\n\n /**\n * Set to `true` to disable the field.\n * Use `disabled` to indicate that the field can normally be interacted\n * with, but is currently disabled. This tells the user that if certain\n * requirements are met, the field may become enabled again.\n */\n @Prop({ reflect: true })\n public disabled?: boolean = false;\n\n /**\n * set to private to avoid usage while under development\n *\n * @private\n * @alpha\n */\n @Prop()\n customElements: CustomElementDefinition[] = [];\n\n /**\n * set to private to avoid usage while under development\n *\n * @private\n * @alpha\n */\n @Prop()\n triggerCharacters: TriggerCharacter[] = [];\n\n /**\n * Specifies the visual appearance of the editor.\n */\n @Prop()\n public ui: EditorUiType = 'standard';\n\n @Element()\n private host: HTMLLimelTextEditorElement;\n\n private portalId: string;\n\n @State()\n private view: EditorView;\n\n @State()\n private actionBarItems: Array<\n ActionBarItem<EditorMenuTypes> | ListSeparator\n > = [];\n\n @State()\n private link: EditorTextLink = { href: 'https://' };\n\n /**\n * Open state of the dialog\n */\n @State()\n public isLinkMenuOpen: boolean = false;\n\n private menuCommandFactory: MenuCommandFactory;\n private schema: Schema;\n private contentConverter: ContentTypeConverter;\n private actionBarElement: HTMLElement;\n private lastEmittedValue: string;\n private changeWaiting = false;\n\n /**\n * Used to stop change event emitting as result of getting updated value from consumer\n */\n private suppressChangeEvent = false;\n\n /**\n * Dispatched when a change is made to the editor\n */\n @Event()\n private change: EventEmitter<string>;\n\n /**\n * Dispatched when a image is pasted into the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private imagePasted: EventEmitter<ImageInserter>;\n\n /**\n * Dispatched when a image is removed from the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private imageRemoved: EventEmitter<ImageInfo>;\n\n constructor() {\n this.portalId = createRandomString();\n }\n\n @Watch('value')\n protected watchValue(newValue: string) {\n if (!this.view) {\n return;\n }\n\n if (this.changeWaiting) {\n // A change is pending; do not update the editor's content\n return;\n }\n\n const currentContent = this.contentConverter.serialize(\n this.view,\n this.schema,\n );\n\n // If the new value is the same as the current content, do nothing\n if (newValue === currentContent) {\n return;\n }\n\n // Update the editor's content with the new value\n this.updateView(newValue);\n }\n\n public componentWillLoad() {\n this.getActionBarItems();\n this.setupContentConverter();\n }\n\n public componentDidLoad() {\n // Stencil complains loudly about triggering rerenders in\n // componentDidLoad, but we have to, so we're using setTimeout to\n // suppress the warning. /Ads\n setTimeout(() => {\n this.initializeTextEditor();\n }, 0);\n }\n\n public connectedCallback() {\n if (this.view) {\n this.initializeTextEditor();\n }\n\n this.host.addEventListener(\n 'open-editor-link-menu',\n this.handleOpenLinkMenu,\n );\n }\n\n public disconnectedCallback() {\n imageCache.clear();\n\n this.host.removeEventListener(\n 'open-editor-link-menu',\n this.handleOpenLinkMenu,\n );\n this.view?.dom?.removeEventListener('blur', this.handleBlur);\n this.view?.destroy();\n }\n\n public render() {\n return (\n <Host onFocus={this.handleFocus}>\n <div id=\"editor\" />\n {this.renderToolbar()}\n {this.renderLinkMenu()}\n </Host>\n );\n }\n\n renderToolbar() {\n if (!this.actionBarItems.length || this.ui === 'no-toolbar') {\n return;\n }\n\n return (\n <div class=\"toolbar\">\n <limel-action-bar\n ref={(el) => (this.actionBarElement = el)}\n accessibleLabel=\"Toolbar\"\n actions={this.actionBarItems}\n onItemSelected={this.handleActionBarItem}\n />\n </div>\n );\n }\n\n renderLinkMenu() {\n if (!this.isLinkMenuOpen) {\n return;\n }\n\n return (\n <limel-portal\n containerId={this.portalId}\n visible={this.isLinkMenuOpen}\n openDirection=\"top\"\n inheritParentWidth={true}\n anchor={this.actionBarElement}\n >\n <limel-text-editor-link-menu\n link={this.link}\n isOpen={this.isLinkMenuOpen}\n onLinkChange={this.handleLinkChange}\n onCancel={this.handleCancelLinkMenu}\n onSave={this.handleSaveLinkMenu}\n />\n </limel-portal>\n );\n }\n\n private setupContentConverter() {\n if (this.contentType === 'markdown') {\n this.contentConverter = new MarkdownConverter(\n this.customElements,\n this.language,\n );\n } else if (this.contentType === 'html') {\n this.contentConverter = new HTMLConverter(this.customElements);\n } else {\n throw new Error(\n `Unsupported content type: ${this.contentType}. Only 'markdown' and 'html' are supported.`,\n );\n }\n }\n\n private getActionBarItems = () => {\n this.actionBarItems = getTextEditorMenuItems().map(\n this.getTranslatedItem,\n );\n };\n\n private getTranslatedItem = (item) => {\n const newItem = cloneDeep(item);\n\n if (isItem(item)) {\n const translationId = menuTranslationIDs[item.value];\n\n if (translationId) {\n newItem.text = translate.get(translationId, this.language);\n }\n }\n\n return newItem;\n };\n\n private async initializeTextEditor() {\n this.schema = this.initializeSchema();\n const initialDoc = await this.parseInitialContent();\n this.menuCommandFactory = new MenuCommandFactory(this.schema);\n this.view = new EditorView(\n this.host.shadowRoot.querySelector('#editor'),\n {\n state: this.createEditorState(initialDoc),\n dispatchTransaction: this.handleTransaction,\n },\n );\n\n this.view.dom.addEventListener('blur', this.handleBlur);\n\n if (this.value) {\n this.updateView(this.value);\n }\n }\n\n private initializeSchema() {\n let nodes = schema.spec.nodes;\n\n this.customElements.forEach((customElement) => {\n const newNodeSpec = createNodeSpec(customElement);\n const nodeName = customElement.tagName;\n\n nodes = nodes.append({ [nodeName]: newNodeSpec });\n });\n nodes = addListNodes(nodes, 'paragraph block*', 'block');\n\n if (this.contentType === 'html') {\n nodes = nodes.append(getTableNodes());\n }\n\n nodes = nodes.append(getImageNode(this.language));\n\n return new Schema({\n nodes: nodes,\n marks: schema.spec.marks.append({\n strikethrough: strikethrough,\n }),\n });\n }\n\n private async parseInitialContent() {\n const initialContentElement = document.createElement('div');\n\n if (this.value) {\n initialContentElement.innerHTML =\n await this.contentConverter.parseAsHTML(\n this.value,\n this.schema,\n );\n } else {\n initialContentElement.innerHTML = '<p></p>';\n }\n\n return DOMParser.fromSchema(this.schema).parse(initialContentElement);\n }\n\n private createEditorState(initialDoc) {\n return EditorState.create({\n doc: initialDoc,\n plugins: [\n ...exampleSetup({ schema: this.schema, menuBar: false }),\n keymap(this.menuCommandFactory.buildKeymap()),\n createTriggerPlugin(\n this.triggerCharacters,\n this.contentConverter,\n ),\n createLinkPlugin(this.handleNewLinkSelection),\n createImageInserterPlugin(\n this.imagePasted.emit,\n this.imageRemoved.emit,\n ),\n createImageViewPlugin(this.language),\n createMenuStateTrackingPlugin(\n editorMenuTypesArray,\n this.menuCommandFactory,\n this.updateActiveActionBarItems,\n ),\n createActionBarInteractionPlugin(this.menuCommandFactory),\n ...getTableEditingPlugins(this.contentType === 'html'),\n ],\n });\n }\n\n private updateActiveActionBarItems = (\n activeTypes: Record<EditorMenuTypes, boolean>,\n allowedTypes: Record<EditorMenuTypes, boolean>,\n ) => {\n const newItems = getTextEditorMenuItems().map((item) => {\n if (isItem(item)) {\n return {\n ...item,\n selected: activeTypes[item.value],\n allowed: allowedTypes[item.value],\n };\n }\n\n return item;\n });\n\n this.actionBarItems = newItems.filter((item) =>\n isItem(item) ? item.allowed : true,\n );\n };\n\n private async updateView(content: string) {\n this.suppressChangeEvent = true;\n const html = await this.contentConverter.parseAsHTML(\n content,\n this.schema,\n );\n const prosemirrorDOMparser = DOMParser.fromSchema(\n this.view.state.schema,\n );\n const domParser = new window.DOMParser();\n const doc = domParser.parseFromString(html, 'text/html');\n const prosemirrorDoc = prosemirrorDOMparser.parse(doc.body);\n const tr = this.view.state.tr;\n tr.replaceWith(0, tr.doc.content.size, prosemirrorDoc.content);\n this.view.dispatch(tr);\n this.suppressChangeEvent = false;\n }\n\n private handleTransaction = (transaction: Transaction) => {\n const newState = this.view.state.apply(transaction);\n this.view.updateState(newState);\n\n if (this.suppressChangeEvent || transaction.getMeta('pointer')) {\n return;\n }\n\n const content = this.contentConverter.serialize(this.view, this.schema);\n\n if (content === this.lastEmittedValue) {\n return;\n }\n\n this.lastEmittedValue = content;\n this.changeWaiting = true;\n this.changeEmitter(content);\n };\n\n private handleActionBarItem = (\n event: CustomEvent<ActionBarItem<EditorMenuTypes>>,\n ) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n const { value } = event.detail;\n\n if (value === EditorMenuTypes.Link) {\n this.isLinkMenuOpen = true;\n\n return;\n }\n\n const actionBarEvent = new CustomEvent('actionBarItemClick', {\n detail: event.detail,\n });\n this.view.dom.dispatchEvent(actionBarEvent);\n };\n\n private handleCancelLinkMenu = (event: CustomEvent<void>) => {\n event.preventDefault();\n event.stopPropagation();\n\n this.isLinkMenuOpen = false;\n this.link = { text: '', href: 'https://' };\n };\n\n private handleSaveLinkMenu = () => {\n this.isLinkMenuOpen = false;\n\n const saveLinkEvent = new CustomEvent('saveLinkMenu', {\n detail: {\n type: EditorMenuTypes.Link,\n link: this.link,\n },\n });\n this.view.dom.dispatchEvent(saveLinkEvent);\n\n this.link = { href: 'https://' };\n };\n\n private handleLinkChange = (event: CustomEvent<EditorTextLink>) => {\n this.link = event.detail;\n };\n\n private handleFocus = () => {\n if (!this.disabled) {\n this.view?.focus();\n }\n };\n\n private handleNewLinkSelection = (text: string, href: string) => {\n this.link.text = text;\n this.link.href = href || 'https://';\n };\n\n private handleOpenLinkMenu = (\n event: CustomEvent<EditorLinkMenuEventDetail>,\n ) => {\n event.stopImmediatePropagation();\n const { href, text } = event.detail;\n this.link = { href: href, text: text };\n this.isLinkMenuOpen = true;\n };\n\n private changeEmitter = debounce((value: string) => {\n this.change.emit(value);\n this.changeWaiting = false;\n }, DEBOUNCE_TIMEOUT);\n\n private handleBlur = () => {\n this.changeEmitter.flush();\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"prosemirror-adapter.js","sourceRoot":"","sources":["../../../../src/components/text-editor/prosemirror-adapter/prosemirror-adapter.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Element,\n Event,\n EventEmitter,\n Host,\n Prop,\n State,\n Watch,\n h,\n} from '@stencil/core';\nimport { EditorState, Transaction } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { Schema, DOMParser } from 'prosemirror-model';\nimport { schema } from 'prosemirror-schema-basic';\nimport { addListNodes } from 'prosemirror-schema-list';\nimport { exampleSetup } from 'prosemirror-example-setup';\nimport { keymap } from 'prosemirror-keymap';\nimport { ActionBarItem } from '../../../components/action-bar/action-bar.types';\nimport { ListSeparator } from '../../../components/list/list-item.types';\nimport { MenuCommandFactory } from './menu/menu-commands';\nimport { menuTranslationIDs, getTextEditorMenuItems } from './menu/menu-items';\nimport { ContentTypeConverter } from '../utils/content-type-converter';\nimport { MarkdownConverter } from '../utils/markdown-converter';\nimport { HTMLConverter } from '../utils/html-converter';\nimport {\n EditorMenuTypes,\n EditorTextLink,\n editorMenuTypesArray,\n} from './menu/types';\nimport translate from '../../../global/translations';\nimport { createRandomString } from '../../../util/random-string';\nimport { isItem } from '../../../components/action-bar/isItem';\nimport { cloneDeep, debounce } from 'lodash-es';\nimport { Languages } from '../../date-picker/date.types';\nimport { strikethrough } from './menu/menu-schema-extender';\nimport { createLinkPlugin } from './plugins/link-plugin';\nimport { createImageInserterPlugin } from './plugins/image/inserter';\nimport { createImageViewPlugin } from './plugins/image/view';\nimport { createMenuStateTrackingPlugin } from './plugins/menu-state-tracking-plugin';\nimport { createActionBarInteractionPlugin } from './plugins/menu-action-interaction-plugin';\nimport { CustomElementDefinition } from '../../../global/shared-types/custom-element.types';\nimport { createNodeSpec } from '../utils/plugin-factory';\nimport { createTriggerPlugin } from './plugins/trigger/factory';\nimport {\n TriggerCharacter,\n ImageInserter,\n EditorImage,\n EditorMetadata,\n EditorLink,\n} from '../text-editor.types';\nimport { getTableNodes, getTableEditingPlugins } from './plugins/table-plugin';\nimport { getImageNode, imageCache } from './plugins/image/node';\nimport { EditorUiType } from '../types';\nimport {\n getMetadataFromDoc,\n hasMetadataChanged,\n} from '../utils/metadata-utils';\n\nconst DEBOUNCE_TIMEOUT = 300;\n\n/**\n * The ProseMirror adapter offers a rich text editing experience with markdown support.\n * [Read more...](https://prosemirror.net/)\n *\n * @exampleComponent limel-example-prosemirror-adapter-basic\n * @exampleComponent limel-example-prosemirror-adapter-with-custom-menu\n * @beta\n * @private\n */\n@Component({\n tag: 'limel-prosemirror-adapter',\n shadow: { delegatesFocus: true },\n styleUrl: 'prosemirror-adapter.scss',\n})\nexport class ProsemirrorAdapter {\n /**\n * The type of content that the editor should handle and emit, defaults to `markdown`\n *\n * Assumed to be set only once, so not reactive to changes\n */\n @Prop()\n public contentType: 'markdown' | 'html' = 'markdown';\n\n /**\n * The value of the editor, expected to be markdown\n */\n @Prop()\n public value: string;\n\n /**\n * Defines the language for translations.\n */\n @Prop({ reflect: true })\n public language: Languages;\n\n /**\n * Set to `true` to disable the field.\n * Use `disabled` to indicate that the field can normally be interacted\n * with, but is currently disabled. This tells the user that if certain\n * requirements are met, the field may become enabled again.\n */\n @Prop({ reflect: true })\n public disabled?: boolean = false;\n\n /**\n * set to private to avoid usage while under development\n *\n * @private\n * @alpha\n */\n @Prop()\n customElements: CustomElementDefinition[] = [];\n\n /**\n * set to private to avoid usage while under development\n *\n * @private\n * @alpha\n */\n @Prop()\n triggerCharacters: TriggerCharacter[] = [];\n\n /**\n * Specifies the visual appearance of the editor.\n */\n @Prop()\n public ui: EditorUiType = 'standard';\n\n @Element()\n private host: HTMLLimelTextEditorElement;\n\n private portalId: string;\n\n @State()\n private view: EditorView;\n\n @State()\n private actionBarItems: Array<\n ActionBarItem<EditorMenuTypes> | ListSeparator\n > = [];\n\n @State()\n private link: EditorTextLink = { href: 'https://' };\n\n /**\n * Open state of the dialog\n */\n @State()\n public isLinkMenuOpen: boolean = false;\n\n private menuCommandFactory: MenuCommandFactory;\n private schema: Schema;\n private contentConverter: ContentTypeConverter;\n private actionBarElement: HTMLElement;\n private lastEmittedValue: string;\n private changeWaiting = false;\n\n private metadata: EditorMetadata = { images: [], links: [] };\n\n /**\n * Used to stop change event emitting as result of getting updated value from consumer\n */\n private suppressChangeEvent = false;\n\n /**\n * Dispatched when a change is made to the editor\n */\n @Event()\n private change: EventEmitter<string>;\n\n /**\n * Dispatched when a image is pasted into the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private imagePasted: EventEmitter<ImageInserter>;\n\n /**\n * Dispatched when a image is removed from the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private imageRemoved: EventEmitter<EditorImage>;\n\n /**\n * Dispatched when the metadata of the editor changes (images and links)\n *\n * @private\n * @alpha\n */\n @Event()\n private metadataChange: EventEmitter<EditorMetadata>;\n\n constructor() {\n this.portalId = createRandomString();\n }\n\n @Watch('value')\n protected watchValue(newValue: string) {\n if (!this.view) {\n return;\n }\n\n if (this.changeWaiting) {\n // A change is pending; do not update the editor's content\n return;\n }\n\n const currentContent = this.contentConverter.serialize(\n this.view,\n this.schema,\n );\n\n // If the new value is the same as the current content, do nothing\n if (newValue === currentContent) {\n return;\n }\n\n // Update the editor's content with the new value\n this.updateView(newValue);\n }\n\n public componentWillLoad() {\n this.getActionBarItems();\n this.setupContentConverter();\n }\n\n public componentDidLoad() {\n // Stencil complains loudly about triggering rerenders in\n // componentDidLoad, but we have to, so we're using setTimeout to\n // suppress the warning. /Ads\n setTimeout(() => {\n this.initializeTextEditor();\n }, 0);\n }\n\n public connectedCallback() {\n if (this.view) {\n this.initializeTextEditor();\n }\n\n this.host.addEventListener(\n 'open-editor-link-menu',\n this.handleOpenLinkMenu,\n );\n }\n\n public disconnectedCallback() {\n imageCache.clear();\n\n this.host.removeEventListener(\n 'open-editor-link-menu',\n this.handleOpenLinkMenu,\n );\n this.view?.dom?.removeEventListener('blur', this.handleBlur);\n this.view?.destroy();\n }\n\n public render() {\n return (\n <Host onFocus={this.handleFocus}>\n <div id=\"editor\" />\n {this.renderToolbar()}\n {this.renderLinkMenu()}\n </Host>\n );\n }\n\n renderToolbar() {\n if (!this.actionBarItems.length || this.ui === 'no-toolbar') {\n return;\n }\n\n return (\n <div class=\"toolbar\">\n <limel-action-bar\n ref={(el) => (this.actionBarElement = el)}\n accessibleLabel=\"Toolbar\"\n actions={this.actionBarItems}\n onItemSelected={this.handleActionBarItem}\n />\n </div>\n );\n }\n\n renderLinkMenu() {\n if (!this.isLinkMenuOpen) {\n return;\n }\n\n return (\n <limel-portal\n containerId={this.portalId}\n visible={this.isLinkMenuOpen}\n openDirection=\"top\"\n inheritParentWidth={true}\n anchor={this.actionBarElement}\n >\n <limel-text-editor-link-menu\n link={this.link}\n isOpen={this.isLinkMenuOpen}\n onLinkChange={this.handleLinkChange}\n onCancel={this.handleCancelLinkMenu}\n onSave={this.handleSaveLinkMenu}\n />\n </limel-portal>\n );\n }\n\n private setupContentConverter() {\n if (this.contentType === 'markdown') {\n this.contentConverter = new MarkdownConverter(\n this.customElements,\n this.language,\n );\n } else if (this.contentType === 'html') {\n this.contentConverter = new HTMLConverter(this.customElements);\n } else {\n throw new Error(\n `Unsupported content type: ${this.contentType}. Only 'markdown' and 'html' are supported.`,\n );\n }\n }\n\n private getActionBarItems = () => {\n this.actionBarItems = getTextEditorMenuItems().map(\n this.getTranslatedItem,\n );\n };\n\n private getTranslatedItem = (item) => {\n const newItem = cloneDeep(item);\n\n if (isItem(item)) {\n const translationId = menuTranslationIDs[item.value];\n\n if (translationId) {\n newItem.text = translate.get(translationId, this.language);\n }\n }\n\n return newItem;\n };\n\n private async initializeTextEditor() {\n this.schema = this.initializeSchema();\n const initialDoc = await this.parseInitialContent();\n this.menuCommandFactory = new MenuCommandFactory(this.schema);\n this.view = new EditorView(\n this.host.shadowRoot.querySelector('#editor'),\n {\n state: this.createEditorState(initialDoc),\n dispatchTransaction: this.handleTransaction,\n },\n );\n\n this.view.dom.addEventListener('blur', this.handleBlur);\n\n if (this.value) {\n this.updateView(this.value);\n }\n }\n\n private initializeSchema() {\n let nodes = schema.spec.nodes;\n\n this.customElements.forEach((customElement) => {\n const newNodeSpec = createNodeSpec(customElement);\n const nodeName = customElement.tagName;\n\n nodes = nodes.append({ [nodeName]: newNodeSpec });\n });\n nodes = addListNodes(nodes, 'paragraph block*', 'block');\n\n if (this.contentType === 'html') {\n nodes = nodes.append(getTableNodes());\n }\n\n nodes = nodes.append(getImageNode(this.language));\n\n return new Schema({\n nodes: nodes,\n marks: schema.spec.marks.append({\n strikethrough: strikethrough,\n }),\n });\n }\n\n private async parseInitialContent() {\n const initialContentElement = document.createElement('div');\n\n if (this.value) {\n initialContentElement.innerHTML =\n await this.contentConverter.parseAsHTML(\n this.value,\n this.schema,\n );\n } else {\n initialContentElement.innerHTML = '<p></p>';\n }\n\n return DOMParser.fromSchema(this.schema).parse(initialContentElement);\n }\n\n private createEditorState(initialDoc) {\n return EditorState.create({\n doc: initialDoc,\n plugins: [\n ...exampleSetup({ schema: this.schema, menuBar: false }),\n keymap(this.menuCommandFactory.buildKeymap()),\n createTriggerPlugin(\n this.triggerCharacters,\n this.contentConverter,\n ),\n createLinkPlugin(this.handleNewLinkSelection),\n createImageInserterPlugin(this.imagePasted.emit),\n createImageViewPlugin(this.language),\n createMenuStateTrackingPlugin(\n editorMenuTypesArray,\n this.menuCommandFactory,\n this.updateActiveActionBarItems,\n ),\n createActionBarInteractionPlugin(this.menuCommandFactory),\n ...getTableEditingPlugins(this.contentType === 'html'),\n ],\n });\n }\n\n private updateActiveActionBarItems = (\n activeTypes: Record<EditorMenuTypes, boolean>,\n allowedTypes: Record<EditorMenuTypes, boolean>,\n ) => {\n const newItems = getTextEditorMenuItems().map((item) => {\n if (isItem(item)) {\n return {\n ...item,\n selected: activeTypes[item.value],\n allowed: allowedTypes[item.value],\n };\n }\n\n return item;\n });\n\n this.actionBarItems = newItems.filter((item) =>\n isItem(item) ? item.allowed : true,\n );\n };\n\n private async updateView(content: string) {\n this.suppressChangeEvent = true;\n const html = await this.contentConverter.parseAsHTML(\n content,\n this.schema,\n );\n const prosemirrorDOMparser = DOMParser.fromSchema(\n this.view.state.schema,\n );\n const domParser = new window.DOMParser();\n const doc = domParser.parseFromString(html, 'text/html');\n const prosemirrorDoc = prosemirrorDOMparser.parse(doc.body);\n const tr = this.view.state.tr;\n tr.replaceWith(0, tr.doc.content.size, prosemirrorDoc.content);\n this.view.dispatch(tr);\n\n const metadata = getMetadataFromDoc(this.view.state.doc);\n this.metadataEmitter(metadata);\n\n this.suppressChangeEvent = false;\n }\n\n private handleTransaction = (transaction: Transaction) => {\n const newState = this.view.state.apply(transaction);\n this.view.updateState(newState);\n\n if (this.suppressChangeEvent || transaction.getMeta('pointer')) {\n return;\n }\n\n const content = this.contentConverter.serialize(this.view, this.schema);\n\n if (content === this.lastEmittedValue) {\n return;\n }\n\n const metadata = getMetadataFromDoc(newState.doc);\n this.metadataEmitter(metadata);\n\n this.lastEmittedValue = content;\n this.changeWaiting = true;\n this.changeEmitter(content);\n };\n\n private metadataEmitter(metadata: EditorMetadata) {\n if (hasMetadataChanged(this.metadata, metadata)) {\n this.removeImagesFromCache(this.metadata, metadata);\n this.metadata = metadata;\n this.metadataChange.emit(metadata);\n }\n }\n\n private removeImagesFromCache(\n oldMetadata: EditorMetadata,\n newMetadata: EditorMetadata,\n ) {\n const removedImages = oldMetadata.images.filter(\n (oldImage) =>\n !newMetadata.images.some(\n (newImage) => newImage.fileInfoId === oldImage.fileInfoId,\n ),\n );\n\n removedImages.forEach((image) => {\n imageCache.delete(image.fileInfoId);\n this.imageRemoved.emit(image);\n });\n }\n\n private handleActionBarItem = (\n event: CustomEvent<ActionBarItem<EditorMenuTypes>>,\n ) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n const { value } = event.detail;\n\n if (value === EditorMenuTypes.Link) {\n this.isLinkMenuOpen = true;\n\n return;\n }\n\n const actionBarEvent = new CustomEvent('actionBarItemClick', {\n detail: event.detail,\n });\n this.view.dom.dispatchEvent(actionBarEvent);\n };\n\n private handleCancelLinkMenu = (event: CustomEvent<void>) => {\n event.preventDefault();\n event.stopPropagation();\n\n this.isLinkMenuOpen = false;\n this.link = { text: '', href: 'https://' };\n };\n\n private handleSaveLinkMenu = () => {\n this.isLinkMenuOpen = false;\n\n const saveLinkEvent = new CustomEvent('saveLinkMenu', {\n detail: {\n type: EditorMenuTypes.Link,\n link: this.link,\n },\n });\n this.view.dom.dispatchEvent(saveLinkEvent);\n\n this.link = { href: 'https://' };\n };\n\n private handleLinkChange = (event: CustomEvent<EditorTextLink>) => {\n this.link = event.detail;\n };\n\n private handleFocus = () => {\n if (!this.disabled) {\n this.view?.focus();\n }\n };\n\n private handleNewLinkSelection = (text: string, href: string) => {\n this.link.text = text;\n this.link.href = href || 'https://';\n };\n\n private handleOpenLinkMenu = (event: CustomEvent<EditorLink>) => {\n event.stopImmediatePropagation();\n const { href, text } = event.detail;\n this.link = { href: href, text: text };\n this.isLinkMenuOpen = true;\n };\n\n private changeEmitter = debounce((value: string) => {\n this.change.emit(value);\n this.changeWaiting = false;\n }, DEBOUNCE_TIMEOUT);\n\n private handleBlur = () => {\n this.changeEmitter.flush();\n };\n}\n"]}
|
|
@@ -49,8 +49,13 @@ export class TextEditor {
|
|
|
49
49
|
event.stopPropagation();
|
|
50
50
|
this.imagePasted.emit(event.detail);
|
|
51
51
|
};
|
|
52
|
+
this.handleMetadataChange = (event) => {
|
|
53
|
+
event.stopPropagation();
|
|
54
|
+
this.metadataChange.emit(event.detail);
|
|
55
|
+
};
|
|
52
56
|
this.handleImageRemoved = (event) => {
|
|
53
57
|
event.stopPropagation();
|
|
58
|
+
// eslint-disable-next-line sonarjs/deprecation
|
|
54
59
|
this.imageRemoved.emit(event.detail);
|
|
55
60
|
};
|
|
56
61
|
this.contentType = 'markdown';
|
|
@@ -77,7 +82,7 @@ export class TextEditor {
|
|
|
77
82
|
if (this.readonly) {
|
|
78
83
|
return (h("limel-markdown", { slot: "content", value: this.value, "aria-controls": this.helperTextId, id: this.editorId }));
|
|
79
84
|
}
|
|
80
|
-
return (h("limel-prosemirror-adapter", { slot: "content", "aria-placeholder": this.placeholder, contentType: this.contentType, onChange: this.handleChange, onImagePasted: this.handleImagePasted, onImageRemoved: this.handleImageRemoved, customElements: this.customElements, value: this.value, "aria-controls": this.helperTextId, id: this.editorId, "aria-disabled": this.disabled, "aria-invalid": this.invalid, "aria-required": this.required, language: this.language, triggerCharacters: this.triggers, disabled: this.disabled, ui: this.ui }));
|
|
85
|
+
return (h("limel-prosemirror-adapter", { slot: "content", "aria-placeholder": this.placeholder, contentType: this.contentType, onChange: this.handleChange, onImagePasted: this.handleImagePasted, onImageRemoved: this.handleImageRemoved, onMetadataChange: this.handleMetadataChange, customElements: this.customElements, value: this.value, "aria-controls": this.helperTextId, id: this.editorId, "aria-disabled": this.disabled, "aria-invalid": this.invalid, "aria-required": this.required, language: this.language, triggerCharacters: this.triggers, disabled: this.disabled, ui: this.ui }));
|
|
81
86
|
}
|
|
82
87
|
renderPlaceholder() {
|
|
83
88
|
if (!this.placeholder || this.value) {
|
|
@@ -433,14 +438,43 @@ export class TextEditor {
|
|
|
433
438
|
}, {
|
|
434
439
|
"name": "alpha",
|
|
435
440
|
"text": undefined
|
|
441
|
+
}, {
|
|
442
|
+
"name": "deprecated",
|
|
443
|
+
"text": "- This event is deprecated and will be removed in a future version.\nUse the `metadataChange` event instead to track image removals."
|
|
436
444
|
}],
|
|
437
445
|
"text": "Dispatched when a image is removed from the editor"
|
|
438
446
|
},
|
|
439
447
|
"complexType": {
|
|
440
|
-
"original": "
|
|
441
|
-
"resolved": "
|
|
448
|
+
"original": "EditorImage",
|
|
449
|
+
"resolved": "EditorImage",
|
|
450
|
+
"references": {
|
|
451
|
+
"EditorImage": {
|
|
452
|
+
"location": "import",
|
|
453
|
+
"path": "./text-editor.types"
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}, {
|
|
458
|
+
"method": "metadataChange",
|
|
459
|
+
"name": "metadataChange",
|
|
460
|
+
"bubbles": true,
|
|
461
|
+
"cancelable": true,
|
|
462
|
+
"composed": true,
|
|
463
|
+
"docs": {
|
|
464
|
+
"tags": [{
|
|
465
|
+
"name": "private",
|
|
466
|
+
"text": undefined
|
|
467
|
+
}, {
|
|
468
|
+
"name": "alpha",
|
|
469
|
+
"text": undefined
|
|
470
|
+
}],
|
|
471
|
+
"text": "Dispatched when the metadata of the editor changes"
|
|
472
|
+
},
|
|
473
|
+
"complexType": {
|
|
474
|
+
"original": "EditorMetadata",
|
|
475
|
+
"resolved": "EditorMetadata",
|
|
442
476
|
"references": {
|
|
443
|
-
"
|
|
477
|
+
"EditorMetadata": {
|
|
444
478
|
"location": "import",
|
|
445
479
|
"path": "./text-editor.types"
|
|
446
480
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-editor.js","sourceRoot":"","sources":["../../../src/components/text-editor/text-editor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, Event, EventEmitter, Host, Prop, h } from '@stencil/core';\nimport { FormComponent } from '../form/form.types';\nimport { Languages } from '../date-picker/date.types';\nimport { createRandomString } from '../../util/random-string';\nimport { CustomElementDefinition } from '../../global/shared-types/custom-element.types';\nimport {\n TriggerCharacter,\n TriggerEventDetail,\n ImageInserter,\n ImageInfo,\n} from './text-editor.types';\nimport { EditorUiType } from './types';\n\n/**\n * A rich text editor that offers a rich text editing experience with markdown support,\n * in the sense that you can easily type markdown syntax and see the rendered\n * result as rich text in real-time. For instance, you can type `# Hello, world!`\n * and see it directly turning to a heading 1 (an `<h1>` HTML element).\n *\n * Naturally, you can use standard keyboard hotkeys such as <kbd>Ctrl</kbd> + <kbd>B</kbd>\n * to toggle bold text, <kbd>Ctrl</kbd> + <kbd>I</kbd> to toggle italic text, and so on.\n *\n * @exampleComponent limel-example-text-editor-basic\n * @exampleComponent limel-example-text-editor-as-form-component\n * @exampleComponent limel-example-text-editor-with-markdown\n * @exampleComponent limel-example-text-editor-with-html\n * @exampleComponent limel-example-text-editor-with-tables\n * @exampleComponent limel-example-text-editor-with-inline-images-file-storage\n * @exampleComponent limel-example-text-editor-with-inline-images-base64\n * @exampleComponent limel-example-text-editor-allow-resize\n * @exampleComponent limel-example-text-editor-size\n * @exampleComponent limel-example-text-editor-ui\n * @exampleComponent limel-example-text-editor-custom-element\n * @exampleComponent limel-example-text-editor-triggers\n * @exampleComponent limel-example-text-editor-composite\n * @beta\n */\n@Component({\n tag: 'limel-text-editor',\n shadow: { delegatesFocus: true },\n styleUrl: 'text-editor.scss',\n})\nexport class TextEditor implements FormComponent<string> {\n /** The type of content that the editor should handle and emit, defaults to `markdown`\n *\n * Assumed to be set only once, so not reactive to changes\n */\n @Prop()\n public contentType: 'markdown' | 'html' = 'markdown';\n\n /**\n * Defines the language for translations.\n */\n @Prop({ reflect: true })\n public language: Languages = 'en';\n\n /**\n * Set to `true` to disable the field.\n * Use `disabled` to indicate that the field can normally be interacted\n * with, but is currently disabled. This tells the user that if certain\n * requirements are met, the field may become enabled again.\n */\n @Prop({ reflect: true })\n public disabled?: boolean = false;\n\n /**\n * Set to `true` to make the component read-only.\n * Use `readonly` when the field is only there to present the data it holds,\n * and will not become possible for the current user to edit.\n * :::note\n * Consider that it might be better to use `limel-markdown`\n * instead of `limel-text-editor` when the goal is visualizing data.\n * :::\n */\n @Prop({ reflect: true })\n public readonly?: boolean = false;\n\n /**\n * Optional helper text to display below the input field when it has focus\n */\n @Prop({ reflect: true })\n public helperText?: string;\n\n /**\n * The placeholder text shown inside the input field,\n * when the field is empty.\n */\n @Prop({ reflect: true })\n public placeholder?: string;\n\n /**\n * The label of the editor\n */\n @Prop({ reflect: true })\n public label?: string;\n\n /**\n * Set to `true` to indicate that the current value of the editor is\n * invalid.\n */\n @Prop({ reflect: true })\n public invalid?: boolean = false;\n\n /**\n * Description of the text inside the editor as markdown\n */\n @Prop({ reflect: true })\n public value: string;\n\n /**\n * A list of custom elements\n *\n * Any `CustomElement` that should be used inside the text editor needs\n * to be defined here.\n *\n * @private\n * @alpha\n */\n @Prop()\n public customElements: CustomElementDefinition[] = [];\n\n /**\n * A set of trigger characters\n *\n * Defining a character here will enable trigger events to be sent if the\n * character is detected in the editor.\n *\n * @private\n * @alpha\n */\n @Prop()\n public triggers: TriggerCharacter[] = [];\n\n /**\n * Set to `true` to indicate that the field is required.\n *\n * :::important\n * An empty but required field is not automatically considered invalid.\n * You must make sure to check the validity of the field on your own,\n * and properly handle the `invalid` state.\n * :::\n */\n @Prop({ reflect: true })\n public required?: boolean = false;\n\n /**\n * Set to `true` to allow the user to vertically resize the editor.\n * Set to `false` to disable the resize functionality.\n */\n @Prop({ reflect: true })\n public allowResize: boolean = true;\n\n /**\n * Specifies the visual appearance of the editor.\n *\n * - `standard`: The default editor appearance with a full toolbar and\n * standard layout.\n * - `minimal`: A compact editor appearance, ideal for limited space\n * scenarios such as mobile devices. In this mode, the toolbar is hidden\n * until the editor is focused.\n * - `no-toolbar`: A basic textarea appearance without any text styling toolbar.\n * This mode is suitable for scenarios where you want to provide a simple\n * text input without any visible formatting options; but still provide\n * support for markdown syntax and rich text, using hotkeys or when pasting.\n */\n @Prop({ reflect: true })\n public ui?: EditorUiType = 'standard';\n\n /**\n * Dispatched when a change is made to the editor\n */\n @Event()\n public change: EventEmitter<string>;\n\n /**\n * Dispatched when a image is pasted into the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private readonly imagePasted: EventEmitter<ImageInserter>;\n\n /**\n * Dispatched when a image is removed from the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private readonly imageRemoved: EventEmitter<ImageInfo>;\n\n /**\n * Dispatched if a trigger character is detected.\n *\n * @private\n * @alpha\n */\n @Event()\n public triggerStart: EventEmitter<TriggerEventDetail>;\n\n /**\n * Dispatched if a trigger session is ended. That is if the selection\n * goes outside the trigger input or if something is inserted using the\n * supplied `TextEditor` insert function.\n *\n * @private\n * @alpha\n */\n @Event()\n public triggerStop: EventEmitter<TriggerEventDetail>;\n\n /**\n * Dispatched if a input is changed during an active trigger.\n *\n * @private\n * @alpha\n */\n @Event()\n public triggerChange: EventEmitter<TriggerEventDetail>;\n\n private readonly helperTextId: string;\n private readonly editorId: string;\n\n public constructor() {\n this.helperTextId = createRandomString();\n this.editorId = createRandomString();\n }\n\n public render() {\n return (\n <Host>\n <limel-notched-outline\n labelId={this.editorId}\n label={this.label}\n required={this.required}\n invalid={this.invalid}\n disabled={this.disabled}\n readonly={this.readonly}\n hasValue={!!this.value}\n hasFloatingLabel={true}\n >\n {this.renderEditor()}\n {this.renderPlaceholder()}\n </limel-notched-outline>\n {this.renderHelperLine()}\n </Host>\n );\n }\n\n private renderEditor() {\n if (this.readonly) {\n return (\n <limel-markdown\n slot=\"content\"\n value={this.value}\n aria-controls={this.helperTextId}\n id={this.editorId}\n />\n );\n }\n\n return (\n <limel-prosemirror-adapter\n slot=\"content\"\n aria-placeholder={this.placeholder}\n contentType={this.contentType}\n onChange={this.handleChange}\n onImagePasted={this.handleImagePasted}\n onImageRemoved={this.handleImageRemoved}\n customElements={this.customElements}\n value={this.value}\n aria-controls={this.helperTextId}\n id={this.editorId}\n aria-disabled={this.disabled}\n aria-invalid={this.invalid}\n aria-required={this.required}\n language={this.language}\n triggerCharacters={this.triggers}\n disabled={this.disabled}\n ui={this.ui}\n />\n );\n }\n\n private renderPlaceholder() {\n if (!this.placeholder || this.value) {\n return;\n }\n\n return (\n <span class=\"placeholder\" aria-hidden=\"true\" slot=\"content\">\n {this.placeholder}\n </span>\n );\n }\n\n private renderHelperLine = () => {\n if (!this.helperText) {\n return;\n }\n\n return (\n <limel-helper-line\n helperText={this.helperText}\n helperTextId={this.helperTextId}\n invalid={this.isInvalid()}\n />\n );\n };\n\n private isInvalid = () => {\n if (this.readonly) {\n // A readonly field can never be invalid.\n return false;\n }\n\n if (this.invalid) {\n return true;\n }\n };\n\n private handleChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n this.change.emit(event.detail);\n };\n\n private handleImagePasted = (event: CustomEvent<ImageInserter>) => {\n event.stopPropagation();\n this.imagePasted.emit(event.detail);\n };\n\n private handleImageRemoved = (event: CustomEvent<ImageInfo>) => {\n event.stopPropagation();\n this.imageRemoved.emit(event.detail);\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"text-editor.js","sourceRoot":"","sources":["../../../src/components/text-editor/text-editor.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, Event, EventEmitter, Host, Prop, h } from '@stencil/core';\nimport { FormComponent } from '../form/form.types';\nimport { Languages } from '../date-picker/date.types';\nimport { createRandomString } from '../../util/random-string';\nimport { CustomElementDefinition } from '../../global/shared-types/custom-element.types';\nimport {\n TriggerCharacter,\n TriggerEventDetail,\n ImageInserter,\n EditorImage,\n EditorMetadata,\n} from './text-editor.types';\nimport { EditorUiType } from './types';\n\n/**\n * A rich text editor that offers a rich text editing experience with markdown support,\n * in the sense that you can easily type markdown syntax and see the rendered\n * result as rich text in real-time. For instance, you can type `# Hello, world!`\n * and see it directly turning to a heading 1 (an `<h1>` HTML element).\n *\n * Naturally, you can use standard keyboard hotkeys such as <kbd>Ctrl</kbd> + <kbd>B</kbd>\n * to toggle bold text, <kbd>Ctrl</kbd> + <kbd>I</kbd> to toggle italic text, and so on.\n *\n * @exampleComponent limel-example-text-editor-basic\n * @exampleComponent limel-example-text-editor-as-form-component\n * @exampleComponent limel-example-text-editor-with-markdown\n * @exampleComponent limel-example-text-editor-with-html\n * @exampleComponent limel-example-text-editor-with-tables\n * @exampleComponent limel-example-text-editor-with-inline-images-file-storage\n * @exampleComponent limel-example-text-editor-with-inline-images-base64\n * @exampleComponent limel-example-text-editor-allow-resize\n * @exampleComponent limel-example-text-editor-size\n * @exampleComponent limel-example-text-editor-ui\n * @exampleComponent limel-example-text-editor-custom-element\n * @exampleComponent limel-example-text-editor-triggers\n * @exampleComponent limel-example-text-editor-composite\n * @beta\n */\n@Component({\n tag: 'limel-text-editor',\n shadow: { delegatesFocus: true },\n styleUrl: 'text-editor.scss',\n})\nexport class TextEditor implements FormComponent<string> {\n /** The type of content that the editor should handle and emit, defaults to `markdown`\n *\n * Assumed to be set only once, so not reactive to changes\n */\n @Prop()\n public contentType: 'markdown' | 'html' = 'markdown';\n\n /**\n * Defines the language for translations.\n */\n @Prop({ reflect: true })\n public language: Languages = 'en';\n\n /**\n * Set to `true` to disable the field.\n * Use `disabled` to indicate that the field can normally be interacted\n * with, but is currently disabled. This tells the user that if certain\n * requirements are met, the field may become enabled again.\n */\n @Prop({ reflect: true })\n public disabled?: boolean = false;\n\n /**\n * Set to `true` to make the component read-only.\n * Use `readonly` when the field is only there to present the data it holds,\n * and will not become possible for the current user to edit.\n * :::note\n * Consider that it might be better to use `limel-markdown`\n * instead of `limel-text-editor` when the goal is visualizing data.\n * :::\n */\n @Prop({ reflect: true })\n public readonly?: boolean = false;\n\n /**\n * Optional helper text to display below the input field when it has focus\n */\n @Prop({ reflect: true })\n public helperText?: string;\n\n /**\n * The placeholder text shown inside the input field,\n * when the field is empty.\n */\n @Prop({ reflect: true })\n public placeholder?: string;\n\n /**\n * The label of the editor\n */\n @Prop({ reflect: true })\n public label?: string;\n\n /**\n * Set to `true` to indicate that the current value of the editor is\n * invalid.\n */\n @Prop({ reflect: true })\n public invalid?: boolean = false;\n\n /**\n * Description of the text inside the editor as markdown\n */\n @Prop({ reflect: true })\n public value: string;\n\n /**\n * A list of custom elements\n *\n * Any `CustomElement` that should be used inside the text editor needs\n * to be defined here.\n *\n * @private\n * @alpha\n */\n @Prop()\n public customElements: CustomElementDefinition[] = [];\n\n /**\n * A set of trigger characters\n *\n * Defining a character here will enable trigger events to be sent if the\n * character is detected in the editor.\n *\n * @private\n * @alpha\n */\n @Prop()\n public triggers: TriggerCharacter[] = [];\n\n /**\n * Set to `true` to indicate that the field is required.\n *\n * :::important\n * An empty but required field is not automatically considered invalid.\n * You must make sure to check the validity of the field on your own,\n * and properly handle the `invalid` state.\n * :::\n */\n @Prop({ reflect: true })\n public required?: boolean = false;\n\n /**\n * Set to `true` to allow the user to vertically resize the editor.\n * Set to `false` to disable the resize functionality.\n */\n @Prop({ reflect: true })\n public allowResize: boolean = true;\n\n /**\n * Specifies the visual appearance of the editor.\n *\n * - `standard`: The default editor appearance with a full toolbar and\n * standard layout.\n * - `minimal`: A compact editor appearance, ideal for limited space\n * scenarios such as mobile devices. In this mode, the toolbar is hidden\n * until the editor is focused.\n * - `no-toolbar`: A basic textarea appearance without any text styling toolbar.\n * This mode is suitable for scenarios where you want to provide a simple\n * text input without any visible formatting options; but still provide\n * support for markdown syntax and rich text, using hotkeys or when pasting.\n */\n @Prop({ reflect: true })\n public ui?: EditorUiType = 'standard';\n\n /**\n * Dispatched when a change is made to the editor\n */\n @Event()\n public change: EventEmitter<string>;\n\n /**\n * Dispatched when a image is pasted into the editor\n *\n * @private\n * @alpha\n */\n @Event()\n private readonly imagePasted: EventEmitter<ImageInserter>;\n\n /**\n * Dispatched when a image is removed from the editor\n *\n * @private\n * @alpha\n * @deprecated - This event is deprecated and will be removed in a future version.\n * Use the `metadataChange` event instead to track image removals.\n */\n @Event()\n private readonly imageRemoved: EventEmitter<EditorImage>;\n\n /**\n * Dispatched when the metadata of the editor changes\n *\n * @private\n * @alpha\n */\n @Event()\n private readonly metadataChange: EventEmitter<EditorMetadata>;\n\n /**\n * Dispatched if a trigger character is detected.\n *\n * @private\n * @alpha\n */\n @Event()\n public triggerStart: EventEmitter<TriggerEventDetail>;\n\n /**\n * Dispatched if a trigger session is ended. That is if the selection\n * goes outside the trigger input or if something is inserted using the\n * supplied `TextEditor` insert function.\n *\n * @private\n * @alpha\n */\n @Event()\n public triggerStop: EventEmitter<TriggerEventDetail>;\n\n /**\n * Dispatched if a input is changed during an active trigger.\n *\n * @private\n * @alpha\n */\n @Event()\n public triggerChange: EventEmitter<TriggerEventDetail>;\n\n private readonly helperTextId: string;\n private readonly editorId: string;\n\n public constructor() {\n this.helperTextId = createRandomString();\n this.editorId = createRandomString();\n }\n\n public render() {\n return (\n <Host>\n <limel-notched-outline\n labelId={this.editorId}\n label={this.label}\n required={this.required}\n invalid={this.invalid}\n disabled={this.disabled}\n readonly={this.readonly}\n hasValue={!!this.value}\n hasFloatingLabel={true}\n >\n {this.renderEditor()}\n {this.renderPlaceholder()}\n </limel-notched-outline>\n {this.renderHelperLine()}\n </Host>\n );\n }\n\n private renderEditor() {\n if (this.readonly) {\n return (\n <limel-markdown\n slot=\"content\"\n value={this.value}\n aria-controls={this.helperTextId}\n id={this.editorId}\n />\n );\n }\n\n return (\n <limel-prosemirror-adapter\n slot=\"content\"\n aria-placeholder={this.placeholder}\n contentType={this.contentType}\n onChange={this.handleChange}\n onImagePasted={this.handleImagePasted}\n onImageRemoved={this.handleImageRemoved}\n onMetadataChange={this.handleMetadataChange}\n customElements={this.customElements}\n value={this.value}\n aria-controls={this.helperTextId}\n id={this.editorId}\n aria-disabled={this.disabled}\n aria-invalid={this.invalid}\n aria-required={this.required}\n language={this.language}\n triggerCharacters={this.triggers}\n disabled={this.disabled}\n ui={this.ui}\n />\n );\n }\n\n private renderPlaceholder() {\n if (!this.placeholder || this.value) {\n return;\n }\n\n return (\n <span class=\"placeholder\" aria-hidden=\"true\" slot=\"content\">\n {this.placeholder}\n </span>\n );\n }\n\n private renderHelperLine = () => {\n if (!this.helperText) {\n return;\n }\n\n return (\n <limel-helper-line\n helperText={this.helperText}\n helperTextId={this.helperTextId}\n invalid={this.isInvalid()}\n />\n );\n };\n\n private isInvalid = () => {\n if (this.readonly) {\n // A readonly field can never be invalid.\n return false;\n }\n\n if (this.invalid) {\n return true;\n }\n };\n\n private handleChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n this.change.emit(event.detail);\n };\n\n private handleImagePasted = (event: CustomEvent<ImageInserter>) => {\n event.stopPropagation();\n this.imagePasted.emit(event.detail);\n };\n\n private handleMetadataChange = (event: CustomEvent<EditorMetadata>) => {\n event.stopPropagation();\n this.metadataChange.emit(event.detail);\n };\n\n private handleImageRemoved = (event: CustomEvent<EditorImage>) => {\n event.stopPropagation();\n // eslint-disable-next-line sonarjs/deprecation\n this.imageRemoved.emit(event.detail);\n };\n}\n"]}
|
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* @alpha
|
|
3
|
-
*/
|
|
4
|
-
export var ImageState;
|
|
5
|
-
(function (ImageState) {
|
|
6
|
-
ImageState["LOADING"] = "loading";
|
|
7
|
-
ImageState["FAILED"] = "failed";
|
|
8
|
-
ImageState["SUCCESS"] = "success";
|
|
9
|
-
})(ImageState || (ImageState = {}));
|
|
1
|
+
export {};
|
|
10
2
|
//# sourceMappingURL=text-editor.types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-editor.types.js","sourceRoot":"","sources":["../../../src/components/text-editor/text-editor.types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"text-editor.types.js","sourceRoot":"","sources":["../../../src/components/text-editor/text-editor.types.ts"],"names":[],"mappings":"","sourcesContent":["import { CustomElement } from '../../global/shared-types/custom-element.types';\nimport { FileInfo } from '../../global/shared-types/file.types';\n\n/**\n * Represents a trigger character and its position in the text.\n *\n * @alpha\n */\nexport type Trigger = {\n character: TriggerCharacter;\n position: number;\n};\n\n/**\n * A character that triggers a specific action in the text editor.\n *\n * @alpha\n */\nexport type TriggerCharacter =\n | '@'\n | '#'\n | '$'\n | '!'\n | '?'\n | '&'\n | '*'\n | '%'\n | '+'\n | '-'\n | '='\n | '/'\n | '\\\\'\n | '^'\n | '~'\n | '`'\n | ':'\n | ';'\n | '|'\n | '.'\n | ','\n | '<'\n | '>'\n | '['\n | ']'\n | '{'\n | '}'\n | '('\n | ')'\n | \"'\";\n\n/**\n * @alpha\n */\nexport type TextEditorNode = {\n /**\n * The top node\n */\n node: CustomElement | string;\n\n /**\n * One more more children under the top node\n */\n children?: Array<TextEditorNode | string>;\n};\n\n/**\n * @alpha\n */\nexport interface ImageInserter {\n fileInfo: FileInfo;\n\n /**\n * Method to insert a thumbnail at the cursor position.\n */\n insertThumbnail: () => void;\n\n /**\n * Method to insert the image at the thumbnail position.\n * Thumbnail must be inserted before calling this method.\n *\n * @param src - The src url of the uploaded image.\n * If not provided, the image will be inserted with base64 data.\n *\n */\n insertImage: (src?: string) => void;\n\n /**\n * Method to insert a failed thumbnail at the thumbnail position.\n * Thumbnail must be inserted before calling this method.\n */\n insertFailedThumbnail: () => void;\n}\n\n/**\n * @alpha\n */\nexport type EditorImageState = 'loading' | 'failed' | 'success';\n\n/**\n * @alpha\n */\nexport interface EditorImage {\n /**\n * Unique ID of the image file.\n */\n fileInfoId: string;\n /**\n * The source of the image.\n * Can either be a URL pointing to the image or a base64 encoded string.\n */\n src: string;\n /**\n * The current state of the image.\n */\n state: EditorImageState;\n}\n\n/**\n * @alpha\n */\nexport interface EditorLink {\n /**\n * The URL of the link.\n */\n href: string;\n\n /**\n * The text associated with the link.\n */\n text: string;\n}\n\n/**\n * @alpha\n */\nexport interface TextEditor {\n /**\n * Method to insert either text or a node at the cursor position\n */\n insert: (input: TextEditorNode | string) => void;\n\n /**\n * Method to insert an HTML string at the cursor position\n */\n insertHtml: (input: string) => Promise<void>;\n\n stopTrigger: () => void;\n}\n\n/**\n * @alpha\n */\nexport interface TriggerEventDetail {\n /**\n * The trigger that triggered this event\n *\n */\n trigger: TriggerCharacter;\n\n /**\n * The text editor\n */\n textEditor: TextEditor;\n\n /**\n * Current value of the trigger\n */\n value: string;\n}\n\n/**\n *\n * @alpha\n *\n * Interface representing metadata extracted from the editor document\n */\nexport interface EditorMetadata {\n /**\n * Collection of image elements found in the document\n */\n images: EditorImage[];\n\n /**\n * Collection of link elements found in the document\n */\n links: EditorLink[];\n}\n"]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts metadata from a ProseMirror document node
|
|
3
|
+
*
|
|
4
|
+
* This function traverses the entire document tree and collects information about
|
|
5
|
+
* special elements like images and links.
|
|
6
|
+
*
|
|
7
|
+
* @param doc - The ProseMirror document node to extract metadata from
|
|
8
|
+
* @returns A metadata object containing arrays of images and links found in the document
|
|
9
|
+
*/
|
|
10
|
+
export function getMetadataFromDoc(doc) {
|
|
11
|
+
const metadata = { images: [], links: [] };
|
|
12
|
+
doc.descendants((node) => {
|
|
13
|
+
if (isImageNode(node)) {
|
|
14
|
+
metadata.images.push(extractImageMetadata(node));
|
|
15
|
+
}
|
|
16
|
+
else if (isTextNodeWithMarks(node)) {
|
|
17
|
+
extractLinkMetadata(node).forEach((link) => metadata.links.push(link));
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
});
|
|
21
|
+
return metadata;
|
|
22
|
+
}
|
|
23
|
+
function isImageNode(node) {
|
|
24
|
+
return node.type.name === 'image' && !!node.attrs;
|
|
25
|
+
}
|
|
26
|
+
function extractImageMetadata(node) {
|
|
27
|
+
return {
|
|
28
|
+
src: node.attrs.src,
|
|
29
|
+
state: node.attrs.state,
|
|
30
|
+
fileInfoId: node.attrs.fileInfoId,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function isTextNodeWithMarks(node) {
|
|
34
|
+
var _a;
|
|
35
|
+
return node.isText && ((_a = node.marks) === null || _a === void 0 ? void 0 : _a.length) > 0;
|
|
36
|
+
}
|
|
37
|
+
function extractLinkMetadata(node) {
|
|
38
|
+
return node.marks
|
|
39
|
+
.filter((mark) => mark.type.name === 'link' && mark.attrs)
|
|
40
|
+
.map((mark) => ({
|
|
41
|
+
href: mark.attrs.href,
|
|
42
|
+
text: node.text,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Determines if metadata has changed between two states
|
|
47
|
+
* Handles duplicates correctly but is order-insensitive
|
|
48
|
+
*
|
|
49
|
+
* @param oldMetadata - The previous metadata state to compare against
|
|
50
|
+
* @param newMetadata - The current metadata state
|
|
51
|
+
* @returns True if there are any differences between the metadata objects, false otherwise
|
|
52
|
+
*/
|
|
53
|
+
export function hasMetadataChanged(oldMetadata, newMetadata) {
|
|
54
|
+
return (hasDifferentLengths(oldMetadata, newMetadata) ||
|
|
55
|
+
hasDifferentLinks(oldMetadata.links, newMetadata.links) ||
|
|
56
|
+
hasDifferentImages(oldMetadata.images, newMetadata.images));
|
|
57
|
+
}
|
|
58
|
+
function hasDifferentLengths(oldMetadata, newMetadata) {
|
|
59
|
+
return (oldMetadata.images.length !== newMetadata.images.length ||
|
|
60
|
+
oldMetadata.links.length !== newMetadata.links.length);
|
|
61
|
+
}
|
|
62
|
+
function hasDifferentLinks(oldLinks, newLinks) {
|
|
63
|
+
const oldLinkCounts = getLinkFrequencyMap(oldLinks);
|
|
64
|
+
const newLinkCounts = getLinkFrequencyMap(newLinks);
|
|
65
|
+
return !areFrequencyMapsEqual(oldLinkCounts, newLinkCounts);
|
|
66
|
+
}
|
|
67
|
+
function hasDifferentImages(oldImages, newImages) {
|
|
68
|
+
const oldImageCounts = getImageFrequencyMap(oldImages);
|
|
69
|
+
const newImageCounts = getImageFrequencyMap(newImages);
|
|
70
|
+
return !areFrequencyMapsEqual(oldImageCounts, newImageCounts);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Creates a frequency map for images based on their key properties
|
|
74
|
+
*/
|
|
75
|
+
function getImageFrequencyMap(images) {
|
|
76
|
+
const countMap = new Map();
|
|
77
|
+
images.forEach((image) => {
|
|
78
|
+
const key = `${image.fileInfoId}|${image.state}|${image.src}`;
|
|
79
|
+
countMap.set(key, (countMap.get(key) || 0) + 1);
|
|
80
|
+
});
|
|
81
|
+
return countMap;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Creates a frequency map for links based on their key properties
|
|
85
|
+
*/
|
|
86
|
+
function getLinkFrequencyMap(links) {
|
|
87
|
+
const countMap = new Map();
|
|
88
|
+
links.forEach((link) => {
|
|
89
|
+
const key = `${link.href}|${link.text}`;
|
|
90
|
+
countMap.set(key, (countMap.get(key) || 0) + 1);
|
|
91
|
+
});
|
|
92
|
+
return countMap;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Compares two frequency maps for equality
|
|
96
|
+
*/
|
|
97
|
+
function areFrequencyMapsEqual(map1, map2) {
|
|
98
|
+
if (map1.size !== map2.size) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
for (const [key, count] of map1.entries()) {
|
|
102
|
+
if (map2.get(key) !== count) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=metadata-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-utils.js","sourceRoot":"","sources":["../../../../src/components/text-editor/utils/metadata-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { EditorImage, EditorLink, EditorMetadata } from '../text-editor.types';\nimport { Node } from 'prosemirror-model';\n\n/**\n * Extracts metadata from a ProseMirror document node\n *\n * This function traverses the entire document tree and collects information about\n * special elements like images and links.\n *\n * @param doc - The ProseMirror document node to extract metadata from\n * @returns A metadata object containing arrays of images and links found in the document\n */\nexport function getMetadataFromDoc(doc: Node): EditorMetadata {\n const metadata: EditorMetadata = { images: [], links: [] };\n\n doc.descendants((node) => {\n if (isImageNode(node)) {\n metadata.images.push(extractImageMetadata(node));\n } else if (isTextNodeWithMarks(node)) {\n extractLinkMetadata(node).forEach((link) =>\n metadata.links.push(link),\n );\n }\n\n return true;\n });\n\n return metadata;\n}\n\nfunction isImageNode(node: Node): boolean {\n return node.type.name === 'image' && !!node.attrs;\n}\n\nfunction extractImageMetadata(node: Node): EditorImage {\n return {\n src: node.attrs.src,\n state: node.attrs.state,\n fileInfoId: node.attrs.fileInfoId,\n };\n}\n\nfunction isTextNodeWithMarks(node: Node): boolean {\n return node.isText && node.marks?.length > 0;\n}\n\nfunction extractLinkMetadata(node: Node): EditorLink[] {\n return node.marks\n .filter((mark) => mark.type.name === 'link' && mark.attrs)\n .map((mark) => ({\n href: mark.attrs.href,\n text: node.text,\n }));\n}\n\n/**\n * Determines if metadata has changed between two states\n * Handles duplicates correctly but is order-insensitive\n *\n * @param oldMetadata - The previous metadata state to compare against\n * @param newMetadata - The current metadata state\n * @returns True if there are any differences between the metadata objects, false otherwise\n */\nexport function hasMetadataChanged(\n oldMetadata: EditorMetadata,\n newMetadata: EditorMetadata,\n): boolean {\n return (\n hasDifferentLengths(oldMetadata, newMetadata) ||\n hasDifferentLinks(oldMetadata.links, newMetadata.links) ||\n hasDifferentImages(oldMetadata.images, newMetadata.images)\n );\n}\n\nfunction hasDifferentLengths(\n oldMetadata: EditorMetadata,\n newMetadata: EditorMetadata,\n): boolean {\n return (\n oldMetadata.images.length !== newMetadata.images.length ||\n oldMetadata.links.length !== newMetadata.links.length\n );\n}\n\nfunction hasDifferentLinks(\n oldLinks: EditorLink[],\n newLinks: EditorLink[],\n): boolean {\n const oldLinkCounts = getLinkFrequencyMap(oldLinks);\n const newLinkCounts = getLinkFrequencyMap(newLinks);\n\n return !areFrequencyMapsEqual(oldLinkCounts, newLinkCounts);\n}\n\nfunction hasDifferentImages(\n oldImages: EditorImage[],\n newImages: EditorImage[],\n): boolean {\n const oldImageCounts = getImageFrequencyMap(oldImages);\n const newImageCounts = getImageFrequencyMap(newImages);\n\n return !areFrequencyMapsEqual(oldImageCounts, newImageCounts);\n}\n\n/**\n * Creates a frequency map for images based on their key properties\n */\nfunction getImageFrequencyMap(images: EditorImage[]): Map<string, number> {\n const countMap = new Map<string, number>();\n\n images.forEach((image) => {\n const key = `${image.fileInfoId}|${image.state}|${image.src}`;\n\n countMap.set(key, (countMap.get(key) || 0) + 1);\n });\n\n return countMap;\n}\n\n/**\n * Creates a frequency map for links based on their key properties\n */\nfunction getLinkFrequencyMap(links: EditorLink[]): Map<string, number> {\n const countMap = new Map<string, number>();\n\n links.forEach((link) => {\n const key = `${link.href}|${link.text}`;\n\n countMap.set(key, (countMap.get(key) || 0) + 1);\n });\n\n return countMap;\n}\n\n/**\n * Compares two frequency maps for equality\n */\nfunction areFrequencyMapsEqual(\n map1: Map<string, number>,\n map2: Map<string, number>,\n): boolean {\n if (map1.size !== map2.size) {\n return false;\n }\n\n for (const [key, count] of map1.entries()) {\n if (map2.get(key) !== count) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|