@limetech/lime-elements 38.11.0 → 38.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/index.cjs.js +0 -9
  3. package/dist/cjs/index.cjs.js.map +1 -1
  4. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +209 -111
  5. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
  6. package/dist/cjs/limel-snackbar.cjs.entry.js.map +1 -1
  7. package/dist/cjs/limel-text-editor.cjs.entry.js +7 -1
  8. package/dist/cjs/limel-text-editor.cjs.entry.js.map +1 -1
  9. package/dist/collection/components/snackbar/snackbar.js +1 -1
  10. package/dist/collection/components/snackbar/snackbar.js.map +1 -1
  11. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-items.js.map +1 -1
  12. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js +15 -54
  13. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js.map +1 -1
  14. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js +52 -44
  15. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js.map +1 -1
  16. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js +11 -13
  17. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js.map +1 -1
  18. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link-plugin.js.map +1 -1
  19. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/append-transaction-handler.js.map +1 -1
  20. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/detect-trigger-removal.js.map +1 -1
  21. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/get-trigger-event-detail.js.map +1 -1
  22. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/monitor-triggered-text.js.map +1 -1
  23. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/send-trigger-event.js.map +1 -1
  24. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/text-input-handler.js.map +1 -1
  25. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory.js.map +1 -1
  26. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/inserter.js.map +1 -1
  27. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +54 -8
  28. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js.map +1 -1
  29. package/dist/collection/components/text-editor/text-editor.js +38 -4
  30. package/dist/collection/components/text-editor/text-editor.js.map +1 -1
  31. package/dist/collection/components/text-editor/text-editor.types.js +1 -9
  32. package/dist/collection/components/text-editor/text-editor.types.js.map +1 -1
  33. package/dist/collection/components/text-editor/utils/metadata-utils.js +108 -0
  34. package/dist/collection/components/text-editor/utils/metadata-utils.js.map +1 -0
  35. package/dist/esm/index.js +0 -2
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/limel-prosemirror-adapter.entry.js +209 -111
  38. package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
  39. package/dist/esm/limel-snackbar.entry.js.map +1 -1
  40. package/dist/esm/limel-text-editor.entry.js +7 -1
  41. package/dist/esm/limel-text-editor.entry.js.map +1 -1
  42. package/dist/lime-elements/index.esm.js +1 -1
  43. package/dist/lime-elements/index.esm.js.map +1 -1
  44. package/dist/lime-elements/lime-elements.esm.js +1 -1
  45. package/dist/lime-elements/p-3a87b175.entry.js.map +1 -1
  46. package/dist/lime-elements/p-7b039dab.entry.js +2 -0
  47. package/dist/lime-elements/p-7b039dab.entry.js.map +1 -0
  48. package/dist/lime-elements/{p-033fa919.entry.js → p-7f3045bd.entry.js} +2 -2
  49. package/dist/lime-elements/p-7f3045bd.entry.js.map +1 -0
  50. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-items.d.ts +2 -2
  51. package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/inserter.d.ts +2 -7
  52. package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/node.d.ts +9 -0
  53. package/dist/types/components/text-editor/prosemirror-adapter/plugins/link-plugin.d.ts +0 -4
  54. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/append-transaction-handler.d.ts +1 -1
  55. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/detect-trigger-removal.d.ts +1 -1
  56. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/get-trigger-event-detail.d.ts +2 -2
  57. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/monitor-triggered-text.d.ts +2 -2
  58. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/send-trigger-event.d.ts +1 -1
  59. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/text-input-handler.d.ts +1 -1
  60. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory.d.ts +1 -1
  61. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/inserter.d.ts +1 -1
  62. package/dist/types/components/text-editor/prosemirror-adapter/prosemirror-adapter.d.ts +10 -0
  63. package/dist/types/components/text-editor/text-editor.d.ts +10 -0
  64. package/dist/types/components/text-editor/text-editor.types.d.ts +32 -7
  65. package/dist/types/components/text-editor/utils/metadata-utils.d.ts +22 -0
  66. package/dist/types/components.d.ts +17 -4
  67. package/package.json +1 -1
  68. package/dist/cjs/text-editor.types-5e5567e2.js +0 -13
  69. package/dist/cjs/text-editor.types-5e5567e2.js.map +0 -1
  70. package/dist/esm/text-editor.types-e82469d1.js +0 -13
  71. package/dist/esm/text-editor.types-e82469d1.js.map +0 -1
  72. package/dist/lime-elements/p-033fa919.entry.js.map +0 -1
  73. package/dist/lime-elements/p-7006fafe.entry.js +0 -2
  74. package/dist/lime-elements/p-7006fafe.entry.js.map +0 -1
  75. package/dist/lime-elements/p-9ca516ed.js +0 -2
  76. package/dist/lime-elements/p-9ca516ed.js.map +0 -1
@@ -13,7 +13,6 @@ const _getPrototype = require('./_getPrototype-18d2118e.js');
13
13
  const isArray = require('./isArray-d188a04f.js');
14
14
  const isObjectLike = require('./isObjectLike-3e3f0cba.js');
15
15
  const markdownParser = require('./markdown-parser-89b425cf.js');
16
- const textEditor_types = require('./text-editor.types-5e5567e2.js');
17
16
  const translations = require('./translations-1d376e48.js');
