@limetech/lime-elements 38.12.4 → 38.13.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/lime-elements.cjs.js +1 -1
- package/dist/cjs/limel-ai-avatar.cjs.entry.js +1 -1
- package/dist/cjs/limel-ai-avatar.cjs.entry.js.map +1 -1
- package/dist/cjs/limel-markdown.cjs.entry.js +49 -1
- package/dist/cjs/limel-markdown.cjs.entry.js.map +1 -1
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +41 -20
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{markdown-parser-5b5ed6c4.js → markdown-parser-564adb69.js} +32 -1
- package/dist/cjs/{markdown-parser-5b5ed6c4.js.map → markdown-parser-564adb69.js.map} +1 -1
- package/dist/collection/components/ai-avatar/ai-avatar.css +7 -4
- package/dist/collection/components/markdown/allowed-css-properties.js +3 -0
- package/dist/collection/components/markdown/allowed-css-properties.js.map +1 -1
- package/dist/collection/components/markdown/image-intersection-observer.js +29 -0
- package/dist/collection/components/markdown/image-intersection-observer.js.map +1 -0
- package/dist/collection/components/markdown/image-markdown-plugin.js +28 -0
- package/dist/collection/components/markdown/image-markdown-plugin.js.map +1 -0
- package/dist/collection/components/markdown/markdown-parser.js +2 -0
- package/dist/collection/components/markdown/markdown-parser.js.map +1 -1
- package/dist/collection/components/markdown/markdown.js +38 -0
- package/dist/collection/components/markdown/markdown.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js +31 -14
- 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 +10 -5
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js.map +1 -1
- package/dist/esm/lime-elements.js +1 -1
- package/dist/esm/limel-ai-avatar.entry.js +1 -1
- package/dist/esm/limel-ai-avatar.entry.js.map +1 -1
- package/dist/esm/limel-markdown.entry.js +49 -1
- package/dist/esm/limel-markdown.entry.js.map +1 -1
- package/dist/esm/limel-prosemirror-adapter.entry.js +41 -20
- package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{markdown-parser-ecdce41c.js → markdown-parser-1c1fdedc.js} +32 -1
- package/dist/esm/{markdown-parser-ecdce41c.js.map → markdown-parser-1c1fdedc.js.map} +1 -1
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/lime-elements.esm.js.map +1 -1
- package/dist/lime-elements/{p-8f4c55fa.entry.js → p-587f6b6d.entry.js} +2 -2
- package/dist/lime-elements/p-587f6b6d.entry.js.map +1 -0
- package/dist/lime-elements/p-98478c6d.entry.js +2 -0
- package/dist/lime-elements/p-98478c6d.entry.js.map +1 -0
- package/dist/lime-elements/p-ce152b39.entry.js +2 -0
- package/dist/lime-elements/p-ce152b39.entry.js.map +1 -0
- package/dist/lime-elements/{p-e5c8cf08.js → p-cf87519f.js} +3 -3
- package/dist/lime-elements/p-cf87519f.js.map +1 -0
- package/dist/types/components/markdown/image-intersection-observer.d.ts +10 -0
- package/dist/types/components/markdown/image-markdown-plugin.d.ts +9 -0
- package/dist/types/components/markdown/markdown-parser.d.ts +1 -0
- package/dist/types/components/markdown/markdown.d.ts +9 -1
- package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/node.d.ts +4 -0
- package/dist/types/components.d.ts +8 -0
- package/package.json +1 -1
- package/dist/lime-elements/p-8f4c55fa.entry.js.map +0 -1
- package/dist/lime-elements/p-e5c8cf08.js.map +0 -1
- package/dist/lime-elements/p-eadff599.entry.js +0 -2
- package/dist/lime-elements/p-eadff599.entry.js.map +0 -1
- package/dist/lime-elements/p-f20b7faa.entry.js +0 -2
- package/dist/lime-elements/p-f20b7faa.entry.js.map +0 -1
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
|
|
27
27
|
.core,
|
|
28
28
|
.orbitals {
|
|
29
|
-
mix-blend-mode: overlay;
|
|
30
29
|
position: absolute;
|
|
31
30
|
z-index: 10;
|
|
32
31
|
inset: 0;
|
|
@@ -35,18 +34,22 @@
|
|
|
35
34
|
align-items: center;
|
|
36
35
|
justify-content: center;
|
|
37
36
|
aspect-ratio: 1;
|
|
38
|
-
width: clamp(0.375rem, 20%, 3.5rem);
|
|
39
37
|
border-radius: 50%;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
.core {
|
|
41
|
+
opacity: 0.8;
|
|
42
|
+
width: 70%;
|
|
43
43
|
animation: breathe 3s ease infinite;
|
|
44
44
|
animation-play-state: var(--ai-avatar-animation-play-state, paused);
|
|
45
|
-
background-color:
|
|
45
|
+
background-color: inherit;
|
|
46
46
|
box-shadow: var(--shadow-depth-8);
|
|
47
|
+
backdrop-filter: blur(1rem);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
.orbitals {
|
|
51
|
+
mix-blend-mode: overlay;
|
|
52
|
+
width: clamp(0.375rem, 20%, 3.5rem);
|
|
50
53
|
animation: rotate 5s linear infinite;
|
|
51
54
|
animation-play-state: var(--ai-avatar-animation-play-state, paused);
|
|
52
55
|
transition: opacity 0.2s ease;
|
|
@@ -91,7 +94,7 @@
|
|
|
91
94
|
transform: scale(1);
|
|
92
95
|
}
|
|
93
96
|
50% {
|
|
94
|
-
transform: scale(0.
|
|
97
|
+
transform: scale(0.9);
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
@keyframes rotate {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allowed-css-properties.js","sourceRoot":"","sources":["../../../src/components/markdown/allowed-css-properties.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;EAChC,kBAAkB;EAClB,OAAO;EACP,YAAY;EACZ,aAAa;EACb,uBAAuB;EACvB,sBAAsB;EACtB,0BAA0B;EAC1B,uBAAuB;EACvB,2BAA2B;EAC3B,iBAAiB;EACjB,OAAO;
|
|
1
|
+
{"version":3,"file":"allowed-css-properties.js","sourceRoot":"","sources":["../../../src/components/markdown/allowed-css-properties.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;EAChC,kBAAkB;EAClB,OAAO;EACP,YAAY;EACZ,aAAa;EACb,uBAAuB;EACvB,sBAAsB;EACtB,0BAA0B;EAC1B,uBAAuB;EACvB,2BAA2B;EAC3B,iBAAiB;EACjB,OAAO;EACP,QAAQ;EACR,WAAW;EACX,YAAY;CACf,CAAC","sourcesContent":["export const allowedCssProperties = [\n 'background-color',\n 'color',\n 'font-style',\n 'font-weight',\n 'text-decoration-color',\n 'text-decoration-line',\n 'text-decoration-skip-ink',\n 'text-decoration-style',\n 'text-decoration-thickness',\n 'text-decoration',\n 'width',\n 'height',\n 'min-width',\n 'min-height',\n];\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class ImageIntersectionObserver {
|
|
2
|
+
/**
|
|
3
|
+
* @param containerElement - The element containing images to observe.
|
|
4
|
+
*/
|
|
5
|
+
constructor(containerElement) {
|
|
6
|
+
this.handleIntersection = (entries) => {
|
|
7
|
+
entries.forEach((entry) => {
|
|
8
|
+
if (entry.isIntersecting) {
|
|
9
|
+
const img = entry.target;
|
|
10
|
+
const dataSrc = img.getAttribute('data-src');
|
|
11
|
+
if (dataSrc) {
|
|
12
|
+
img.setAttribute('src', dataSrc);
|
|
13
|
+
img.removeAttribute('data-src');
|
|
14
|
+
}
|
|
15
|
+
this.observer.unobserve(img);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
this.observer = new IntersectionObserver(this.handleIntersection);
|
|
20
|
+
const images = containerElement.querySelectorAll('img');
|
|
21
|
+
images.forEach((img) => {
|
|
22
|
+
this.observer.observe(img);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
disconnect() {
|
|
26
|
+
this.observer.disconnect();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=image-intersection-observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-intersection-observer.js","sourceRoot":"","sources":["../../../src/components/markdown/image-intersection-observer.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,yBAAyB;EAGlC;;KAEG;EACH,YAAmB,gBAA6B;IAa/B,uBAAkB,GAAG,CAClC,OAAoC,EACtC,EAAE;MACA,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACtB,IAAI,KAAK,CAAC,cAAc,EAAE;UACtB,MAAM,GAAG,GAAG,KAAK,CAAC,MAA0B,CAAC;UAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;UAE7C,IAAI,OAAO,EAAE;YACT,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACjC,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;WACnC;UAED,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;SAChC;MACL,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IA5BE,IAAI,CAAC,QAAQ,GAAG,IAAI,oBAAoB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAElE,MAAM,MAAM,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;MACnB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;EACP,CAAC;EAEM,UAAU;IACb,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;EAC/B,CAAC;CAmBJ","sourcesContent":["export class ImageIntersectionObserver {\n private observer: IntersectionObserver;\n\n /**\n * @param containerElement - The element containing images to observe.\n */\n public constructor(containerElement: HTMLElement) {\n this.observer = new IntersectionObserver(this.handleIntersection);\n\n const images = containerElement.querySelectorAll('img');\n images.forEach((img) => {\n this.observer.observe(img);\n });\n }\n\n public disconnect() {\n this.observer.disconnect();\n }\n\n private readonly handleIntersection = (\n entries: IntersectionObserverEntry[],\n ) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const img = entry.target as HTMLImageElement;\n const dataSrc = img.getAttribute('data-src');\n\n if (dataSrc) {\n img.setAttribute('src', dataSrc);\n img.removeAttribute('data-src');\n }\n\n this.observer.unobserve(img);\n }\n });\n };\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a unified.js plugin that transforms image elements for lazy loading
|
|
4
|
+
*
|
|
5
|
+
* @param lazyLoadImages - Whether to enable lazy loading for images
|
|
6
|
+
* @returns A unified.js plugin function
|
|
7
|
+
*/
|
|
8
|
+
export function createLazyLoadImagesPlugin(lazyLoadImages = false) {
|
|
9
|
+
return () => {
|
|
10
|
+
if (!lazyLoadImages) {
|
|
11
|
+
return (tree) => tree;
|
|
12
|
+
}
|
|
13
|
+
return (tree) => {
|
|
14
|
+
visit(tree, 'element', (node) => {
|
|
15
|
+
if (node.tagName === 'img') {
|
|
16
|
+
node.properties = node.properties || {};
|
|
17
|
+
node.properties.loading = 'lazy';
|
|
18
|
+
if (node.properties.src) {
|
|
19
|
+
node.properties['data-src'] = node.properties.src;
|
|
20
|
+
node.properties.src = undefined;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return tree;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=image-markdown-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-markdown-plugin.js","sourceRoot":"","sources":["../../../src/components/markdown/image-markdown-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAIzC;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,cAAc,GAAG,KAAK;EAC7D,OAAO,GAAgB,EAAE;IACrB,IAAI,CAAC,cAAc,EAAE;MACjB,OAAO,CAAC,IAAU,EAAE,EAAE,CAAC,IAAI,CAAC;KAC/B;IAED,OAAO,CAAC,IAAU,EAAE,EAAE;MAClB,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,IAAS,EAAE,EAAE;QACjC,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,EAAE;UACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;UACxC,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC;UAEjC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE;YACrB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAClD,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,SAAS,CAAC;WACnC;SACJ;MACL,CAAC,CAAC,CAAC;MAEH,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC;EACN,CAAC,CAAC;AACN,CAAC","sourcesContent":["import { visit } from 'unist-util-visit';\nimport { Node } from 'unist';\nimport { Plugin, Transformer } from 'unified';\n\n/**\n * Creates a unified.js plugin that transforms image elements for lazy loading\n *\n * @param lazyLoadImages - Whether to enable lazy loading for images\n * @returns A unified.js plugin function\n */\nexport function createLazyLoadImagesPlugin(lazyLoadImages = false): Plugin {\n return (): Transformer => {\n if (!lazyLoadImages) {\n return (tree: Node) => tree;\n }\n\n return (tree: Node) => {\n visit(tree, 'element', (node: any) => {\n if (node.tagName === 'img') {\n node.properties = node.properties || {};\n node.properties.loading = 'lazy';\n\n if (node.properties.src) {\n node.properties['data-src'] = node.properties.src;\n node.properties.src = undefined;\n }\n }\n });\n\n return tree;\n };\n };\n}\n"]}
|
|
@@ -9,6 +9,7 @@ import rehypeStringify from 'rehype-stringify';
|
|
|
9
9
|
import rehypeRaw from 'rehype-raw';
|
|
10
10
|
import { visit } from 'unist-util-visit';
|
|
11
11
|
import { sanitizeStyle } from './sanitize-style';
|
|
12
|
+
import { createLazyLoadImagesPlugin } from './image-markdown-plugin';
|
|
12
13
|
/**
|
|
13
14
|
* Takes a string as input and returns a new string
|
|
14
15
|
* where the text has been converted to HTML.
|
|
@@ -42,6 +43,7 @@ export async function markdownToHTML(text, options) {
|
|
|
42
43
|
visit(tree, 'element', sanitizeStyle);
|
|
43
44
|
};
|
|
44
45
|
})
|
|
46
|
+
.use(createLazyLoadImagesPlugin(options === null || options === void 0 ? void 0 : options.lazyLoadImages))
|
|
45
47
|
.use(rehypeStringify)
|
|
46
48
|
.process(text);
|
|
47
49
|
return file.toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-parser.js","sourceRoot":"","sources":["../../../src/components/markdown/markdown-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,YAAY,MAAM,eAAe,CAAC;AACzC,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,cAAc,EAAE,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,eAAe,MAAM,kBAAkB,CAAC;AAC/C,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"markdown-parser.js","sourceRoot":"","sources":["../../../src/components/markdown/markdown-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkRehype from 'remark-rehype';\nimport remarkGfm from 'remark-gfm';\nimport rehypeParse from 'rehype-parse';\nimport rehypeExternalLinks from 'rehype-external-links';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport rehypeStringify from 'rehype-stringify';\nimport rehypeRaw from 'rehype-raw';\nimport { visit } from 'unist-util-visit';\nimport { sanitizeStyle } from './sanitize-style';\nimport { Node } from 'unist';\nimport { Schema } from 'rehype-sanitize/lib';\nimport { createLazyLoadImagesPlugin } from './image-markdown-plugin';\nimport { CustomElementDefinition } from '../../global/shared-types/custom-element.types';\n\n/**\n * Takes a string as input and returns a new string\n * where the text has been converted to HTML.\n *\n * If the text is formatted with .md markdown, it will\n * be transformed to HTML.\n *\n * If the text already is in HTML it will be sanitized and\n * \"dangerous\" tags such as <script> will be removed.\n *\n * @param text - The string to convert.\n * @param options - Options for the conversions.\n * @returns The resulting HTML.\n */\nexport async function markdownToHTML(\n text: string,\n options?: MarkdownToHTMLOptions,\n): Promise<string> {\n if (options?.forceHardLineBreaks) {\n text = text.replace(/(?<!\\\\)([\\n\\r])/g, ' $1');\n }\n\n const file = await unified()\n .use(remarkParse)\n .use(remarkGfm)\n .use(remarkRehype, { allowDangerousHtml: true })\n .use(rehypeExternalLinks, { target: '_blank' })\n .use(rehypeRaw)\n .use(rehypeSanitize, {\n ...getWhiteList(options?.whitelist ?? []),\n })\n .use(() => {\n return (tree: Node) => {\n // Run the sanitizeStyle function on all elements, to sanitize\n // the value of the `style` attribute, if there is one.\n visit(tree, 'element', sanitizeStyle);\n };\n })\n .use(createLazyLoadImagesPlugin(options?.lazyLoadImages))\n .use(rehypeStringify)\n .process(text);\n\n return file.toString();\n}\n\n/**\n * Sanitizes a given HTML string by removing dangerous tags and attributes.\n *\n * @param html - The string containing HTML to sanitize.\n * @param whitelist - Optional whitelist of custom components.\n * @returns The sanitized HTML string.\n */\nexport async function sanitizeHTML(\n html: string,\n whitelist?: CustomElementDefinition[],\n): Promise<string> {\n const file = await unified()\n .use(rehypeParse)\n .use(rehypeSanitize, {\n ...getWhiteList(whitelist ?? []),\n })\n .use(() => {\n return (tree: Node) => {\n // Run the sanitizeStyle function on all elements, to sanitize\n // the value of the `style` attribute, if there is one.\n visit(tree, 'element', sanitizeStyle);\n };\n })\n .use(rehypeStringify)\n .process(html);\n\n return file.toString();\n}\n\nfunction getWhiteList(allowedComponents: CustomElementDefinition[]): Schema {\n const defaultSchemaClone = [...(defaultSchema.attributes['*'] ?? [])];\n const asteriskAttributeWhitelist = defaultSchemaClone.filter((attr) => {\n return attr !== 'height';\n });\n asteriskAttributeWhitelist.push('style');\n\n const whitelist: Schema = {\n ...defaultSchema,\n tagNames: [\n ...(defaultSchema.tagNames || []),\n ...allowedComponents.map((component) => component.tagName),\n ],\n attributes: {\n ...defaultSchema.attributes,\n p: [\n ...(defaultSchema.attributes.p ?? []),\n ['className', 'MsoNormal'],\n ], // Allow the class 'MsoNormal' on <p> elements\n '*': asteriskAttributeWhitelist,\n },\n };\n\n for (const component of allowedComponents) {\n whitelist.attributes[component.tagName] = component.attributes;\n }\n\n return whitelist;\n}\n\n/**\n * Options for markdownToHTML.\n */\nexport interface MarkdownToHTMLOptions {\n /**\n * Set to `true` to convert all soft line breaks to hard line breaks.\n */\n forceHardLineBreaks?: boolean;\n whitelist?: CustomElementDefinition[];\n lazyLoadImages?: boolean;\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { h } from '@stencil/core';
|
|
2
2
|
import { markdownToHTML } from './markdown-parser';
|
|
3
3
|
import { globalConfig } from '../../global/config';
|
|
4
|
+
import { ImageIntersectionObserver } from './image-intersection-observer';
|
|
4
5
|
/**
|
|
5
6
|
* The Markdown component receives markdown syntax
|
|
6
7
|
* and renders it as HTML.
|
|
@@ -22,17 +23,22 @@ import { globalConfig } from '../../global/config';
|
|
|
22
23
|
*/
|
|
23
24
|
export class Markdown {
|
|
24
25
|
constructor() {
|
|
26
|
+
this.imageIntersectionObserver = null;
|
|
25
27
|
this.value = undefined;
|
|
26
28
|
this.whitelist = globalConfig.markdownWhitelist;
|
|
29
|
+
this.lazyLoadImages = false;
|
|
27
30
|
}
|
|
28
31
|
async textChanged() {
|
|
29
32
|
var _a;
|
|
30
33
|
try {
|
|
34
|
+
this.cleanupImageIntersectionObserver();
|
|
31
35
|
const html = await markdownToHTML(this.value, {
|
|
32
36
|
forceHardLineBreaks: true,
|
|
33
37
|
whitelist: (_a = this.whitelist) !== null && _a !== void 0 ? _a : [],
|
|
38
|
+
lazyLoadImages: this.lazyLoadImages,
|
|
34
39
|
});
|
|
35
40
|
this.rootElement.innerHTML = html;
|
|
41
|
+
this.setupImageIntersectionObserver();
|
|
36
42
|
}
|
|
37
43
|
catch (error) {
|
|
38
44
|
// eslint-disable-next-line no-console
|
|
@@ -42,11 +48,25 @@ export class Markdown {
|
|
|
42
48
|
async componentDidLoad() {
|
|
43
49
|
this.textChanged();
|
|
44
50
|
}
|
|
51
|
+
disconnectedCallback() {
|
|
52
|
+
this.cleanupImageIntersectionObserver();
|
|
53
|
+
}
|
|
45
54
|
render() {
|
|
46
55
|
return [
|
|
47
56
|
h("div", { id: "markdown", ref: (el) => (this.rootElement = el) }),
|
|
48
57
|
];
|
|
49
58
|
}
|
|
59
|
+
setupImageIntersectionObserver() {
|
|
60
|
+
if (this.lazyLoadImages) {
|
|
61
|
+
this.imageIntersectionObserver = new ImageIntersectionObserver(this.rootElement);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
cleanupImageIntersectionObserver() {
|
|
65
|
+
if (this.imageIntersectionObserver) {
|
|
66
|
+
this.imageIntersectionObserver.disconnect();
|
|
67
|
+
this.imageIntersectionObserver = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
50
70
|
static get is() { return "limel-markdown"; }
|
|
51
71
|
static get encapsulation() { return "shadow"; }
|
|
52
72
|
static get originalStyleUrls() {
|
|
@@ -101,6 +121,24 @@ export class Markdown {
|
|
|
101
121
|
"text": "Whitelisted html elements.\n\nAny custom element added here will not be sanitized and thus rendered.\nCan also be set via `limel-config`. Setting this property will override\nthe global config."
|
|
102
122
|
},
|
|
103
123
|
"defaultValue": "globalConfig.markdownWhitelist"
|
|
124
|
+
},
|
|
125
|
+
"lazyLoadImages": {
|
|
126
|
+
"type": "boolean",
|
|
127
|
+
"mutable": false,
|
|
128
|
+
"complexType": {
|
|
129
|
+
"original": "boolean",
|
|
130
|
+
"resolved": "boolean",
|
|
131
|
+
"references": {}
|
|
132
|
+
},
|
|
133
|
+
"required": false,
|
|
134
|
+
"optional": false,
|
|
135
|
+
"docs": {
|
|
136
|
+
"tags": [],
|
|
137
|
+
"text": "Enable lazy loading for images"
|
|
138
|
+
},
|
|
139
|
+
"attribute": "lazy-load-images",
|
|
140
|
+
"reflect": false,
|
|
141
|
+
"defaultValue": "false"
|
|
104
142
|
}
|
|
105
143
|
};
|
|
106
144
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/components/markdown/markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/components/markdown/markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAE1E;;;;;;;;;;;;;;;;;;GAkBG;AAMH,MAAM,OAAO,QAAQ;;IAgDT,8BAAyB,GAAqC,IAAI,CAAC;;qBA7BvE,YAAY,CAAC,iBAAiB;0BAMV,KAAK;;EAGtB,KAAK,CAAC,WAAW;;IACpB,IAAI;MACA,IAAI,CAAC,gCAAgC,EAAE,CAAC;MAExC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE;QAC1C,mBAAmB,EAAE,IAAI;QACzB,SAAS,EAAE,MAAA,IAAI,CAAC,SAAS,mCAAI,EAAE;QAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;OACtC,CAAC,CAAC;MAEH,IAAI,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC;MAElC,IAAI,CAAC,8BAA8B,EAAE,CAAC;KACzC;IAAC,OAAO,KAAK,EAAE;MACZ,sCAAsC;MACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;KACxB;EACL,CAAC;EAKM,KAAK,CAAC,gBAAgB;IACzB,IAAI,CAAC,WAAW,EAAE,CAAC;EACvB,CAAC;EAEM,oBAAoB;IACvB,IAAI,CAAC,gCAAgC,EAAE,CAAC;EAC5C,CAAC;EAEM,MAAM;IACT,OAAO;MACH,WACI,EAAE,EAAC,UAAU,EACb,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,EAAoB,CAAC,GACxD;KACL,CAAC;EACN,CAAC;EAEO,8BAA8B;IAClC,IAAI,IAAI,CAAC,cAAc,EAAE;MACrB,IAAI,CAAC,yBAAyB,GAAG,IAAI,yBAAyB,CAC1D,IAAI,CAAC,WAAW,CACnB,CAAC;KACL;EACL,CAAC;EAEO,gCAAgC;IACpC,IAAI,IAAI,CAAC,yBAAyB,EAAE;MAChC,IAAI,CAAC,yBAAyB,CAAC,UAAU,EAAE,CAAC;MAC5C,IAAI,CAAC,yBAAyB,GAAG,IAAI,CAAC;KACzC;EACL,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACJ","sourcesContent":["import { Component, h, Prop, Watch } from '@stencil/core';\nimport { markdownToHTML } from './markdown-parser';\nimport { globalConfig } from '../../global/config';\nimport { CustomElementDefinition } from '../../global/shared-types/custom-element.types';\nimport { ImageIntersectionObserver } from './image-intersection-observer';\n\n/**\n * The Markdown component receives markdown syntax\n * and renders it as HTML.\n *\n * @exampleComponent limel-example-markdown-headings\n * @exampleComponent limel-example-markdown-emphasis\n * @exampleComponent limel-example-markdown-lists\n * @exampleComponent limel-example-markdown-links\n * @exampleComponent limel-example-markdown-images\n * @exampleComponent limel-example-markdown-code\n * @exampleComponent limel-example-markdown-footnotes\n * @exampleComponent limel-example-markdown-tables\n * @exampleComponent limel-example-markdown-html\n * @exampleComponent limel-example-markdown-keys\n * @exampleComponent limel-example-markdown-blockquotes\n * @exampleComponent limel-example-markdown-horizontal-rule\n * @exampleComponent limel-example-markdown-composite\n * @exampleComponent limel-example-markdown-custom-component\n */\n@Component({\n tag: 'limel-markdown',\n styleUrl: 'markdown.scss',\n shadow: true,\n})\nexport class Markdown {\n /**\n * The input text. Treated as GitHub Flavored Markdown, with the addition\n * that any included HTML will be parsed and rendered as HTML, rather than\n * as text.\n */\n @Prop()\n public value: string;\n\n /**\n * Whitelisted html elements.\n *\n * Any custom element added here will not be sanitized and thus rendered.\n * Can also be set via `limel-config`. Setting this property will override\n * the global config.\n * @alpha\n */\n @Prop()\n public whitelist?: CustomElementDefinition[] =\n globalConfig.markdownWhitelist;\n\n /**\n * Enable lazy loading for images\n */\n @Prop()\n public lazyLoadImages = false;\n\n @Watch('value')\n public async textChanged() {\n try {\n this.cleanupImageIntersectionObserver();\n\n const html = await markdownToHTML(this.value, {\n forceHardLineBreaks: true,\n whitelist: this.whitelist ?? [],\n lazyLoadImages: this.lazyLoadImages,\n });\n\n this.rootElement.innerHTML = html;\n\n this.setupImageIntersectionObserver();\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n }\n\n private rootElement: HTMLDivElement;\n private imageIntersectionObserver: ImageIntersectionObserver | null = null;\n\n public async componentDidLoad() {\n this.textChanged();\n }\n\n public disconnectedCallback() {\n this.cleanupImageIntersectionObserver();\n }\n\n public render() {\n return [\n <div\n id=\"markdown\"\n ref={(el) => (this.rootElement = el as HTMLDivElement)}\n />,\n ];\n }\n\n private setupImageIntersectionObserver() {\n if (this.lazyLoadImages) {\n this.imageIntersectionObserver = new ImageIntersectionObserver(\n this.rootElement,\n );\n }\n }\n\n private cleanupImageIntersectionObserver() {\n if (this.imageIntersectionObserver) {\n this.imageIntersectionObserver.disconnect();\n this.imageIntersectionObserver = null;\n }\n }\n}\n"]}
|
|
@@ -6,6 +6,13 @@ export function getImageNode(language) {
|
|
|
6
6
|
export function getImageNodeMarkdownSerializer(language) {
|
|
7
7
|
return { image: createImageNodeMarkdownSerializer(language) };
|
|
8
8
|
}
|
|
9
|
+
export function applyImageStyles(img, node) {
|
|
10
|
+
img.style.height = node.attrs.height;
|
|
11
|
+
img.style.width = node.attrs.width;
|
|
12
|
+
img.style.minHeight = node.attrs.minHeight;
|
|
13
|
+
img.style.minWidth = node.attrs.minWidth;
|
|
14
|
+
img.style.maxWidth = node.attrs.maxWidth;
|
|
15
|
+
}
|
|
9
16
|
/**
|
|
10
17
|
* Recursively checks if a ProseMirror node or
|
|
11
18
|
* any of its child nodes is an image node.
|
|
@@ -24,16 +31,16 @@ export function hasImageNode(node) {
|
|
|
24
31
|
}
|
|
25
32
|
function createImageNodeMarkdownSerializer(language) {
|
|
26
33
|
return (markdownSerializerState, node) => {
|
|
27
|
-
const
|
|
34
|
+
const state = node.attrs.state;
|
|
28
35
|
if (!isEditorImageState(state)) {
|
|
29
36
|
return;
|
|
30
37
|
}
|
|
31
38
|
if (state === 'success') {
|
|
32
|
-
const imageHTML = getImageHTML(
|
|
39
|
+
const imageHTML = getImageHTML(node.attrs);
|
|
33
40
|
markdownSerializerState.write(imageHTML);
|
|
34
41
|
return;
|
|
35
42
|
}
|
|
36
|
-
const statusHTML = getStatusHTML(state, alt, language);
|
|
43
|
+
const statusHTML = getStatusHTML(state, node.attrs.alt, language);
|
|
37
44
|
markdownSerializerState.write(statusHTML);
|
|
38
45
|
};
|
|
39
46
|
}
|
|
@@ -44,16 +51,25 @@ function getStatusHTML(state, alt, language) {
|
|
|
44
51
|
});
|
|
45
52
|
return `<span>${text}</span>`;
|
|
46
53
|
}
|
|
47
|
-
function getImageHTML(
|
|
54
|
+
function getImageHTML(attrs) {
|
|
48
55
|
const style = [];
|
|
49
|
-
if (
|
|
50
|
-
style.push(`
|
|
56
|
+
if (attrs.height) {
|
|
57
|
+
style.push(`height: ${attrs.height};`);
|
|
58
|
+
}
|
|
59
|
+
if (attrs.width) {
|
|
60
|
+
style.push(`width: ${attrs.width};`);
|
|
61
|
+
}
|
|
62
|
+
if (attrs.minHeight) {
|
|
63
|
+
style.push(`min-height: ${attrs.minHeight};`);
|
|
51
64
|
}
|
|
52
|
-
if (
|
|
53
|
-
style.push(`
|
|
65
|
+
if (attrs.minWidth) {
|
|
66
|
+
style.push(`min-width: ${attrs.minWidth};`);
|
|
54
67
|
}
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
if (attrs.maxWidth) {
|
|
69
|
+
style.push(`max-width: ${attrs.maxWidth};`);
|
|
70
|
+
}
|
|
71
|
+
const styleAttribute = style.length > 0 ? ` style="${style.join('')}"` : '';
|
|
72
|
+
return `<img src="${attrs.src}" alt="${attrs.alt}"${styleAttribute} />`;
|
|
57
73
|
}
|
|
58
74
|
function createImageNodeSpec(language) {
|
|
59
75
|
return {
|
|
@@ -63,7 +79,10 @@ function createImageNodeSpec(language) {
|
|
|
63
79
|
src: { default: '' },
|
|
64
80
|
alt: { default: '' },
|
|
65
81
|
fileInfoId: { default: '' },
|
|
82
|
+
height: { default: '' },
|
|
66
83
|
width: { default: '' },
|
|
84
|
+
minHeight: { default: '' },
|
|
85
|
+
minWidth: { default: '' },
|
|
67
86
|
maxWidth: { default: '100%' },
|
|
68
87
|
state: { default: 'success' },
|
|
69
88
|
},
|
|
@@ -121,16 +140,14 @@ function createStatusSpan(key, node, language) {
|
|
|
121
140
|
}
|
|
122
141
|
function updateImageElement(img, node) {
|
|
123
142
|
img.alt = node.attrs.alt;
|
|
124
|
-
img
|
|
125
|
-
img.style.width = node.attrs.width;
|
|
143
|
+
applyImageStyles(img, node);
|
|
126
144
|
return img;
|
|
127
145
|
}
|
|
128
146
|
function createImageElement(node) {
|
|
129
147
|
const img = document.createElement('img');
|
|
130
148
|
img.src = node.attrs.src;
|
|
131
149
|
img.alt = node.attrs.alt;
|
|
132
|
-
img
|
|
133
|
-
img.style.width = node.attrs.width;
|
|
150
|
+
applyImageStyles(img, node);
|
|
134
151
|
return img;
|
|
135
152
|
}
|
|
136
153
|
//# sourceMappingURL=node.js.map
|
package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/image/node.ts"],"names":[],"mappings":"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","sourcesContent":["import { NodeSpec, Node, DOMOutputSpec } from 'prosemirror-model';\nimport { EditorImageState } from '../../../text-editor.types';\nimport { MarkdownSerializerState } from 'prosemirror-markdown';\nimport { Languages } from '../../../../date-picker/date.types';\nimport translate from '../../../../../global/translations';\n\nexport const imageCache = new Map<string, HTMLImageElement>();\n\ntype MarkdownSerializerFunction = (\n state: MarkdownSerializerState,\n node: Node,\n) => void;\n\nexport function getImageNode(language: Languages): Record<string, NodeSpec> {\n return { image: createImageNodeSpec(language) };\n}\n\nexport function getImageNodeMarkdownSerializer(\n language: Languages,\n): Record<string, MarkdownSerializerFunction> {\n return { image: createImageNodeMarkdownSerializer(language) };\n}\n\n/**\n * Recursively checks if a ProseMirror node or\n * any of its child nodes is an image node.\n */\nexport function hasImageNode(node: Node): boolean {\n if (node.type.name === 'image') {\n return true;\n }\n\n for (let i = 0; i < node.childCount; i++) {\n const childNode = node.child(i);\n if (hasImageNode(childNode)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction createImageNodeMarkdownSerializer(\n language: Languages,\n): MarkdownSerializerFunction {\n return (markdownSerializerState: MarkdownSerializerState, node: Node) => {\n const { state, alt, src, width, maxWidth } = node.attrs;\n\n if (!isEditorImageState(state)) {\n return;\n }\n\n if (state === 'success') {\n const imageHTML = getImageHTML(src, alt, width, maxWidth);\n markdownSerializerState.write(imageHTML);\n\n return;\n }\n\n const statusHTML = getStatusHTML(state, alt, language);\n markdownSerializerState.write(statusHTML);\n };\n}\n\nfunction getStatusHTML(\n state: EditorImageState,\n alt: string,\n language: Languages,\n): string {\n const key = state === 'failed' ? 'failed' : 'loading';\n const text = translate.get(`editor-image-view.${key}`, language, {\n filename: alt || 'file',\n });\n\n return `<span>${text}</span>`;\n}\n\nfunction getImageHTML(\n src: string,\n alt: string,\n width: string,\n maxWidth: string,\n): string {\n const style = [];\n\n if (width) {\n style.push(`width: ${width};`);\n }\n\n if (maxWidth) {\n style.push(`max-width: ${maxWidth};`);\n }\n\n const styleAttribute =\n style.length > 0 ? ` style=\"${style.join(' ')}\"` : '';\n\n return `<img src=\"${src}\" alt=\"${alt}\"${styleAttribute} />`;\n}\n\nexport interface ImageNodeAttrs {\n src: string;\n alt: string;\n state: EditorImageState;\n fileInfoId: string | number;\n width?: string;\n maxWidth?: string;\n}\n\nfunction createImageNodeSpec(language: Languages): NodeSpec {\n return {\n group: 'inline',\n inline: true,\n attrs: {\n src: { default: '' },\n alt: { default: '' },\n fileInfoId: { default: '' },\n width: { default: '' },\n maxWidth: { default: '100%' },\n state: { default: 'success' },\n },\n toDOM: (node): DOMOutputSpec => {\n if (!isEditorImageState(node.attrs.state)) {\n return;\n }\n\n if (node.attrs.state === 'success') {\n return getOrCreateImageElement(node.attrs.fileInfoId, node);\n }\n\n return createStatusSpanForState(node.attrs.state, node, language);\n },\n parseDOM: [\n {\n tag: 'img',\n getAttrs: (dom: HTMLElement): ImageNodeAttrs => {\n return {\n src: dom.getAttribute('src') || '',\n alt: dom.getAttribute('alt') || 'file',\n width: dom.style.width || '',\n maxWidth: '100%',\n state: 'success',\n fileInfoId: crypto.randomUUID(),\n };\n },\n },\n ],\n };\n}\n\nfunction isEditorImageState(state: unknown): state is EditorImageState {\n return state === 'loading' || state === 'failed' || state === 'success';\n}\n\nfunction getOrCreateImageElement(\n fileInfoId: string,\n node: Node,\n): HTMLImageElement {\n let img = imageCache.get(fileInfoId);\n\n if (img) {\n updateImageElement(img, node);\n } else {\n img = createImageElement(node);\n imageCache.set(fileInfoId, img);\n }\n\n return img;\n}\n\nfunction createStatusSpanForState(\n state: EditorImageState,\n node: Node,\n language: Languages,\n): HTMLSpanElement {\n const statusKey = state === 'failed' ? 'failed' : 'loading';\n\n return createStatusSpan(statusKey, node, language);\n}\n\nfunction createStatusSpan(\n key: string,\n node: Node,\n language: Languages,\n): HTMLSpanElement {\n const text = translate.get(`editor-image-view.${key}`, language, {\n filename: node.attrs.alt || 'file',\n });\n const span = document.createElement('span');\n span.textContent = text;\n\n return span;\n}\n\nfunction updateImageElement(\n img: HTMLImageElement,\n node: Node,\n): HTMLImageElement {\n img.alt = node.attrs.alt;\n img.style.maxWidth = node.attrs.maxWidth;\n img.style.width = node.attrs.width;\n\n return img;\n}\n\nfunction createImageElement(node: Node): HTMLImageElement {\n const img = document.createElement('img');\n img.src = node.attrs.src;\n img.alt = node.attrs.alt;\n img.style.maxWidth = node.attrs.maxWidth;\n img.style.width = node.attrs.width;\n\n return img;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/image/node.ts"],"names":[],"mappings":"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","sourcesContent":["import { NodeSpec, Node, DOMOutputSpec } from 'prosemirror-model';\nimport { EditorImageState } from '../../../text-editor.types';\nimport { MarkdownSerializerState } from 'prosemirror-markdown';\nimport { Languages } from '../../../../date-picker/date.types';\nimport translate from '../../../../../global/translations';\n\nexport const imageCache = new Map<string, HTMLImageElement>();\n\ntype MarkdownSerializerFunction = (\n state: MarkdownSerializerState,\n node: Node,\n) => void;\n\nexport function getImageNode(language: Languages): Record<string, NodeSpec> {\n return { image: createImageNodeSpec(language) };\n}\n\nexport function getImageNodeMarkdownSerializer(\n language: Languages,\n): Record<string, MarkdownSerializerFunction> {\n return { image: createImageNodeMarkdownSerializer(language) };\n}\n\nexport function applyImageStyles(img: HTMLImageElement, node: Node) {\n img.style.height = node.attrs.height;\n img.style.width = node.attrs.width;\n img.style.minHeight = node.attrs.minHeight;\n img.style.minWidth = node.attrs.minWidth;\n img.style.maxWidth = node.attrs.maxWidth;\n}\n\n/**\n * Recursively checks if a ProseMirror node or\n * any of its child nodes is an image node.\n */\nexport function hasImageNode(node: Node): boolean {\n if (node.type.name === 'image') {\n return true;\n }\n\n for (let i = 0; i < node.childCount; i++) {\n const childNode = node.child(i);\n if (hasImageNode(childNode)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction createImageNodeMarkdownSerializer(\n language: Languages,\n): MarkdownSerializerFunction {\n return (markdownSerializerState: MarkdownSerializerState, node: Node) => {\n const state = node.attrs.state;\n if (!isEditorImageState(state)) {\n return;\n }\n\n if (state === 'success') {\n const imageHTML = getImageHTML(node.attrs as ImageNodeAttrs);\n markdownSerializerState.write(imageHTML);\n\n return;\n }\n\n const statusHTML = getStatusHTML(state, node.attrs.alt, language);\n markdownSerializerState.write(statusHTML);\n };\n}\n\nfunction getStatusHTML(\n state: EditorImageState,\n alt: string,\n language: Languages,\n): string {\n const key = state === 'failed' ? 'failed' : 'loading';\n const text = translate.get(`editor-image-view.${key}`, language, {\n filename: alt || 'file',\n });\n\n return `<span>${text}</span>`;\n}\n\nfunction getImageHTML(attrs: ImageNodeAttrs): string {\n const style = [];\n\n if (attrs.height) {\n style.push(`height: ${attrs.height};`);\n }\n\n if (attrs.width) {\n style.push(`width: ${attrs.width};`);\n }\n\n if (attrs.minHeight) {\n style.push(`min-height: ${attrs.minHeight};`);\n }\n\n if (attrs.minWidth) {\n style.push(`min-width: ${attrs.minWidth};`);\n }\n\n if (attrs.maxWidth) {\n style.push(`max-width: ${attrs.maxWidth};`);\n }\n\n const styleAttribute = style.length > 0 ? ` style=\"${style.join('')}\"` : '';\n\n return `<img src=\"${attrs.src}\" alt=\"${attrs.alt}\"${styleAttribute} />`;\n}\n\nexport interface ImageNodeAttrs {\n src: string;\n alt: string;\n state: EditorImageState;\n fileInfoId: string | number;\n height?: string;\n width?: string;\n minHeight?: string;\n minWidth?: string;\n maxWidth?: string;\n}\n\nfunction createImageNodeSpec(language: Languages): NodeSpec {\n return {\n group: 'inline',\n inline: true,\n attrs: {\n src: { default: '' },\n alt: { default: '' },\n fileInfoId: { default: '' },\n height: { default: '' },\n width: { default: '' },\n minHeight: { default: '' },\n minWidth: { default: '' },\n maxWidth: { default: '100%' },\n state: { default: 'success' },\n },\n toDOM: (node): DOMOutputSpec => {\n if (!isEditorImageState(node.attrs.state)) {\n return;\n }\n\n if (node.attrs.state === 'success') {\n return getOrCreateImageElement(node.attrs.fileInfoId, node);\n }\n\n return createStatusSpanForState(node.attrs.state, node, language);\n },\n parseDOM: [\n {\n tag: 'img',\n getAttrs: (dom: HTMLElement): ImageNodeAttrs => {\n return {\n src: dom.getAttribute('src') || '',\n alt: dom.getAttribute('alt') || 'file',\n width: dom.style.width || '',\n maxWidth: '100%',\n state: 'success',\n fileInfoId: crypto.randomUUID(),\n };\n },\n },\n ],\n };\n}\n\nfunction isEditorImageState(state: unknown): state is EditorImageState {\n return state === 'loading' || state === 'failed' || state === 'success';\n}\n\nfunction getOrCreateImageElement(\n fileInfoId: string,\n node: Node,\n): HTMLImageElement {\n let img = imageCache.get(fileInfoId);\n\n if (img) {\n updateImageElement(img, node);\n } else {\n img = createImageElement(node);\n imageCache.set(fileInfoId, img);\n }\n\n return img;\n}\n\nfunction createStatusSpanForState(\n state: EditorImageState,\n node: Node,\n language: Languages,\n): HTMLSpanElement {\n const statusKey = state === 'failed' ? 'failed' : 'loading';\n\n return createStatusSpan(statusKey, node, language);\n}\n\nfunction createStatusSpan(\n key: string,\n node: Node,\n language: Languages,\n): HTMLSpanElement {\n const text = translate.get(`editor-image-view.${key}`, language, {\n filename: node.attrs.alt || 'file',\n });\n const span = document.createElement('span');\n span.textContent = text;\n\n return span;\n}\n\nfunction updateImageElement(\n img: HTMLImageElement,\n node: Node,\n): HTMLImageElement {\n img.alt = node.attrs.alt;\n applyImageStyles(img, node);\n\n return img;\n}\n\nfunction createImageElement(node: Node): HTMLImageElement {\n const img = document.createElement('img');\n img.src = node.attrs.src;\n img.alt = node.attrs.alt;\n applyImageStyles(img, node);\n\n return img;\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Plugin } from 'prosemirror-state';
|
|
2
2
|
import translate from '../../../../../global/translations';
|
|
3
|
+
import { applyImageStyles } from './node';
|
|
3
4
|
const MIN_WIDTH = 10;
|
|
4
5
|
export const createImageViewPlugin = (language) => {
|
|
5
6
|
return new Plugin({
|
|
@@ -50,7 +51,7 @@ class ImageView {
|
|
|
50
51
|
window.removeEventListener('pointermove', onPointerMove);
|
|
51
52
|
window.removeEventListener('pointerup', onPointerUp);
|
|
52
53
|
handle.setAttribute('aria-grabbed', 'false');
|
|
53
|
-
this.
|
|
54
|
+
this.persistDimensions();
|
|
54
55
|
};
|
|
55
56
|
window.addEventListener('pointermove', onPointerMove);
|
|
56
57
|
window.addEventListener('pointerup', onPointerUp);
|
|
@@ -115,19 +116,23 @@ class ImageView {
|
|
|
115
116
|
this.img = document.createElement('img');
|
|
116
117
|
this.img.src = node.attrs.src;
|
|
117
118
|
this.img.alt = node.attrs.alt;
|
|
118
|
-
this.img
|
|
119
|
-
this.img.
|
|
119
|
+
applyImageStyles(this.img, node);
|
|
120
|
+
this.img.onload = () => {
|
|
121
|
+
this.persistDimensions();
|
|
122
|
+
};
|
|
120
123
|
this.dom.appendChild(this.img);
|
|
121
124
|
this.transitionBetweenStates();
|
|
122
125
|
}
|
|
126
|
+
persistDimensions() {
|
|
127
|
+
this.view.dispatch(this.view.state.tr.setNodeMarkup(this.getPos(), undefined, Object.assign(Object.assign({}, this.node.attrs), { height: `${this.img.offsetHeight}px`, width: `${this.img.offsetWidth}px`, minHeight: `${this.img.offsetHeight}px`, minWidth: `${this.img.offsetWidth}px` })));
|
|
128
|
+
}
|
|
123
129
|
// Ensure that the existing NodeView is reused rather than recreated.
|
|
124
130
|
// Recreating the NodeView will cause flickering between states.
|
|
125
131
|
update(node) {
|
|
126
132
|
if (!this.transitioningBetweenSuccessStates(node)) {
|
|
127
133
|
this.img.src = node.attrs.src;
|
|
128
134
|
this.img.alt = node.attrs.alt;
|
|
129
|
-
this.img
|
|
130
|
-
this.img.style.width = node.attrs.width;
|
|
135
|
+
applyImageStyles(this.img, node);
|
|
131
136
|
}
|
|
132
137
|
this.node = node;
|
|
133
138
|
this.transitionBetweenStates();
|
package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/image/view.ts"],"names":[],"mappings":"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","sourcesContent":["import { EditorView, NodeView } from 'prosemirror-view';\nimport { Node } from 'prosemirror-model';\nimport { Plugin } from 'prosemirror-state';\nimport { EditorImageState } from '../../../text-editor.types';\nimport translate from '../../../../../global/translations';\nimport { Languages } from '../../../../date-picker/date.types';\n\nconst MIN_WIDTH = 10;\n\nexport const createImageViewPlugin = (language: Languages) => {\n return new Plugin({\n props: {\n nodeViews: {\n image: (node, view, getPos) => {\n return new ImageView(node, view, getPos, language);\n },\n },\n },\n });\n};\n\nclass ImageView implements NodeView {\n node: Node;\n view: EditorView;\n getPos: () => number;\n dom: HTMLDivElement;\n img: HTMLImageElement;\n language: Languages;\n\n public constructor(\n node: Node,\n view: EditorView,\n getPos: () => number,\n language: Languages,\n ) {\n this.node = node;\n this.view = view;\n this.getPos = getPos;\n this.language = language;\n\n this.dom = document.createElement('div');\n this.dom.className = `image-wrapper state-${node.attrs.state}`;\n\n this.img = document.createElement('img');\n this.img.src = node.attrs.src;\n this.img.alt = node.attrs.alt;\n this.img.style.maxWidth = node.attrs.maxWidth;\n this.img.style.width = node.attrs.width;\n\n this.dom.appendChild(this.img);\n\n this.transitionBetweenStates();\n }\n\n private createResizeHandle = (position: 'bottom-right' | 'top-left') => {\n const handle = document.createElement('div');\n handle.className = `resize-handle ${position}`;\n handle.setAttribute('role', 'slider');\n handle.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.resize-handle', this.language),\n );\n handle.setAttribute('tabindex', '0');\n handle.setAttribute('aria-valuemin', MIN_WIDTH.toString());\n handle.setAttribute('aria-valuenow', this.img.offsetWidth.toString());\n handle.setAttribute('aria-valuetext', `${this.img.offsetWidth} pixels`);\n handle.setAttribute('aria-grabbed', 'false');\n\n handle.addEventListener('pointerdown', (e: PointerEvent) => {\n handle.setAttribute('aria-grabbed', 'true');\n this.onResizeStart(e, position);\n });\n\n return handle;\n };\n\n private onResizeStart = (\n event: PointerEvent,\n position: 'bottom-right' | 'top-left',\n ) => {\n event.preventDefault();\n const handle = event.target as HTMLElement;\n\n const startX = event.clientX;\n const startWidth = this.img.offsetWidth;\n\n const onPointerMove = (e: PointerEvent) => {\n const delta = e.clientX - startX;\n const widthDelta = position === 'top-left' ? -delta : delta;\n const newWidth = Math.max(MIN_WIDTH, startWidth + widthDelta);\n\n this.img.style.width = `${newWidth}px`;\n\n const handles = this.dom.querySelectorAll('.resize-handle');\n handles.forEach((resizeHandle) => {\n resizeHandle.setAttribute('aria-valuenow', newWidth.toString());\n resizeHandle.setAttribute(\n 'aria-valuetext',\n `${newWidth} pixels`,\n );\n });\n };\n\n const onPointerUp = () => {\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n handle.setAttribute('aria-grabbed', 'false');\n\n this.view.dispatch(\n this.view.state.tr.setNodeMarkup(this.getPos(), undefined, {\n ...this.node.attrs,\n width: this.img.style.width,\n height: this.node.attrs.height,\n }),\n );\n };\n\n window.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUp);\n };\n\n private createLoadingState = () => {\n this.dom.setAttribute('aria-live', 'polite');\n this.dom.setAttribute('aria-busy', 'true');\n this.dom.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.loading', this.language, {\n filename: this.node.attrs.alt || 'file',\n }),\n );\n\n const spinnerElement = document.createElement('limel-linear-progress');\n spinnerElement.setAttribute('indeterminate', 'true');\n this.dom.appendChild(spinnerElement);\n };\n\n private createSuccessState = () => {\n this.dom.setAttribute('aria-live', 'polite');\n this.dom.setAttribute('aria-busy', 'false');\n this.dom.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.success', this.language, {\n filename: this.node.attrs.alt || 'file',\n }),\n );\n\n const bottomRightHandle = this.createResizeHandle('bottom-right');\n const topLeftHandle = this.createResizeHandle('top-left');\n\n this.dom.appendChild(bottomRightHandle);\n this.dom.appendChild(topLeftHandle);\n };\n\n private createFailedState = () => {\n this.dom.setAttribute('aria-live', 'assertive');\n this.dom.setAttribute('aria-busy', 'false');\n this.dom.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.failed', this.language, {\n filename: this.node.attrs.alt || 'file',\n }),\n );\n };\n\n private cleanUpPreviousState = () => {\n Array.from(this.dom.childNodes).forEach((child) => {\n if (!(child instanceof HTMLImageElement)) {\n child.remove();\n }\n });\n };\n\n private transitionBetweenStates = () => {\n this.cleanUpPreviousState();\n this.dom.className = `image-wrapper state-${this.node.attrs.state}`;\n\n const stateHandlers: Record<EditorImageState, () => void> = {\n loading: this.createLoadingState,\n success: this.createSuccessState,\n failed: this.createFailedState,\n };\n\n const state: EditorImageState = this.node.attrs.state;\n stateHandlers[state]?.();\n };\n\n private transitioningBetweenSuccessStates = (newNode: Node): boolean => {\n return (\n this.node.attrs.state === 'success' &&\n newNode.attrs.state === 'success'\n );\n };\n\n // Ensure that the existing NodeView is reused rather than recreated.\n // Recreating the NodeView will cause flickering between states.\n public update(node: Node): boolean {\n if (!this.transitioningBetweenSuccessStates(node)) {\n this.img.src = node.attrs.src;\n this.img.alt = node.attrs.alt;\n this.img.style.maxWidth = node.attrs.maxWidth;\n this.img.style.width = node.attrs.width;\n }\n\n this.node = node;\n this.transitionBetweenStates();\n\n return true;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../../../../src/components/text-editor/prosemirror-adapter/plugins/image/view.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,SAAS,MAAM,oCAAoC,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE1C,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,QAAmB,EAAE,EAAE;EACzD,OAAO,IAAI,MAAM,CAAC;IACd,KAAK,EAAE;MACH,SAAS,EAAE;QACP,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;UAC1B,OAAO,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvD,CAAC;OACJ;KACJ;GACJ,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,SAAS;EAQX,YACI,IAAU,EACV,IAAgB,EAChB,MAAoB,EACpB,QAAmB;IAoCf,uBAAkB,GAAG,CAAC,QAAqC,EAAE,EAAE;MACnE,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;MAC7C,MAAM,CAAC,SAAS,GAAG,iBAAiB,QAAQ,EAAE,CAAC;MAC/C,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;MACtC,MAAM,CAAC,YAAY,CACf,YAAY,EACZ,SAAS,CAAC,GAAG,CAAC,iCAAiC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAClE,CAAC;MACF,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;MACrC,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;MAC3D,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;MACtE,MAAM,CAAC,YAAY,CAAC,gBAAgB,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,SAAS,CAAC,CAAC;MACxE,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;MAE7C,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAe,EAAE,EAAE;QACvD,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;MACpC,CAAC,CAAC,CAAC;MAEH,OAAO,MAAM,CAAC;IAClB,CAAC,CAAC;IAEM,kBAAa,GAAG,CACpB,KAAmB,EACnB,QAAqC,EACvC,EAAE;MACA,KAAK,CAAC,cAAc,EAAE,CAAC;MACvB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB,CAAC;MAE3C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC;MAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;MAExC,MAAM,aAAa,GAAG,CAAC,CAAe,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC;QACjC,MAAM,UAAU,GAAG,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;QAE9D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,QAAQ,IAAI,CAAC;QAEvC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;QAC5D,OAAO,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;UAC7B,YAAY,CAAC,YAAY,CAAC,eAAe,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;UAChE,YAAY,CAAC,YAAY,CACrB,gBAAgB,EAChB,GAAG,QAAQ,SAAS,CACvB,CAAC;QACN,CAAC,CAAC,CAAC;MACP,CAAC,CAAC;MAEF,MAAM,WAAW,GAAG,GAAG,EAAE;QACrB,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QACzD,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACrD,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QAE7C,IAAI,CAAC,iBAAiB,EAAE,CAAC;MAC7B,CAAC,CAAC;MAEF,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;MACtD,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACtD,CAAC,CAAC;IAEM,uBAAkB,GAAG,GAAG,EAAE;MAC9B,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;MAC7C,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;MAC3C,IAAI,CAAC,GAAG,CAAC,YAAY,CACjB,YAAY,EACZ,SAAS,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,QAAQ,EAAE;QACtD,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,MAAM;OAC1C,CAAC,CACL,CAAC;MAEF,MAAM,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC;MACvE,cAAc,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;MACrD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACzC,CAAC,CAAC;IAEM,uBAAkB,GAAG,GAAG,EAAE;MAC9B,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;MAC7C,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;MAC5C,IAAI,CAAC,GAAG,CAAC,YAAY,CACjB,YAAY,EACZ,SAAS,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,QAAQ,EAAE;QACtD,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,MAAM;OAC1C,CAAC,CACL,CAAC;MAEF,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;MAClE,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;MAE1D,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;MACxC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC,CAAC;IAEM,sBAAiB,GAAG,GAAG,EAAE;MAC7B,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;MAChD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;MAC5C,IAAI,CAAC,GAAG,CAAC,YAAY,CACjB,YAAY,EACZ,SAAS,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,CAAC,QAAQ,EAAE;QACrD,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,MAAM;OAC1C,CAAC,CACL,CAAC;IACN,CAAC,CAAC;IAEM,yBAAoB,GAAG,GAAG,EAAE;MAChC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9C,IAAI,CAAC,CAAC,KAAK,YAAY,gBAAgB,CAAC,EAAE;UACtC,KAAK,CAAC,MAAM,EAAE,CAAC;SAClB;MACL,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEM,4BAAuB,GAAG,GAAG,EAAE;;MACnC,IAAI,CAAC,oBAAoB,EAAE,CAAC;MAC5B,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,uBAAuB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;MAEpE,MAAM,aAAa,GAAyC;QACxD,OAAO,EAAE,IAAI,CAAC,kBAAkB;QAChC,OAAO,EAAE,IAAI,CAAC,kBAAkB;QAChC,MAAM,EAAE,IAAI,CAAC,iBAAiB;OACjC,CAAC;MAEF,MAAM,KAAK,GAAqB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;MACtD,MAAA,aAAa,CAAC,KAAK,CAAC,6DAAI,CAAC;IAC7B,CAAC,CAAC;IAEM,sCAAiC,GAAG,CAAC,OAAa,EAAW,EAAE;MACnE,OAAO,CACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS;QACnC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CACpC,CAAC;IACN,CAAC,CAAC;IArKE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAEzB,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,uBAAuB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAE/D,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAC9B,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEjC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;MACnB,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC7B,CAAC,CAAC;IAEF,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE/B,IAAI,CAAC,uBAAuB,EAAE,CAAC;EACnC,CAAC;EAEO,iBAAiB;IACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,CACd,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,kCAClD,IAAI,CAAC,IAAI,CAAC,KAAK,KAClB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,EACpC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,EAClC,SAAS,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,EACvC,QAAQ,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,IACvC,CACL,CAAC;EACN,CAAC;EAuID,qEAAqE;EACrE,gEAAgE;EACzD,MAAM,CAAC,IAAU;IACpB,IAAI,CAAC,IAAI,CAAC,iCAAiC,CAAC,IAAI,CAAC,EAAE;MAC/C,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;MAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;MAC9B,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;KACpC;IAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,uBAAuB,EAAE,CAAC;IAE/B,OAAO,IAAI,CAAC;EAChB,CAAC;CACJ","sourcesContent":["import { EditorView, NodeView } from 'prosemirror-view';\nimport { Node } from 'prosemirror-model';\nimport { Plugin } from 'prosemirror-state';\nimport { EditorImageState } from '../../../text-editor.types';\nimport translate from '../../../../../global/translations';\nimport { Languages } from '../../../../date-picker/date.types';\nimport { applyImageStyles } from './node';\n\nconst MIN_WIDTH = 10;\n\nexport const createImageViewPlugin = (language: Languages) => {\n return new Plugin({\n props: {\n nodeViews: {\n image: (node, view, getPos) => {\n return new ImageView(node, view, getPos, language);\n },\n },\n },\n });\n};\n\nclass ImageView implements NodeView {\n node: Node;\n view: EditorView;\n getPos: () => number;\n dom: HTMLDivElement;\n img: HTMLImageElement;\n language: Languages;\n\n public constructor(\n node: Node,\n view: EditorView,\n getPos: () => number,\n language: Languages,\n ) {\n this.node = node;\n this.view = view;\n this.getPos = getPos;\n this.language = language;\n\n this.dom = document.createElement('div');\n this.dom.className = `image-wrapper state-${node.attrs.state}`;\n\n this.img = document.createElement('img');\n this.img.src = node.attrs.src;\n this.img.alt = node.attrs.alt;\n applyImageStyles(this.img, node);\n\n this.img.onload = () => {\n this.persistDimensions();\n };\n\n this.dom.appendChild(this.img);\n\n this.transitionBetweenStates();\n }\n\n private persistDimensions() {\n this.view.dispatch(\n this.view.state.tr.setNodeMarkup(this.getPos(), undefined, {\n ...this.node.attrs,\n height: `${this.img.offsetHeight}px`,\n width: `${this.img.offsetWidth}px`,\n minHeight: `${this.img.offsetHeight}px`,\n minWidth: `${this.img.offsetWidth}px`,\n }),\n );\n }\n\n private createResizeHandle = (position: 'bottom-right' | 'top-left') => {\n const handle = document.createElement('div');\n handle.className = `resize-handle ${position}`;\n handle.setAttribute('role', 'slider');\n handle.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.resize-handle', this.language),\n );\n handle.setAttribute('tabindex', '0');\n handle.setAttribute('aria-valuemin', MIN_WIDTH.toString());\n handle.setAttribute('aria-valuenow', this.img.offsetWidth.toString());\n handle.setAttribute('aria-valuetext', `${this.img.offsetWidth} pixels`);\n handle.setAttribute('aria-grabbed', 'false');\n\n handle.addEventListener('pointerdown', (e: PointerEvent) => {\n handle.setAttribute('aria-grabbed', 'true');\n this.onResizeStart(e, position);\n });\n\n return handle;\n };\n\n private onResizeStart = (\n event: PointerEvent,\n position: 'bottom-right' | 'top-left',\n ) => {\n event.preventDefault();\n const handle = event.target as HTMLElement;\n\n const startX = event.clientX;\n const startWidth = this.img.offsetWidth;\n\n const onPointerMove = (e: PointerEvent) => {\n const delta = e.clientX - startX;\n const widthDelta = position === 'top-left' ? -delta : delta;\n const newWidth = Math.max(MIN_WIDTH, startWidth + widthDelta);\n\n this.img.style.width = `${newWidth}px`;\n\n const handles = this.dom.querySelectorAll('.resize-handle');\n handles.forEach((resizeHandle) => {\n resizeHandle.setAttribute('aria-valuenow', newWidth.toString());\n resizeHandle.setAttribute(\n 'aria-valuetext',\n `${newWidth} pixels`,\n );\n });\n };\n\n const onPointerUp = () => {\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n handle.setAttribute('aria-grabbed', 'false');\n\n this.persistDimensions();\n };\n\n window.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUp);\n };\n\n private createLoadingState = () => {\n this.dom.setAttribute('aria-live', 'polite');\n this.dom.setAttribute('aria-busy', 'true');\n this.dom.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.loading', this.language, {\n filename: this.node.attrs.alt || 'file',\n }),\n );\n\n const spinnerElement = document.createElement('limel-linear-progress');\n spinnerElement.setAttribute('indeterminate', 'true');\n this.dom.appendChild(spinnerElement);\n };\n\n private createSuccessState = () => {\n this.dom.setAttribute('aria-live', 'polite');\n this.dom.setAttribute('aria-busy', 'false');\n this.dom.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.success', this.language, {\n filename: this.node.attrs.alt || 'file',\n }),\n );\n\n const bottomRightHandle = this.createResizeHandle('bottom-right');\n const topLeftHandle = this.createResizeHandle('top-left');\n\n this.dom.appendChild(bottomRightHandle);\n this.dom.appendChild(topLeftHandle);\n };\n\n private createFailedState = () => {\n this.dom.setAttribute('aria-live', 'assertive');\n this.dom.setAttribute('aria-busy', 'false');\n this.dom.setAttribute(\n 'aria-label',\n translate.get('editor-image-view.failed', this.language, {\n filename: this.node.attrs.alt || 'file',\n }),\n );\n };\n\n private cleanUpPreviousState = () => {\n Array.from(this.dom.childNodes).forEach((child) => {\n if (!(child instanceof HTMLImageElement)) {\n child.remove();\n }\n });\n };\n\n private transitionBetweenStates = () => {\n this.cleanUpPreviousState();\n this.dom.className = `image-wrapper state-${this.node.attrs.state}`;\n\n const stateHandlers: Record<EditorImageState, () => void> = {\n loading: this.createLoadingState,\n success: this.createSuccessState,\n failed: this.createFailedState,\n };\n\n const state: EditorImageState = this.node.attrs.state;\n stateHandlers[state]?.();\n };\n\n private transitioningBetweenSuccessStates = (newNode: Node): boolean => {\n return (\n this.node.attrs.state === 'success' &&\n newNode.attrs.state === 'success'\n );\n };\n\n // Ensure that the existing NodeView is reused rather than recreated.\n // Recreating the NodeView will cause flickering between states.\n public update(node: Node): boolean {\n if (!this.transitioningBetweenSuccessStates(node)) {\n this.img.src = node.attrs.src;\n this.img.alt = node.attrs.alt;\n applyImageStyles(this.img, node);\n }\n\n this.node = node;\n this.transitionBetweenStates();\n\n return true;\n }\n}\n"]}
|