@threadlabs/looma 0.16.3 → 0.16.5

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.
@@ -8631,6 +8631,13 @@ function parseHtmlSlice(schema, value) {
8631
8631
  const parsed = new globalThis.DOMParser().parseFromString(value, "text/html");
8632
8632
  if (parsed.body.style.display === "none") return Slice.empty;
8633
8633
  for (const element of parsed.body.querySelectorAll("[style]")) if (element.style.display === "none") element.remove();
8634
+ for (const wrapper of parsed.body.querySelectorAll("div")) for (const child of wrapper.children) {
8635
+ const next = child.nextSibling;
8636
+ if (child.localName !== "span" || next?.nodeType !== 1 || next.localName !== "span") continue;
8637
+ if (!child.textContent?.trim() || !next.textContent?.trim()) continue;
8638
+ if (/\s$/.test(child.textContent) || /^\s/.test(next.textContent)) continue;
8639
+ wrapper.insertBefore(parsed.createTextNode(" "), next);
8640
+ }
8634
8641
  const container = document.createElement("div");
8635
8642
  container.append(purify.sanitize(parsed.body.innerHTML, {
8636
8643
  USE_PROFILES: { html: true },
@@ -8648,8 +8655,20 @@ function parseHtmlSlice(schema, value) {
8648
8655
  if (!container.textContent?.trim() && !container.querySelector("img, hr")) return Slice.empty;
8649
8656
  return DOMParser.fromSchema(schema).parseSlice(container, { preserveWhitespace: false });
8650
8657
  }
8658
+ function markdownFrontmatter(value) {
8659
+ const match = /^---[ \t]*\r?\n([\s\S]*?)\r?\n(?:---|\.\.\.)[ \t]*(?:\r?\n|$)/.exec(value.slice(0, 8192));
8660
+ if (!match || !/^[A-Za-z][\w-]*:[ \t]*\S/m.test(match[1])) return null;
8661
+ return {
8662
+ source: match[0].trimEnd(),
8663
+ body: value.slice(match[0].length)
8664
+ };
8665
+ }
8666
+ function escapeHtmlText(value) {
8667
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
8668
+ }
8651
8669
  function documentSlice(schema, plainText) {
8652
- if (looksLikeMarkdown(plainText)) return parseHtmlSlice(schema, markdown.render(plainText));
8670
+ const frontmatter = markdownFrontmatter(plainText);
8671
+ if (frontmatter || looksLikeMarkdown(plainText)) return parseHtmlSlice(schema, frontmatter ? `<pre><code class="language-yaml">${escapeHtmlText(frontmatter.source)}</code></pre>${markdown.render(frontmatter.body)}` : markdown.render(plainText));
8653
8672
  if (looksLikeDocumentHtml(plainText)) return parseHtmlSlice(schema, plainText);
8654
8673
  return null;
8655
8674
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.16.3",
3
+ "version": "0.16.5",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -8929,7 +8929,7 @@ html[data-ui-input-modality="touch"]
8929
8929
  .ProseMirror table {
8930
8930
  border-collapse: collapse;
8931
8931
  margin: 0;
8932
- width: max-content !important;
8932
+ width: 100% !important;
8933
8933
  min-width: 100%;
8934
8934
  max-width: none !important;
8935
8935
  table-layout: fixed;
@@ -495,6 +495,7 @@ var LoomaEditor = defineComponent({
495
495
  });
496
496
  const imageDelivery = createLoomaImageDeliveryController({ resolveAttributes: () => props.resolveImageAttributes });
497
497
  let lastFocusedSelection = null;
498
+ let linkPressedSelection = null;
498
499
  const rememberSelection = (instance) => {
499
500
  if (!instance.isFocused) return;
500
501
  const selection = instance.view.state.selection;
@@ -541,8 +542,10 @@ var LoomaEditor = defineComponent({
541
542
  if (!instance || !props.editable) return;
542
543
  const current = instance.state.selection;
543
544
  const preserved = lastFocusedSelection?.text && lastFocusedSelection.from !== lastFocusedSelection.to ? lastFocusedSelection : null;
544
- const from = current.empty && preserved ? preserved.from : current.from;
545
- const to = current.empty && preserved ? preserved.to : current.to;
545
+ const selection = linkPressedSelection ?? (current.empty ? preserved : null);
546
+ linkPressedSelection = null;
547
+ const from = selection?.from ?? current.from;
548
+ const to = selection?.to ?? current.to;
546
549
  const empty = from === to;
547
550
  const existing = instance.isActive("link");
548
551
  linkSelection = {
@@ -1084,6 +1087,13 @@ var LoomaEditor = defineComponent({
1084
1087
  "data-active": instance.isActive("link") ? "true" : "false",
1085
1088
  onPointerenter: () => showTool(linkAnchorId, "Link", false),
1086
1089
  onPointerleave: hideTool,
1090
+ onPointerdown: () => {
1091
+ const selection = instance.state.selection;
1092
+ linkPressedSelection = selection.empty ? null : {
1093
+ from: selection.from,
1094
+ to: selection.to
1095
+ };
1096
+ },
1087
1097
  onFocusin: () => showTool(linkAnchorId, "Link", true),
1088
1098
  onFocusout: hideTool
1089
1099
  }, () => loomaIcon("link")),
@@ -1282,7 +1292,7 @@ var LoomaEditor = defineComponent({
1282
1292
  class: "looma-editor__chip-popover",
1283
1293
  open: chipOpen.value,
1284
1294
  for: chipAnchorId,
1285
- placement: mobile.value ? "top-start" : "bottom-start",
1295
+ placement: "bottom-start",
1286
1296
  onClose: () => {
1287
1297
  chipOpen.value = false;
1288
1298
  }
@@ -1334,6 +1344,7 @@ var LoomaEditor = defineComponent({
1334
1344
  onOpen: openLinkEditor,
1335
1345
  onClose: () => {
1336
1346
  linkOpen.value = false;
1347
+ linkPressedSelection = null;
1337
1348
  }
1338
1349
  }, () => h("form", {
1339
1350
  class: "looma-editor__link-form",