18
17
  const randomString = require('./random-string-e8ad4419.js');
19
18
  const isItem = require('./isItem-3f8ad629.js');
@@ -25933,39 +25932,38 @@ function hasImageNode(node) {
25933
25932
  return false;
25934
25933
  }
25935
25934
  function createImageNodeMarkdownSerializer(language) {
25936
- return (state, node) => {
25937
- if (node.attrs.state === textEditor_types.ImageState.FAILED) {
25938
- const text = translations.translate.get('editor-image-view.failed', language, {
25939
- filename: node.attrs.alt || 'file',
25940
- });
25941
- state.write(`<span>${text}</span>`);
25935
+ return (markdownSerializerState, node) => {
25936
+ const { state, alt, src, width, maxWidth } = node.attrs;
25937
+ if (!isEditorImageState(state)) {
25942
25938
  return;
25943
25939
  }
25944
- else if (node.attrs.state === textEditor_types.ImageState.LOADING) {
25945
- const text = translations.translate.get('editor-image-view.loading', language, {
25946
- filename: node.attrs.alt || 'file',
25947
- });
25948
- state.write(`<span>${text}</span>`);
25940
+ if (state === 'success') {
25941
+ const imageHTML = getImageHTML(src, alt, width, maxWidth);
25942
+ markdownSerializerState.write(imageHTML);
25949
25943
  return;
25950
25944
  }
25951
- let imageHTML = `<img src="${node.attrs.src}"`;
25952
- if (node.attrs.alt) {
25953
- imageHTML += ` alt="${node.attrs.alt}"`;
25954
- }
25955
- const style = [];
25956
- if (node.attrs.width) {
25957
- style.push(`width: ${node.attrs.width};`);
25958
- }
25959
- if (node.attrs.maxWidth) {
25960
- style.push(`max-width: ${node.attrs.maxWidth};`);
25961
- }
25962
- if (style.length > 0) {
25963
- imageHTML += ` style="${style.join(' ')}"`;
25964
- }
25965
- imageHTML += ' />';
25966
- state.write(imageHTML);
25945
+ const statusHTML = getStatusHTML(state, alt, language);
25946
+ markdownSerializerState.write(statusHTML);
25967
25947
  };
25968
25948
  }
25949
+ function getStatusHTML(state, alt, language) {
25950
+ const key = state === 'failed' ? 'failed' : 'loading';
25951
+ const text = translations.translate.get(`editor-image-view.${key}`, language, {
25952
+ filename: alt || 'file',
25953
+ });
25954
+ return `<span>${text}</span>`;
25955
+ }
25956
+ function getImageHTML(src, alt, width, maxWidth) {
25957
+ const style = [];
25958
+ if (width) {
25959
+ style.push(`width: ${width};`);
25960
+ }
25961
+ if (maxWidth) {
25962
+ style.push(`max-width: ${maxWidth};`);
25963
+ }
25964
+ const styleAttribute = style.length > 0 ? ` style="${style.join(' ')}"` : '';
25965
+ return `<img src="${src}" alt="${alt}"${styleAttribute} />`;
25966
+ }
25969
25967
  function createImageNodeSpec(language) {
25970
25968
  return {
25971
25969
  group: 'inline',
@@ -25976,24 +25974,16 @@ function createImageNodeSpec(language) {
25976
25974
  fileInfoId: { default: '' },
25977
25975
  width: { default: '' },
25978
25976
  maxWidth: { default: '100%' },
25979
- state: { default: '' },
25977
+ state: { default: 'success' },
25980
25978
  },
25981
25979
  toDOM: (node) => {
25982
- if (node.attrs.state === textEditor_types.ImageState.FAILED) {
25983
- return createStatusSpan('failed', node, language);
25984
- }
25985
- else if (node.attrs.state === textEditor_types.ImageState.LOADING) {
25986
- return createStatusSpan('loading', node, language);
25987
- }
25988
- let img = imageCache.get(node.attrs.fileInfoId);
25989
- if (img) {
25990
- updateImageElement(img, node);
25980
+ if (!isEditorImageState(node.attrs.state)) {
25981
+ return;
25991
25982
  }
25992
- else {
25993
- img = createImageElement(node);
25994
- imageCache.set(node.attrs.fileInfoId, img);
25983
+ if (node.attrs.state === 'success') {
25984
+ return getOrCreateImageElement(node.attrs.fileInfoId, node);
25995
25985
  }
25996
- return img;
25986
+ return createStatusSpanForState(node.attrs.state, node, language);
25997
25987
  },
25998
25988
  parseDOM: [
25999
25989
  {
@@ -26004,7 +25994,7 @@ function createImageNodeSpec(language) {
26004
25994
  alt: dom.getAttribute('alt') || 'file',
26005
25995
  width: dom.style.width || '',
26006
25996
  maxWidth: '100%',
26007
- state: textEditor_types.ImageState.SUCCESS,
25997
+ state: 'success',
26008
25998
  fileInfoId: crypto.randomUUID(),
26009
25999
  };
26010
26000
  },
@@ -26012,6 +26002,24 @@ function createImageNodeSpec(language) {
26012
26002
  ],
26013
26003
  };
26014
26004
  }
26005
+ function isEditorImageState(state) {
26006
+ return state === 'loading' || state === 'failed' || state === 'success';
26007
+ }
26008
+ function getOrCreateImageElement(fileInfoId, node) {
26009
+ let img = imageCache.get(fileInfoId);
26010
+ if (img) {
26011
+ updateImageElement(img, node);
26012
+ }
26013
+ else {
26014
+ img = createImageElement(node);
26015
+ imageCache.set(fileInfoId, img);
26016
+ }
26017
+ return img;
26018
+ }
26019
+ function createStatusSpanForState(state, node, language) {
26020
+ const statusKey = state === 'failed' ? 'failed' : 'loading';
26021
+ return createStatusSpan(statusKey, node, language);
26022
+ }
26015
26023
  function createStatusSpan(key, node, language) {
26016
26024
  const text = translations.translate.get(`editor-image-view.${key}`, language, {
26017
26025
  filename: node.attrs.alt || 'file',
@@ -26303,7 +26311,7 @@ const createLinkPlugin = (updateLinkCallback) => {
26303
26311
  };
26304
26312
 
26305
26313
  const pluginKey = new PluginKey('imageInserterPlugin');
26306
- const createImageInserterPlugin = (imagePastedCallback, imageRemovedCallback) => {
26314
+ const createImageInserterPlugin = (imagePastedCallback) => {
26307
26315
  return new Plugin({
26308
26316
  key: pluginKey,
26309
26317
  props: {
@@ -26316,40 +26324,7 @@ const createImageInserterPlugin = (imagePastedCallback, imageRemovedCallback) =>
26316
26324
  },
26317
26325
  },
26318
26326
  },
26319
- state: {
26320
- init: () => {
26321
- return { insertedImages: {} };
26322
- },
26323
- apply: (tr, pluginState) => {
26324
- const newState = Object.assign({}, pluginState);
26325
- newState.insertedImages = getImagesFromTransaction(tr);
26326
- findAndHandleRemovedImages(imageRemovedCallback, pluginState.insertedImages, newState.insertedImages);
26327
- return newState;
26328
- },
26329
- },
26330
- });
26331
- };
26332
- const getImagesFromTransaction = (tr) => {
26333
- const images = {};
26334
- tr.doc.descendants((node) => {
26335
- if (node.type.name === 'image') {
26336
- images[node.attrs.fileInfoId] = node;
26337
- }
26338
26327
  });
26339
- return images;
26340
- };
26341
- const findAndHandleRemovedImages = (imageRemovedCallback, previousImages, newImages) => {
26342
- const removedKeys = Object.keys(previousImages).filter((key) => !(key in newImages));
26343
- for (const removedKey of removedKeys) {
26344
- const removedImage = previousImages[removedKey];
26345
- const imageInfo = {
26346
- fileInfoId: removedImage.attrs.fileInfoId,
26347
- src: removedImage.attrs.src,
26348
- state: removedImage.attrs.state,
26349
- };
26350
- imageRemovedCallback(imageInfo);
26351
- imageCache.delete(removedImage.attrs.fileInfoId);
26352
- }
26353
26328
  };
26354
26329
  const imageInserterFactory = (view, base64Data, fileInfo) => {
26355
26330
  return {
@@ -26362,12 +26337,8 @@ const imageInserterFactory = (view, base64Data, fileInfo) => {
26362
26337
  const createThumbnailInserter = (view, base64Data, fileInfo) => () => {
26363
26338
  const { state, dispatch } = view;
26364
26339
  const { schema } = state;
26365
- const placeholderNode = schema.nodes.image.create({
26366
- src: base64Data,
26367
- alt: fileInfo.filename,
26368
- fileInfoId: fileInfo.id,
26369
- state: textEditor_types.ImageState.LOADING,
26370
- });
26340
+ const imageNodeAttrs = createImageNodeAttrs(base64Data, fileInfo, 'loading');
26341
+ const placeholderNode = schema.nodes.image.create(imageNodeAttrs);
26371
26342
  const transaction = state.tr.replaceSelectionWith(placeholderNode);
26372
26343
  dispatch(transaction);
26373
26344
  };
@@ -26377,12 +26348,8 @@ const createImageInserter = (view, fileInfo) => (src) => {
26377
26348
  const tr = state.tr;
26378
26349
  state.doc.descendants((node, pos) => {
26379
26350
  if (node.attrs.fileInfoId === fileInfo.id) {
26380
- const imageNode = schema.nodes.image.create({
26381
- src: src ? src : node.attrs.src,
26382
- alt: fileInfo.filename,
26383
- fileInfoId: fileInfo.id,
26384
- state: textEditor_types.ImageState.SUCCESS,
26385
- });
26351
+ const imageNodeAttrs = createImageNodeAttrs(src ? src : node.attrs.src, fileInfo, 'success');
26352
+ const imageNode = schema.nodes.image.create(imageNodeAttrs);
26386
26353
  tr.replaceWith(pos, pos + node.nodeSize, imageNode);
26387
26354
  return false;
26388
26355
  }
@@ -26395,31 +26362,35 @@ const createFailedThumbnailInserter = (view, fileInfo) => () => {
26395
26362
  const tr = state.tr;
26396
26363
  state.doc.descendants((node, pos) => {
26397
26364
  if (node.attrs.fileInfoId === fileInfo.id) {
26398
- const errorPlaceholderNode = schema.nodes.image.create({
26399
- src: node.attrs.src,
26400
- alt: fileInfo.filename,
26401
- fileInfoId: fileInfo.id,
26402
- state: textEditor_types.ImageState.FAILED,
26403
- });
26365
+ const imageNodeAttrs = createImageNodeAttrs(node.attrs.src, fileInfo, 'failed');
26366
+ const errorPlaceholderNode = schema.nodes.image.create(imageNodeAttrs);
26404
26367
  tr.replaceWith(pos, pos + node.nodeSize, errorPlaceholderNode);
26405
26368
  return false;
26406
26369
  }
26407
26370
  });
26408
26371
  dispatch(tr);
26409
26372
  };
26373
+ function createImageNodeAttrs(src, fileInfo, state) {
26374
+ return {
26375
+ src: src,
26376
+ alt: fileInfo.filename,
26377
+ fileInfoId: fileInfo.id,
26378
+ state: state,
26379
+ };
26380
+ }
26410
26381
  /**
26411
26382
  * Check if a given ProseMirror node or fragment contains any image nodes.
26412
26383
  * @param node - The ProseMirror node or fragment to check.
26413
26384
  * @returns A boolean indicating whether the node contains any image nodes.
26414
26385
  */
26415
- const isImageNode = (node) => {
26386
+ const isImageNode$1 = (node) => {
26416
26387
  if (node instanceof Node$1) {
26417
26388
  if (node.type.name === 'image') {
26418
26389
  return true;
26419
26390
  }
26420
26391
  let found = false;
26421
26392
  node.content.forEach((child) => {
26422
- if (isImageNode(child)) {
26393
+ if (isImageNode$1(child)) {
26423
26394
  found = true;
26424
26395
  }
26425
26396
  });
@@ -26428,7 +26399,7 @@ const isImageNode = (node) => {
26428
26399
  else if (node instanceof Fragment) {
26429
26400
  let found = false;
26430
26401
  node.forEach((child) => {
26431
- if (isImageNode(child)) {
26402
+ if (isImageNode$1(child)) {
26432
26403
  found = true;
26433
26404
  }
26434
26405
  });
@@ -26444,7 +26415,7 @@ const isImageNode = (node) => {
26444
26415
  const filterImageNodes = (fragment) => {
26445
26416
  const filteredChildren = [];
26446
26417
  fragment.forEach((child) => {
26447
- if (!isImageNode(child)) {
26418
+ if (!isImageNode$1(child)) {
26448
26419
  if (child.content.size > 0) {
26449
26420
  const filteredContent = filterImageNodes(child.content);
26450
26421
  const newNode = child.copy(filteredContent);
@@ -26583,21 +26554,20 @@ class ImageView {
26583
26554
  });
26584
26555
  };
26585
26556
  this.transitionBetweenStates = () => {
26557
+ var _a;
26586
26558
  this.cleanUpPreviousState();
26587
26559
  this.dom.className = `image-wrapper state-${this.node.attrs.state}`;
26588
- if (this.node.attrs.state === textEditor_types.ImageState.LOADING) {
26589
- this.createLoadingState();
26590
- }
26591
- else if (this.node.attrs.state === textEditor_types.ImageState.SUCCESS) {
26592
- this.createSuccessState();
26593
- }
26594
- else if (this.node.attrs.state === textEditor_types.ImageState.FAILED) {
26595
- this.createFailedState();
26596
- }
26560
+ const stateHandlers = {
26561
+ loading: this.createLoadingState,
26562
+ success: this.createSuccessState,
26563
+ failed: this.createFailedState,
26564
+ };
26565
+ const state = this.node.attrs.state;
26566
+ (_a = stateHandlers[state]) === null || _a === void 0 ? void 0 : _a.call(stateHandlers);
26597
26567
  };
26598
26568
  this.transitioningBetweenSuccessStates = (newNode) => {
26599
- return (this.node.attrs.state === textEditor_types.ImageState.SUCCESS &&
26600
- newNode.attrs.state === textEditor_types.ImageState.SUCCESS);
26569
+ return (this.node.attrs.state === 'success' &&
26570
+ newNode.attrs.state === 'success');
26601
26571
  };
26602
26572
  this.node = node;
26603
26573
  this.view = view;
@@ -28320,6 +28290,114 @@ const getTableNodes = () => {
28320
28290
  });
28321
28291
  };
28322
28292
 
28293
+ /**
28294
+ * Extracts metadata from a ProseMirror document node
28295
+ *
28296
+ * This function traverses the entire document tree and collects information about
28297
+ * special elements like images and links.
28298
+ *
28299
+ * @param doc - The ProseMirror document node to extract metadata from
28300
+ * @returns A metadata object containing arrays of images and links found in the document
28301
+ */
28302
+ function getMetadataFromDoc(doc) {
28303
+ const metadata = { images: [], links: [] };
28304
+ doc.descendants((node) => {
28305
+ if (isImageNode(node)) {
28306
+ metadata.images.push(extractImageMetadata(node));
28307
+ }
28308
+ else if (isTextNodeWithMarks(node)) {
28309
+ extractLinkMetadata(node).forEach((link) => metadata.links.push(link));
28310
+ }
28311
+ return true;
28312
+ });
28313
+ return metadata;
28314
+ }
28315
+ function isImageNode(node) {
28316
+ return node.type.name === 'image' && !!node.attrs;
28317
+ }
28318
+ function extractImageMetadata(node) {
28319
+ return {
28320
+ src: node.attrs.src,
28321
+ state: node.attrs.state,
28322
+ fileInfoId: node.attrs.fileInfoId,
28323
+ };
28324
+ }
28325
+ function isTextNodeWithMarks(node) {
28326
+ var _a;
28327
+ return node.isText && ((_a = node.marks) === null || _a === void 0 ? void 0 : _a.length) > 0;
28328
+ }
28329
+ function extractLinkMetadata(node) {
28330
+ return node.marks
28331
+ .filter((mark) => mark.type.name === 'link' && mark.attrs)
28332
+ .map((mark) => ({
28333
+ href: mark.attrs.href,
28334
+ text: node.text,
28335
+ }));
28336
+ }
28337
+ /**
28338
+ * Determines if metadata has changed between two states
28339
+ * Handles duplicates correctly but is order-insensitive
28340
+ *
28341
+ * @param oldMetadata - The previous metadata state to compare against
28342
+ * @param newMetadata - The current metadata state
28343
+ * @returns True if there are any differences between the metadata objects, false otherwise
28344
+ */
28345
+ function hasMetadataChanged(oldMetadata, newMetadata) {
28346
+ return (hasDifferentLengths(oldMetadata, newMetadata) ||
28347
+ hasDifferentLinks(oldMetadata.links, newMetadata.links) ||
28348
+ hasDifferentImages(oldMetadata.images, newMetadata.images));
28349
+ }
28350
+ function hasDifferentLengths(oldMetadata, newMetadata) {
28351
+ return (oldMetadata.images.length !== newMetadata.images.length ||
28352
+ oldMetadata.links.length !== newMetadata.links.length);
28353
+ }
28354
+ function hasDifferentLinks(oldLinks, newLinks) {
28355
+ const oldLinkCounts = getLinkFrequencyMap(oldLinks);
28356
+ const newLinkCounts = getLinkFrequencyMap(newLinks);
28357
+ return !areFrequencyMapsEqual(oldLinkCounts, newLinkCounts);
28358
+ }
28359
+ function hasDifferentImages(oldImages, newImages) {
28360
+ const oldImageCounts = getImageFrequencyMap(oldImages);
28361
+ const newImageCounts = getImageFrequencyMap(newImages);
28362
+ return !areFrequencyMapsEqual(oldImageCounts, newImageCounts);
28363
+ }
28364
+ /**
28365
+ * Creates a frequency map for images based on their key properties
28366
+ */
28367
+ function getImageFrequencyMap(images) {
28368
+ const countMap = new Map();
28369
+ images.forEach((image) => {
28370
+ const key = `${image.fileInfoId}|${image.state}|${image.src}`;
28371
+ countMap.set(key, (countMap.get(key) || 0) + 1);
28372
+ });
28373
+ return countMap;
28374
+ }
28375
+ /**
28376
+ * Creates a frequency map for links based on their key properties
28377
+ */
28378
+ function getLinkFrequencyMap(links) {
28379
+ const countMap = new Map();
28380
+ links.forEach((link) => {
28381
+ const key = `${link.href}|${link.text}`;
28382
+ countMap.set(key, (countMap.get(key) || 0) + 1);
28383
+ });
28384
+ return countMap;
28385
+ }
28386
+ /**
28387
+ * Compares two frequency maps for equality
28388
+ */
28389
+ function areFrequencyMapsEqual(map1, map2) {
28390
+ if (map1.size !== map2.size) {
28391
+ return false;
28392
+ }
28393
+ for (const [key, count] of map1.entries()) {
28394
+ if (map2.get(key) !== count) {
28395
+ return false;
28396
+ }
28397
+ }
28398
+ return true;
28399
+ }
28400
+
28323
28401
  const prosemirrorAdapterCss = "@charset \"UTF-8\";:host{--mdc-theme-primary:var(\n --lime-primary-color,\n rgb(var(--color-teal-default))\n );--mdc-theme-secondary:var(\n --lime-secondary-color,\n rgb(var(--contrast-1100))\n );--mdc-theme-on-primary:var(\n --lime-on-primary-color,\n rgb(var(--contrast-100))\n );--mdc-theme-on-secondary:var(\n --lime-on-secondary-color,\n rgb(var(--contrast-100))\n );--mdc-theme-text-disabled-on-background:var(\n --lime-text-disabled-on-background-color,\n rgba(var(--contrast-1700), 0.38)\n );--mdc-theme-text-primary-on-background:var(\n --lime-text-primary-on-background-color,\n rgba(var(--contrast-1700), 0.87)\n );--mdc-theme-text-secondary-on-background:var(\n --lime-text-secondary-on-background-color,\n rgba(var(--contrast-1700), 0.54)\n );--mdc-theme-error:var(\n --lime-error-background-color,\n rgb(var(--color-red-dark))\n );--lime-error-text-color:rgb(var(--color-red-darker));--mdc-theme-surface:var(\n --lime-surface-background-color,\n rgb(var(--contrast-100))\n );--mdc-theme-on-surface:var(\n --lime-on-surface-color,\n rgb(var(--contrast-1500))\n )}blockquote{position:relative;font-weight:100;font-size:0.875rem;max-width:100%;line-height:1.4;margin:0;padding:0.5rem 1.25rem;border-radius:0.05rem 0.75rem;background-color:rgb(var(--contrast-300))}blockquote:before,blockquote:after{position:absolute;font-size:2.75rem;opacity:0.4}blockquote:before{content:\"“\";left:0;top:-0.75rem}blockquote:after{content:\"”\";right:0;bottom:-2rem}:host(limel-markdown.truncate-paragraphs) p{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}p,li{font-size:0.875rem;word-break:break-word}a{word-break:break-all}p{margin-top:0;margin-bottom:0.5rem}p:only-child{margin-bottom:0}a{transition:color 0.2s ease;color:var(--markdown-hyperlink-color, rgb(var(--color-blue-dark)));text-decoration:none}a:hover{color:var(--markdown-hyperlink-color--hovered, rgb(var(--color-blue-default)))}hr{margin:1.75rem 0 2rem 0;border-width:0;border-top:1px solid rgb(var(--contrast-500))}dl{display:grid;grid-template-columns:1fr 2fr;grid-template-rows:1fr;margin-bottom:2rem;border:1px solid rgb(var(--contrast-400));border-radius:0.375rem;background-color:rgb(var(--contrast-200))}dl dt,dl dd{padding:0.375rem 0.5rem;font-size:0.875rem;margin:0}dl dt:nth-of-type(even),dl dd:nth-of-type(even){background-color:rgb(var(--contrast-300))}dl dt:first-child{border-top-left-radius:0.375rem}dl dt:last-child{border-bottom-left-radius:0.375rem}dl dd:first-child{border-top-right-radius:0.375rem}dl dd:last-child{border-bottom-right-radius:0.375rem}h1{font-size:1.5rem}h2{font-size:1.25rem}h3{font-size:1.125rem}h4{font-size:1rem}h5{font-size:0.875rem}h6{font-size:0.75rem}h1,h2{margin-top:0.5rem;margin-bottom:0.5rem;letter-spacing:-0.03125rem;font-weight:500}h3,h4{margin-top:0.75rem;margin-bottom:0.25rem;font-weight:600}h5,h6{margin-top:0.5rem;margin-bottom:0.125rem;font-weight:600}h1,h2,h3,h4,h5,h6{word-break:break-word;hyphens:auto;-webkit-hyphens:auto}:not([contenteditable=true]) h1,:not([contenteditable=true]) h2,:not([contenteditable=true]) h3,:not([contenteditable=true]) h4,:not([contenteditable=true]) h5,:not([contenteditable=true]) h6{text-wrap:balance}[contenteditable=true] h1,[contenteditable=true] h2,[contenteditable=true] h3,[contenteditable=true] h4,[contenteditable=true] h5,[contenteditable=true] h6{text-wrap:initial}ul{list-style:none}ul li{position:relative;margin-left:0.75rem}ul li:before{content:\"\";position:absolute;left:-0.5rem;top:0.5rem;width:0.25rem;height:0.25rem;border-radius:50%;background-color:rgb(var(--contrast-700));display:block}ol{margin-top:0.25rem;padding-left:1rem}ul{margin-top:0.25rem;padding-left:0}ul ul,ul ol,ol ol,ol ul{margin-left:0}li{margin-bottom:0.25rem}code{font-family:ui-monospace, \"Cascadia Code\", \"Source Code Pro\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace;font-size:0.8125rem;letter-spacing:-0.0125rem;color:rgb(var(--contrast-1300));-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;display:inline-block;border-radius:0.25rem;padding:0.03125rem 0.25rem;background-color:rgb(var(--contrast-600))}pre>code{display:block;margin:0.5rem 0;padding:0.5rem 0.75rem;overflow:auto;white-space:pre-wrap}:host(limel-markdown:not(.no-table-styles)) table{table-layout:auto;min-width:100%;border-collapse:collapse;border-spacing:0;background:transparent;margin:0.75rem 0}:host(limel-markdown:not(.no-table-styles)) tbody{border:1px solid rgb(var(--contrast-400));border-radius:0.25rem}:host(limel-markdown:not(.no-table-styles)) th,:host(limel-markdown:not(.no-table-styles)) td{text-align:left;vertical-align:top;transition:background-color 0.2s ease;font-size:0.875rem}:host(limel-markdown:not(.no-table-styles)) td{padding:0.5rem 0.375rem 0.75rem 0.375rem}:host(limel-markdown:not(.no-table-styles)) tr th{background-color:rgb(var(--contrast-400));padding:0.25rem 0.375rem;font-weight:normal}:host(limel-markdown:not(.no-table-styles)) tr th:only-child{text-align:center}:host(limel-markdown:not(.no-table-styles)) tbody tr:nth-child(odd) td{background-color:rgb(var(--contrast-200))}:host(limel-markdown:not(.no-table-styles)) tbody tr:hover td{background-color:rgb(var(--contrast-300))}table{display:block;box-sizing:border-box;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}kbd{font-family:ui-monospace, \"Cascadia Code\", \"Source Code Pro\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace;font-weight:600;color:rgb(var(--contrast-1100));background-color:rgb(var(--contrast-200));white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:normal;padding:0.125rem 0.5rem;margin:0 0.25rem;box-shadow:var(--button-shadow-normal), 0 0.03125rem 0.21875rem 0 rgba(var(--contrast-100), 0.5) inset;border-radius:0.125rem;border-style:solid;border-color:rgba(var(--contrast-600), 0.8);border-width:0 1px 0.125rem 1px}img{max-width:100%;border-radius:0.25rem}.image-wrapper{display:inline-flex;position:relative}.image-wrapper limel-linear-progress{position:absolute;inset:0.25rem auto auto 0.25rem;width:calc(100% - 0.5rem)}.image-wrapper img{transition:opacity 0.2s ease, scale 0.6s ease}.image-wrapper.state-failed,.image-wrapper.state-loading{background:url(\"data:image/svg+xml;charset=utf-8, <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' style='fill-rule:evenodd;'><path fill='rgba(186,186,192,0.16)' d='M0 0h4v4H0zM4 4h4v4H4z'/></svg>\");background-size:0.5rem}.image-wrapper.state-failed img,.image-wrapper.state-loading img{opacity:0.3;scale:0.98}.image-wrapper::before{pointer-events:none;content:\"\";display:block;position:absolute;inset:0;border-radius:0.25rem;transition:border-color 0.4s ease, opacity 0.2s ease, box-shadow 0.6s ease;border:1px dashed transparent;opacity:0.2}.image-wrapper.state-failed img{filter:grayscale(0.8)}.image-wrapper.state-failed:before{opacity:0.8;box-shadow:var(--shadow-error-state)}.image-wrapper:hover::before{opacity:0.8;box-shadow:var(--shadow-depth-8)}.image-wrapper:has(.resize-handle[aria-grabbed=true])::before{border-color:var(--mdc-theme-primary);opacity:0.8;box-shadow:var(--shadow-depth-16), var(--shadow-depth-8)}.resize-handle{transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--mdc-theme-on-surface);background-color:rgb(var(--contrast-900));box-shadow:var(--button-shadow-normal);cursor:nwse-resize;position:absolute;display:flex;align-items:center;justify-content:center;width:0.5rem;height:0.5rem;border-radius:50%;opacity:0.6}.resize-handle:hover,.resize-handle:focus,.resize-handle:focus-visible{will-change:color, background-color, box-shadow, transform}.resize-handle:hover{transform:translate3d(0, -0.04rem, 0);color:var(--mdc-theme-on-surface);background-color:var(--lime-elevated-surface-background-color);box-shadow:var(--button-shadow-hovered)}.resize-handle:active{--limel-clickable-transform-timing-function:cubic-bezier(\n 0.83,\n -0.15,\n 0.49,\n 1.16\n );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}.resize-handle:hover,.resize-handle:active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}.resize-handle:focus{outline:none}.resize-handle:focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}.resize-handle.top-left{left:-0.25rem;top:-0.25rem;translate:-50%, -50%}.resize-handle.bottom-right{right:-0.25rem;bottom:-0.25rem;translate:50%, 50%}.resize-wrapper:has(.resize-handle[aria-grabbed=true]) .resize-handle,.resize-wrapper:hover .resize-handle,.resize-handle:hover,.resize-handle:focus-visible{opacity:1}.resize-handle[aria-grabbed=true],.resize-handle:hover,.resize-handle:focus-visible{opacity:1;background-color:var(--mdc-theme-primary)}.resize-handle:hover,.resize-handle[aria-grabbed=true]{scale:1.4}.resize-handle:hover:before,.resize-handle[aria-grabbed=true]:before{background-color:rgb(var(--color-white))}.resize-handle:before{content:\"\";display:block;position:absolute;inset:0;margin:auto;border-radius:50%;width:0.25rem;height:0.25rem;background-color:rgb(var(--contrast-100))}:host(limel-prosemirror-adapter){display:flex;flex-direction:column}:host(limel-prosemirror-adapter) .toolbar{order:1}:host(limel-prosemirror-adapter) div#editor{order:2;height:100%;flex-grow:1}:host(limel-prosemirror-adapter) div[contenteditable=true]{height:100%}*{box-sizing:border-box}:host(limel-prosemirror-adapter:hover) .toolbar,:host(limel-prosemirror-adapter:focus-within) .toolbar{will-change:grid-template-rows}:host(limel-prosemirror-adapter:hover) limel-action-bar,:host(limel-prosemirror-adapter:focus-within) limel-action-bar{will-change:opacity, padding}.ProseMirror-menubar-wrapper{display:grid;grid-template-rows:auto 1fr}.ProseMirror-textblock-dropdown{min-width:3em}.ProseMirror-tooltip .ProseMirror-menu{width:-webkit-fit-content;width:fit-content;white-space:pre}.toolbar{--action-bar-border-radius:0.25rem;border-radius:var(--action-bar-border-radius);flex-shrink:0;position:sticky;z-index:1;top:0;width:100%;display:grid;grid-template-rows:var(--limel-prosemirror-adapter-toolbar-grid-template-rows);transition-property:grid-template-rows;transition-duration:var(--limel-prosemirror-adapter-toolbar-grid-template-rows-transition-duration);transition-timing-function:var(--limel-prosemirror-adapter-toolbar-transition-timing-function);background-color:rgba(var(--contrast-200), 0.5);backdrop-filter:blur(0.5rem);-webkit-backdrop-filter:blur(0.5rem)}limel-action-bar{min-width:0;transition-property:padding, opacity;transition-duration:var(--limel-prosemirror-adapter-toolbar-grid-template-rows-transition-duration);transition-timing-function:var(--limel-prosemirror-adapter-toolbar-transition-timing-function);opacity:var(--limel-prosemirror-adapter-toolbar-opacity);padding:var(--limel-prosemirror-adapter-action-bar-padding-top-bottom, 0.125rem) 0.25rem;background-color:transparent;overflow:hidden}.ProseMirror{position:relative;word-wrap:break-word;white-space:pre-wrap;white-space:break-spaces;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-feature-settings:\"liga\" 0;padding:var(--limel-text-editor-padding)}.ProseMirror [draggable][contenteditable=false]{user-select:text}.ProseMirror:focus-visible{outline:none}.ProseMirror-hideselection{caret-color:transparent}.ProseMirror-hideselection *::selection{background:transparent}.ProseMirror-hideselection *::-moz-selection{background:transparent}.ProseMirror-selectednode{outline:0.125rem solid rgb(var(--color-sky-light))}li.ProseMirror-selectednode{outline:none}li.ProseMirror-selectednode:after{content:\"\";position:absolute;left:-2rem;right:-0.125rem;top:-0.125rem;bottom:-0.125rem;border:0.125rem solid rgb(var(--color-sky-light));pointer-events:none}img.ProseMirror-separator{display:inline !important;border:none !important;margin:0 !important}limel-portal{width:25rem}";
28324
28402
 
28325
28403
  const DEBOUNCE_TIMEOUT = 300;
@@ -28329,7 +28407,9 @@ const ProsemirrorAdapter = class {
28329
28407
  this.change = index.createEvent(this, "change", 7);
28330
28408
  this.imagePasted = index.createEvent(this, "imagePasted", 7);
28331
28409
  this.imageRemoved = index.createEvent(this, "imageRemoved", 7);
28410
+ this.metadataChange = index.createEvent(this, "metadataChange", 7);
28332
28411
  this.changeWaiting = false;
28412
+ this.metadata = { images: [], links: [] };
28333
28413
  /**
28334
28414
  * Used to stop change event emitting as result of getting updated value from consumer
28335
28415
  */
@@ -28366,6 +28446,8 @@ const ProsemirrorAdapter = class {
28366
28446
  if (content === this.lastEmittedValue) {
28367
28447
  return;
28368
28448
  }
28449
+ const metadata = getMetadataFromDoc(newState.doc);
28450
+ this.metadataEmitter(metadata);
28369
28451
  this.lastEmittedValue = content;
28370
28452
  this.changeWaiting = true;
28371
28453
  this.changeEmitter(content);
@@ -28557,7 +28639,7 @@ const ProsemirrorAdapter = class {
28557
28639
  keymap(this.menuCommandFactory.buildKeymap()),
28558
28640
  createTriggerPlugin(this.triggerCharacters, this.contentConverter),
28559
28641
  createLinkPlugin(this.handleNewLinkSelection),
28560
- createImageInserterPlugin(this.imagePasted.emit, this.imageRemoved.emit),
28642
+ createImageInserterPlugin(this.imagePasted.emit),
28561
28643
  createImageViewPlugin(this.language),
28562
28644
  createMenuStateTrackingPlugin(editorMenuTypesArray, this.menuCommandFactory, this.updateActiveActionBarItems),
28563
28645
  createActionBarInteractionPlugin(this.menuCommandFactory),
@@ -28575,8 +28657,24 @@ const ProsemirrorAdapter = class {
28575
28657
  const tr = this.view.state.tr;
28576
28658
  tr.replaceWith(0, tr.doc.content.size, prosemirrorDoc.content);
28577
28659
  this.view.dispatch(tr);
28660
+ const metadata = getMetadataFromDoc(this.view.state.doc);
28661
+ this.metadataEmitter(metadata);
28578
28662
  this.suppressChangeEvent = false;
28579
28663
  }
28664
+ metadataEmitter(metadata) {
28665
+ if (hasMetadataChanged(this.metadata, metadata)) {
28666
+ this.removeImagesFromCache(this.metadata, metadata);
28667
+ this.metadata = metadata;
28668
+ this.metadataChange.emit(metadata);
28669
+ }
28670
+ }
28671
+ removeImagesFromCache(oldMetadata, newMetadata) {
28672
+ const removedImages = oldMetadata.images.filter((oldImage) => !newMetadata.images.some((newImage) => newImage.fileInfoId === oldImage.fileInfoId));
28673
+ removedImages.forEach((image) => {
28674
+ imageCache.delete(image.fileInfoId);
28675
+ this.imageRemoved.emit(image);
28676
+ });
28677
+ }
28580
28678
  static get delegatesFocus() { return true; }
28581
28679
  get host() { return index.getElement(this); }
28582
28680
  static get watchers() { return {