@limetech/lime-elements 38.28.0 → 38.28.1

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 CHANGED
@@ -1,3 +1,15 @@
1
+ ## [38.28.1](https://github.com/Lundalogik/lime-elements/compare/v38.28.0...v38.28.1) (2025-10-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+
7
+ * **text editor:** add noopener/noreferrer for security ([7109ac8](https://github.com/Lundalogik/lime-elements/commit/7109ac86b57bb60c33c4366b489521e40292649f))
8
+ * **text editor:** guard against potential null destructuring ([c1d4d4f](https://github.com/Lundalogik/lime-elements/commit/c1d4d4fedf5197bbfc7554c9286a138d2ed880fe))
9
+ * **text editor:** mousedown handling should only return true once handled ([3a81f98](https://github.com/Lundalogik/lime-elements/commit/3a81f98d2af3d3f2ffba4a16aafde24183f2742d))
10
+ * **text editor:** only open popup to edit link on double click ([d78f408](https://github.com/Lundalogik/lime-elements/commit/d78f408fab30428a84559683a3e20d6eca65668c))
11
+ * **text editor:** preserve linebreaks when handling paste events ([80d1cde](https://github.com/Lundalogik/lime-elements/commit/80d1cde244c5586c8ae087ac65087913b0d07fdd))
12
+
1
13
  ## [38.28.0](https://github.com/Lundalogik/lime-elements/compare/v38.27.0...v38.28.0) (2025-10-07)
2
14
 
3
15
 
package/README.md CHANGED
@@ -23,6 +23,15 @@ Whether you're building from scratch or enhancing existing applications, Lime El
23
23
 
24
24
  Visit our [📚 **Documentation**](https://lundalogik.github.io/lime-elements/) for comprehensive guides and examples, or install directly from [📦 **NPM**](https://www.npmjs.com/package/@limetech/lime-elements).
25
25
 
26
+ ---
27
+
28
+ ### Recent Updates
29
+
30
+ - 🆕 **What's New:** Get an overview of the recent [most noteworthy updates and features](https://lundalogik.github.io/lime-elements/versions/latest/#/Home/updates.md/)
31
+ - 📋 **Changelog:** Check our [changelog](https://github.com/Lundalogik/lime-elements/blob/main/CHANGELOG.md) for detailed info about the new features, bug fixes, and design improvements
32
+
33
+ ---
34
+
26
35
  ### Project Status
27
36
 
28
37
  [![Version](https://img.shields.io/npm/v/@limetech/lime-elements.svg)](https://www.npmjs.com/package/@limetech/lime-elements) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![npm downloads](https://img.shields.io/npm/dt/@limetech/lime-elements.svg)](https://www.npmjs.com/package/@limetech/lime-elements)
@@ -138,7 +147,7 @@ Remember: All components can change, but `@beta` components change more often an
138
147
  - 💬 **Questions?** [create an issue](https://github.com/Lundalogik/lime-elements/issues/new?template=03_question.md)
139
148
  - 🐛 **Found a bug?** [Report it here](https://github.com/Lundalogik/lime-elements/issues/new?template=01_bug_report.md)
140
149
  - 💡 **Feature request?** [Share your ideas](https://github.com/Lundalogik/lime-elements/issues/new?template=02_feature_request.md)
141
- - 🆕 **What's new?** Check our [changelog](https://github.com/Lundalogik/lime-elements/blob/main/CHANGELOG.md) for the latest updates
150
+ - 🆕 **Changelog** Check our [changelog](https://github.com/Lundalogik/lime-elements/blob/main/CHANGELOG.md) for detailed info about the new features, bug fixes, and design improvements
142
151
 
143
152
  ---
144
153
 
@@ -26192,9 +26192,14 @@ const getLinkDataAtPosition = (view, event) => {
26192
26192
  return { href: href, text: text, from: from, to: to };
26193
26193
  };
26194
26194
  const processModClickEvent = (view, event) => {
26195
- const { href } = getLinkDataAtPosition(view, event);
26195
+ const linkData = getLinkDataAtPosition(view, event);
26196
+ if (!linkData.href) {
26197
+ return false;
26198
+ }
26199
+ event.preventDefault();
26200
+ const { href } = linkData;
26196
26201
  if (href) {
26197
- window.open(href, '_blank');
26202
+ window.open(href, '_blank', 'noopener,noreferrer');
26198
26203
  return true;
26199
26204
  }
26200
26205
  return false;
@@ -26207,32 +26212,21 @@ const openLinkMenu = (view, href, text) => {
26207
26212
  });
26208
26213
  view.dom.dispatchEvent(event);
26209
26214
  };
26210
- let lastClickTime = 0;
26211
- const DOUBLE_CLICK_DELAY = 200;
26212
- let clickTimeout;
26213
- const processClickEvent = (view, event) => {
26214
- const now = Date.now();
26215
- if (now - lastClickTime < DOUBLE_CLICK_DELAY) {
26216
- clearTimeout(clickTimeout);
26217
- lastClickTime = now; // Reset lastClickTime to prevent single-click action
26215
+ const processDoubleClickEvent = (view, event) => {
26216
+ const linkData = getLinkDataAtPosition(view, event);
26217
+ if (!linkData) {
26218
26218
  return false;
26219
26219
  }
26220
- lastClickTime = now;
26221
- clickTimeout = setTimeout(() => {
26222
- const linkData = getLinkDataAtPosition(view, event);
26223
- if (linkData) {
26224
- const { href, text, from, to } = linkData;
26225
- const transaction = view.state.tr.setSelection(TextSelection.create(view.state.doc, from, to));
26226
- view.dispatch(transaction);
26227
- openLinkMenu(view, href, text);
26228
- }
26229
- }, DOUBLE_CLICK_DELAY);
26220
+ const { href, text, from, to } = linkData;
26221
+ const transaction = view.state.tr.setSelection(TextSelection.create(view.state.doc, from, to));
26222
+ view.dispatch(transaction);
26223
+ openLinkMenu(view, href, text);
26230
26224
  return true;
26231
26225
  };
26232
26226
  /**
26233
- * Regular expression for matching URLs, mailto links, and phone links
26227
+ * Regular expression for matching URLs, mailto links, phone links, and bare www-links
26234
26228
  */
26235
- const URL_REGEX = /(https?:\/\/[^\s<>"']+|mailto:[^\s<>"']+|tel:[^\s<>"']+)/g;
26229
+ const URL_REGEX = /(https?:\/\/[^\s<>"']+|mailto:[^\s<>"']+|tel:[^\s<>"']+|www\.[^\s<>"']+)/g;
26236
26230
  /**
26237
26231
  * Checks if the text contains any URLs, mailto links, or phone links
26238
26232
  * @param text
@@ -26256,8 +26250,19 @@ const createTextNode = (schema, content) => {
26256
26250
  * @param url
26257
26251
  */
26258
26252
  const createLinkNode = (schema, url) => {
26259
- const linkMark = schema.marks.link.create(markdownParser.getLinkAttributes(url, url));
26260
- return schema.text(url, [linkMark]);
26253
+ const normalizeUrlForLinkMark = (input) => {
26254
+ let output = input.trim();
26255
+ while (output.endsWith('\\')) {
26256
+ output = output.slice(0, -1);
26257
+ }
26258
+ if (output.toLowerCase().startsWith('www.')) {
26259
+ output = `https://${output}`;
26260
+ }
26261
+ return output;
26262
+ };
26263
+ const normalizedUrl = normalizeUrlForLinkMark(url);
26264
+ const linkMark = schema.marks.link.create(markdownParser.getLinkAttributes(normalizedUrl, normalizedUrl));
26265
+ return schema.text(normalizedUrl, [linkMark]);
26261
26266
  };
26262
26267
  /**
26263
26268
  * Finds all link matches in the provided text
@@ -26277,6 +26282,36 @@ const findLinkMatches = (text) => {
26277
26282
  }
26278
26283
  return matches;
26279
26284
  };
26285
+ /**
26286
+ * Creates nodes for the pasted text while preserving soft line breaks.
26287
+ * - Each newline becomes a `hard_break`.
26288
+ * - Empty lines are preserved (consecutive newlines => multiple `hard_break`s).
26289
+ * - URLs inside each line are converted to link-marked text.
26290
+ * @param text - Raw pasted text
26291
+ * @param schema - ProseMirror schema
26292
+ */
26293
+ const createNodesWithLinksAndBreaks = (text, schema) => {
26294
+ // Split preserves empty lines between consecutive newlines
26295
+ const lines = text.split(/\r\n|\r|\n/);
26296
+ const nodes = [];
26297
+ for (const [index, line] of lines.entries()) {
26298
+ if (line.length > 0) {
26299
+ nodes.push(...createNodesWithLinks(line, schema));
26300
+ }
26301
+ if (index < lines.length - 1) {
26302
+ const hb = schema.nodes.hard_break;
26303
+ if (hb) {
26304
+ nodes.push(hb.create());
26305
+ }
26306
+ else {
26307
+ // Fallback: if schema lacks hard_break, defer to default paste behavior
26308
+ // (Do NOT throw; keep behavior stable across versions)
26309
+ console.warn('hard_break node not found in schema');
26310
+ }
26311
+ }
26312
+ }
26313
+ return nodes;
26314
+ };
26280
26315
  /**
26281
26316
  * Creates text nodes with links for any URLs, mailto links, or phone links found in the text
26282
26317
  * @param text
@@ -26378,7 +26413,8 @@ const processPasteEvent$1 = (view, event) => {
26378
26413
  if (!text || !hasUrls(text)) {
26379
26414
  return false;
26380
26415
  }
26381
- const nodes = createNodesWithLinks(text, view.state.schema);
26416
+ const nodes = createNodesWithLinksAndBreaks(text, view.state.schema);
26417
+ event.preventDefault();
26382
26418
  pasteAsLink(view, nodes);
26383
26419
  return true;
26384
26420
  };
@@ -26395,11 +26431,12 @@ const createLinkPlugin = (updateLinkCallback) => {
26395
26431
  event.button === 0) {
26396
26432
  return processModClickEvent(view, event);
26397
26433
  }
26434
+ },
26435
+ dblclick: (view, event) => {
26398
26436
  if (event.button !== MouseButtons.Right) {
26399
26437
  // We want to ignore right-clicks
26400
- return processClickEvent(view, event);
26438
+ return processDoubleClickEvent(view, event);
26401
26439
  }
26402
- return true;
26403
26440
  },
26404
26441
  click: (_view, event) => {
26405
26442
  if (!(event.target instanceof HTMLElement)) {