@noirmd/previewer 2.1.3 → 2.1.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.
package/dist/index.d.cts CHANGED
@@ -11,6 +11,7 @@ interface HeaderToken {
11
11
  text: string;
12
12
  id: string;
13
13
  classes?: string;
14
+ align?: 'center' | 'right';
14
15
  }
15
16
  interface ParagraphToken {
16
17
  type: 'paragraph';
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ interface HeaderToken {
11
11
  text: string;
12
12
  id: string;
13
13
  classes?: string;
14
+ align?: 'center' | 'right';
14
15
  }
15
16
  interface ParagraphToken {
16
17
  type: 'paragraph';
package/dist/index.js CHANGED
@@ -1653,6 +1653,22 @@ function parseHtmlAttrs(attrsString) {
1653
1653
  }
1654
1654
 
1655
1655
  // core/parser.ts
1656
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
1657
+ "area",
1658
+ "base",
1659
+ "br",
1660
+ "col",
1661
+ "embed",
1662
+ "hr",
1663
+ "img",
1664
+ "input",
1665
+ "link",
1666
+ "meta",
1667
+ "param",
1668
+ "source",
1669
+ "track",
1670
+ "wbr"
1671
+ ]);
1656
1672
  function parseMarkdown(markdown2) {
1657
1673
  if (!markdown2) return [];
1658
1674
  const lines = markdown2.replace(/\r\n/g, "\n").replace(/\r/g, "").split("\n");
@@ -1666,8 +1682,19 @@ function parseMarkdown(markdown2) {
1666
1682
  if (match = trimmed.match(/^(#{1,6})\s+(.+)$/)) {
1667
1683
  const level = match[1].length;
1668
1684
  const rawText = match[2];
1669
- const { text: text2, classes: classes2, id: customId } = extractAttributes(rawText);
1670
- const baseId = customId || generateId(text2.replace(/->|<-/g, ""));
1685
+ const { text: rawParsedText, classes: classes2, id: customId } = extractAttributes(rawText);
1686
+ let text2 = rawParsedText;
1687
+ let align;
1688
+ const alignCenter = text2.match(/^->\s*(.+?)\s*<-\s*$/);
1689
+ const alignRight = text2.match(/^->\s*(.+?)\s*->\s*$/);
1690
+ if (alignCenter) {
1691
+ text2 = alignCenter[1];
1692
+ align = "center";
1693
+ } else if (alignRight) {
1694
+ text2 = alignRight[1];
1695
+ align = "right";
1696
+ }
1697
+ const baseId = customId || generateId(text2);
1671
1698
  let id2 = baseId;
1672
1699
  let n = 1;
1673
1700
  while (usedIds.has(id2)) {
@@ -1675,7 +1702,7 @@ function parseMarkdown(markdown2) {
1675
1702
  id2 = `${baseId}-${n}`;
1676
1703
  }
1677
1704
  usedIds.add(id2);
1678
- result.push({ type: "header", level, text: text2, id: id2, classes: classes2 || void 0 });
1705
+ result.push({ type: "header", level, text: text2, id: id2, classes: classes2 || void 0, align });
1679
1706
  i++;
1680
1707
  continue;
1681
1708
  }
@@ -1851,29 +1878,13 @@ function parseMarkdown(markdown2) {
1851
1878
  let tagStartMatch = trimmed.match(/^<([a-zA-Z][\w-]*)/);
1852
1879
  if (tagStartMatch) {
1853
1880
  const tagName = tagStartMatch[1].toLowerCase();
1854
- const voidElements = /* @__PURE__ */ new Set([
1855
- "area",
1856
- "base",
1857
- "br",
1858
- "col",
1859
- "embed",
1860
- "hr",
1861
- "img",
1862
- "input",
1863
- "link",
1864
- "meta",
1865
- "param",
1866
- "source",
1867
- "track",
1868
- "wbr"
1869
- ]);
1870
1881
  const remainingText = lines.slice(i).join("\n");
1871
1882
  const openTagRegex = new RegExp(`^\\s*<${tagName}\\b([^>]*?)>`, "i");
1872
1883
  const openTagMatch = remainingText.match(openTagRegex);
1873
1884
  if (openTagMatch) {
1874
1885
  const fullOpenTag = openTagMatch[0];
1875
1886
  const attrs = openTagMatch[1].replace(/\s+/g, " ").trim();
1876
- const isSelfClosing = fullOpenTag.endsWith("/>") || voidElements.has(tagName);
1887
+ const isSelfClosing = fullOpenTag.endsWith("/>") || VOID_ELEMENTS.has(tagName);
1877
1888
  if (isSelfClosing) {
1878
1889
  const blockText = remainingText.substring(0, openTagMatch.index + fullOpenTag.length);
1879
1890
  const consumedLines = blockText.split("\n").length;
@@ -11270,11 +11281,77 @@ function parseInlinePart(part) {
11270
11281
  return document.createTextNode(part);
11271
11282
  }
11272
11283
 
11284
+ // vanilla/utils.ts
11285
+ var THEME_TOKENS = /* @__PURE__ */ new Set([
11286
+ "primary",
11287
+ "secondary",
11288
+ "accent",
11289
+ "neutral",
11290
+ "info",
11291
+ "success",
11292
+ "warning",
11293
+ "error"
11294
+ ]);
11295
+ function isThemeToken(color) {
11296
+ return !!color && THEME_TOKENS.has(color);
11297
+ }
11298
+ function isArbitraryColor(value) {
11299
+ if (THEME_TOKENS.has(value)) return false;
11300
+ if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
11301
+ if (/^[a-zA-Z]+$/.test(value)) return true;
11302
+ return false;
11303
+ }
11304
+ function applyBaseProps(el, props) {
11305
+ if (props.class) {
11306
+ el.classList.add(...props.class.split(/\s+/).filter(Boolean));
11307
+ }
11308
+ if (props.style) {
11309
+ const styles = parseCssString(props.style);
11310
+ for (const [key, value] of Object.entries(styles)) {
11311
+ el.style.setProperty(key, String(value));
11312
+ }
11313
+ }
11314
+ }
11315
+ function applyFloatStyle(el, float, width) {
11316
+ if (!float) return;
11317
+ if (float === "left" || float === "right") {
11318
+ el.style.float = float;
11319
+ if (!width) el.style.maxWidth = "50%";
11320
+ el.style.marginInlineStart = float === "right" ? "1rem" : "";
11321
+ el.style.marginInlineEnd = float === "left" ? "1rem" : "";
11322
+ } else if (float === "center") {
11323
+ el.style.marginInline = "auto";
11324
+ }
11325
+ }
11326
+ function applyColor(el, color, classSuffix) {
11327
+ if (!color) return "";
11328
+ if (isThemeToken(color)) {
11329
+ return ` ${classSuffix}--${color}`;
11330
+ }
11331
+ if (isArbitraryColor(color)) {
11332
+ el.style.background = color;
11333
+ el.style.color = "white";
11334
+ }
11335
+ return "";
11336
+ }
11337
+ function openModal(dialog) {
11338
+ if (!dialog.open) {
11339
+ document.body.appendChild(dialog);
11340
+ dialog.showModal();
11341
+ dialog.addEventListener("close", () => dialog.remove(), { once: true });
11342
+ }
11343
+ }
11344
+ var IMG_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
11345
+ function parseIntProp(value, defaultValue) {
11346
+ if (!value) return defaultValue;
11347
+ const n = parseInt(value, 10);
11348
+ return Number.isNaN(n) ? defaultValue : n;
11349
+ }
11350
+
11273
11351
  // vanilla/directives/admonition.ts
11274
11352
  var admonitionDirective = ({ directiveType, props, renderSlot }) => {
11275
11353
  const el = createAdmonition(directiveType, props.title, props.icon);
11276
- if (props.class) el.classList.add(...props.class.split(/\s+/).filter(Boolean));
11277
- if (props.style) el.setAttribute("style", props.style);
11354
+ applyBaseProps(el, props);
11278
11355
  const body = el.querySelector(".nr-admonition__body");
11279
11356
  if (body) {
11280
11357
  body.appendChild(renderSlot("default"));
@@ -11290,8 +11367,7 @@ var detailsDirective = ({ props, renderSlot }) => {
11290
11367
  props.icon,
11291
11368
  props.defaultOpen === "true"
11292
11369
  );
11293
- if (props.class) el.classList.add(...props.class.split(/\s+/).filter(Boolean));
11294
- if (props.style) el.setAttribute("style", props.style);
11370
+ applyBaseProps(el, props);
11295
11371
  const body = el.querySelector(".nr-details__body");
11296
11372
  if (body) {
11297
11373
  body.appendChild(renderSlot("default"));
@@ -11304,12 +11380,12 @@ var details_default = detailsDirective;
11304
11380
  var modalDirective = ({ props, renderSlot }) => {
11305
11381
  const label = props.label || props.title || "Open";
11306
11382
  const modalTitle = props.title || "Modal";
11307
- const customClass = props.class || "";
11383
+ const align = props.align || "left";
11308
11384
  const wrapper = document.createElement("div");
11309
- wrapper.className = "nr-modal-trigger";
11385
+ wrapper.className = `nr-modal-trigger${align === "center" ? " nr-modal-trigger--center" : align === "right" ? " nr-modal-trigger--right" : ""}`;
11310
11386
  const btn = document.createElement("button");
11311
11387
  btn.className = `nr-button nr-button--default`;
11312
- if (customClass) btn.classList.add(...customClass.split(/\s+/).filter(Boolean));
11388
+ applyBaseProps(btn, props);
11313
11389
  const icon = props.icon || "open_in_new";
11314
11390
  if (icon) btn.appendChild(createIcon(icon));
11315
11391
  btn.appendChild(document.createTextNode(label));
@@ -11321,15 +11397,7 @@ var modalDirective = ({ props, renderSlot }) => {
11321
11397
  prose.appendChild(renderSlot("default"));
11322
11398
  body.appendChild(prose);
11323
11399
  }
11324
- btn.addEventListener("click", () => {
11325
- if (!dialog.open) {
11326
- document.body.appendChild(dialog);
11327
- dialog.showModal();
11328
- dialog.addEventListener("close", () => {
11329
- dialog.remove();
11330
- }, { once: true });
11331
- }
11332
- });
11400
+ btn.addEventListener("click", () => openModal(dialog));
11333
11401
  wrapper.appendChild(btn);
11334
11402
  wrapper.appendChild(dialog);
11335
11403
  return wrapper;
@@ -11339,19 +11407,20 @@ var modal_default = modalDirective;
11339
11407
  // vanilla/directives/button.ts
11340
11408
  var buttonDirective = ({ props, renderSlot }) => {
11341
11409
  const url = props.url || props.href || "#";
11342
- const label = props.label;
11410
+ const label = props.label || props.title;
11343
11411
  const icon = props.icon || "near_me";
11344
11412
  const target = props.target || "_blank";
11345
11413
  const customClass = props.class || "";
11414
+ const align = props.align || "left";
11346
11415
  const wrapper = document.createElement("div");
11347
- wrapper.className = "nr-button-wrap";
11416
+ wrapper.className = `nr-button-wrap${align === "center" ? " nr-button-wrap--center" : align === "right" ? " nr-button-wrap--right" : ""}`;
11348
11417
  if (label) {
11349
11418
  const a = document.createElement("a");
11350
11419
  a.href = url;
11351
11420
  a.target = target;
11352
11421
  a.rel = "noopener noreferrer";
11353
11422
  a.className = "nr-button nr-button--default";
11354
- if (customClass) a.classList.add(...customClass.split(/\s+/).filter(Boolean));
11423
+ applyBaseProps(a, props);
11355
11424
  a.appendChild(createIcon(icon));
11356
11425
  a.appendChild(document.createTextNode(label));
11357
11426
  wrapper.appendChild(a);
@@ -11362,7 +11431,7 @@ var buttonDirective = ({ props, renderSlot }) => {
11362
11431
  if (links.length > 0) {
11363
11432
  links.forEach((link) => {
11364
11433
  link.classList.add("nr-button", "nr-button--default");
11365
- if (customClass) link.classList.add(...customClass.split(/\s+/).filter(Boolean));
11434
+ applyBaseProps(link, props);
11366
11435
  });
11367
11436
  wrapper.appendChild(slotContent);
11368
11437
  } else {
@@ -11371,7 +11440,7 @@ var buttonDirective = ({ props, renderSlot }) => {
11371
11440
  a.target = target;
11372
11441
  a.rel = "noopener noreferrer";
11373
11442
  a.className = "nr-button nr-button--default";
11374
- if (customClass) a.classList.add(...customClass.split(/\s+/).filter(Boolean));
11443
+ applyBaseProps(a, props);
11375
11444
  a.appendChild(createIcon(icon));
11376
11445
  a.appendChild(slotContent);
11377
11446
  wrapper.appendChild(a);
@@ -11394,12 +11463,9 @@ var cardDirective = ({
11394
11463
  const { isSingleCard } = options || {};
11395
11464
  const isModal = directiveType === "card-m";
11396
11465
  const isLink = directiveType === "card-b";
11397
- const inlineStyles = props.style ? parseCssString(props.style) : {};
11398
11466
  const card = document.createElement("div");
11399
11467
  card.className = `nr-card${isModal || isLink ? " nr-card--interactive" : ""} ${customClass}`.trim();
11400
- for (const [key, value] of Object.entries(inlineStyles)) {
11401
- card.style.setProperty(key, String(value));
11402
- }
11468
+ applyBaseProps(card, props);
11403
11469
  if (image) {
11404
11470
  const imgWrap = document.createElement("div");
11405
11471
  imgWrap.className = `nr-card__image${isSingleCard ? " nr-card__image--tall" : ""}`;
@@ -11478,13 +11544,7 @@ var cardDirective = ({
11478
11544
  prose.appendChild(renderSlot("content") || renderSlot("default"));
11479
11545
  modalBody.appendChild(prose);
11480
11546
  }
11481
- card.addEventListener("click", () => {
11482
- if (!dialog.open) {
11483
- document.body.appendChild(dialog);
11484
- dialog.showModal();
11485
- dialog.addEventListener("close", () => dialog.remove(), { once: true });
11486
- }
11487
- });
11547
+ card.addEventListener("click", () => openModal(dialog));
11488
11548
  const frag = document.createDocumentFragment();
11489
11549
  frag.appendChild(card);
11490
11550
  frag.appendChild(dialog);
@@ -11532,8 +11592,8 @@ var slideDirective = ({
11532
11592
  if (lines.length === 0) {
11533
11593
  return document.createDocumentFragment();
11534
11594
  }
11535
- const interval = parseInt(props.interval || "3000", 10);
11536
- const speed = parseInt(props.speed || "500", 10);
11595
+ const interval = parseIntProp(props.interval, 3e3);
11596
+ const speed = parseIntProp(props.speed, 500);
11537
11597
  const rawClass = props.class || "";
11538
11598
  const inlineStyle = props.style ? parseCssString(props.style) : {};
11539
11599
  const scopeClass = `sld-${++slideCounter}`;
@@ -11584,10 +11644,11 @@ var slideDirective = ({
11584
11644
  }
11585
11645
  });
11586
11646
  if (lines.length > 1) {
11587
- setInterval(() => {
11647
+ const id = setInterval(() => {
11588
11648
  current = (current + 1) % lines.length;
11589
11649
  track.style.transform = `translateY(${-current * maxH}px)`;
11590
11650
  }, interval);
11651
+ container.dataset.nrIntervalId = String(id);
11591
11652
  }
11592
11653
  return container;
11593
11654
  };
@@ -11597,8 +11658,7 @@ var slide_default = slideDirective;
11597
11658
  var keysDirective = ({ props, slots }) => {
11598
11659
  const wrap = document.createElement("div");
11599
11660
  wrap.className = "nr-keys";
11600
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11601
- if (props.style) wrap.setAttribute("style", props.style);
11661
+ applyBaseProps(wrap, props);
11602
11662
  const sizeClass = props.size ? ` nr-kbd--${props.size}` : "";
11603
11663
  const parts = (slots.default || "").split("+").map((p) => p.trim()).filter(Boolean);
11604
11664
  parts.forEach((part, i) => {
@@ -11622,8 +11682,7 @@ var accordionCounter = 0;
11622
11682
  var accordionItemDirective = ({ props, renderSlot }) => {
11623
11683
  const item = document.createElement("div");
11624
11684
  item.className = "nr-accordion__item";
11625
- if (props.class) item.classList.add(...props.class.split(/\s+/).filter(Boolean));
11626
- if (props.style) item.setAttribute("style", props.style);
11685
+ applyBaseProps(item, props);
11627
11686
  const input = document.createElement("input");
11628
11687
  input.type = "radio";
11629
11688
  input.className = "nr-accordion__input";
@@ -11642,8 +11701,7 @@ var accordionItemDirective = ({ props, renderSlot }) => {
11642
11701
  var accordionDirective = ({ props, renderSlot }) => {
11643
11702
  const wrap = document.createElement("div");
11644
11703
  wrap.className = "nr-accordion";
11645
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11646
- if (props.style) wrap.setAttribute("style", props.style);
11704
+ applyBaseProps(wrap, props);
11647
11705
  wrap.appendChild(renderSlot("default"));
11648
11706
  const mode = props.mode === "checkbox" ? "checkbox" : "radio";
11649
11707
  const group = `nr-acc-${++accordionCounter}`;
@@ -11656,7 +11714,6 @@ var accordionDirective = ({ props, renderSlot }) => {
11656
11714
  var accordion_default = accordionDirective;
11657
11715
 
11658
11716
  // vanilla/directives/carousel.ts
11659
- var IMG_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
11660
11717
  var carouselDirective = ({ props, slots }) => {
11661
11718
  const images = [];
11662
11719
  const raw = slots.default || "";
@@ -11672,19 +11729,9 @@ var carouselDirective = ({ props, slots }) => {
11672
11729
  wrap.className = "nr-carousel";
11673
11730
  wrap.tabIndex = 0;
11674
11731
  wrap.setAttribute("aria-label", "Image carousel");
11675
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11676
- if (props.style) wrap.setAttribute("style", props.style);
11732
+ applyBaseProps(wrap, props);
11677
11733
  if (props.width) wrap.style.width = props.width;
11678
- if (props.float) {
11679
- if (props.float === "left" || props.float === "right") {
11680
- wrap.style.float = props.float;
11681
- if (!props.width) wrap.style.maxWidth = "50%";
11682
- wrap.style.marginInlineStart = props.float === "right" ? "1rem" : "";
11683
- wrap.style.marginInlineEnd = props.float === "left" ? "1rem" : "";
11684
- } else if (props.float === "center") {
11685
- wrap.style.marginInline = "auto";
11686
- }
11687
- }
11734
+ applyFloatStyle(wrap, props.float, props.width);
11688
11735
  const viewport = document.createElement("div");
11689
11736
  viewport.className = "nr-carousel__viewport";
11690
11737
  if (props.height) viewport.style.height = props.height;
@@ -11754,11 +11801,10 @@ var DEFAULT_LABELS = ["days", "hours", "min", "sec"];
11754
11801
  var countdownDirective = ({ props }) => {
11755
11802
  const wrap = document.createElement("div");
11756
11803
  wrap.className = "nr-countdown";
11757
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
11758
- if (props.style) wrap.setAttribute("style", props.style);
11804
+ applyBaseProps(wrap, props);
11759
11805
  const labelParts = (props.labels || "").split("|").map((s) => s.trim());
11760
11806
  const labels = DEFAULT_LABELS.map((label, i) => labelParts[i] || label);
11761
- const digits = parseInt(props.digits || "2", 10);
11807
+ const digits = parseIntProp(props.digits, 2);
11762
11808
  const targetTime = props.target ? new Date(props.target).getTime() : NaN;
11763
11809
  const hasTarget = !Number.isNaN(targetTime);
11764
11810
  const blocks = [];
@@ -11805,13 +11851,15 @@ var countdownDirective = ({ props }) => {
11805
11851
  blocks.push({ value });
11806
11852
  });
11807
11853
  render();
11808
- if (hasTarget) setInterval(render, 1e3);
11854
+ if (hasTarget) {
11855
+ const id = setInterval(render, 1e3);
11856
+ wrap.dataset.nrIntervalId = String(id);
11857
+ }
11809
11858
  return wrap;
11810
11859
  };
11811
11860
  var countdown_default = countdownDirective;
11812
11861
 
11813
11862
  // vanilla/directives/diff.ts
11814
- var IMG_RE2 = /!\[([^\]]*)\]\(([^)]+)\)/g;
11815
11863
  var diffDirective = ({ props, slots }) => {
11816
11864
  let before = (props.before || "").split("#")[0].trim();
11817
11865
  let after = (props.after || "").split("#")[0].trim();
@@ -11819,8 +11867,8 @@ var diffDirective = ({ props, slots }) => {
11819
11867
  const urls = [];
11820
11868
  const raw = slots.default || "";
11821
11869
  let m;
11822
- IMG_RE2.lastIndex = 0;
11823
- while ((m = IMG_RE2.exec(raw)) !== null) {
11870
+ IMG_RE.lastIndex = 0;
11871
+ while ((m = IMG_RE.exec(raw)) !== null) {
11824
11872
  urls.push(m[2].split("#")[0].trim());
11825
11873
  }
11826
11874
  if (!before && urls.length > 0) before = urls[0];
@@ -11833,21 +11881,11 @@ var diffDirective = ({ props, slots }) => {
11833
11881
  figure.className = "nr-diff";
11834
11882
  figure.tabIndex = 0;
11835
11883
  figure.setAttribute("aria-label", "Image comparison slider");
11836
- if (props.class) figure.classList.add(...props.class.split(/\s+/).filter(Boolean));
11837
- if (props.style) figure.setAttribute("style", props.style);
11884
+ applyBaseProps(figure, props);
11838
11885
  if (props.aspect) figure.style.aspectRatio = props.aspect;
11839
11886
  if (props.height) figure.style.height = props.height;
11840
11887
  if (props.width) figure.style.width = props.width;
11841
- if (props.float) {
11842
- if (props.float === "left" || props.float === "right") {
11843
- figure.style.float = props.float;
11844
- if (!props.width) figure.style.maxWidth = "50%";
11845
- figure.style.marginInlineStart = props.float === "right" ? "1rem" : "";
11846
- figure.style.marginInlineEnd = props.float === "left" ? "1rem" : "";
11847
- } else if (props.float === "center") {
11848
- figure.style.marginInline = "auto";
11849
- }
11850
- }
11888
+ applyFloatStyle(figure, props.float, props.width);
11851
11889
  const beforeItem = document.createElement("div");
11852
11890
  beforeItem.className = "nr-diff__item nr-diff__item--before";
11853
11891
  beforeItem.setAttribute("role", "img");
@@ -11910,8 +11948,7 @@ var diff_default = diffDirective;
11910
11948
  var hover3dDirective = ({ props, renderSlot }) => {
11911
11949
  const container = document.createElement("div");
11912
11950
  container.className = "nr-hover-3d";
11913
- if (props.class) container.classList.add(...props.class.split(/\s+/).filter(Boolean));
11914
- if (props.style) container.setAttribute("style", props.style);
11951
+ applyBaseProps(container, props);
11915
11952
  const stage = document.createElement("div");
11916
11953
  stage.className = "nr-hover-3d__stage";
11917
11954
  stage.appendChild(renderSlot("default"));
@@ -11924,14 +11961,13 @@ var hover3dDirective = ({ props, renderSlot }) => {
11924
11961
  var hover3d_default = hover3dDirective;
11925
11962
 
11926
11963
  // vanilla/directives/hovergallery.ts
11927
- var IMG_RE3 = /!\[([^\]]*)\]\(([^)]+)\)/g;
11928
11964
  var MAX_IMAGES = 10;
11929
11965
  var hovergalleryDirective = ({ props, slots }) => {
11930
11966
  const images = [];
11931
11967
  const raw = slots.default || "";
11932
11968
  let m;
11933
- IMG_RE3.lastIndex = 0;
11934
- while ((m = IMG_RE3.exec(raw)) !== null) {
11969
+ IMG_RE.lastIndex = 0;
11970
+ while ((m = IMG_RE.exec(raw)) !== null) {
11935
11971
  images.push({ src: m[2].split("#")[0].trim(), alt: m[1].trim() || "gallery image" });
11936
11972
  }
11937
11973
  if (images.length === 0) {
@@ -11940,9 +11976,8 @@ var hovergalleryDirective = ({ props, slots }) => {
11940
11976
  const count = Math.min(images.length, MAX_IMAGES);
11941
11977
  const figure = document.createElement("figure");
11942
11978
  figure.className = "nr-hover-gallery";
11979
+ applyBaseProps(figure, props);
11943
11980
  if (props.aspect) figure.style.aspectRatio = props.aspect;
11944
- if (props.class) figure.classList.add(...props.class.split(/\s+/).filter(Boolean));
11945
- if (props.style) figure.setAttribute("style", (figure.getAttribute("style") || "") + ";" + props.style);
11946
11981
  const imgEls = [];
11947
11982
  for (let i = 0; i < count; i++) {
11948
11983
  const el = document.createElement("img");
@@ -11992,28 +12027,11 @@ var hovergalleryDirective = ({ props, slots }) => {
11992
12027
  var hovergallery_default = hovergalleryDirective;
11993
12028
 
11994
12029
  // vanilla/directives/chat.ts
11995
- var CHAT_THEME_TOKENS = /* @__PURE__ */ new Set([
11996
- "primary",
11997
- "secondary",
11998
- "accent",
11999
- "neutral",
12000
- "info",
12001
- "success",
12002
- "warning",
12003
- "error"
12004
- ]);
12005
- function isArbitraryColor(value) {
12006
- if (CHAT_THEME_TOKENS.has(value)) return false;
12007
- if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
12008
- if (/^[a-zA-Z]+$/.test(value)) return true;
12009
- return false;
12010
- }
12011
12030
  var chatItemDirective = ({ props, renderSlot }) => {
12012
12031
  const side = props.side === "end" ? "end" : "start";
12013
12032
  const wrap = document.createElement("div");
12014
12033
  wrap.className = `nr-chat nr-chat--${side}`;
12015
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
12016
- if (props.style) wrap.setAttribute("style", props.style);
12034
+ applyBaseProps(wrap, props);
12017
12035
  const header = document.createElement("div");
12018
12036
  header.className = "nr-chat__header";
12019
12037
  if (props.name) {
@@ -12038,14 +12056,8 @@ var chatItemDirective = ({ props, renderSlot }) => {
12038
12056
  avatar.appendChild(img);
12039
12057
  wrap.appendChild(avatar);
12040
12058
  }
12041
- const isThemeToken = CHAT_THEME_TOKENS.has(props.color || "");
12042
- const colorClass = isThemeToken ? ` nr-chat__bubble--${props.color}` : "";
12043
12059
  const bubble = document.createElement("div");
12044
- bubble.className = `nr-chat__bubble${colorClass}`;
12045
- if (props.color && isArbitraryColor(props.color) && !isThemeToken) {
12046
- bubble.style.background = props.color;
12047
- bubble.style.color = "white";
12048
- }
12060
+ bubble.className = `nr-chat__bubble${applyColor(bubble, props.color, "nr-chat__bubble")}`;
12049
12061
  bubble.appendChild(renderSlot("default"));
12050
12062
  wrap.appendChild(bubble);
12051
12063
  if (props.footer) {
@@ -12059,8 +12071,7 @@ var chatItemDirective = ({ props, renderSlot }) => {
12059
12071
  var chatDirective = ({ props, renderSlot }) => {
12060
12072
  const wrap = document.createElement("div");
12061
12073
  wrap.className = "nr-chat";
12062
- if (props.class) wrap.classList.add(...props.class.split(/\s+/).filter(Boolean));
12063
- if (props.style) wrap.setAttribute("style", props.style);
12074
+ applyBaseProps(wrap, props);
12064
12075
  wrap.appendChild(renderSlot("default"));
12065
12076
  return wrap;
12066
12077
  };
@@ -12096,8 +12107,7 @@ function bindEventProp(el, eventProp) {
12096
12107
  var richlistItemDirective = ({ props, renderSlot }) => {
12097
12108
  const li = document.createElement("li");
12098
12109
  li.className = "nr-richlist__item";
12099
- if (props.class) li.classList.add(...props.class.split(/\s+/).filter(Boolean));
12100
- if (props.style) li.setAttribute("style", props.style);
12110
+ applyBaseProps(li, props);
12101
12111
  if (props.image) {
12102
12112
  const thumb = document.createElement("div");
12103
12113
  thumb.className = "nr-richlist__thumb";
@@ -12159,36 +12169,20 @@ var richlistItemDirective = ({ props, renderSlot }) => {
12159
12169
  var richlistDirective = ({ props, renderSlot }) => {
12160
12170
  const ul = document.createElement("ul");
12161
12171
  ul.className = "nr-richlist";
12162
- if (props.class) ul.classList.add(...props.class.split(/\s+/).filter(Boolean));
12163
- if (props.style) ul.setAttribute("style", props.style);
12172
+ applyBaseProps(ul, props);
12164
12173
  ul.appendChild(renderSlot("default"));
12165
12174
  return ul;
12166
12175
  };
12167
12176
  var richlist_default = richlistDirective;
12168
12177
 
12169
12178
  // vanilla/directives/stat.ts
12170
- var STAT_THEME_TOKENS = /* @__PURE__ */ new Set([
12171
- "primary",
12172
- "secondary",
12173
- "info",
12174
- "success",
12175
- "warning",
12176
- "error"
12177
- ]);
12178
- function isArbitraryColor2(value) {
12179
- if (STAT_THEME_TOKENS.has(value)) return false;
12180
- if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
12181
- if (/^[a-zA-Z]+$/.test(value)) return true;
12182
- return false;
12183
- }
12184
12179
  var statDirective = ({ props }) => {
12185
- const isThemeToken = STAT_THEME_TOKENS.has(props.color || "");
12186
- const colorClass = isThemeToken ? ` nr-stat--${props.color}` : "";
12180
+ const statIsThemeToken = isThemeToken(props.color);
12181
+ const colorClass = statIsThemeToken ? ` nr-stat--${props.color}` : "";
12187
12182
  const stat = document.createElement("div");
12188
12183
  stat.className = `nr-stat${colorClass}`;
12189
- if (props.class) stat.classList.add(...props.class.split(/\s+/).filter(Boolean));
12190
- if (props.style) stat.setAttribute("style", props.style);
12191
- const useInlineColor = props.color && isArbitraryColor2(props.color) && !isThemeToken;
12184
+ applyBaseProps(stat, props);
12185
+ const useInlineColor = props.color && isArbitraryColor(props.color) && !statIsThemeToken;
12192
12186
  if (props.icon) {
12193
12187
  const figure = document.createElement("div");
12194
12188
  figure.className = "nr-stat__figure";
@@ -12281,9 +12275,12 @@ function renderHtmlString(html) {
12281
12275
  processedContent = processedContent.replace(
12282
12276
  /<style(?:\s+[^>]*)?>([\s\S]*?)<\/style>/gi,
12283
12277
  (_match, cssContent) => {
12278
+ const trimmed = cssContent.trim();
12279
+ const existing = document.head.querySelector("style[data-nr-global]");
12280
+ if (existing && existing.textContent === trimmed) return "";
12284
12281
  const styleEl = document.createElement("style");
12285
12282
  styleEl.setAttribute("data-nr-global", "");
12286
- styleEl.textContent = cssContent;
12283
+ styleEl.textContent = trimmed;
12287
12284
  document.head.appendChild(styleEl);
12288
12285
  return "";
12289
12286
  }
@@ -12353,19 +12350,14 @@ function renderElement(element, ctx, allElements) {
12353
12350
  switch (element.type) {
12354
12351
  case "header": {
12355
12352
  const tag = `h${element.level}`;
12356
- let text = element.text;
12357
- const alignCenter = text.match(/^->\s*(.+?)\s*<-\s*$/);
12358
- const alignRight = text.match(/^->\s*(.+?)\s*->\s*$/);
12359
- if (alignCenter) text = alignCenter[1];
12360
- else if (alignRight) text = alignRight[1];
12361
12353
  const h = document.createElement(tag);
12362
12354
  h.id = element.id;
12363
12355
  let cls = `md-h${element.level}`;
12364
- if (alignCenter) cls += " text-center";
12365
- if (alignRight) cls += " text-right";
12356
+ if (element.align === "center") cls += " text-center";
12357
+ else if (element.align === "right") cls += " text-right";
12366
12358
  if (element.classes) cls += ` ${element.classes}`;
12367
12359
  h.className = cls;
12368
- h.appendChild(renderInline(text));
12360
+ h.appendChild(renderInline(element.text));
12369
12361
  return h;
12370
12362
  }
12371
12363
  case "paragraph": {