@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/NReditor.cjs +189 -169
- package/dist/NReditor.cjs.map +1 -1
- package/dist/NReditor.js +189 -169
- package/dist/NReditor.js.map +1 -1
- package/dist/button.css +31 -1
- package/dist/card.css +5 -5
- package/dist/core.cjs +31 -20
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +31 -20
- package/dist/core.js.map +1 -1
- package/dist/hover3d.css +1 -1
- package/dist/index.cjs +178 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +178 -166
- package/dist/index.js.map +1 -1
- package/dist/modal.css +7 -1
- package/dist/react.cjs +189 -169
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +189 -169
- package/dist/react.js.map +1 -1
- package/dist/vanilla.cjs +178 -166
- package/dist/vanilla.cjs.map +1 -1
- package/dist/vanilla.d.cts +1 -0
- package/dist/vanilla.d.ts +1 -0
- package/dist/vanilla.js +178 -166
- package/dist/vanilla.js.map +1 -1
- package/dist/vue.cjs +178 -166
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +1 -0
- package/dist/vue.d.ts +1 -0
- package/dist/vue.js +178 -166
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/react.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:
|
|
1692
|
-
|
|
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("/>") ||
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
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
|
|
11445
|
+
const label = props.label || props.title;
|
|
11446
|
+
const iconName = resolveIcon(props.icon, "touch_app");
|
|
11363
11447
|
const target = props.target || "_blank";
|
|
11364
|
-
const
|
|
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
|
-
|
|
11374
|
-
a
|
|
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
|
-
|
|
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
|
-
|
|
11394
|
-
a
|
|
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
|
-
|
|
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 =
|
|
11555
|
-
const speed =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11695
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
11771
|
+
applyBaseProps(wrap, props);
|
|
11696
11772
|
if (props.width) wrap.style.width = props.width;
|
|
11697
|
-
|
|
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
|
-
|
|
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 =
|
|
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)
|
|
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
|
-
|
|
11842
|
-
while ((m =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11953
|
-
while ((m =
|
|
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
|
-
|
|
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${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
12205
|
-
const colorClass =
|
|
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
|
-
|
|
12209
|
-
|
|
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 =
|
|
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 h = document.createElement(tag);
|
|
12381
12393
|
h.id = element.id;
|
|
12382
12394
|
let cls = `md-h${element.level}`;
|
|
12383
|
-
if (
|
|
12384
|
-
if (
|
|
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
|
h.className = cls;
|
|
12387
|
-
h.appendChild(renderInline(text));
|
|
12399
|
+
h.appendChild(renderInline(element.text));
|
|
12388
12400
|
return h;
|
|
12389
12401
|
}
|
|
12390
12402
|
case "paragraph": {
|
|
@@ -12727,7 +12739,7 @@ var guideData = [
|
|
|
12727
12739
|
"title": "Introducci\xF3n",
|
|
12728
12740
|
"icon": "menu_book",
|
|
12729
12741
|
"order": 1,
|
|
12730
|
-
"md": '# Introducci\xF3n a NoirMD\n\n**NoirMD** es un editor y motor de renderizado Markdown con extensiones propias: **admoniciones**, **componentes**, **directivas interactivas** y **markdown enriquecido**.\n\nEsta gu\xEDa est\xE1 escrita con el propio motor: cada directiva que ves aqu\xED es una muestra **viva** y funcional, no una captura.\n\n## C\xF3mo usar el editor\n\n| Elemento | Descripci\xF3n |\n| --- | --- |\n| Toolbar superior | Modo (editor / split / preview), guardar, copiar, imprimir, tema, gu\xEDa y configurar |\n| Panel izquierdo | Editor de c\xF3digo con resaltado de sintaxis |\n| Panel derecho | Preview en vivo (en modo split o preview) |\n| Atajo | `Ctrl+S` guarda el contenido |\n\n## Sintaxis de una directiva\n\nLas directivas se escriben con tres dos puntos `:::` y un nombre, opcionalmente con atributos entre llaves:\n\n```\n:::card {title="Mi tarjeta" icon="star"}\n\nContenido **markdown** aqu\xED dentro.\n\n:::\n```\n\nTodo lo que est\xE1 entre la apertura y el cierre `:::` se renderiza con el mismo motor, as\xED que puedes **anidar** directivas.\n\n## Cheatsheet r\xE1pido\n\n| Sintaxis | Resultado |\n| --- | --- |\n| `# T\xEDtulo` \u2192 `###### T\xEDtulo` | Encabezados |\n| `**negrita**` \xB7
|
|
12742
|
+
"md": '# Introducci\xF3n a NoirMD\n\n**NoirMD** es un editor y motor de renderizado Markdown con extensiones propias: **admoniciones**, **componentes**, **directivas interactivas** y **markdown enriquecido**.\n\nEsta gu\xEDa est\xE1 escrita con el propio motor: cada directiva que ves aqu\xED es una muestra **viva** y funcional, no una captura.\n\n## C\xF3mo usar el editor\n\n| Elemento | Descripci\xF3n |\n| --- | --- |\n| Toolbar superior | Modo (editor / split / preview), guardar, copiar, imprimir, tema, gu\xEDa y configurar |\n| Panel izquierdo | Editor de c\xF3digo con resaltado de sintaxis |\n| Panel derecho | Preview en vivo (en modo split o preview) |\n| Atajo | `Ctrl+S` guarda el contenido |\n\n## Sintaxis de una directiva\n\nLas directivas se escriben con tres dos puntos `:::` y un nombre, opcionalmente con atributos entre llaves:\n\n```\n:::card {title="Mi tarjeta" icon="star"}\n\nContenido **markdown** aqu\xED dentro.\n\n:::\n```\n\nTodo lo que est\xE1 entre la apertura y el cierre `:::` se renderiza con el mismo motor, as\xED que puedes **anidar** directivas.\n\n## Cheatsheet r\xE1pido\n\n| Sintaxis | Resultado |\n| --- | --- |\n| `# T\xEDtulo` \u2192 `###### T\xEDtulo` | Encabezados |\n| `**negrita**` \xB7 `_cursiva_` \xB7 `~~tachado~~` | \xC9nfasis |\n| `` `c\xF3digo` `` | C\xF3digo inline |\n| `` ```js `` | Bloque de c\xF3digo con resaltado |\n| `[texto](url)` | Enlace |\n| `` | Imagen |\n| `` | Imagen flotante a la izquierda |\n| `==resaltado==` | Resaltado |\n| `%color%texto%%` | Texto de color |\n| `->centrado<-` | Texto centrado |\n| `!>spoiler<!` | Spoiler oculto |\n| `|[[icono]]|` | Icono Material |\n| `[TOC]` | \xCDndice de contenidos |\n| `:::note` `:::warning` `:::danger` `:::info` `:::greentext` | Admoniciones |\n| `:::card` `:::accordion` `:::carousel` `:::diff` `:::chat` `:::stat` `:::countdown` `:::keys` `:::hover-3d` `:::hover-gallery` `:::richlist` | Componentes |\n| `:::details` `:::modal` `:::button` `:::slide` | Interactivos |\n| `<style>` HTML inline | Bloques HTML (CSS global, HTML crudo) |\n\n## Organizaci\xF3n de la gu\xEDa\n\n- **Markdown** \u2014 sintaxis base y enriquecida (t\xEDtulos, \xE9nfasis, tablas, c\xF3digo, im\xE1genes, inline).\n- **Admoniciones** \u2014 cajas de aviso: nota, warning, danger, info y greentext.\n- **Componentes** \u2014 los 10 componentes de tarjeta, teclas, acorde\xF3n, carrusel, etc.\n- **Interactivos** \u2014 details, modal, botones y slides.\n- **Layout** \u2014 bloques HTML crudo: CSS global con `<style>` e HTML inline.\n\nCada p\xE1gina incluye: la sintaxis exacta, la tabla de props, un ejemplo en vivo y el c\xF3digo fuente para copiar.'
|
|
12731
12743
|
},
|
|
12732
12744
|
{
|
|
12733
12745
|
"id": "titulos",
|
|
@@ -12943,7 +12955,7 @@ var guideData = [
|
|
|
12943
12955
|
"title": "Modal",
|
|
12944
12956
|
"icon": "open_in_full",
|
|
12945
12957
|
"order": 2,
|
|
12946
|
-
"md": '# Modal\n\nLa directiva `:::modal` crea un **di\xE1logo modal** con su bot\xF3n de apertura.\n\n## Sintaxis\n\n```md\n:::modal {title="Confirmar borrado" label="Abrir modal" icon="delete"}\n\xBFSeguro que quieres borrar este documento? Esta acci\xF3n no se puede deshacer.\n\n| Acci\xF3n | Efecto |\n| --- | --- |\n| Aceptar | Borra el documento |\n| Cancelar | No hace nada |\n:::\n```\n\n:::modal {title="Confirmar borrado" label="Abrir modal" icon="delete"}\n\xBFSeguro que quieres borrar este documento? Esta acci\xF3n no se puede deshacer.\n\n| Acci\xF3n | Efecto |\n| --- | --- |\n| Aceptar | Borra el documento |\n| Cancelar | No hace nada |\n:::\n\n## Contenido enriquecido\n\n```md\n:::modal {title="Notas de la versi\xF3n" label="Ver novedades" icon="new_releases"}\n**v2.0** \u2014 cambios principales:\n\n- Nuevo componente `:::diff`\n- Gu\xEDa integrada en el editor\n- Especificidad CSS corregida en im\xE1genes\n:::\n```\n\n:::modal {title="Notas de la versi\xF3n" label="Ver novedades" icon="new_releases"}\n**v2.0** \u2014 cambios principales:\n\n- Nuevo componente `:::diff`\n- Gu\xEDa integrada en el editor\n- Especificidad CSS corregida en im\xE1genes\n:::\n\n## Props\n\n| Prop | Tipo | Descripci\xF3n |\n| --- | --- | --- |\n| `title` | texto | T\xEDtulo del modal |\n| `label` | texto | Texto del bot\xF3n de apertura (
|
|
12958
|
+
"md": '# Modal\n\nLa directiva `:::modal` crea un **di\xE1logo modal** con su bot\xF3n de apertura.\n\n## Sintaxis\n\n```md\n:::modal {title="Confirmar borrado" label="Abrir modal" icon="delete"}\n\xBFSeguro que quieres borrar este documento? Esta acci\xF3n no se puede deshacer.\n\n| Acci\xF3n | Efecto |\n| --- | --- |\n| Aceptar | Borra el documento |\n| Cancelar | No hace nada |\n:::\n```\n\n:::modal {title="Confirmar borrado" label="Abrir modal" icon="delete"}\n\xBFSeguro que quieres borrar este documento? Esta acci\xF3n no se puede deshacer.\n\n| Acci\xF3n | Efecto |\n| --- | --- |\n| Aceptar | Borra el documento |\n| Cancelar | No hace nada |\n:::\n\n## Contenido enriquecido\n\n```md\n:::modal {title="Notas de la versi\xF3n" label="Ver novedades" icon="new_releases"}\n**v2.0** \u2014 cambios principales:\n\n- Nuevo componente `:::diff`\n- Gu\xEDa integrada en el editor\n- Especificidad CSS corregida en im\xE1genes\n:::\n```\n\n:::modal {title="Notas de la versi\xF3n" label="Ver novedades" icon="new_releases"}\n**v2.0** \u2014 cambios principales:\n\n- Nuevo componente `:::diff`\n- Gu\xEDa integrada en el editor\n- Especificidad CSS corregida en im\xE1genes\n:::\n\n## Sin icono\n\nPara ocultar el icono del bot\xF3n de apertura, usa `icon="none"`:\n\n```md\n:::modal {title="Sin icono" label="Abrir" icon="none"}\nContenido del modal.\n:::\n```\n\n:::modal {title="Sin icono" label="Abrir" icon="none"}\nContenido del modal.\n:::\n\n## Color\n\nEl bot\xF3n de apertura acepta tokens de tema (`primary`, `secondary`, `info`, `success`, `warning`, `error`) o colores CSS arbitrarios:\n\n```md\n:::modal {title="\xC9xito" label="Abrir" icon="check_circle" color="success"}\nAcci\xF3n completada correctamente.\n:::\n```\n\n:::modal {title="\xC9xito" label="Abrir" icon="check_circle" color="success"}\nAcci\xF3n completada correctamente.\n:::\n\n## Alineaci\xF3n del bot\xF3n\n\nEl bot\xF3n de apertura se alinea a la izquierda por defecto. Usa el prop `align` para cambiar la alineaci\xF3n:\n\n### Centrado\n\n```md\n:::modal {title="Centrado" label="Abrir" icon="open_in_full" align="center"}\nContenido del modal centrado.\n:::\n```\n\n:::modal {title="Centrado" label="Abrir" icon="open_in_full" align="center"}\nContenido del modal centrado.\n:::\n\n### Alineado a la derecha\n\n```md\n:::modal {title="Derecha" label="Abrir" icon="open_in_full" align="right"}\nContenido del modal alineado a la derecha.\n:::\n```\n\n:::modal {title="Derecha" label="Abrir" icon="open_in_full" align="right"}\nContenido del modal alineado a la derecha.\n:::\n\n## Props\n\n| Prop | Tipo | Descripci\xF3n |\n| --- | --- | --- |\n| `title` | texto | T\xEDtulo del modal |\n| `label` (o `title`) | texto | Texto del bot\xF3n de apertura (`title` funciona como alias, default: \xABOpen\xBB) |\n| `icon` | nombre Material | Icono del bot\xF3n (default `open_in_full`). Usa `icon="none"` para ocultar |\n| `color` | token de tema o CSS | Color del bot\xF3n de apertura |\n| `align` | `left` / `center` / `right` | Alineaci\xF3n del bot\xF3n de apertura (default `left`) |\n| `class` | texto | Clases CSS adicionales (se aplican al bot\xF3n de apertura) |\n| `style` | CSS | Estilos inline (se aplican al bot\xF3n de apertura) |\n\n## Interacci\xF3n\n\n- **Bot\xF3n**: abre el modal (focus se mueve dentro).\n- **Overlay** o bot\xF3n **\xD7**: cierra.\n- **Esc**: cierra (en desktop).\n- `dialog` nativo \u2192 accesible por defecto, focus trapped y `inert` al fondo.'
|
|
12947
12959
|
},
|
|
12948
12960
|
{
|
|
12949
12961
|
"id": "button",
|
|
@@ -12951,7 +12963,7 @@ var guideData = [
|
|
|
12951
12963
|
"title": "Button",
|
|
12952
12964
|
"icon": "touch_app",
|
|
12953
12965
|
"order": 3,
|
|
12954
|
-
"md": '# Button\n\nLa directiva `:::button` crea un **bot\xF3n con enlace** (se abre en pesta\xF1a nueva por defecto).\n\n## Sintaxis\n\n```md\n:::button {label="Documentaci\xF3n" url="https://example.com" icon="menu_book"}\n:::\n```\n\n:::button {label="Documentaci\xF3n" url="https://example.com" icon="menu_book"}\n:::\n\n## Variante con enlace interno\n\n```md\n:::button {label="Ir a la p\xE1gina de notas" url="#admonici\xF3n-nota" icon="sticky_note_2" target="_self"}\n:::\n```\n\n:::button {label="Ir a la p\xE1gina de notas" url="#admonici\xF3n-nota" icon="sticky_note_2" target="_self"}\n:::\n\n## Con contenido markdown\n\nSi el bloque contiene texto/enlaces, se renderizan dentro del bot\xF3n:\n\n```md\n:::button {label="Descargar" url="https://example.com/download" icon="download"}\nDescarga el **manual** en PDF\n:::\n```\n\n:::button {label="Descargar" url="https://example.com/download" icon="download"}\nDescarga el **manual** en PDF\n:::\n\n## Props\n\n| Prop | Tipo | Descripci\xF3n |\n| --- | --- | --- |\n| `label` | texto | Texto del bot\xF3n |\n| `url` (o `href`) | URL | Destino del enlace (default `#`) |\n| `icon` | nombre Material | Icono (default `
|
|
12966
|
+
"md": '# Button\n\nLa directiva `:::button` crea un **bot\xF3n con enlace** (se abre en pesta\xF1a nueva por defecto).\n\n## Sintaxis\n\n```md\n:::button {label="Documentaci\xF3n" url="https://example.com" icon="menu_book"}\n:::\n```\n\n:::button {label="Documentaci\xF3n" url="https://example.com" icon="menu_book"}\n:::\n\n## Variante con enlace interno\n\n```md\n:::button {label="Ir a la p\xE1gina de notas" url="#admonici\xF3n-nota" icon="sticky_note_2" target="_self"}\n:::\n```\n\n:::button {label="Ir a la p\xE1gina de notas" url="#admonici\xF3n-nota" icon="sticky_note_2" target="_self"}\n:::\n\n## Con contenido markdown\n\nSi el bloque contiene texto/enlaces, se renderizan dentro del bot\xF3n. El icono se a\xF1ade autom\xE1ticamente a cada enlace del contenido:\n\n```md\n:::button {label="Descargar" url="https://example.com/download" icon="download"}\nDescarga el **manual** en PDF\n:::\n```\n\n:::button {label="Descargar" url="https://example.com/download" icon="download"}\nDescarga el **manual** en PDF\n:::\n\n## Con enlace en el contenido\n\nSi el contenido es un enlace markdown, el bot\xF3n usa el enlace del contenido y el icono se a\xF1ade al principio:\n\n```md\n:::button {icon="star"}\n[Descarga con FDM](https://example.com/download)\n:::\n```\n\n:::button {icon="star"}\n[Descarga con FDM](https://example.com/download)\n:::\n\n## Sin icono\n\nPara ocultar el icono, usa `icon="none"`:\n\n```md\n:::button {label="Sin icono" url="https://example.com" icon="none"}\n:::\n```\n\n:::button {label="Sin icono" url="https://example.com" icon="none"}\n:::\n\n## Color\n\nLos botones aceptan tokens de tema (`primary`, `secondary`, `info`, `success`, `warning`, `error`) o colores CSS arbitrarios (`red`, `#ff0000`, `rgb(255,0,0)`):\n\n```md\n:::button {label="\xC9xito" url="https://example.com" icon="check_circle" color="success"}\n:::\n```\n\n:::button {label="\xC9xito" url="https://example.com" icon="check_circle" color="success"}\n:::\n\n```md\n:::button {label="Rojo" url="https://example.com" icon="error" color="#e11d48"}\n:::\n```\n\n:::button {label="Rojo" url="https://example.com" icon="error" color="#e11d48"}\n:::\n\n## Alineaci\xF3n\n\nLos botones se alinean a la izquierda por defecto. Usa el prop `align` para cambiar la alineaci\xF3n:\n\n### Centrado\n\n```md\n:::button {label="Centrado" url="https://example.com" icon="center_focus_strong" align="center"}\n:::\n```\n\n:::button {label="Centrado" url="https://example.com" icon="center_focus_strong" align="center"}\n:::\n\n### Alineado a la derecha\n\n```md\n:::button {label="Derecha" url="https://example.com" icon="arrow_forward" align="right"}\n:::\n```\n\n:::button {label="Derecha" url="https://example.com" icon="arrow_forward" align="right"}\n:::\n\n## Props\n\n| Prop | Tipo | Descripci\xF3n |\n| --- | --- | --- |\n| `label` (o `title`) | texto | Texto del bot\xF3n (`title` funciona como alias por compatibilidad) |\n| `url` (o `href`) | URL | Destino del enlace (default `#`) |\n| `icon` | nombre Material | Icono (default `touch_app`). Usa `icon="none"` para ocultar |\n| `target` | `_blank` / `_self` / ... | Destino del enlace (default `_blank`) |\n| `color` | token de tema o CSS | Color del bot\xF3n (ver colores soportados arriba) |\n| `align` | `left` / `center` / `right` | Alineaci\xF3n del bot\xF3n (default `left`) |\n| `class` | texto | Clases CSS adicionales |\n| `style` | CSS | Estilos inline (ej: `style="font-size:1rem"`) |'
|
|
12955
12967
|
},
|
|
12956
12968
|
{
|
|
12957
12969
|
"id": "slide",
|
|
@@ -12968,6 +12980,14 @@ var guideData = [
|
|
|
12968
12980
|
"icon": "code_off",
|
|
12969
12981
|
"order": 1,
|
|
12970
12982
|
"md": '# Bloques HTML\r\n\r\nNoirMD permite escribir **HTML crudo** directamente en el markdown. Seg\xFAn la etiqueta, el comportamiento var\xEDa.\r\n\r\n## CSS global con `<style>`\r\n\r\nEscribe un bloque `<style>` para inyectar CSS en el documento. El contenido se extrae autom\xE1ticamente y se inserta en el `<head>` del DOM.\r\n\r\n```md\r\n<style>\r\n.mi-clase {\r\n background: #f1f5f9;\r\n border-radius: 10px;\r\n padding: 1rem;\r\n}\r\n</style>\r\n```\r\n\r\n<style>\r\n.nr-demo-box {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 1rem;\r\n padding: 1rem;\r\n border-radius: 12px;\r\n background: color-mix(in srgb, var(--color-accent-primary, #0ea5e9) 10%, transparent);\r\n}\r\n.nr-demo-box > div {\r\n padding: 1rem;\r\n border-radius: 8px;\r\n background: var(--color-background-secondary-solid, #1e293b);\r\n}\r\n</style>\r\n\r\n<div class="nr-demo-box">\r\n<div>**A**</div>\r\n<div>**B**</div>\r\n</div>\r\n\r\n> El CSS se aplica al **documento renderizado completo**, no solo al bloque. Define clases una vez y \xFAsalas despu\xE9s en cualquier etiqueta HTML.\r\n\r\n## HTML inline\r\n\r\nCualquier etiqueta HTML escrita directamente en el markdown se renderiza sin procesar como markdown. El contenido dentro se preserva tal cual.\r\n\r\n```md\r\n<div style="text-align: center; padding: 1rem; border: 1px solid #334155; border-radius: 10px;">\r\n HTML escrito a mano funciona tal cual.\r\n</div>\r\n```\r\n\r\n<div style="text-align: center; padding: 1rem; border: 1px solid #334155; border-radius: 10px;">\r\n HTML escrito a mano funciona tal cual.\r\n</div>\r\n\r\n## Elementos interactivos nativos\r\n\r\n```md\r\n<details class="nr-details">\r\n <summary>Detalle nativo con <b>HTML</b></summary>\r\n <p>Los atributos, estilos y eventos se conservan intactos.</p>\r\n</details>\r\n```\r\n\r\n<details class="nr-details">\r\n <summary>Detalle nativo con <b>HTML</b></summary>\r\n <p>Los atributos, estilos y eventos se conservan intactos.</p>\r\n</details>\r\n\r\n## Scripts\r\n\r\nLos bloques `<script>` se ejecutan autom\xE1ticamente al renderizar:\r\n\r\n```md\r\n<script>\r\n console.log(\'Este script se ejecuta al renderizar\');\r\n</script>\r\n```\r\n\r\n> \u26A0\uFE0F Al ser HTML y scripts sin filtrar, \xFAsalos solo con contenido de confianza.\r\n\r\n## Cu\xE1ndo usar bloques HTML\r\n\r\n- Insertar embeds (`iframe`, `video`, widgets externos).\r\n- Estructuras que el markdown no cubre (layouts complejos, formularios nativos).\r\n- Inyectar CSS reutilizable con `<style>`.\r\n- Prototipar HTML antes de convertirlo a directiva.'
|
|
12983
|
+
},
|
|
12984
|
+
{
|
|
12985
|
+
"id": "wrapper-directives",
|
|
12986
|
+
"category": "Layout",
|
|
12987
|
+
"title": "Wrapper Directives",
|
|
12988
|
+
"icon": "crop_free",
|
|
12989
|
+
"order": 1,
|
|
12990
|
+
"md": '# Wrapper Directives\r\n\r\nLas directivas `:::div`, `:::style`, `:::custom` y `:::raw` son wrappers gen\xE9ricos para **envolver contenido** con clases, estilos y atributos personalizados.\r\n\r\n## `:::div` \u2014 Div gen\xE9rico\r\n\r\nEnvuelve contenido en un `<div>` con clases, id, estilos y atributos `data-*`.\r\n\r\n```md\r\n:::div {class="mi-clase" id="seccion" style="padding: 2rem; background: #f0f0f0"}\r\n\r\nContenido **markdown** aqu\xED.\r\n\r\n:::\r\n```\r\n\r\n:::div {class="mi-clase" id="seccion" style="padding: 2rem; background: #f0f0f0"}\r\n\r\nContenido **markdown** aqu\xED.\r\n\r\n:::\r\n\r\n## `:::style` \u2014 Inyectar CSS\r\n\r\nInyecta un bloque `<style>` global. \xDAtil para estilos que afectan m\xFAltiples componentes.\r\n\r\n```md\r\n:::style\r\n.nr-mi-clase { color: red; }\r\n:::\r\n```\r\n\r\n## `:::custom` \u2014 Elemento personalizado\r\n\r\nSimilar a `div`, pero permite crear cualquier elemento HTML.\r\n\r\n## `:::raw` \u2014 HTML crudo\r\n\r\nRenderiza contenido HTML sin procesar.\r\n\r\n## Props\r\n\r\n| Prop | Tipo | Descripci\xF3n |\r\n| --- | --- | --- |\r\n| `class` | texto | Clases CSS (soporta `.shorthand` tambi\xE9n) |\r\n| `id` | texto | ID del elemento |\r\n| `style` | CSS inline | Estilos inline (se aplica con `setProperty`, no sobreescribe otros estilos) |\r\n| `data-*` | texto | Cualquier atributo `data-*` se aplica al elemento |\r\n\r\n## Shorthands\r\n\r\n```md\r\n:::div {.mi-clase #mi-id}\r\n\r\nIgual que usar `class="mi-clase" id="mi-id"`.\r\n\r\n:::\r\n```'
|
|
12971
12991
|
}
|
|
12972
12992
|
];
|
|
12973
12993
|
|