@broberg/cms-inline-edit 0.7.1 → 0.8.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/dist/index.cjs CHANGED
@@ -31,6 +31,7 @@ __export(index_exports, {
31
31
  isDangerousUrl: () => isDangerousUrl,
32
32
  isExternalHost: () => isExternalHost,
33
33
  isSchemeless: () => isSchemeless,
34
+ plainTextWithBreaks: () => plainTextWithBreaks,
34
35
  positionPopover: () => positionPopover,
35
36
  renderCurrentRefLine: () => renderCurrentRefLine,
36
37
  rescanFields: () => rescanFields,
@@ -439,7 +440,7 @@ function wireField(el, token, options) {
439
440
  e.preventDefault();
440
441
  e.stopPropagation();
441
442
  const tokenSafe = hasTokenChips(el);
442
- el.dataset.cmsOriginalValue = tokenSafe ? serializeTokenSafe(el) : el.textContent ?? "";
443
+ el.dataset.cmsOriginalValue = tokenSafe ? serializeTokenSafe(el) : plainTextWithBreaks(el);
443
444
  el.setAttribute("contenteditable", "true");
444
445
  if (tokenSafe) lockTokenChips(el);
445
446
  el.focus();
@@ -447,7 +448,7 @@ function wireField(el, token, options) {
447
448
  el.addEventListener("blur", () => {
448
449
  el.removeAttribute("contenteditable");
449
450
  const original = el.dataset.cmsOriginalValue ?? "";
450
- const current = hasTokenChips(el) ? serializeTokenSafe(el) : el.textContent ?? "";
451
+ const current = hasTokenChips(el) ? serializeTokenSafe(el) : plainTextWithBreaks(el);
451
452
  if (current.trim() === original.trim()) return;
452
453
  void saveField(el, current.trim(), token, options);
453
454
  });
@@ -457,12 +458,35 @@ function wireField(el, token, options) {
457
458
  document.execCommand("insertText", false, text);
458
459
  });
459
460
  el.addEventListener("keydown", (e) => {
460
- if (e.key === "Enter") {
461
- e.preventDefault();
462
- el.blur();
461
+ if (e.key !== "Enter") return;
462
+ e.preventDefault();
463
+ if (e.shiftKey) {
464
+ document.execCommand("insertLineBreak");
465
+ return;
463
466
  }
467
+ el.blur();
464
468
  });
465
469
  }
470
+ function plainTextWithBreaks(el) {
471
+ let out = "";
472
+ const walk = (node) => {
473
+ if (node.nodeType === Node.TEXT_NODE) {
474
+ out += node.textContent ?? "";
475
+ return;
476
+ }
477
+ if (node.nodeType !== Node.ELEMENT_NODE) return;
478
+ const tag = node.tagName.toLowerCase();
479
+ if (tag === "br") {
480
+ out += "\n";
481
+ return;
482
+ }
483
+ const blocky = tag === "div" || tag === "p";
484
+ if (blocky && out !== "" && !out.endsWith("\n")) out += "\n";
485
+ node.childNodes.forEach(walk);
486
+ };
487
+ el.childNodes.forEach(walk);
488
+ return out;
489
+ }
466
490
  var richCtx = null;
467
491
  var richToolbar = null;
468
492
  function wireRichField(el, token, options, mode) {
@@ -1419,11 +1443,48 @@ function togglePageTools(options, forankring) {
1419
1443
  plus.setAttribute("data-testid", "page-tools-tags-plus");
1420
1444
  plus.style.cssText = "background:rgba(255,255,255,.04);border:1px solid #3a3f4a;border-radius:9px;padding:8px 12px;color:#fff;font:600 12px system-ui,sans-serif;cursor:pointer;";
1421
1445
  plus.textContent = "# Tags +";
1446
+ const boks = document.createElement("div");
1447
+ boks.setAttribute("data-testid", "page-tools-tags-boks");
1448
+ boks.style.cssText = "flex:1;min-width:0;display:none;flex-wrap:wrap;align-items:center;gap:5px;background:#12151a;border:1px solid #3a3f4a;border-radius:8px;padding:5px 7px;cursor:text;";
1449
+ const chips = [];
1422
1450
  const felt = document.createElement("input");
1423
1451
  felt.type = "text";
1424
1452
  felt.placeholder = "tag1, tag2, tag3";
1425
1453
  felt.setAttribute("data-testid", "page-tools-tags-input");
1426
- felt.style.cssText = "flex:1;min-width:0;display:none;background:#12151a;border:1px solid #3a3f4a;border-radius:8px;padding:7px 9px;color:#fff;font:12px system-ui,sans-serif;outline:none;";
1454
+ felt.style.cssText = "flex:1;min-width:70px;background:transparent;border:none;padding:2px;color:#fff;font:12px system-ui,sans-serif;outline:none;";
1455
+ const tegnChips = () => {
1456
+ Array.prototype.forEach.call(boks.querySelectorAll("[data-chip]"), (c) => c.remove());
1457
+ chips.forEach((t, i) => {
1458
+ const chip = document.createElement("span");
1459
+ chip.setAttribute("data-chip", "");
1460
+ chip.setAttribute("data-testid", "page-tools-tag-chip");
1461
+ chip.style.cssText = "display:inline-flex;align-items:center;gap:4px;background:rgba(0,178,255,.15);border:1px solid rgba(0,178,255,.45);border-radius:999px;padding:2px 4px 2px 8px;color:#7fd8ff;font:600 11px system-ui,sans-serif;";
1462
+ chip.textContent = t;
1463
+ const x = document.createElement("button");
1464
+ x.type = "button";
1465
+ x.setAttribute("data-testid", "page-tools-tag-fjern");
1466
+ x.setAttribute("aria-label", `Fjern ${t}`);
1467
+ x.style.cssText = "background:none;border:none;color:#7fd8ff;font:700 13px system-ui,sans-serif;cursor:pointer;line-height:1;padding:0 3px;";
1468
+ x.textContent = "\xD7";
1469
+ x.addEventListener("click", (e) => {
1470
+ e.stopPropagation();
1471
+ chips.splice(i, 1);
1472
+ tegnChips();
1473
+ felt.focus();
1474
+ });
1475
+ chip.appendChild(x);
1476
+ boks.insertBefore(chip, felt);
1477
+ });
1478
+ };
1479
+ const tagify = () => {
1480
+ const nye = parseTags(felt.value);
1481
+ for (const t of nye) {
1482
+ if (!chips.some((c) => c.toLowerCase() === t.toLowerCase())) chips.push(t);
1483
+ }
1484
+ felt.value = "";
1485
+ tegnChips();
1486
+ };
1487
+ boks.addEventListener("click", () => felt.focus());
1427
1488
  const gem = document.createElement("button");
1428
1489
  gem.type = "button";
1429
1490
  gem.setAttribute("data-testid", "page-tools-tags-gem");
@@ -1431,12 +1492,13 @@ function togglePageTools(options, forankring) {
1431
1492
  gem.textContent = "Gem";
1432
1493
  plus.addEventListener("click", () => {
1433
1494
  plus.style.display = "none";
1434
- felt.style.display = "block";
1495
+ boks.style.display = "flex";
1435
1496
  gem.style.display = "inline-block";
1436
1497
  felt.focus();
1437
1498
  });
1438
1499
  const gemTags = async () => {
1439
- const nye = parseTags(felt.value);
1500
+ tagify();
1501
+ const nye = [...chips];
1440
1502
  if (!nye.length) return;
1441
1503
  gem.disabled = true;
1442
1504
  gem.textContent = "\u2026";
@@ -1449,6 +1511,8 @@ function togglePageTools(options, forankring) {
1449
1511
  gem.textContent = holdt ? "Gemt \u2713" : "Fejl";
1450
1512
  if (holdt) {
1451
1513
  felt.value = "";
1514
+ chips.length = 0;
1515
+ tegnChips();
1452
1516
  setTimeout(() => {
1453
1517
  gem.textContent = "Gem";
1454
1518
  gem.disabled = false;
@@ -1463,12 +1527,27 @@ function togglePageTools(options, forankring) {
1463
1527
  };
1464
1528
  gem.addEventListener("click", () => void gemTags());
1465
1529
  felt.addEventListener("keydown", (e) => {
1530
+ if (e.key === ",") {
1531
+ e.preventDefault();
1532
+ tagify();
1533
+ return;
1534
+ }
1466
1535
  if (e.key === "Enter") {
1467
1536
  e.preventDefault();
1468
1537
  void gemTags();
1538
+ return;
1469
1539
  }
1540
+ if (e.key === "Backspace" && felt.value === "" && chips.length) {
1541
+ e.preventDefault();
1542
+ chips.pop();
1543
+ tegnChips();
1544
+ }
1545
+ });
1546
+ felt.addEventListener("input", () => {
1547
+ if (felt.value.includes(",")) tagify();
1470
1548
  });
1471
- tagRow.append(plus, felt, gem);
1549
+ boks.appendChild(felt);
1550
+ tagRow.append(plus, boks, gem);
1472
1551
  popup.appendChild(tagRow);
1473
1552
  const lukP\u00E5Klik = (e) => {
1474
1553
  if (!popup.contains(e.target) && !forankring.contains(e.target)) luk();
@@ -1520,6 +1599,7 @@ function injectStyles() {
1520
1599
  isDangerousUrl,
1521
1600
  isExternalHost,
1522
1601
  isSchemeless,
1602
+ plainTextWithBreaks,
1523
1603
  positionPopover,
1524
1604
  renderCurrentRefLine,
1525
1605
  rescanFields,