@malva-ui/editor 0.1.13 → 0.1.14
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/README.md +5 -5
- package/fesm2022/malva-ui-editor-ai.mjs +17 -0
- package/fesm2022/malva-ui-editor-ai.mjs.map +1 -0
- package/fesm2022/malva-ui-editor.mjs +10227 -0
- package/fesm2022/malva-ui-editor.mjs.map +1 -0
- package/package.json +35 -26
- package/types/malva-ui-editor-ai.d.ts +1 -0
- package/types/malva-ui-editor.d.ts +2995 -0
- package/ai/index.d.ts +0 -12
- package/ai/malva-ui-editor-ai.d.ts +0 -5
- package/esm2022/ai/index.js +0 -12
- package/esm2022/ai/index.js.map +0 -1
- package/esm2022/ai/malva-ui-editor-ai.js +0 -5
- package/esm2022/ai/malva-ui-editor-ai.js.map +0 -1
- package/esm2022/index.js +0 -37
- package/esm2022/index.js.map +0 -1
- package/esm2022/lib/ai/editor-ai-actions.js +0 -69
- package/esm2022/lib/ai/editor-ai-actions.js.map +0 -1
- package/esm2022/lib/ai/editor-ai-context.js +0 -612
- package/esm2022/lib/ai/editor-ai-context.js.map +0 -1
- package/esm2022/lib/ai/editor-ai-menu.js +0 -288
- package/esm2022/lib/ai/editor-ai-menu.js.map +0 -1
- package/esm2022/lib/ai/editor-ai-review-bar.js +0 -223
- package/esm2022/lib/ai/editor-ai-review-bar.js.map +0 -1
- package/esm2022/lib/ai/editor-ai-stream.js +0 -677
- package/esm2022/lib/ai/editor-ai-stream.js.map +0 -1
- package/esm2022/lib/ai/editor-ai-suggestions.js +0 -751
- package/esm2022/lib/ai/editor-ai-suggestions.js.map +0 -1
- package/esm2022/lib/ai/editor-ai.tokens.js +0 -10
- package/esm2022/lib/ai/editor-ai.tokens.js.map +0 -1
- package/esm2022/lib/ai/editor-ai.types.js +0 -1
- package/esm2022/lib/ai/editor-ai.types.js.map +0 -1
- package/esm2022/lib/editor/editor.js +0 -985
- package/esm2022/lib/editor/editor.js.map +0 -1
- package/esm2022/lib/editor-extension-preflight.js +0 -83
- package/esm2022/lib/editor-extension-preflight.js.map +0 -1
- package/esm2022/lib/editor-serialization.js +0 -152
- package/esm2022/lib/editor-serialization.js.map +0 -1
- package/esm2022/lib/editor-toolbar-context.js +0 -259
- package/esm2022/lib/editor-toolbar-context.js.map +0 -1
- package/esm2022/lib/editor.tokens.js +0 -10
- package/esm2022/lib/editor.tokens.js.map +0 -1
- package/esm2022/lib/editor.types.js +0 -48
- package/esm2022/lib/editor.types.js.map +0 -1
- package/esm2022/lib/extensions/editor-block-handle.js +0 -760
- package/esm2022/lib/extensions/editor-block-handle.js.map +0 -1
- package/esm2022/lib/extensions/editor-extensions.js +0 -321
- package/esm2022/lib/extensions/editor-extensions.js.map +0 -1
- package/esm2022/lib/extensions/editor-markdown-compatibility.js +0 -162
- package/esm2022/lib/extensions/editor-markdown-compatibility.js.map +0 -1
- package/esm2022/lib/extensions/editor-upload-placeholder.js +0 -156
- package/esm2022/lib/extensions/editor-upload-placeholder.js.map +0 -1
- package/esm2022/lib/status/editor-status.js +0 -64
- package/esm2022/lib/status/editor-status.js.map +0 -1
- package/esm2022/lib/toolbar/editor-alignment.js +0 -203
- package/esm2022/lib/toolbar/editor-alignment.js.map +0 -1
- package/esm2022/lib/toolbar/editor-block-insert.js +0 -101
- package/esm2022/lib/toolbar/editor-block-insert.js.map +0 -1
- package/esm2022/lib/toolbar/editor-color-control.js +0 -71
- package/esm2022/lib/toolbar/editor-color-control.js.map +0 -1
- package/esm2022/lib/toolbar/editor-command-button.js +0 -115
- package/esm2022/lib/toolbar/editor-command-button.js.map +0 -1
- package/esm2022/lib/toolbar/editor-heading.js +0 -266
- package/esm2022/lib/toolbar/editor-heading.js.map +0 -1
- package/esm2022/lib/toolbar/editor-highlight.js +0 -84
- package/esm2022/lib/toolbar/editor-highlight.js.map +0 -1
- package/esm2022/lib/toolbar/editor-image-upload-dialog.js +0 -289
- package/esm2022/lib/toolbar/editor-image-upload-dialog.js.map +0 -1
- package/esm2022/lib/toolbar/editor-image-upload.js +0 -315
- package/esm2022/lib/toolbar/editor-image-upload.js.map +0 -1
- package/esm2022/lib/toolbar/editor-inline-marks.js +0 -124
- package/esm2022/lib/toolbar/editor-inline-marks.js.map +0 -1
- package/esm2022/lib/toolbar/editor-link.js +0 -265
- package/esm2022/lib/toolbar/editor-link.js.map +0 -1
- package/esm2022/lib/toolbar/editor-list.js +0 -249
- package/esm2022/lib/toolbar/editor-list.js.map +0 -1
- package/esm2022/lib/toolbar/editor-table.js +0 -292
- package/esm2022/lib/toolbar/editor-table.js.map +0 -1
- package/esm2022/lib/toolbar/editor-text-color.js +0 -82
- package/esm2022/lib/toolbar/editor-text-color.js.map +0 -1
- package/esm2022/lib/toolbar/editor-toolbar-widget.js +0 -41
- package/esm2022/lib/toolbar/editor-toolbar-widget.js.map +0 -1
- package/esm2022/lib/toolbar/editor-toolbar.defs.js +0 -60
- package/esm2022/lib/toolbar/editor-toolbar.defs.js.map +0 -1
- package/esm2022/lib/toolbar/editor-toolbar.js +0 -826
- package/esm2022/lib/toolbar/editor-toolbar.js.map +0 -1
- package/esm2022/lib/toolbar/editor-undo-redo.js +0 -72
- package/esm2022/lib/toolbar/editor-undo-redo.js.map +0 -1
- package/esm2022/lib/toolbar/editor-zoom.js +0 -330
- package/esm2022/lib/toolbar/editor-zoom.js.map +0 -1
- package/esm2022/lib/upload/editor-image-upload-coordinator.js +0 -480
- package/esm2022/lib/upload/editor-image-upload-coordinator.js.map +0 -1
- package/esm2022/malva-ui-editor.js +0 -5
- package/esm2022/malva-ui-editor.js.map +0 -1
- package/index.d.ts +0 -35
- package/lib/ai/editor-ai-actions.d.ts +0 -27
- package/lib/ai/editor-ai-context.d.ts +0 -307
- package/lib/ai/editor-ai-menu.d.ts +0 -142
- package/lib/ai/editor-ai-review-bar.d.ts +0 -116
- package/lib/ai/editor-ai-stream.d.ts +0 -207
- package/lib/ai/editor-ai-suggestions.d.ts +0 -219
- package/lib/ai/editor-ai.tokens.d.ts +0 -10
- package/lib/ai/editor-ai.types.d.ts +0 -176
- package/lib/editor/editor.d.ts +0 -243
- package/lib/editor-extension-preflight.d.ts +0 -23
- package/lib/editor-serialization.d.ts +0 -74
- package/lib/editor-toolbar-context.d.ts +0 -116
- package/lib/editor.tokens.d.ts +0 -6
- package/lib/editor.types.d.ts +0 -194
- package/lib/extensions/editor-block-handle.d.ts +0 -59
- package/lib/extensions/editor-extensions.d.ts +0 -165
- package/lib/extensions/editor-markdown-compatibility.d.ts +0 -11
- package/lib/extensions/editor-upload-placeholder.d.ts +0 -75
- package/lib/status/editor-status.d.ts +0 -24
- package/lib/toolbar/editor-alignment.d.ts +0 -61
- package/lib/toolbar/editor-block-insert.d.ts +0 -26
- package/lib/toolbar/editor-color-control.d.ts +0 -32
- package/lib/toolbar/editor-command-button.d.ts +0 -29
- package/lib/toolbar/editor-heading.d.ts +0 -68
- package/lib/toolbar/editor-highlight.d.ts +0 -21
- package/lib/toolbar/editor-image-upload-dialog.d.ts +0 -96
- package/lib/toolbar/editor-image-upload.d.ts +0 -71
- package/lib/toolbar/editor-inline-marks.d.ts +0 -30
- package/lib/toolbar/editor-link.d.ts +0 -78
- package/lib/toolbar/editor-list.d.ts +0 -67
- package/lib/toolbar/editor-table.d.ts +0 -133
- package/lib/toolbar/editor-text-color.d.ts +0 -21
- package/lib/toolbar/editor-toolbar-widget.d.ts +0 -19
- package/lib/toolbar/editor-toolbar.d.ts +0 -157
- package/lib/toolbar/editor-toolbar.defs.d.ts +0 -35
- package/lib/toolbar/editor-undo-redo.d.ts +0 -26
- package/lib/toolbar/editor-zoom.d.ts +0 -108
- package/lib/upload/editor-image-upload-coordinator.d.ts +0 -55
- package/malva-ui-editor.d.ts +0 -5
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { generateHTML, getExtensionField, } from '@tiptap/core';
|
|
2
|
-
import Highlight from '@tiptap/extension-highlight';
|
|
3
|
-
import { TextStyle } from '@tiptap/extension-text-style';
|
|
4
|
-
import { TableKit } from '@tiptap/extension-table';
|
|
5
|
-
import StarterKit from '@tiptap/starter-kit';
|
|
6
|
-
/** @internal Escapes a value before it is interpolated into an HTML attribute. */
|
|
7
|
-
function escapeAttribute(value) {
|
|
8
|
-
return value
|
|
9
|
-
.replace(/&/g, '&')
|
|
10
|
-
.replace(/</g, '<')
|
|
11
|
-
.replace(/>/g, '>')
|
|
12
|
-
.replace(/"/g, '"')
|
|
13
|
-
.replace(/'/g, ''');
|
|
14
|
-
}
|
|
15
|
-
/** @internal Resolves an extension's inherited Markdown renderer through Tiptap's public API. */
|
|
16
|
-
function parentMarkdownRenderer(extension) {
|
|
17
|
-
return getExtensionField(extension, 'renderMarkdown', {
|
|
18
|
-
name: extension.name,
|
|
19
|
-
options: extension.options,
|
|
20
|
-
storage: extension.storage,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
/** @internal Emits a complete node as HTML rather than embedding Markdown inside an HTML fragment. */
|
|
24
|
-
function renderNodeAsHtml(node, extensions) {
|
|
25
|
-
return generateHTML({
|
|
26
|
-
type: 'doc',
|
|
27
|
-
content: [node],
|
|
28
|
-
}, extensions);
|
|
29
|
-
}
|
|
30
|
-
/** @internal Builds the color-aware same-name TextStyle mark used by Malva's default preset. */
|
|
31
|
-
export function createMarkdownCompatibleTextStyle() {
|
|
32
|
-
return TextStyle.configure({}).extend({
|
|
33
|
-
priority: 98,
|
|
34
|
-
renderMarkdown(node, helpers) {
|
|
35
|
-
const color = node.attrs?.['color'];
|
|
36
|
-
const children = helpers.renderChildren(node);
|
|
37
|
-
if (typeof color !== 'string' || color.length === 0)
|
|
38
|
-
return children;
|
|
39
|
-
return `<span style="color: ${escapeAttribute(color)}">${children}</span>`;
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
/** @internal Builds the color-aware same-name Highlight mark used by Malva's default preset. */
|
|
44
|
-
export function createMarkdownCompatibleHighlight() {
|
|
45
|
-
const base = Highlight.configure({ multicolor: true });
|
|
46
|
-
const renderParent = parentMarkdownRenderer(base);
|
|
47
|
-
return base.extend({
|
|
48
|
-
priority: 99,
|
|
49
|
-
renderMarkdown(node, helpers, context) {
|
|
50
|
-
const color = node.attrs?.['color'];
|
|
51
|
-
if (typeof color !== 'string' || color.length === 0) {
|
|
52
|
-
return renderParent?.(node, helpers, context) ?? '';
|
|
53
|
-
}
|
|
54
|
-
const escaped = escapeAttribute(color);
|
|
55
|
-
return `<mark data-color="${escaped}" style="background-color: ${escaped}; color: inherit">${helpers.renderChildren(node)}</mark>`;
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
/** @internal Extends one block child with an alignment-preserving renderer. */
|
|
60
|
-
function alignedBlockExtension(extension, activeExtensions) {
|
|
61
|
-
const renderParent = parentMarkdownRenderer(extension);
|
|
62
|
-
return extension.extend({
|
|
63
|
-
renderMarkdown(node, helpers, context) {
|
|
64
|
-
const alignment = node.attrs?.['textAlign'];
|
|
65
|
-
if (alignment !== 'left' &&
|
|
66
|
-
alignment !== 'center' &&
|
|
67
|
-
alignment !== 'right' &&
|
|
68
|
-
alignment !== 'justify') {
|
|
69
|
-
return renderParent?.(node, helpers, context) ?? '';
|
|
70
|
-
}
|
|
71
|
-
return renderNodeAsHtml(node, activeExtensions());
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
/** @internal Builds the same-name StarterKit whose block children preserve explicit alignment. */
|
|
76
|
-
export function createMarkdownCompatibleStarterKit(options) {
|
|
77
|
-
let editorExtensions = [];
|
|
78
|
-
const base = StarterKit.configure(options);
|
|
79
|
-
return base.extend({
|
|
80
|
-
addExtensions() {
|
|
81
|
-
return (this.parent?.() ?? []).map((extension) => extension.name === 'paragraph' || extension.name === 'heading'
|
|
82
|
-
? alignedBlockExtension(extension, () => editorExtensions)
|
|
83
|
-
: extension);
|
|
84
|
-
},
|
|
85
|
-
onBeforeCreate() {
|
|
86
|
-
editorExtensions = this.editor.options.extensions;
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
/** @internal Whether a table can be represented without loss by the GFM table renderer. */
|
|
91
|
-
function isLosslessGfmTable(node) {
|
|
92
|
-
const rows = node.content;
|
|
93
|
-
if (!rows?.length)
|
|
94
|
-
return false;
|
|
95
|
-
const columnCount = rows[0]?.content?.length ?? 0;
|
|
96
|
-
if (columnCount === 0)
|
|
97
|
-
return false;
|
|
98
|
-
const columnAlignments = Array.from({
|
|
99
|
-
length: columnCount,
|
|
100
|
-
});
|
|
101
|
-
return rows.every((row, rowIndex) => {
|
|
102
|
-
const cells = row.type === 'tableRow' ? row.content : undefined;
|
|
103
|
-
if (!cells || cells.length !== columnCount)
|
|
104
|
-
return false;
|
|
105
|
-
return cells.every((cell, columnIndex) => {
|
|
106
|
-
if ((rowIndex === 0 && cell.type !== 'tableHeader') ||
|
|
107
|
-
(rowIndex > 0 && cell.type !== 'tableCell')) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
const attrs = cell.attrs ?? {};
|
|
111
|
-
if ((attrs['colspan'] ?? 1) !== 1 ||
|
|
112
|
-
(attrs['rowspan'] ?? 1) !== 1 ||
|
|
113
|
-
attrs['colwidth'] != null) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
const alignment = attrs['align'] ?? null;
|
|
117
|
-
if (alignment !== null &&
|
|
118
|
-
alignment !== 'left' &&
|
|
119
|
-
alignment !== 'center' &&
|
|
120
|
-
alignment !== 'right') {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
if (rowIndex === 0) {
|
|
124
|
-
columnAlignments[columnIndex] = alignment;
|
|
125
|
-
}
|
|
126
|
-
else if (columnAlignments[columnIndex] !== alignment) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
const content = cell.content;
|
|
130
|
-
if (content?.length !== 1 || content[0]?.type !== 'paragraph') {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
const paragraphAlignment = content[0].attrs?.['textAlign'];
|
|
134
|
-
return paragraphAlignment == null;
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
/** @internal Builds the same-name TableKit whose table child falls back to complete HTML. */
|
|
139
|
-
export function createMarkdownCompatibleTableKit(options) {
|
|
140
|
-
let editorExtensions = [];
|
|
141
|
-
const base = TableKit.configure(options);
|
|
142
|
-
return base.extend({
|
|
143
|
-
addExtensions() {
|
|
144
|
-
return (this.parent?.() ?? []).map((extension) => {
|
|
145
|
-
if (extension.name !== 'table')
|
|
146
|
-
return extension;
|
|
147
|
-
const renderParent = parentMarkdownRenderer(extension);
|
|
148
|
-
return extension.extend({
|
|
149
|
-
renderMarkdown(node, helpers, context) {
|
|
150
|
-
return isLosslessGfmTable(node)
|
|
151
|
-
? (renderParent?.(node, helpers, context) ?? '')
|
|
152
|
-
: renderNodeAsHtml(node, editorExtensions);
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
},
|
|
157
|
-
onBeforeCreate() {
|
|
158
|
-
editorExtensions = this.editor.options.extensions;
|
|
159
|
-
},
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=editor-markdown-compatibility.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"editor-markdown-compatibility.js","sourceRoot":"","sources":["../../../../../../libs/editor/src/lib/extensions/editor-markdown-compatibility.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n generateHTML,\n getExtensionField,\n type AnyExtension,\n type Extensions,\n type JSONContent,\n type MarkdownRendererHelpers,\n type RenderContext,\n} from '@tiptap/core';\nimport Highlight from '@tiptap/extension-highlight';\nimport { TextStyle } from '@tiptap/extension-text-style';\nimport { TableKit, type TableKitOptions } from '@tiptap/extension-table';\nimport StarterKit, { type StarterKitOptions } from '@tiptap/starter-kit';\n\n/** @internal Markdown renderer signature resolved from a Tiptap extension. */\ntype MarkdownRenderer = (\n node: JSONContent,\n helpers: MarkdownRendererHelpers,\n context: RenderContext,\n) => string;\n\n/** @internal Escapes a value before it is interpolated into an HTML attribute. */\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/** @internal Resolves an extension's inherited Markdown renderer through Tiptap's public API. */\nfunction parentMarkdownRenderer(\n extension: AnyExtension,\n): MarkdownRenderer | undefined {\n return getExtensionField<MarkdownRenderer>(extension, 'renderMarkdown', {\n name: extension.name,\n options: extension.options,\n storage: extension.storage,\n });\n}\n\n/** @internal Emits a complete node as HTML rather than embedding Markdown inside an HTML fragment. */\nfunction renderNodeAsHtml(node: JSONContent, extensions: Extensions): string {\n return generateHTML(\n {\n type: 'doc',\n content: [node],\n },\n extensions,\n );\n}\n\n/** @internal Builds the color-aware same-name TextStyle mark used by Malva's default preset. */\nexport function createMarkdownCompatibleTextStyle(): AnyExtension {\n return TextStyle.configure({}).extend({\n priority: 98,\n renderMarkdown(node, helpers) {\n const color = node.attrs?.['color'];\n const children = helpers.renderChildren(node);\n if (typeof color !== 'string' || color.length === 0) return children;\n return `<span style=\"color: ${escapeAttribute(color)}\">${children}</span>`;\n },\n });\n}\n\n/** @internal Builds the color-aware same-name Highlight mark used by Malva's default preset. */\nexport function createMarkdownCompatibleHighlight(): AnyExtension {\n const base = Highlight.configure({ multicolor: true });\n const renderParent = parentMarkdownRenderer(base);\n\n return base.extend({\n priority: 99,\n renderMarkdown(node, helpers, context) {\n const color = node.attrs?.['color'];\n if (typeof color !== 'string' || color.length === 0) {\n return renderParent?.(node, helpers, context) ?? '';\n }\n const escaped = escapeAttribute(color);\n return `<mark data-color=\"${escaped}\" style=\"background-color: ${escaped}; color: inherit\">${helpers.renderChildren(node)}</mark>`;\n },\n });\n}\n\n/** @internal Extends one block child with an alignment-preserving renderer. */\nfunction alignedBlockExtension(\n extension: AnyExtension,\n activeExtensions: () => Extensions,\n): AnyExtension {\n const renderParent = parentMarkdownRenderer(extension);\n\n return extension.extend({\n renderMarkdown(node, helpers, context) {\n const alignment = node.attrs?.['textAlign'];\n if (\n alignment !== 'left' &&\n alignment !== 'center' &&\n alignment !== 'right' &&\n alignment !== 'justify'\n ) {\n return renderParent?.(node, helpers, context) ?? '';\n }\n return renderNodeAsHtml(node, activeExtensions());\n },\n });\n}\n\n/** @internal Builds the same-name StarterKit whose block children preserve explicit alignment. */\nexport function createMarkdownCompatibleStarterKit(\n options: Partial<StarterKitOptions>,\n): AnyExtension {\n let editorExtensions: Extensions = [];\n const base = StarterKit.configure(options);\n\n return base.extend({\n addExtensions() {\n return (this.parent?.() ?? []).map((extension) =>\n extension.name === 'paragraph' || extension.name === 'heading'\n ? alignedBlockExtension(extension, () => editorExtensions)\n : extension,\n );\n },\n onBeforeCreate() {\n editorExtensions = this.editor.options.extensions;\n },\n });\n}\n\n/** @internal Whether a table can be represented without loss by the GFM table renderer. */\nfunction isLosslessGfmTable(node: JSONContent): boolean {\n const rows = node.content;\n if (!rows?.length) return false;\n const columnCount = rows[0]?.content?.length ?? 0;\n if (columnCount === 0) return false;\n const columnAlignments: Array<unknown> = Array.from({\n length: columnCount,\n });\n\n return rows.every((row, rowIndex) => {\n const cells = row.type === 'tableRow' ? row.content : undefined;\n if (!cells || cells.length !== columnCount) return false;\n\n return cells.every((cell, columnIndex) => {\n if (\n (rowIndex === 0 && cell.type !== 'tableHeader') ||\n (rowIndex > 0 && cell.type !== 'tableCell')\n ) {\n return false;\n }\n const attrs = cell.attrs ?? {};\n if (\n (attrs['colspan'] ?? 1) !== 1 ||\n (attrs['rowspan'] ?? 1) !== 1 ||\n attrs['colwidth'] != null\n ) {\n return false;\n }\n const alignment = attrs['align'] ?? null;\n if (\n alignment !== null &&\n alignment !== 'left' &&\n alignment !== 'center' &&\n alignment !== 'right'\n ) {\n return false;\n }\n if (rowIndex === 0) {\n columnAlignments[columnIndex] = alignment;\n } else if (columnAlignments[columnIndex] !== alignment) {\n return false;\n }\n const content = cell.content;\n if (content?.length !== 1 || content[0]?.type !== 'paragraph') {\n return false;\n }\n const paragraphAlignment = content[0].attrs?.['textAlign'];\n return paragraphAlignment == null;\n });\n });\n}\n\n/** @internal Builds the same-name TableKit whose table child falls back to complete HTML. */\nexport function createMarkdownCompatibleTableKit(\n options: Partial<TableKitOptions>,\n): AnyExtension {\n let editorExtensions: Extensions = [];\n const base = TableKit.configure(options);\n\n return base.extend({\n addExtensions() {\n return (this.parent?.() ?? []).map((extension) => {\n if (extension.name !== 'table') return extension;\n const renderParent = parentMarkdownRenderer(extension);\n return extension.extend({\n renderMarkdown(node, helpers, context) {\n return isLosslessGfmTable(node)\n ? (renderParent?.(node, helpers, context) ?? '')\n : renderNodeAsHtml(node, editorExtensions);\n },\n });\n });\n },\n onBeforeCreate() {\n editorExtensions = this.editor.options.extensions;\n },\n });\n}\n"]}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core';
|
|
2
|
-
import { Plugin, PluginKey } from '@tiptap/pm/state';
|
|
3
|
-
import { Decoration, DecorationSet } from '@tiptap/pm/view';
|
|
4
|
-
const MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY = new PluginKey('mlvEditorUploadPlaceholder');
|
|
5
|
-
const findPlaceholderDecorations = (decorations, id) => decorations.find(undefined, undefined, (spec) => spec.id === id);
|
|
6
|
-
const clampProgress = (progress) => Number.isFinite(progress) ? Math.max(0, Math.min(100, progress ?? 0)) : 0;
|
|
7
|
-
const renderPlaceholder = (progress) => () => {
|
|
8
|
-
const element = document.createElement('span');
|
|
9
|
-
element.className = 'mlv-editor__upload-placeholder';
|
|
10
|
-
element.dataset['progress'] = String(progress);
|
|
11
|
-
element.setAttribute('aria-hidden', 'true');
|
|
12
|
-
return element;
|
|
13
|
-
};
|
|
14
|
-
const createPlaceholderDecoration = (position, id, progress) => Decoration.widget(position, renderPlaceholder(progress), {
|
|
15
|
-
id,
|
|
16
|
-
progress,
|
|
17
|
-
side: -1,
|
|
18
|
-
});
|
|
19
|
-
const synchronizeStorage = (storage, decorations) => {
|
|
20
|
-
storage.placeholders = decorations.find().map(({ from, spec }) => ({
|
|
21
|
-
id: spec.id,
|
|
22
|
-
position: from,
|
|
23
|
-
progress: spec.progress,
|
|
24
|
-
}));
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Tiptap extension that renders image-upload progress outside the document model.
|
|
28
|
-
*
|
|
29
|
-
* Its widget decorations are intentionally excluded from HTML and Markdown output,
|
|
30
|
-
* so a pending upload can never become persisted editor content.
|
|
31
|
-
*/
|
|
32
|
-
export const MlvEditorUploadPlaceholder = Extension.create({
|
|
33
|
-
name: 'mlvEditorUploadPlaceholder',
|
|
34
|
-
addStorage() {
|
|
35
|
-
return { placeholders: [] };
|
|
36
|
-
},
|
|
37
|
-
addCommands() {
|
|
38
|
-
return {
|
|
39
|
-
insertUploadPlaceholder: (options) => ({ tr, dispatch }) => {
|
|
40
|
-
const position = options.position ?? tr.selection.from;
|
|
41
|
-
const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(this.editor.state);
|
|
42
|
-
if (!existing ||
|
|
43
|
-
position < 0 ||
|
|
44
|
-
position > tr.doc.content.size ||
|
|
45
|
-
findPlaceholderDecorations(existing, options.id).length > 0) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
dispatch?.(tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {
|
|
49
|
-
type: 'insert',
|
|
50
|
-
id: options.id,
|
|
51
|
-
position,
|
|
52
|
-
progress: clampProgress(options.progress),
|
|
53
|
-
}));
|
|
54
|
-
return true;
|
|
55
|
-
},
|
|
56
|
-
updateUploadPlaceholder: (options) => ({ tr, dispatch }) => {
|
|
57
|
-
const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(this.editor.state);
|
|
58
|
-
if (!existing ||
|
|
59
|
-
findPlaceholderDecorations(existing, options.id).length === 0) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
dispatch?.(tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {
|
|
63
|
-
type: 'update',
|
|
64
|
-
id: options.id,
|
|
65
|
-
progress: clampProgress(options.progress),
|
|
66
|
-
}));
|
|
67
|
-
return true;
|
|
68
|
-
},
|
|
69
|
-
removeUploadPlaceholder: (options) => ({ tr, dispatch }) => {
|
|
70
|
-
const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(this.editor.state);
|
|
71
|
-
if (!existing ||
|
|
72
|
-
findPlaceholderDecorations(existing, options.id).length === 0) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
dispatch?.(tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {
|
|
76
|
-
type: 'remove',
|
|
77
|
-
id: options.id,
|
|
78
|
-
}));
|
|
79
|
-
return true;
|
|
80
|
-
},
|
|
81
|
-
replaceUploadPlaceholder: (options) => ({ tr, commands }) => {
|
|
82
|
-
const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(this.editor.state);
|
|
83
|
-
const matches = existing
|
|
84
|
-
? findPlaceholderDecorations(existing, options.id)
|
|
85
|
-
: [];
|
|
86
|
-
const imageType = tr.doc.type.schema.nodes['image'];
|
|
87
|
-
if (matches.length !== 1 || !imageType)
|
|
88
|
-
return false;
|
|
89
|
-
const position = matches[0]?.from;
|
|
90
|
-
if (position === undefined ||
|
|
91
|
-
position < 0 ||
|
|
92
|
-
position > tr.doc.content.size) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const inserted = commands.insertContentAt(position, {
|
|
97
|
-
type: imageType.name,
|
|
98
|
-
attrs: options.attributes,
|
|
99
|
-
}, {
|
|
100
|
-
errorOnInvalidContent: true,
|
|
101
|
-
updateSelection: false,
|
|
102
|
-
});
|
|
103
|
-
if (!inserted)
|
|
104
|
-
return false;
|
|
105
|
-
tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {
|
|
106
|
-
type: 'remove',
|
|
107
|
-
id: options.id,
|
|
108
|
-
});
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
},
|
|
117
|
-
addProseMirrorPlugins() {
|
|
118
|
-
const storage = this.storage;
|
|
119
|
-
return [
|
|
120
|
-
new Plugin({
|
|
121
|
-
key: MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY,
|
|
122
|
-
state: {
|
|
123
|
-
init: (_) => {
|
|
124
|
-
const decorations = DecorationSet.empty;
|
|
125
|
-
synchronizeStorage(storage, decorations);
|
|
126
|
-
return decorations;
|
|
127
|
-
},
|
|
128
|
-
apply: (transaction, decorations) => {
|
|
129
|
-
const metadata = transaction.getMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY);
|
|
130
|
-
let next = decorations.map(transaction.mapping, transaction.doc);
|
|
131
|
-
if (metadata?.type === 'insert' &&
|
|
132
|
-
metadata.position !== undefined) {
|
|
133
|
-
next = next.add(transaction.doc, [
|
|
134
|
-
createPlaceholderDecoration(metadata.position, metadata.id, clampProgress(metadata.progress)),
|
|
135
|
-
]);
|
|
136
|
-
}
|
|
137
|
-
if (metadata?.type === 'update') {
|
|
138
|
-
const matches = findPlaceholderDecorations(next, metadata.id);
|
|
139
|
-
const replacements = matches.map((decoration) => createPlaceholderDecoration(decoration.from, metadata.id, clampProgress(metadata.progress)));
|
|
140
|
-
next = next.remove(matches).add(transaction.doc, replacements);
|
|
141
|
-
}
|
|
142
|
-
if (metadata?.type === 'remove') {
|
|
143
|
-
next = next.remove(findPlaceholderDecorations(next, metadata.id));
|
|
144
|
-
}
|
|
145
|
-
synchronizeStorage(storage, next);
|
|
146
|
-
return next;
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
props: {
|
|
150
|
-
decorations: (state) => MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(state),
|
|
151
|
-
},
|
|
152
|
-
}),
|
|
153
|
-
];
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
//# sourceMappingURL=editor-upload-placeholder.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"editor-upload-placeholder.js","sourceRoot":"","sources":["../../../../../../libs/editor/src/lib/extensions/editor-upload-placeholder.ts"],"names":[],"mappings":"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","sourcesContent":["import { Extension } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\n\n/** A rendered, temporary image-upload placeholder tracked by its stable identifier. */\nexport interface MlvEditorUploadPlaceholderItem {\n /** Identifier that associates this placeholder with one upload operation. */\n readonly id: string;\n\n /** Current document position of the placeholder decoration. */\n readonly position: number;\n\n /** Upload progress percentage from 0 through 100. */\n readonly progress: number;\n}\n\n/** Options accepted when a temporary upload placeholder is inserted. */\nexport interface MlvEditorInsertUploadPlaceholderOptions {\n /** Unique caller-owned identifier for the upload operation. */\n readonly id: string;\n\n /** Optional document position; the current selection is used when omitted. */\n readonly position?: number;\n\n /** Initial upload progress percentage. Defaults to zero. */\n readonly progress?: number;\n}\n\n/** Options accepted when an existing upload placeholder is updated. */\nexport interface MlvEditorUpdateUploadPlaceholderOptions {\n /** Identifier of the placeholder to update. */\n readonly id: string;\n\n /** New upload progress percentage, clamped to the inclusive 0–100 range. */\n readonly progress: number;\n}\n\n/** Options accepted when a temporary upload placeholder is removed. */\nexport interface MlvEditorRemoveUploadPlaceholderOptions {\n /** Identifier of the placeholder to remove. */\n readonly id: string;\n}\n\n/** Image attributes inserted while atomically removing an upload placeholder. */\nexport interface MlvEditorReplaceUploadPlaceholderOptions {\n /** Identifier of the placeholder to replace. */\n readonly id: string;\n\n /** Validated image attributes used to create the final schema node. */\n readonly attributes: {\n /** Trimmed image URL. */\n readonly src: string;\n\n /** Optional alternative text. */\n readonly alt?: string;\n\n /** Optional image title. */\n readonly title?: string;\n\n /** Optional finite positive rendered width. */\n readonly width?: number;\n\n /** Optional finite positive rendered height. */\n readonly height?: number;\n };\n}\n\n/** Read-only upload-placeholder state exposed through Tiptap extension storage. */\nexport interface MlvEditorUploadPlaceholderStorage {\n /** Current temporary placeholders; decorations, never serializable document nodes. */\n readonly placeholders: readonly MlvEditorUploadPlaceholderItem[];\n}\n\ninterface MlvEditorUploadPlaceholderMetadata {\n readonly type: 'insert' | 'update' | 'remove';\n readonly id: string;\n readonly position?: number;\n readonly progress?: number;\n}\n\ninterface MlvEditorUploadPlaceholderDecorationSpec {\n readonly id: string;\n readonly progress: number;\n readonly side?: number;\n}\n\ninterface MlvEditorMutableUploadPlaceholderStorage {\n placeholders: readonly MlvEditorUploadPlaceholderItem[];\n}\n\nconst MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY = new PluginKey<DecorationSet>(\n 'mlvEditorUploadPlaceholder',\n);\n\nconst findPlaceholderDecorations = (decorations: DecorationSet, id: string) =>\n decorations.find(\n undefined,\n undefined,\n (spec: MlvEditorUploadPlaceholderDecorationSpec) => spec.id === id,\n );\n\nconst clampProgress = (progress: number | undefined) =>\n Number.isFinite(progress) ? Math.max(0, Math.min(100, progress ?? 0)) : 0;\n\nconst renderPlaceholder = (progress: number) => () => {\n const element = document.createElement('span');\n element.className = 'mlv-editor__upload-placeholder';\n element.dataset['progress'] = String(progress);\n element.setAttribute('aria-hidden', 'true');\n return element;\n};\n\nconst createPlaceholderDecoration = (\n position: number,\n id: string,\n progress: number,\n) =>\n Decoration.widget(position, renderPlaceholder(progress), {\n id,\n progress,\n side: -1,\n } satisfies MlvEditorUploadPlaceholderDecorationSpec);\n\nconst synchronizeStorage = (\n storage: MlvEditorMutableUploadPlaceholderStorage,\n decorations: DecorationSet,\n) => {\n storage.placeholders = decorations.find().map(({ from, spec }) => ({\n id: (spec as MlvEditorUploadPlaceholderDecorationSpec).id,\n position: from,\n progress: (spec as MlvEditorUploadPlaceholderDecorationSpec).progress,\n }));\n};\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n mlvEditorUploadPlaceholder: {\n /** Inserts an upload decoration without changing persisted editor content. */\n insertUploadPlaceholder: (\n options: MlvEditorInsertUploadPlaceholderOptions,\n ) => ReturnType;\n\n /** Updates the progress decoration for one pending image upload. */\n updateUploadPlaceholder: (\n options: MlvEditorUpdateUploadPlaceholderOptions,\n ) => ReturnType;\n\n /** Removes the decoration for one completed, failed, or cancelled image upload. */\n removeUploadPlaceholder: (\n options: MlvEditorRemoveUploadPlaceholderOptions,\n ) => ReturnType;\n\n /** Atomically inserts an image at the mapped placeholder and removes it. */\n replaceUploadPlaceholder: (\n options: MlvEditorReplaceUploadPlaceholderOptions,\n ) => ReturnType;\n };\n }\n}\n\n/**\n * Tiptap extension that renders image-upload progress outside the document model.\n *\n * Its widget decorations are intentionally excluded from HTML and Markdown output,\n * so a pending upload can never become persisted editor content.\n */\nexport const MlvEditorUploadPlaceholder = Extension.create<\n Record<string, never>,\n MlvEditorUploadPlaceholderStorage\n>({\n name: 'mlvEditorUploadPlaceholder',\n\n addStorage() {\n return { placeholders: [] };\n },\n\n addCommands() {\n return {\n insertUploadPlaceholder:\n (options) =>\n ({ tr, dispatch }) => {\n const position = options.position ?? tr.selection.from;\n const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(\n this.editor.state,\n );\n\n if (\n !existing ||\n position < 0 ||\n position > tr.doc.content.size ||\n findPlaceholderDecorations(existing, options.id).length > 0\n ) {\n return false;\n }\n\n dispatch?.(\n tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {\n type: 'insert',\n id: options.id,\n position,\n progress: clampProgress(options.progress),\n } satisfies MlvEditorUploadPlaceholderMetadata),\n );\n return true;\n },\n updateUploadPlaceholder:\n (options) =>\n ({ tr, dispatch }) => {\n const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(\n this.editor.state,\n );\n\n if (\n !existing ||\n findPlaceholderDecorations(existing, options.id).length === 0\n ) {\n return false;\n }\n\n dispatch?.(\n tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {\n type: 'update',\n id: options.id,\n progress: clampProgress(options.progress),\n } satisfies MlvEditorUploadPlaceholderMetadata),\n );\n return true;\n },\n removeUploadPlaceholder:\n (options) =>\n ({ tr, dispatch }) => {\n const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(\n this.editor.state,\n );\n\n if (\n !existing ||\n findPlaceholderDecorations(existing, options.id).length === 0\n ) {\n return false;\n }\n\n dispatch?.(\n tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {\n type: 'remove',\n id: options.id,\n } satisfies MlvEditorUploadPlaceholderMetadata),\n );\n return true;\n },\n replaceUploadPlaceholder:\n (options) =>\n ({ tr, commands }) => {\n const existing = MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(\n this.editor.state,\n );\n const matches = existing\n ? findPlaceholderDecorations(existing, options.id)\n : [];\n const imageType = tr.doc.type.schema.nodes['image'];\n\n if (matches.length !== 1 || !imageType) return false;\n\n const position = matches[0]?.from;\n if (\n position === undefined ||\n position < 0 ||\n position > tr.doc.content.size\n ) {\n return false;\n }\n\n try {\n const inserted = commands.insertContentAt(\n position,\n {\n type: imageType.name,\n attrs: options.attributes,\n },\n {\n errorOnInvalidContent: true,\n updateSelection: false,\n },\n );\n if (!inserted) return false;\n\n tr.setMeta(MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY, {\n type: 'remove',\n id: options.id,\n } satisfies MlvEditorUploadPlaceholderMetadata);\n return true;\n } catch {\n return false;\n }\n },\n };\n },\n\n addProseMirrorPlugins() {\n const storage = this.storage as MlvEditorMutableUploadPlaceholderStorage;\n\n return [\n new Plugin<DecorationSet>({\n key: MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY,\n state: {\n init: (_) => {\n const decorations = DecorationSet.empty;\n synchronizeStorage(storage, decorations);\n return decorations;\n },\n apply: (transaction, decorations) => {\n const metadata = transaction.getMeta(\n MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY,\n ) as MlvEditorUploadPlaceholderMetadata | undefined;\n let next = decorations.map(transaction.mapping, transaction.doc);\n\n if (\n metadata?.type === 'insert' &&\n metadata.position !== undefined\n ) {\n next = next.add(transaction.doc, [\n createPlaceholderDecoration(\n metadata.position,\n metadata.id,\n clampProgress(metadata.progress),\n ),\n ]);\n }\n\n if (metadata?.type === 'update') {\n const matches = findPlaceholderDecorations(next, metadata.id);\n const replacements = matches.map((decoration) =>\n createPlaceholderDecoration(\n decoration.from,\n metadata.id,\n clampProgress(metadata.progress),\n ),\n );\n next = next.remove(matches).add(transaction.doc, replacements);\n }\n\n if (metadata?.type === 'remove') {\n next = next.remove(findPlaceholderDecorations(next, metadata.id));\n }\n\n synchronizeStorage(storage, next);\n return next;\n },\n },\n props: {\n decorations: (state) =>\n MLV_EDITOR_UPLOAD_PLACEHOLDER_KEY.getState(state),\n },\n }),\n ];\n },\n});\n"]}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, computed, inject, input, ViewEncapsulation, } from '@angular/core';
|
|
2
|
-
import { MLV_EDITOR_TOOLBAR_CONTEXT, MLV_EDITOR_TOOLBAR_REVISION, } from '../editor-toolbar-context';
|
|
3
|
-
import { normalizeMlvEditorCharacterLimit } from '../extensions/editor-extensions';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
/** Public character and word summary for the nearest editor context. */
|
|
6
|
-
export class MlvEditorStatus {
|
|
7
|
-
/** Optional maximum character count; invalid values mean unlimited. */
|
|
8
|
-
characterLimit = input(null, /* @ts-ignore */
|
|
9
|
-
...(ngDevMode ? [{ debugName: "characterLimit" }] : /* istanbul ignore next */ []));
|
|
10
|
-
/** Current character count, or zero when CharacterCount is unavailable. */
|
|
11
|
-
characters = computed(() => {
|
|
12
|
-
this._revision();
|
|
13
|
-
const storage = this._storage();
|
|
14
|
-
return storage?.characters?.() ?? 0;
|
|
15
|
-
}, /* @ts-ignore */
|
|
16
|
-
...(ngDevMode ? [{ debugName: "characters" }] : /* istanbul ignore next */ []));
|
|
17
|
-
/** Current Unicode-whitespace-aware word count. */
|
|
18
|
-
words = computed(() => {
|
|
19
|
-
this._revision();
|
|
20
|
-
const storage = this._storage();
|
|
21
|
-
return storage?.words?.() ?? 0;
|
|
22
|
-
}, /* @ts-ignore */
|
|
23
|
-
...(ngDevMode ? [{ debugName: "words" }] : /* istanbul ignore next */ []));
|
|
24
|
-
/** Whether the active extension set exposes CharacterCount storage. */
|
|
25
|
-
available = computed(() => this._storage() !== null, /* @ts-ignore */
|
|
26
|
-
...(ngDevMode ? [{ debugName: "available" }] : /* istanbul ignore next */ []));
|
|
27
|
-
/** @protected Normalized limit displayed by the summary. */
|
|
28
|
-
_limit = computed(() => normalizeMlvEditorCharacterLimit(this.characterLimit()), /* @ts-ignore */
|
|
29
|
-
...(ngDevMode ? [{ debugName: "_limit" }] : /* istanbul ignore next */ []));
|
|
30
|
-
/** @protected Accessible count and remaining-limit description. */
|
|
31
|
-
_ariaLabel = computed(() => {
|
|
32
|
-
const characters = this.characters();
|
|
33
|
-
const words = this.words();
|
|
34
|
-
const limit = this._limit();
|
|
35
|
-
if (limit === null)
|
|
36
|
-
return `${characters} characters, ${words} words`;
|
|
37
|
-
return `${Math.max(0, limit - characters)} characters remaining, ${characters} of ${limit} characters, ${words} words`;
|
|
38
|
-
}, /* @ts-ignore */
|
|
39
|
-
...(ngDevMode ? [{ debugName: "_ariaLabel" }] : /* istanbul ignore next */ []));
|
|
40
|
-
/** @private Nearest public editor command context. */
|
|
41
|
-
_context = inject(MLV_EDITOR_TOOLBAR_CONTEXT);
|
|
42
|
-
/** @private Invalidates storage reads after transactions and selections. */
|
|
43
|
-
_revision = inject(MLV_EDITOR_TOOLBAR_REVISION);
|
|
44
|
-
/** @private Safely resolves optional Tiptap CharacterCount storage. */
|
|
45
|
-
_storage = computed(() => {
|
|
46
|
-
this._revision();
|
|
47
|
-
const editor = this._context.editor();
|
|
48
|
-
if (!editor)
|
|
49
|
-
return null;
|
|
50
|
-
const storage = editor.storage['characterCount'];
|
|
51
|
-
return typeof storage?.characters === 'function' ? storage : null;
|
|
52
|
-
}, /* @ts-ignore */
|
|
53
|
-
...(ngDevMode ? [{ debugName: "_storage" }] : /* istanbul ignore next */ []));
|
|
54
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvEditorStatus, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
55
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MlvEditorStatus, isStandalone: true, selector: "mlv-editor-status", inputs: { characterLimit: { classPropertyName: "characterLimit", publicName: "characterLimit", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!available()" }, classAttribute: "mlv-editor-status" }, ngImport: i0, template: "@if (available()) {\n<span\n class=\"mlv-editor-status__summary\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"_ariaLabel()\"\n>\n @if (_limit(); as limit) {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }}/{{ limit }} characters</span\n >\n } @else {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }} characters</span\n >\n }\n <span aria-hidden=\"true\"> \u00B7 </span>\n <span class=\"mlv-editor-status__words\">{{ words() }} words</span>\n</span>\n}\n", styles: [".mlv-editor-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-status *{box-sizing:border-box}.mlv-editor-status{display:inline-flex;color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}.mlv-editor-status__summary{display:inline-flex;gap:var(--mlv-spacing-1)}.mlv-editor-status__summary *{color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
56
|
-
}
|
|
57
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvEditorStatus, decorators: [{
|
|
58
|
-
type: Component,
|
|
59
|
-
args: [{ selector: 'mlv-editor-status', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
60
|
-
class: 'mlv-editor-status',
|
|
61
|
-
'[hidden]': '!available()',
|
|
62
|
-
}, template: "@if (available()) {\n<span\n class=\"mlv-editor-status__summary\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"_ariaLabel()\"\n>\n @if (_limit(); as limit) {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }}/{{ limit }} characters</span\n >\n } @else {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }} characters</span\n >\n }\n <span aria-hidden=\"true\"> \u00B7 </span>\n <span class=\"mlv-editor-status__words\">{{ words() }} words</span>\n</span>\n}\n", styles: [".mlv-editor-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-status *{box-sizing:border-box}.mlv-editor-status{display:inline-flex;color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}.mlv-editor-status__summary{display:inline-flex;gap:var(--mlv-spacing-1)}.mlv-editor-status__summary *{color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}\n"] }]
|
|
63
|
-
}], propDecorators: { characterLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "characterLimit", required: false }] }] } });
|
|
64
|
-
//# sourceMappingURL=editor-status.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"editor-status.js","sourceRoot":"","sources":["../../../../../../libs/editor/src/lib/status/editor-status.ts","../../../../../../libs/editor/src/lib/status/editor-status.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,QAAQ,EACR,MAAM,EACN,KAAK,EACL,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;;AAQnF,wEAAwE;AAYxE,MAAM,OAAO,eAAe;IAC1B,uEAAuE;IAC9D,cAAc,GAAG,KAAK,CAAgB,IAAI;uFAAC,CAAC;IAErD,2EAA2E;IAClE,UAAU,GAAG,QAAQ,CAAC,GAAG,EAAE;QAClC,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,OAAO,OAAO,EAAE,UAAU,EAAE,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;mFAAC,CAAC;IAEH,mDAAmD;IAC1C,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,OAAO,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;8EAAC,CAAC;IAEH,uEAAuE;IAC9D,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI;kFAAC,CAAC;IAE9D,4DAA4D;IACzC,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,CACxC,gCAAgC,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;+EACxD,CAAC;IAEF,mEAAmE;IAChD,UAAU,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,GAAG,UAAU,gBAAgB,KAAK,QAAQ,CAAC;QACtE,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,0BAA0B,UAAU,OAAO,KAAK,gBAAgB,KAAK,QAAQ,CAAC;IACzH,CAAC;mFAAC,CAAC;IAEH,sDAAsD;IACrC,QAAQ,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAE/D,4EAA4E;IAC3D,SAAS,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAEjE,uEAAuE;IACtD,QAAQ,GAAG,QAAQ,CAA+B,GAAG,EAAE;QACtE,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,OAAO,GACX,MAAM,CAAC,OAIR,CAAC,gBAAgB,CAAC,CAAC;QACpB,OAAO,OAAO,OAAO,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,CAAC;iFAAC,CAAC;uGArDQ,eAAe;2FAAf,eAAe,qUChC5B,uhBAoBA;;2FDYa,eAAe;kBAX3B,SAAS;+BACE,mBAAmB,iBAGd,iBAAiB,CAAC,IAAI,mBACpB,uBAAuB,CAAC,MAAM,QACzC;wBACJ,KAAK,EAAE,mBAAmB;wBAC1B,UAAU,EAAE,cAAc;qBAC3B","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n input,\n ViewEncapsulation,\n} from '@angular/core';\nimport {\n MLV_EDITOR_TOOLBAR_CONTEXT,\n MLV_EDITOR_TOOLBAR_REVISION,\n} from '../editor-toolbar-context';\nimport { normalizeMlvEditorCharacterLimit } from '../extensions/editor-extensions';\n\n/** Runtime CharacterCount storage kept optional for literal extension replacement. */\ninterface CharacterCountStorage {\n readonly characters?: () => number;\n readonly words?: () => number;\n}\n\n/** Public character and word summary for the nearest editor context. */\n@Component({\n selector: 'mlv-editor-status',\n templateUrl: './editor-status.html',\n styleUrl: './editor-status.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'mlv-editor-status',\n '[hidden]': '!available()',\n },\n})\nexport class MlvEditorStatus {\n /** Optional maximum character count; invalid values mean unlimited. */\n readonly characterLimit = input<number | null>(null);\n\n /** Current character count, or zero when CharacterCount is unavailable. */\n readonly characters = computed(() => {\n this._revision();\n const storage = this._storage();\n return storage?.characters?.() ?? 0;\n });\n\n /** Current Unicode-whitespace-aware word count. */\n readonly words = computed(() => {\n this._revision();\n const storage = this._storage();\n return storage?.words?.() ?? 0;\n });\n\n /** Whether the active extension set exposes CharacterCount storage. */\n readonly available = computed(() => this._storage() !== null);\n\n /** @protected Normalized limit displayed by the summary. */\n protected readonly _limit = computed(() =>\n normalizeMlvEditorCharacterLimit(this.characterLimit()),\n );\n\n /** @protected Accessible count and remaining-limit description. */\n protected readonly _ariaLabel = computed(() => {\n const characters = this.characters();\n const words = this.words();\n const limit = this._limit();\n if (limit === null) return `${characters} characters, ${words} words`;\n return `${Math.max(0, limit - characters)} characters remaining, ${characters} of ${limit} characters, ${words} words`;\n });\n\n /** @private Nearest public editor command context. */\n private readonly _context = inject(MLV_EDITOR_TOOLBAR_CONTEXT);\n\n /** @private Invalidates storage reads after transactions and selections. */\n private readonly _revision = inject(MLV_EDITOR_TOOLBAR_REVISION);\n\n /** @private Safely resolves optional Tiptap CharacterCount storage. */\n private readonly _storage = computed<CharacterCountStorage | null>(() => {\n this._revision();\n const editor = this._context.editor();\n if (!editor) return null;\n const storage = (\n editor.storage as unknown as Record<\n string,\n CharacterCountStorage | undefined\n >\n )['characterCount'];\n return typeof storage?.characters === 'function' ? storage : null;\n });\n}\n","@if (available()) {\n<span\n class=\"mlv-editor-status__summary\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"_ariaLabel()\"\n>\n @if (_limit(); as limit) {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }}/{{ limit }} characters</span\n >\n } @else {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }} characters</span\n >\n }\n <span aria-hidden=\"true\"> · </span>\n <span class=\"mlv-editor-status__words\">{{ words() }} words</span>\n</span>\n}\n"]}
|