@noirmd/previewer 2.1.4 → 2.1.6

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/vue.cjs CHANGED
@@ -1675,6 +1675,22 @@ function parseHtmlAttrs(attrsString) {
1675
1675
  }
1676
1676
 
1677
1677
  // core/parser.ts
1678
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
1679
+ "area",
1680
+ "base",
1681
+ "br",
1682
+ "col",
1683
+ "embed",
1684
+ "hr",
1685
+ "img",
1686
+ "input",
1687
+ "link",
1688
+ "meta",
1689
+ "param",
1690
+ "source",
1691
+ "track",
1692
+ "wbr"
1693
+ ]);
1678
1694
  function parseMarkdown(markdown2) {
1679
1695
  if (!markdown2) return [];
1680
1696
  const lines = markdown2.replace(/\r\n/g, "\n").replace(/\r/g, "").split("\n");
@@ -1688,8 +1704,19 @@ function parseMarkdown(markdown2) {
1688
1704
  if (match = trimmed.match(/^(#{1,6})\s+(.+)$/)) {
1689
1705
  const level = match[1].length;
1690
1706
  const rawText = match[2];
1691
- const { text: text2, classes: classes2, id: customId } = extractAttributes(rawText);
1692
- const baseId = customId || generateId(text2.replace(/->|<-/g, ""));
1707
+ const { text: rawParsedText, classes: classes2, id: customId } = extractAttributes(rawText);
1708
+ let text2 = rawParsedText;
1709
+ let align;
1710
+ const alignCenter = text2.match(/^->\s*(.+?)\s*<-\s*$/);
1711
+ const alignRight = text2.match(/^->\s*(.+?)\s*->\s*$/);
1712
+ if (alignCenter) {
1713
+ text2 = alignCenter[1];
1714
+ align = "center";
1715
+ } else if (alignRight) {
1716
+ text2 = alignRight[1];
1717
+ align = "right";
1718
+ }
1719
+ const baseId = customId || generateId(text2);
1693
1720
  let id2 = baseId;
1694
1721
  let n = 1;
1695
1722
  while (usedIds.has(id2)) {
@@ -1697,7 +1724,7 @@ function parseMarkdown(markdown2) {
1697
1724
  id2 = `${baseId}-${n}`;
1698
1725
  }
1699
1726
  usedIds.add(id2);
1700
- result.push({ type: "header", level, text: text2, id: id2, classes: classes2 || void 0 });
1727
+ result.push({ type: "header", level, text: text2, id: id2, classes: classes2 || void 0, align });
1701
1728
  i++;
1702
1729
  continue;
1703
1730
  }
@@ -1873,29 +1900,13 @@ function parseMarkdown(markdown2) {
1873
1900
  let tagStartMatch = trimmed.match(/^<([a-zA-Z][\w-]*)/);
1874
1901
  if (tagStartMatch) {
1875
1902
  const tagName = tagStartMatch[1].toLowerCase();
1876
- const voidElements = /* @__PURE__ */ new Set([
1877
- "area",
1878
- "base",
1879
- "br",
1880
- "col",
1881
- "embed",
1882
- "hr",
1883
- "img",
1884
- "input",
1885
- "link",
1886
- "meta",
1887
- "param",
1888
- "source",
1889
- "track",
1890
- "wbr"
1891
- ]);
1892
1903
  const remainingText = lines.slice(i).join("\n");
1893
1904
  const openTagRegex = new RegExp(`^\\s*<${tagName}\\b([^>]*?)>`, "i");
1894
1905
  const openTagMatch = remainingText.match(openTagRegex);
1895
1906
  if (openTagMatch) {
1896
1907
  const fullOpenTag = openTagMatch[0];
1897
1908
  const attrs = openTagMatch[1].replace(/\s+/g, " ").trim();
1898
- const isSelfClosing = fullOpenTag.endsWith("/>") || voidElements.has(tagName);
1909
+ const isSelfClosing = fullOpenTag.endsWith("/>") || VOID_ELEMENTS.has(tagName);
1899
1910
  if (isSelfClosing) {
1900
1911
  const blockText = remainingText.substring(0, openTagMatch.index + fullOpenTag.length);
1901
1912
  const consumedLines = blockText.split("\n").length;
@@ -11069,6 +11080,7 @@ function createModal(title) {
11069
11080
  header.appendChild(titleEl);
11070
11081
  const closeBtn = document.createElement("button");
11071
11082
  closeBtn.className = "nr-modal__close";
11083
+ closeBtn.setAttribute("aria-label", "Close");
11072
11084
  closeBtn.appendChild(createIcon("close"));
11073
11085
  closeBtn.addEventListener("click", () => dialog.close());
11074
11086
  header.appendChild(closeBtn);
@@ -11289,11 +11301,89 @@ function parseInlinePart(part) {
11289
11301
  return document.createTextNode(part);
11290
11302
  }
11291
11303
 
11304
+ // vanilla/utils.ts
11305
+ var THEME_TOKENS = /* @__PURE__ */ new Set([
11306
+ "primary",
11307
+ "secondary",
11308
+ "accent",
11309
+ "neutral",
11310
+ "info",
11311
+ "success",
11312
+ "warning",
11313
+ "error"
11314
+ ]);
11315
+ function isThemeToken(color) {
11316
+ return !!color && THEME_TOKENS.has(color);
11317
+ }
11318
+ function isArbitraryColor(value) {
11319
+ if (THEME_TOKENS.has(value)) return false;
11320
+ if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
11321
+ if (/^[a-zA-Z]+$/.test(value)) return true;
11322
+ return false;
11323
+ }
11324
+ function applyBaseProps(el, props) {
11325
+ if (props.class) {
11326
+ el.classList.add(...props.class.split(/\s+/).filter(Boolean));
11327
+ }
11328
+ if (props.style) {
11329
+ const styles = parseCssString(props.style);
11330
+ for (const [key, value] of Object.entries(styles)) {
11331
+ el.style.setProperty(key, String(value));
11332
+ }
11333
+ }
11334
+ }
11335
+ function applyFloatStyle(el, float, width) {
11336
+ if (!float) return;
11337
+ if (float === "left" || float === "right") {
11338
+ el.style.float = float;
11339
+ if (!width) el.style.maxWidth = "50%";
11340
+ el.style.marginInlineStart = float === "right" ? "1rem" : "";
11341
+ el.style.marginInlineEnd = float === "left" ? "1rem" : "";
11342
+ } else if (float === "center") {
11343
+ el.style.marginInline = "auto";
11344
+ }
11345
+ }
11346
+ function applyColor(el, color, classSuffix) {
11347
+ if (!color) return "";
11348
+ if (isThemeToken(color)) {
11349
+ return ` ${classSuffix}--${color}`;
11350
+ }
11351
+ if (isArbitraryColor(color)) {
11352
+ el.style.background = color;
11353
+ el.style.color = "white";
11354
+ }
11355
+ return "";
11356
+ }
11357
+ function openModal(dialog) {
11358
+ if (!dialog.open) {
11359
+ document.body.appendChild(dialog);
11360
+ dialog.showModal();
11361
+ dialog.addEventListener("close", () => dialog.remove(), { once: true });
11362
+ }
11363
+ }
11364
+ var IMG_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
11365
+ function applyAlignClass(el, baseClass, align) {
11366
+ if (align === "center") {
11367
+ el.classList.add(`${baseClass}--center`);
11368
+ } else if (align === "right") {
11369
+ el.classList.add(`${baseClass}--right`);
11370
+ }
11371
+ }
11372
+ function resolveIcon(value, fallback) {
11373
+ if (!value) return fallback;
11374
+ if (value === "none" || value === "off") return null;
11375
+ return value;
11376
+ }
11377
+ function parseIntProp(value, defaultValue) {
11378
+ if (!value) return defaultValue;
11379
+ const n = parseInt(value, 10);
11380
+ return Number.isNaN(n) ? defaultValue : n;
11381
+ }
11382
+
11292
11383
  // vanilla/directives/admonition.ts
11293
11384
  var admonitionDirective = ({ directiveType, props, renderSlot }) => {
11294
11385
  const el = createAdmonition(directiveType, props.title, props.icon);
11295
- if (props.class) el.classList.add(...props.class.split(/\s+/).filter(Boolean));
11296
- if (props.style) el.setAttribute("style", props.style);
11386
+ applyBaseProps(el, props);
11297
11387
  const body = el.querySelector(".nr-admonition__body");
11298
11388
  if (body) {
11299
11389
  body.appendChild(renderSlot("default"));
@@ -11309,8 +11399,7 @@ var detailsDirective = ({ props, renderSlot }) => {
11309
11399
  props.icon,
11310
11400
  props.defaultOpen === "true"
11311
11401
  );
11312
- if (props.class) el.classList.add(...props.class.split(/\s+/).filter(Boolean));
11313
- if (props.style) el.setAttribute("style", props.style);
11402
+ applyBaseProps(el, props);
11314
11403
  const body = el.querySelector(".nr-details__body");
11315
11404
  if (body) {
11316
11405
  body.appendChild(renderSlot("default"));
@@ -11323,14 +11412,17 @@ var details_default = detailsDirective;
11323
11412
  var modalDirective = ({ props, renderSlot }) => {
11324
11413
  const label = props.label || props.title || "Open";
11325
11414
  const modalTitle = props.title || "Modal";
11326
- const customClass = props.class || "";
11415
+ const align = props.align || "left";
11416
+ const iconName = resolveIcon(props.icon, "open_in_full");
11327
11417
  const wrapper = document.createElement("div");
11328
11418
  wrapper.className = "nr-modal-trigger";
11419
+ applyAlignClass(wrapper, "nr-modal-trigger", align);
11329
11420
  const btn = document.createElement("button");
11330
- btn.className = `nr-button nr-button--default`;
11331
- if (customClass) btn.classList.add(...customClass.split(/\s+/).filter(Boolean));
11332
- const icon = props.icon || "open_in_new";
11333
- if (icon) btn.appendChild(createIcon(icon));
11421
+ btn.className = "nr-button nr-button--default";
11422
+ btn.setAttribute("aria-haspopup", "dialog");
11423
+ applyColor(btn, props.color, "nr-button");
11424
+ applyBaseProps(btn, props);
11425
+ if (iconName) btn.appendChild(createIcon(iconName));
11334
11426
  btn.appendChild(document.createTextNode(label));
11335
11427
  const dialog = createModal(modalTitle);
11336
11428
  const body = dialog.querySelector(".nr-modal__body");
@@ -11340,15 +11432,7 @@ var modalDirective = ({ props, renderSlot }) => {
11340
11432
  prose.appendChild(renderSlot("default"));
11341
11433
  body.appendChild(prose);
11342
11434
  }
11343
- btn.addEventListener("click", () => {
11344
- if (!dialog.open) {
11345
- document.body.appendChild(dialog);
11346
- dialog.showModal();
11347
- dialog.addEventListener("close", () => {
11348
- dialog.remove();
11349
- }, { once: true });
11350
- }
11351
- });
11435
+ btn.addEventListener("click", () => openModal(dialog));
11352
11436
  wrapper.appendChild(btn);
11353
11437
  wrapper.appendChild(dialog);
11354
11438
  return wrapper;
@@ -11358,20 +11442,22 @@ var modal_default = modalDirective;
11358
11442
  // vanilla/directives/button.ts
11359
11443
  var buttonDirective = ({ props, renderSlot }) => {
11360
11444
  const url = props.url || props.href || "#";
11361
- const label = props.label;
11362
- const icon = props.icon || "near_me";
11445
+ const label = props.label || props.title;
11446
+ const iconName = resolveIcon(props.icon, "touch_app");
11363
11447
  const target = props.target || "_blank";
11364
- const customClass = props.class || "";
11448
+ const align = props.align || "left";
11365
11449
  const wrapper = document.createElement("div");
11366
11450
  wrapper.className = "nr-button-wrap";
11451
+ applyAlignClass(wrapper, "nr-button-wrap", align);
11367
11452
  if (label) {
11368
11453
  const a = document.createElement("a");
11369
11454
  a.href = url;
11370
11455
  a.target = target;
11371
- a.rel = "noopener noreferrer";
11456
+ if (target === "_blank") a.rel = "noopener noreferrer";
11372
11457
  a.className = "nr-button nr-button--default";
11373
- if (customClass) a.classList.add(...customClass.split(/\s+/).filter(Boolean));
11374
- a.appendChild(createIcon(icon));
11458
+ applyColor(a, props.color, "nr-button");
11459
+ applyBaseProps(a, props);
11460
+ if (iconName) a.appendChild(createIcon(iconName));
11375
11461
  a.appendChild(document.createTextNode(label));
11376
11462
  wrapper.appendChild(a);
11377
11463
  return wrapper;
@@ -11381,17 +11467,20 @@ var buttonDirective = ({ props, renderSlot }) => {
11381
11467
  if (links.length > 0) {
11382
11468
  links.forEach((link) => {
11383
11469
  link.classList.add("nr-button", "nr-button--default");
11384
- if (customClass) link.classList.add(...customClass.split(/\s+/).filter(Boolean));
11470
+ applyColor(link, props.color, "nr-button");
11471
+ if (iconName) link.prepend(createIcon(iconName));
11472
+ applyBaseProps(link, props);
11385
11473
  });
11386
11474
  wrapper.appendChild(slotContent);
11387
11475
  } else {
11388
11476
  const a = document.createElement("a");
11389
11477
  a.href = url;
11390
11478
  a.target = target;
11391
- a.rel = "noopener noreferrer";
11479
+ if (target === "_blank") a.rel = "noopener noreferrer";
11392
11480
  a.className = "nr-button nr-button--default";
11393
- if (customClass) a.classList.add(...customClass.split(/\s+/).filter(Boolean));
11394
- a.appendChild(createIcon(icon));
11481
+ applyColor(a, props.color, "nr-button");
11482
+ applyBaseProps(a, props);
11483
+ if (iconName) a.appendChild(createIcon(iconName));
11395
11484
  a.appendChild(slotContent);
11396
11485
  wrapper.appendChild(a);
11397
11486
  }
@@ -11413,12 +11502,9 @@ var cardDirective = ({
11413
11502
  const { isSingleCard } = options || {};
11414
11503
  const isModal = directiveType === "card-m";
11415
11504
  const isLink = directiveType === "card-b";
11416
- const inlineStyles = props.style ? parseCssString(props.style) : {};
11417
11505
  const card = document.createElement("div");
11418
11506
  card.className = `nr-card${isModal || isLink ? " nr-card--interactive" : ""} ${customClass}`.trim();
11419
- for (const [key, value] of Object.entries(inlineStyles)) {
11420
- card.style.setProperty(key, String(value));
11421
- }
11507
+ applyBaseProps(card, props);
11422
11508
  if (image) {
11423
11509
  const imgWrap = document.createElement("div");
11424
11510
  imgWrap.className = `nr-card__image${isSingleCard ? " nr-card__image--tall" : ""}`;
@@ -11497,13 +11583,7 @@ var cardDirective = ({
11497
11583
  prose.appendChild(renderSlot("content") || renderSlot("default"));
11498
11584
  modalBody.appendChild(prose);
11499
11585
  }
11500
- card.addEventListener("click", () => {
11501
- if (!dialog.open) {
11502
- document.body.appendChild(dialog);
11503
- dialog.showModal();
11504
- dialog.addEventListener("close", () => dialog.remove(), { once: true });
11505
- }
11506
- });
11586
+ card.addEventListener("click", () => openModal(dialog));
11507
11587
  const frag = document.createDocumentFragment();
11508
11588
  frag.appendChild(card);
11509
11589
  frag.appendChild(dialog);
@@ -11551,8 +11631,8 @@ var slideDirective = ({
11551
11631
  if (lines.length === 0) {
11552
11632
  return document.createDocumentFragment();
11553
11633
  }
11554
- const interval = parseInt(props.interval || "3000", 10);
11555
- const speed = parseInt(props.speed || "500", 10);
11634
+ const interval = parseIntProp(props.interval, 3e3);
11635
+ const speed = parseIntProp(props.speed, 500);
11556
11636
  const rawClass = props.class || "";
11557
11637
  const inlineStyle = props.style ? parseCssString(props.style) : {};
11558
11638
  const scopeClass = `sld-${++slideCounter}`;
@@ -11603,10 +11683,11 @@ var slideDirective = ({
11603
11683
  }
11604
11684
  });
11605
11685
  if (lines.length > 1) {
11606
- setInterval(() => {
11686
+ const id = setInterval(() => {
11607
11687
  current = (current + 1) % lines.length;
11608
11688
  track.style.transform = `translateY(${-current * maxH}px)`;
11609
11689
  }, interval);
11690
+ container.dataset.nrIntervalId = String(id);
11610
11691
  }
11611
11692
  return container;
11612
11693
  };
@@ -11616,8 +11697,7 @@ var slide_default = slideDirective;
11616
11697
  var keysDirective = ({ props, slots }) => {
11617
11698
  const wrap = document.createElement("div");
11618
11699
  wrap.className = "nr-keys";
11619
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11620
- if (props.style) wrap.setAttribute("style", props.style);
11700
+ applyBaseProps(wrap, props);
11621
11701
  const sizeClass = props.size ? ` nr-kbd--${props.size}` : "";
11622
11702
  const parts = (slots.default || "").split("+").map((p) => p.trim()).filter(Boolean);
11623
11703
  parts.forEach((part, i) => {
@@ -11641,8 +11721,7 @@ var accordionCounter = 0;
11641
11721
  var accordionItemDirective = ({ props, renderSlot }) => {
11642
11722
  const item = document.createElement("div");
11643
11723
  item.className = "nr-accordion__item";
11644
- if (props.class) item.classList.add(...props.class.split(/\s+/).filter(Boolean));
11645
- if (props.style) item.setAttribute("style", props.style);
11724
+ applyBaseProps(item, props);
11646
11725
  const input = document.createElement("input");
11647
11726
  input.type = "radio";
11648
11727
  input.className = "nr-accordion__input";
@@ -11661,8 +11740,7 @@ var accordionItemDirective = ({ props, renderSlot }) => {
11661
11740
  var accordionDirective = ({ props, renderSlot }) => {
11662
11741
  const wrap = document.createElement("div");
11663
11742
  wrap.className = "nr-accordion";
11664
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11665
- if (props.style) wrap.setAttribute("style", props.style);
11743
+ applyBaseProps(wrap, props);
11666
11744
  wrap.appendChild(renderSlot("default"));
11667
11745
  const mode = props.mode === "checkbox" ? "checkbox" : "radio";
11668
11746
  const group = `nr-acc-${++accordionCounter}`;
@@ -11675,7 +11753,6 @@ var accordionDirective = ({ props, renderSlot }) => {
11675
11753
  var accordion_default = accordionDirective;
11676
11754
 
11677
11755
  // vanilla/directives/carousel.ts
11678
- var IMG_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
11679
11756
  var carouselDirective = ({ props, slots }) => {
11680
11757
  const images = [];
11681
11758
  const raw = slots.default || "";
@@ -11691,19 +11768,9 @@ var carouselDirective = ({ props, slots }) => {
11691
11768
  wrap.className = "nr-carousel";
11692
11769
  wrap.tabIndex = 0;
11693
11770
  wrap.setAttribute("aria-label", "Image carousel");
11694
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11695
- if (props.style) wrap.setAttribute("style", props.style);
11771
+ applyBaseProps(wrap, props);
11696
11772
  if (props.width) wrap.style.width = props.width;
11697
- if (props.float) {
11698
- if (props.float === "left" || props.float === "right") {
11699
- wrap.style.float = props.float;
11700
- if (!props.width) wrap.style.maxWidth = "50%";
11701
- wrap.style.marginInlineStart = props.float === "right" ? "1rem" : "";
11702
- wrap.style.marginInlineEnd = props.float === "left" ? "1rem" : "";
11703
- } else if (props.float === "center") {
11704
- wrap.style.marginInline = "auto";
11705
- }
11706
- }
11773
+ applyFloatStyle(wrap, props.float, props.width);
11707
11774
  const viewport = document.createElement("div");
11708
11775
  viewport.className = "nr-carousel__viewport";
11709
11776
  if (props.height) viewport.style.height = props.height;
@@ -11773,11 +11840,10 @@ var DEFAULT_LABELS = ["days", "hours", "min", "sec"];
11773
11840
  var countdownDirective = ({ props }) => {
11774
11841
  const wrap = document.createElement("div");
11775
11842
  wrap.className = "nr-countdown";
11776
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11777
- if (props.style) wrap.setAttribute("style", props.style);
11843
+ applyBaseProps(wrap, props);
11778
11844
  const labelParts = (props.labels || "").split("|").map((s) => s.trim());
11779
11845
  const labels = DEFAULT_LABELS.map((label, i) => labelParts[i] || label);
11780
- const digits = parseInt(props.digits || "2", 10);
11846
+ const digits = parseIntProp(props.digits, 2);
11781
11847
  const targetTime = props.target ? new Date(props.target).getTime() : NaN;
11782
11848
  const hasTarget = !Number.isNaN(targetTime);
11783
11849
  const blocks = [];
@@ -11824,13 +11890,15 @@ var countdownDirective = ({ props }) => {
11824
11890
  blocks.push({ value });
11825
11891
  });
11826
11892
  render();
11827
- if (hasTarget) setInterval(render, 1e3);
11893
+ if (hasTarget) {
11894
+ const id = setInterval(render, 1e3);
11895
+ wrap.dataset.nrIntervalId = String(id);
11896
+ }
11828
11897
  return wrap;
11829
11898
  };
11830
11899
  var countdown_default = countdownDirective;
11831
11900
 
11832
11901
  // vanilla/directives/diff.ts
11833
- var IMG_RE2 = /!\[([^\]]*)\]\(([^)]+)\)/g;
11834
11902
  var diffDirective = ({ props, slots }) => {
11835
11903
  let before = (props.before || "").split("#")[0].trim();
11836
11904
  let after = (props.after || "").split("#")[0].trim();
@@ -11838,8 +11906,8 @@ var diffDirective = ({ props, slots }) => {
11838
11906
  const urls = [];
11839
11907
  const raw = slots.default || "";
11840
11908
  let m;
11841
- IMG_RE2.lastIndex = 0;
11842
- while ((m = IMG_RE2.exec(raw)) !== null) {
11909
+ IMG_RE.lastIndex = 0;
11910
+ while ((m = IMG_RE.exec(raw)) !== null) {
11843
11911
  urls.push(m[2].split("#")[0].trim());
11844
11912
  }
11845
11913
  if (!before && urls.length > 0) before = urls[0];
@@ -11852,21 +11920,11 @@ var diffDirective = ({ props, slots }) => {
11852
11920
  figure.className = "nr-diff";
11853
11921
  figure.tabIndex = 0;
11854
11922
  figure.setAttribute("aria-label", "Image comparison slider");
11855
- if (props.class) figure.classList.add(...props.class.split(/\s+/).filter(Boolean));
11856
- if (props.style) figure.setAttribute("style", props.style);
11923
+ applyBaseProps(figure, props);
11857
11924
  if (props.aspect) figure.style.aspectRatio = props.aspect;
11858
11925
  if (props.height) figure.style.height = props.height;
11859
11926
  if (props.width) figure.style.width = props.width;
11860
- if (props.float) {
11861
- if (props.float === "left" || props.float === "right") {
11862
- figure.style.float = props.float;
11863
- if (!props.width) figure.style.maxWidth = "50%";
11864
- figure.style.marginInlineStart = props.float === "right" ? "1rem" : "";
11865
- figure.style.marginInlineEnd = props.float === "left" ? "1rem" : "";
11866
- } else if (props.float === "center") {
11867
- figure.style.marginInline = "auto";
11868
- }
11869
- }
11927
+ applyFloatStyle(figure, props.float, props.width);
11870
11928
  const beforeItem = document.createElement("div");
11871
11929
  beforeItem.className = "nr-diff__item nr-diff__item--before";
11872
11930
  beforeItem.setAttribute("role", "img");
@@ -11929,8 +11987,7 @@ var diff_default = diffDirective;
11929
11987
  var hover3dDirective = ({ props, renderSlot }) => {
11930
11988
  const container = document.createElement("div");
11931
11989
  container.className = "nr-hover-3d";
11932
- if (props.class) container.classList.add(...props.class.split(/\s+/).filter(Boolean));
11933
- if (props.style) container.setAttribute("style", props.style);
11990
+ applyBaseProps(container, props);
11934
11991
  const stage = document.createElement("div");
11935
11992
  stage.className = "nr-hover-3d__stage";
11936
11993
  stage.appendChild(renderSlot("default"));
@@ -11943,14 +12000,13 @@ var hover3dDirective = ({ props, renderSlot }) => {
11943
12000
  var hover3d_default = hover3dDirective;
11944
12001
 
11945
12002
  // vanilla/directives/hovergallery.ts
11946
- var IMG_RE3 = /!\[([^\]]*)\]\(([^)]+)\)/g;
11947
12003
  var MAX_IMAGES = 10;
11948
12004
  var hovergalleryDirective = ({ props, slots }) => {
11949
12005
  const images = [];
11950
12006
  const raw = slots.default || "";
11951
12007
  let m;
11952
- IMG_RE3.lastIndex = 0;
11953
- while ((m = IMG_RE3.exec(raw)) !== null) {
12008
+ IMG_RE.lastIndex = 0;
12009
+ while ((m = IMG_RE.exec(raw)) !== null) {
11954
12010
  images.push({ src: m[2].split("#")[0].trim(), alt: m[1].trim() || "gallery image" });
11955
12011
  }
11956
12012
  if (images.length === 0) {
@@ -11959,9 +12015,8 @@ var hovergalleryDirective = ({ props, slots }) => {
11959
12015
  const count = Math.min(images.length, MAX_IMAGES);
11960
12016
  const figure = document.createElement("figure");
11961
12017
  figure.className = "nr-hover-gallery";
12018
+ applyBaseProps(figure, props);
11962
12019
  if (props.aspect) figure.style.aspectRatio = props.aspect;
11963
- if (props.class) figure.classList.add(...props.class.split(/\s+/).filter(Boolean));
11964
- if (props.style) figure.setAttribute("style", (figure.getAttribute("style") || "") + ";" + props.style);
11965
12020
  const imgEls = [];
11966
12021
  for (let i = 0; i < count; i++) {
11967
12022
  const el = document.createElement("img");
@@ -12011,28 +12066,11 @@ var hovergalleryDirective = ({ props, slots }) => {
12011
12066
  var hovergallery_default = hovergalleryDirective;
12012
12067
 
12013
12068
  // vanilla/directives/chat.ts
12014
- var CHAT_THEME_TOKENS = /* @__PURE__ */ new Set([
12015
- "primary",
12016
- "secondary",
12017
- "accent",
12018
- "neutral",
12019
- "info",
12020
- "success",
12021
- "warning",
12022
- "error"
12023
- ]);
12024
- function isArbitraryColor(value) {
12025
- if (CHAT_THEME_TOKENS.has(value)) return false;
12026
- if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
12027
- if (/^[a-zA-Z]+$/.test(value)) return true;
12028
- return false;
12029
- }
12030
12069
  var chatItemDirective = ({ props, renderSlot }) => {
12031
12070
  const side = props.side === "end" ? "end" : "start";
12032
12071
  const wrap = document.createElement("div");
12033
12072
  wrap.className = `nr-chat nr-chat--${side}`;
12034
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
12035
- if (props.style) wrap.setAttribute("style", props.style);
12073
+ applyBaseProps(wrap, props);
12036
12074
  const header = document.createElement("div");
12037
12075
  header.className = "nr-chat__header";
12038
12076
  if (props.name) {
@@ -12057,14 +12095,8 @@ var chatItemDirective = ({ props, renderSlot }) => {
12057
12095
  avatar.appendChild(img);
12058
12096
  wrap.appendChild(avatar);
12059
12097
  }
12060
- const isThemeToken = CHAT_THEME_TOKENS.has(props.color || "");
12061
- const colorClass = isThemeToken ? ` nr-chat__bubble--${props.color}` : "";
12062
12098
  const bubble = document.createElement("div");
12063
- bubble.className = `nr-chat__bubble${colorClass}`;
12064
- if (props.color && isArbitraryColor(props.color) && !isThemeToken) {
12065
- bubble.style.background = props.color;
12066
- bubble.style.color = "white";
12067
- }
12099
+ bubble.className = `nr-chat__bubble${applyColor(bubble, props.color, "nr-chat__bubble")}`;
12068
12100
  bubble.appendChild(renderSlot("default"));
12069
12101
  wrap.appendChild(bubble);
12070
12102
  if (props.footer) {
@@ -12078,8 +12110,7 @@ var chatItemDirective = ({ props, renderSlot }) => {
12078
12110
  var chatDirective = ({ props, renderSlot }) => {
12079
12111
  const wrap = document.createElement("div");
12080
12112
  wrap.className = "nr-chat";
12081
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
12082
- if (props.style) wrap.setAttribute("style", props.style);
12113
+ applyBaseProps(wrap, props);
12083
12114
  wrap.appendChild(renderSlot("default"));
12084
12115
  return wrap;
12085
12116
  };
@@ -12115,8 +12146,7 @@ function bindEventProp(el, eventProp) {
12115
12146
  var richlistItemDirective = ({ props, renderSlot }) => {
12116
12147
  const li = document.createElement("li");
12117
12148
  li.className = "nr-richlist__item";
12118
- if (props.class) li.classList.add(...props.class.split(/\s+/).filter(Boolean));
12119
- if (props.style) li.setAttribute("style", props.style);
12149
+ applyBaseProps(li, props);
12120
12150
  if (props.image) {
12121
12151
  const thumb = document.createElement("div");
12122
12152
  thumb.className = "nr-richlist__thumb";
@@ -12178,36 +12208,20 @@ var richlistItemDirective = ({ props, renderSlot }) => {
12178
12208
  var richlistDirective = ({ props, renderSlot }) => {
12179
12209
  const ul = document.createElement("ul");
12180
12210
  ul.className = "nr-richlist";
12181
- if (props.class) ul.classList.add(...props.class.split(/\s+/).filter(Boolean));
12182
- if (props.style) ul.setAttribute("style", props.style);
12211
+ applyBaseProps(ul, props);
12183
12212
  ul.appendChild(renderSlot("default"));
12184
12213
  return ul;
12185
12214
  };
12186
12215
  var richlist_default = richlistDirective;
12187
12216
 
12188
12217
  // vanilla/directives/stat.ts
12189
- var STAT_THEME_TOKENS = /* @__PURE__ */ new Set([
12190
- "primary",
12191
- "secondary",
12192
- "info",
12193
- "success",
12194
- "warning",
12195
- "error"
12196
- ]);
12197
- function isArbitraryColor2(value) {
12198
- if (STAT_THEME_TOKENS.has(value)) return false;
12199
- if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
12200
- if (/^[a-zA-Z]+$/.test(value)) return true;
12201
- return false;
12202
- }
12203
12218
  var statDirective = ({ props }) => {
12204
- const isThemeToken = STAT_THEME_TOKENS.has(props.color || "");
12205
- const colorClass = isThemeToken ? ` nr-stat--${props.color}` : "";
12219
+ const statIsThemeToken = isThemeToken(props.color);
12220
+ const colorClass = statIsThemeToken ? ` nr-stat--${props.color}` : "";
12206
12221
  const stat = document.createElement("div");
12207
12222
  stat.className = `nr-stat${colorClass}`;
12208
- if (props.class) stat.classList.add(...props.class.split(/\s+/).filter(Boolean));
12209
- if (props.style) stat.setAttribute("style", props.style);
12210
- const useInlineColor = props.color && isArbitraryColor2(props.color) && !isThemeToken;
12223
+ applyBaseProps(stat, props);
12224
+ const useInlineColor = props.color && isArbitraryColor(props.color) && !statIsThemeToken;
12211
12225
  if (props.icon) {
12212
12226
  const figure = document.createElement("div");
12213
12227
  figure.className = "nr-stat__figure";
@@ -12300,9 +12314,12 @@ function renderHtmlString(html) {
12300
12314
  processedContent = processedContent.replace(
12301
12315
  /<style(?:\s+[^>]*)?>([\s\S]*?)<\/style>/gi,
12302
12316
  (_match, cssContent) => {
12317
+ const trimmed = cssContent.trim();
12318
+ const existing = document.head.querySelector("style[data-nr-global]");
12319
+ if (existing && existing.textContent === trimmed) return "";
12303
12320
  const styleEl = document.createElement("style");
12304
12321
  styleEl.setAttribute("data-nr-global", "");
12305
- styleEl.textContent = cssContent;
12322
+ styleEl.textContent = trimmed;
12306
12323
  document.head.appendChild(styleEl);
12307
12324
  return "";
12308
12325
  }
@@ -12372,19 +12389,14 @@ function renderElement(element, ctx, allElements) {
12372
12389
  switch (element.type) {
12373
12390
  case "header": {
12374
12391
  const tag = `h${element.level}`;
12375
- let text = element.text;
12376
- const alignCenter = text.match(/^->\s*(.+?)\s*<-\s*$/);
12377
- const alignRight = text.match(/^->\s*(.+?)\s*->\s*$/);
12378
- if (alignCenter) text = alignCenter[1];
12379
- else if (alignRight) text = alignRight[1];
12380
12392
  const h4 = document.createElement(tag);
12381
12393
  h4.id = element.id;
12382
12394
  let cls = `md-h${element.level}`;
12383
- if (alignCenter) cls += " text-center";
12384
- if (alignRight) cls += " text-right";
12395
+ if (element.align === "center") cls += " text-center";
12396
+ else if (element.align === "right") cls += " text-right";
12385
12397
  if (element.classes) cls += ` ${element.classes}`;
12386
12398
  h4.className = cls;
12387
- h4.appendChild(renderInline(text));
12399
+ h4.appendChild(renderInline(element.text));
12388
12400
  return h4;
12389
12401
  }
12390
12402
  case "paragraph": {