@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.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:
|
|
1670
|
-
|
|
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("/>") ||
|
|
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;
|
|
@@ -11047,6 +11058,7 @@ function createModal(title) {
|
|
|
11047
11058
|
header.appendChild(titleEl);
|
|
11048
11059
|
const closeBtn = document.createElement("button");
|
|
11049
11060
|
closeBtn.className = "nr-modal__close";
|
|
11061
|
+
closeBtn.setAttribute("aria-label", "Close");
|
|
11050
11062
|
closeBtn.appendChild(createIcon("close"));
|
|
11051
11063
|
closeBtn.addEventListener("click", () => dialog.close());
|
|
11052
11064
|
header.appendChild(closeBtn);
|
|
@@ -11267,11 +11279,89 @@ function parseInlinePart(part) {
|
|
|
11267
11279
|
return document.createTextNode(part);
|
|
11268
11280
|
}
|
|
11269
11281
|
|
|
11282
|
+
// vanilla/utils.ts
|
|
11283
|
+
var THEME_TOKENS = /* @__PURE__ */ new Set([
|
|
11284
|
+
"primary",
|
|
11285
|
+
"secondary",
|
|
11286
|
+
"accent",
|
|
11287
|
+
"neutral",
|
|
11288
|
+
"info",
|
|
11289
|
+
"success",
|
|
11290
|
+
"warning",
|
|
11291
|
+
"error"
|
|
11292
|
+
]);
|
|
11293
|
+
function isThemeToken(color) {
|
|
11294
|
+
return !!color && THEME_TOKENS.has(color);
|
|
11295
|
+
}
|
|
11296
|
+
function isArbitraryColor(value) {
|
|
11297
|
+
if (THEME_TOKENS.has(value)) return false;
|
|
11298
|
+
if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
|
|
11299
|
+
if (/^[a-zA-Z]+$/.test(value)) return true;
|
|
11300
|
+
return false;
|
|
11301
|
+
}
|
|
11302
|
+
function applyBaseProps(el, props) {
|
|
11303
|
+
if (props.class) {
|
|
11304
|
+
el.classList.add(...props.class.split(/\s+/).filter(Boolean));
|
|
11305
|
+
}
|
|
11306
|
+
if (props.style) {
|
|
11307
|
+
const styles = parseCssString(props.style);
|
|
11308
|
+
for (const [key, value] of Object.entries(styles)) {
|
|
11309
|
+
el.style.setProperty(key, String(value));
|
|
11310
|
+
}
|
|
11311
|
+
}
|
|
11312
|
+
}
|
|
11313
|
+
function applyFloatStyle(el, float, width) {
|
|
11314
|
+
if (!float) return;
|
|
11315
|
+
if (float === "left" || float === "right") {
|
|
11316
|
+
el.style.float = float;
|
|
11317
|
+
if (!width) el.style.maxWidth = "50%";
|
|
11318
|
+
el.style.marginInlineStart = float === "right" ? "1rem" : "";
|
|
11319
|
+
el.style.marginInlineEnd = float === "left" ? "1rem" : "";
|
|
11320
|
+
} else if (float === "center") {
|
|
11321
|
+
el.style.marginInline = "auto";
|
|
11322
|
+
}
|
|
11323
|
+
}
|
|
11324
|
+
function applyColor(el, color, classSuffix) {
|
|
11325
|
+
if (!color) return "";
|
|
11326
|
+
if (isThemeToken(color)) {
|
|
11327
|
+
return ` ${classSuffix}--${color}`;
|
|
11328
|
+
}
|
|
11329
|
+
if (isArbitraryColor(color)) {
|
|
11330
|
+
el.style.background = color;
|
|
11331
|
+
el.style.color = "white";
|
|
11332
|
+
}
|
|
11333
|
+
return "";
|
|
11334
|
+
}
|
|
11335
|
+
function openModal(dialog) {
|
|
11336
|
+
if (!dialog.open) {
|
|
11337
|
+
document.body.appendChild(dialog);
|
|
11338
|
+
dialog.showModal();
|
|
11339
|
+
dialog.addEventListener("close", () => dialog.remove(), { once: true });
|
|
11340
|
+
}
|
|
11341
|
+
}
|
|
11342
|
+
var IMG_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
11343
|
+
function applyAlignClass(el, baseClass, align) {
|
|
11344
|
+
if (align === "center") {
|
|
11345
|
+
el.classList.add(`${baseClass}--center`);
|
|
11346
|
+
} else if (align === "right") {
|
|
11347
|
+
el.classList.add(`${baseClass}--right`);
|
|
11348
|
+
}
|
|
11349
|
+
}
|
|
11350
|
+
function resolveIcon(value, fallback) {
|
|
11351
|
+
if (!value) return fallback;
|
|
11352
|
+
if (value === "none" || value === "off") return null;
|
|
11353
|
+
return value;
|
|
11354
|
+
}
|
|
11355
|
+
function parseIntProp(value, defaultValue) {
|
|
11356
|
+
if (!value) return defaultValue;
|
|
11357
|
+
const n = parseInt(value, 10);
|
|
11358
|
+
return Number.isNaN(n) ? defaultValue : n;
|
|
11359
|
+
}
|
|
11360
|
+
|
|
11270
11361
|
// vanilla/directives/admonition.ts
|
|
11271
11362
|
var admonitionDirective = ({ directiveType, props, renderSlot }) => {
|
|
11272
11363
|
const el = createAdmonition(directiveType, props.title, props.icon);
|
|
11273
|
-
|
|
11274
|
-
if (props.style) el.setAttribute("style", props.style);
|
|
11364
|
+
applyBaseProps(el, props);
|
|
11275
11365
|
const body = el.querySelector(".nr-admonition__body");
|
|
11276
11366
|
if (body) {
|
|
11277
11367
|
body.appendChild(renderSlot("default"));
|
|
@@ -11287,8 +11377,7 @@ var detailsDirective = ({ props, renderSlot }) => {
|
|
|
11287
11377
|
props.icon,
|
|
11288
11378
|
props.defaultOpen === "true"
|
|
11289
11379
|
);
|
|
11290
|
-
|
|
11291
|
-
if (props.style) el.setAttribute("style", props.style);
|
|
11380
|
+
applyBaseProps(el, props);
|
|
11292
11381
|
const body = el.querySelector(".nr-details__body");
|
|
11293
11382
|
if (body) {
|
|
11294
11383
|
body.appendChild(renderSlot("default"));
|
|
@@ -11301,14 +11390,17 @@ var details_default = detailsDirective;
|
|
|
11301
11390
|
var modalDirective = ({ props, renderSlot }) => {
|
|
11302
11391
|
const label = props.label || props.title || "Open";
|
|
11303
11392
|
const modalTitle = props.title || "Modal";
|
|
11304
|
-
const
|
|
11393
|
+
const align = props.align || "left";
|
|
11394
|
+
const iconName = resolveIcon(props.icon, "open_in_full");
|
|
11305
11395
|
const wrapper = document.createElement("div");
|
|
11306
11396
|
wrapper.className = "nr-modal-trigger";
|
|
11397
|
+
applyAlignClass(wrapper, "nr-modal-trigger", align);
|
|
11307
11398
|
const btn = document.createElement("button");
|
|
11308
|
-
btn.className =
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11399
|
+
btn.className = "nr-button nr-button--default";
|
|
11400
|
+
btn.setAttribute("aria-haspopup", "dialog");
|
|
11401
|
+
applyColor(btn, props.color, "nr-button");
|
|
11402
|
+
applyBaseProps(btn, props);
|
|
11403
|
+
if (iconName) btn.appendChild(createIcon(iconName));
|
|
11312
11404
|
btn.appendChild(document.createTextNode(label));
|
|
11313
11405
|
const dialog = createModal(modalTitle);
|
|
11314
11406
|
const body = dialog.querySelector(".nr-modal__body");
|
|
@@ -11318,15 +11410,7 @@ var modalDirective = ({ props, renderSlot }) => {
|
|
|
11318
11410
|
prose.appendChild(renderSlot("default"));
|
|
11319
11411
|
body.appendChild(prose);
|
|
11320
11412
|
}
|
|
11321
|
-
btn.addEventListener("click", () =>
|
|
11322
|
-
if (!dialog.open) {
|
|
11323
|
-
document.body.appendChild(dialog);
|
|
11324
|
-
dialog.showModal();
|
|
11325
|
-
dialog.addEventListener("close", () => {
|
|
11326
|
-
dialog.remove();
|
|
11327
|
-
}, { once: true });
|
|
11328
|
-
}
|
|
11329
|
-
});
|
|
11413
|
+
btn.addEventListener("click", () => openModal(dialog));
|
|
11330
11414
|
wrapper.appendChild(btn);
|
|
11331
11415
|
wrapper.appendChild(dialog);
|
|
11332
11416
|
return wrapper;
|
|
@@ -11336,20 +11420,22 @@ var modal_default = modalDirective;
|
|
|
11336
11420
|
// vanilla/directives/button.ts
|
|
11337
11421
|
var buttonDirective = ({ props, renderSlot }) => {
|
|
11338
11422
|
const url = props.url || props.href || "#";
|
|
11339
|
-
const label = props.label;
|
|
11340
|
-
const
|
|
11423
|
+
const label = props.label || props.title;
|
|
11424
|
+
const iconName = resolveIcon(props.icon, "touch_app");
|
|
11341
11425
|
const target = props.target || "_blank";
|
|
11342
|
-
const
|
|
11426
|
+
const align = props.align || "left";
|
|
11343
11427
|
const wrapper = document.createElement("div");
|
|
11344
11428
|
wrapper.className = "nr-button-wrap";
|
|
11429
|
+
applyAlignClass(wrapper, "nr-button-wrap", align);
|
|
11345
11430
|
if (label) {
|
|
11346
11431
|
const a = document.createElement("a");
|
|
11347
11432
|
a.href = url;
|
|
11348
11433
|
a.target = target;
|
|
11349
|
-
a.rel = "noopener noreferrer";
|
|
11434
|
+
if (target === "_blank") a.rel = "noopener noreferrer";
|
|
11350
11435
|
a.className = "nr-button nr-button--default";
|
|
11351
|
-
|
|
11352
|
-
a
|
|
11436
|
+
applyColor(a, props.color, "nr-button");
|
|
11437
|
+
applyBaseProps(a, props);
|
|
11438
|
+
if (iconName) a.appendChild(createIcon(iconName));
|
|
11353
11439
|
a.appendChild(document.createTextNode(label));
|
|
11354
11440
|
wrapper.appendChild(a);
|
|
11355
11441
|
return wrapper;
|
|
@@ -11359,17 +11445,20 @@ var buttonDirective = ({ props, renderSlot }) => {
|
|
|
11359
11445
|
if (links.length > 0) {
|
|
11360
11446
|
links.forEach((link) => {
|
|
11361
11447
|
link.classList.add("nr-button", "nr-button--default");
|
|
11362
|
-
|
|
11448
|
+
applyColor(link, props.color, "nr-button");
|
|
11449
|
+
if (iconName) link.prepend(createIcon(iconName));
|
|
11450
|
+
applyBaseProps(link, props);
|
|
11363
11451
|
});
|
|
11364
11452
|
wrapper.appendChild(slotContent);
|
|
11365
11453
|
} else {
|
|
11366
11454
|
const a = document.createElement("a");
|
|
11367
11455
|
a.href = url;
|
|
11368
11456
|
a.target = target;
|
|
11369
|
-
a.rel = "noopener noreferrer";
|
|
11457
|
+
if (target === "_blank") a.rel = "noopener noreferrer";
|
|
11370
11458
|
a.className = "nr-button nr-button--default";
|
|
11371
|
-
|
|
11372
|
-
a
|
|
11459
|
+
applyColor(a, props.color, "nr-button");
|
|
11460
|
+
applyBaseProps(a, props);
|
|
11461
|
+
if (iconName) a.appendChild(createIcon(iconName));
|
|
11373
11462
|
a.appendChild(slotContent);
|
|
11374
11463
|
wrapper.appendChild(a);
|
|
11375
11464
|
}
|
|
@@ -11391,12 +11480,9 @@ var cardDirective = ({
|
|
|
11391
11480
|
const { isSingleCard } = options || {};
|
|
11392
11481
|
const isModal = directiveType === "card-m";
|
|
11393
11482
|
const isLink = directiveType === "card-b";
|
|
11394
|
-
const inlineStyles = props.style ? parseCssString(props.style) : {};
|
|
11395
11483
|
const card = document.createElement("div");
|
|
11396
11484
|
card.className = `nr-card${isModal || isLink ? " nr-card--interactive" : ""} ${customClass}`.trim();
|
|
11397
|
-
|
|
11398
|
-
card.style.setProperty(key, String(value));
|
|
11399
|
-
}
|
|
11485
|
+
applyBaseProps(card, props);
|
|
11400
11486
|
if (image) {
|
|
11401
11487
|
const imgWrap = document.createElement("div");
|
|
11402
11488
|
imgWrap.className = `nr-card__image${isSingleCard ? " nr-card__image--tall" : ""}`;
|
|
@@ -11475,13 +11561,7 @@ var cardDirective = ({
|
|
|
11475
11561
|
prose.appendChild(renderSlot("content") || renderSlot("default"));
|
|
11476
11562
|
modalBody.appendChild(prose);
|
|
11477
11563
|
}
|
|
11478
|
-
card.addEventListener("click", () =>
|
|
11479
|
-
if (!dialog.open) {
|
|
11480
|
-
document.body.appendChild(dialog);
|
|
11481
|
-
dialog.showModal();
|
|
11482
|
-
dialog.addEventListener("close", () => dialog.remove(), { once: true });
|
|
11483
|
-
}
|
|
11484
|
-
});
|
|
11564
|
+
card.addEventListener("click", () => openModal(dialog));
|
|
11485
11565
|
const frag = document.createDocumentFragment();
|
|
11486
11566
|
frag.appendChild(card);
|
|
11487
11567
|
frag.appendChild(dialog);
|
|
@@ -11529,8 +11609,8 @@ var slideDirective = ({
|
|
|
11529
11609
|
if (lines.length === 0) {
|
|
11530
11610
|
return document.createDocumentFragment();
|
|
11531
11611
|
}
|
|
11532
|
-
const interval =
|
|
11533
|
-
const speed =
|
|
11612
|
+
const interval = parseIntProp(props.interval, 3e3);
|
|
11613
|
+
const speed = parseIntProp(props.speed, 500);
|
|
11534
11614
|
const rawClass = props.class || "";
|
|
11535
11615
|
const inlineStyle = props.style ? parseCssString(props.style) : {};
|
|
11536
11616
|
const scopeClass = `sld-${++slideCounter}`;
|
|
@@ -11581,10 +11661,11 @@ var slideDirective = ({
|
|
|
11581
11661
|
}
|
|
11582
11662
|
});
|
|
11583
11663
|
if (lines.length > 1) {
|
|
11584
|
-
setInterval(() => {
|
|
11664
|
+
const id = setInterval(() => {
|
|
11585
11665
|
current = (current + 1) % lines.length;
|
|
11586
11666
|
track.style.transform = `translateY(${-current * maxH}px)`;
|
|
11587
11667
|
}, interval);
|
|
11668
|
+
container.dataset.nrIntervalId = String(id);
|
|
11588
11669
|
}
|
|
11589
11670
|
return container;
|
|
11590
11671
|
};
|
|
@@ -11594,8 +11675,7 @@ var slide_default = slideDirective;
|
|
|
11594
11675
|
var keysDirective = ({ props, slots }) => {
|
|
11595
11676
|
const wrap = document.createElement("div");
|
|
11596
11677
|
wrap.className = "nr-keys";
|
|
11597
|
-
|
|
11598
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
11678
|
+
applyBaseProps(wrap, props);
|
|
11599
11679
|
const sizeClass = props.size ? ` nr-kbd--${props.size}` : "";
|
|
11600
11680
|
const parts = (slots.default || "").split("+").map((p) => p.trim()).filter(Boolean);
|
|
11601
11681
|
parts.forEach((part, i) => {
|
|
@@ -11619,8 +11699,7 @@ var accordionCounter = 0;
|
|
|
11619
11699
|
var accordionItemDirective = ({ props, renderSlot }) => {
|
|
11620
11700
|
const item = document.createElement("div");
|
|
11621
11701
|
item.className = "nr-accordion__item";
|
|
11622
|
-
|
|
11623
|
-
if (props.style) item.setAttribute("style", props.style);
|
|
11702
|
+
applyBaseProps(item, props);
|
|
11624
11703
|
const input = document.createElement("input");
|
|
11625
11704
|
input.type = "radio";
|
|
11626
11705
|
input.className = "nr-accordion__input";
|
|
@@ -11639,8 +11718,7 @@ var accordionItemDirective = ({ props, renderSlot }) => {
|
|
|
11639
11718
|
var accordionDirective = ({ props, renderSlot }) => {
|
|
11640
11719
|
const wrap = document.createElement("div");
|
|
11641
11720
|
wrap.className = "nr-accordion";
|
|
11642
|
-
|
|
11643
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
11721
|
+
applyBaseProps(wrap, props);
|
|
11644
11722
|
wrap.appendChild(renderSlot("default"));
|
|
11645
11723
|
const mode = props.mode === "checkbox" ? "checkbox" : "radio";
|
|
11646
11724
|
const group = `nr-acc-${++accordionCounter}`;
|
|
@@ -11653,7 +11731,6 @@ var accordionDirective = ({ props, renderSlot }) => {
|
|
|
11653
11731
|
var accordion_default = accordionDirective;
|
|
11654
11732
|
|
|
11655
11733
|
// vanilla/directives/carousel.ts
|
|
11656
|
-
var IMG_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
11657
11734
|
var carouselDirective = ({ props, slots }) => {
|
|
11658
11735
|
const images = [];
|
|
11659
11736
|
const raw = slots.default || "";
|
|
@@ -11669,19 +11746,9 @@ var carouselDirective = ({ props, slots }) => {
|
|
|
11669
11746
|
wrap.className = "nr-carousel";
|
|
11670
11747
|
wrap.tabIndex = 0;
|
|
11671
11748
|
wrap.setAttribute("aria-label", "Image carousel");
|
|
11672
|
-
|
|
11673
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
11749
|
+
applyBaseProps(wrap, props);
|
|
11674
11750
|
if (props.width) wrap.style.width = props.width;
|
|
11675
|
-
|
|
11676
|
-
if (props.float === "left" || props.float === "right") {
|
|
11677
|
-
wrap.style.float = props.float;
|
|
11678
|
-
if (!props.width) wrap.style.maxWidth = "50%";
|
|
11679
|
-
wrap.style.marginInlineStart = props.float === "right" ? "1rem" : "";
|
|
11680
|
-
wrap.style.marginInlineEnd = props.float === "left" ? "1rem" : "";
|
|
11681
|
-
} else if (props.float === "center") {
|
|
11682
|
-
wrap.style.marginInline = "auto";
|
|
11683
|
-
}
|
|
11684
|
-
}
|
|
11751
|
+
applyFloatStyle(wrap, props.float, props.width);
|
|
11685
11752
|
const viewport = document.createElement("div");
|
|
11686
11753
|
viewport.className = "nr-carousel__viewport";
|
|
11687
11754
|
if (props.height) viewport.style.height = props.height;
|
|
@@ -11751,11 +11818,10 @@ var DEFAULT_LABELS = ["days", "hours", "min", "sec"];
|
|
|
11751
11818
|
var countdownDirective = ({ props }) => {
|
|
11752
11819
|
const wrap = document.createElement("div");
|
|
11753
11820
|
wrap.className = "nr-countdown";
|
|
11754
|
-
|
|
11755
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
11821
|
+
applyBaseProps(wrap, props);
|
|
11756
11822
|
const labelParts = (props.labels || "").split("|").map((s) => s.trim());
|
|
11757
11823
|
const labels = DEFAULT_LABELS.map((label, i) => labelParts[i] || label);
|
|
11758
|
-
const digits =
|
|
11824
|
+
const digits = parseIntProp(props.digits, 2);
|
|
11759
11825
|
const targetTime = props.target ? new Date(props.target).getTime() : NaN;
|
|
11760
11826
|
const hasTarget = !Number.isNaN(targetTime);
|
|
11761
11827
|
const blocks = [];
|
|
@@ -11802,13 +11868,15 @@ var countdownDirective = ({ props }) => {
|
|
|
11802
11868
|
blocks.push({ value });
|
|
11803
11869
|
});
|
|
11804
11870
|
render();
|
|
11805
|
-
if (hasTarget)
|
|
11871
|
+
if (hasTarget) {
|
|
11872
|
+
const id = setInterval(render, 1e3);
|
|
11873
|
+
wrap.dataset.nrIntervalId = String(id);
|
|
11874
|
+
}
|
|
11806
11875
|
return wrap;
|
|
11807
11876
|
};
|
|
11808
11877
|
var countdown_default = countdownDirective;
|
|
11809
11878
|
|
|
11810
11879
|
// vanilla/directives/diff.ts
|
|
11811
|
-
var IMG_RE2 = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
11812
11880
|
var diffDirective = ({ props, slots }) => {
|
|
11813
11881
|
let before = (props.before || "").split("#")[0].trim();
|
|
11814
11882
|
let after = (props.after || "").split("#")[0].trim();
|
|
@@ -11816,8 +11884,8 @@ var diffDirective = ({ props, slots }) => {
|
|
|
11816
11884
|
const urls = [];
|
|
11817
11885
|
const raw = slots.default || "";
|
|
11818
11886
|
let m;
|
|
11819
|
-
|
|
11820
|
-
while ((m =
|
|
11887
|
+
IMG_RE.lastIndex = 0;
|
|
11888
|
+
while ((m = IMG_RE.exec(raw)) !== null) {
|
|
11821
11889
|
urls.push(m[2].split("#")[0].trim());
|
|
11822
11890
|
}
|
|
11823
11891
|
if (!before && urls.length > 0) before = urls[0];
|
|
@@ -11830,21 +11898,11 @@ var diffDirective = ({ props, slots }) => {
|
|
|
11830
11898
|
figure.className = "nr-diff";
|
|
11831
11899
|
figure.tabIndex = 0;
|
|
11832
11900
|
figure.setAttribute("aria-label", "Image comparison slider");
|
|
11833
|
-
|
|
11834
|
-
if (props.style) figure.setAttribute("style", props.style);
|
|
11901
|
+
applyBaseProps(figure, props);
|
|
11835
11902
|
if (props.aspect) figure.style.aspectRatio = props.aspect;
|
|
11836
11903
|
if (props.height) figure.style.height = props.height;
|
|
11837
11904
|
if (props.width) figure.style.width = props.width;
|
|
11838
|
-
|
|
11839
|
-
if (props.float === "left" || props.float === "right") {
|
|
11840
|
-
figure.style.float = props.float;
|
|
11841
|
-
if (!props.width) figure.style.maxWidth = "50%";
|
|
11842
|
-
figure.style.marginInlineStart = props.float === "right" ? "1rem" : "";
|
|
11843
|
-
figure.style.marginInlineEnd = props.float === "left" ? "1rem" : "";
|
|
11844
|
-
} else if (props.float === "center") {
|
|
11845
|
-
figure.style.marginInline = "auto";
|
|
11846
|
-
}
|
|
11847
|
-
}
|
|
11905
|
+
applyFloatStyle(figure, props.float, props.width);
|
|
11848
11906
|
const beforeItem = document.createElement("div");
|
|
11849
11907
|
beforeItem.className = "nr-diff__item nr-diff__item--before";
|
|
11850
11908
|
beforeItem.setAttribute("role", "img");
|
|
@@ -11907,8 +11965,7 @@ var diff_default = diffDirective;
|
|
|
11907
11965
|
var hover3dDirective = ({ props, renderSlot }) => {
|
|
11908
11966
|
const container = document.createElement("div");
|
|
11909
11967
|
container.className = "nr-hover-3d";
|
|
11910
|
-
|
|
11911
|
-
if (props.style) container.setAttribute("style", props.style);
|
|
11968
|
+
applyBaseProps(container, props);
|
|
11912
11969
|
const stage = document.createElement("div");
|
|
11913
11970
|
stage.className = "nr-hover-3d__stage";
|
|
11914
11971
|
stage.appendChild(renderSlot("default"));
|
|
@@ -11921,14 +11978,13 @@ var hover3dDirective = ({ props, renderSlot }) => {
|
|
|
11921
11978
|
var hover3d_default = hover3dDirective;
|
|
11922
11979
|
|
|
11923
11980
|
// vanilla/directives/hovergallery.ts
|
|
11924
|
-
var IMG_RE3 = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
11925
11981
|
var MAX_IMAGES = 10;
|
|
11926
11982
|
var hovergalleryDirective = ({ props, slots }) => {
|
|
11927
11983
|
const images = [];
|
|
11928
11984
|
const raw = slots.default || "";
|
|
11929
11985
|
let m;
|
|
11930
|
-
|
|
11931
|
-
while ((m =
|
|
11986
|
+
IMG_RE.lastIndex = 0;
|
|
11987
|
+
while ((m = IMG_RE.exec(raw)) !== null) {
|
|
11932
11988
|
images.push({ src: m[2].split("#")[0].trim(), alt: m[1].trim() || "gallery image" });
|
|
11933
11989
|
}
|
|
11934
11990
|
if (images.length === 0) {
|
|
@@ -11937,9 +11993,8 @@ var hovergalleryDirective = ({ props, slots }) => {
|
|
|
11937
11993
|
const count = Math.min(images.length, MAX_IMAGES);
|
|
11938
11994
|
const figure = document.createElement("figure");
|
|
11939
11995
|
figure.className = "nr-hover-gallery";
|
|
11996
|
+
applyBaseProps(figure, props);
|
|
11940
11997
|
if (props.aspect) figure.style.aspectRatio = props.aspect;
|
|
11941
|
-
if (props.class) figure.classList.add(...props.class.split(/\s+/).filter(Boolean));
|
|
11942
|
-
if (props.style) figure.setAttribute("style", (figure.getAttribute("style") || "") + ";" + props.style);
|
|
11943
11998
|
const imgEls = [];
|
|
11944
11999
|
for (let i = 0; i < count; i++) {
|
|
11945
12000
|
const el = document.createElement("img");
|
|
@@ -11989,28 +12044,11 @@ var hovergalleryDirective = ({ props, slots }) => {
|
|
|
11989
12044
|
var hovergallery_default = hovergalleryDirective;
|
|
11990
12045
|
|
|
11991
12046
|
// vanilla/directives/chat.ts
|
|
11992
|
-
var CHAT_THEME_TOKENS = /* @__PURE__ */ new Set([
|
|
11993
|
-
"primary",
|
|
11994
|
-
"secondary",
|
|
11995
|
-
"accent",
|
|
11996
|
-
"neutral",
|
|
11997
|
-
"info",
|
|
11998
|
-
"success",
|
|
11999
|
-
"warning",
|
|
12000
|
-
"error"
|
|
12001
|
-
]);
|
|
12002
|
-
function isArbitraryColor(value) {
|
|
12003
|
-
if (CHAT_THEME_TOKENS.has(value)) return false;
|
|
12004
|
-
if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
|
|
12005
|
-
if (/^[a-zA-Z]+$/.test(value)) return true;
|
|
12006
|
-
return false;
|
|
12007
|
-
}
|
|
12008
12047
|
var chatItemDirective = ({ props, renderSlot }) => {
|
|
12009
12048
|
const side = props.side === "end" ? "end" : "start";
|
|
12010
12049
|
const wrap = document.createElement("div");
|
|
12011
12050
|
wrap.className = `nr-chat nr-chat--${side}`;
|
|
12012
|
-
|
|
12013
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
12051
|
+
applyBaseProps(wrap, props);
|
|
12014
12052
|
const header = document.createElement("div");
|
|
12015
12053
|
header.className = "nr-chat__header";
|
|
12016
12054
|
if (props.name) {
|
|
@@ -12035,14 +12073,8 @@ var chatItemDirective = ({ props, renderSlot }) => {
|
|
|
12035
12073
|
avatar.appendChild(img);
|
|
12036
12074
|
wrap.appendChild(avatar);
|
|
12037
12075
|
}
|
|
12038
|
-
const isThemeToken = CHAT_THEME_TOKENS.has(props.color || "");
|
|
12039
|
-
const colorClass = isThemeToken ? ` nr-chat__bubble--${props.color}` : "";
|
|
12040
12076
|
const bubble = document.createElement("div");
|
|
12041
|
-
bubble.className = `nr-chat__bubble${
|
|
12042
|
-
if (props.color && isArbitraryColor(props.color) && !isThemeToken) {
|
|
12043
|
-
bubble.style.background = props.color;
|
|
12044
|
-
bubble.style.color = "white";
|
|
12045
|
-
}
|
|
12077
|
+
bubble.className = `nr-chat__bubble${applyColor(bubble, props.color, "nr-chat__bubble")}`;
|
|
12046
12078
|
bubble.appendChild(renderSlot("default"));
|
|
12047
12079
|
wrap.appendChild(bubble);
|
|
12048
12080
|
if (props.footer) {
|
|
@@ -12056,8 +12088,7 @@ var chatItemDirective = ({ props, renderSlot }) => {
|
|
|
12056
12088
|
var chatDirective = ({ props, renderSlot }) => {
|
|
12057
12089
|
const wrap = document.createElement("div");
|
|
12058
12090
|
wrap.className = "nr-chat";
|
|
12059
|
-
|
|
12060
|
-
if (props.style) wrap.setAttribute("style", props.style);
|
|
12091
|
+
applyBaseProps(wrap, props);
|
|
12061
12092
|
wrap.appendChild(renderSlot("default"));
|
|
12062
12093
|
return wrap;
|
|
12063
12094
|
};
|
|
@@ -12093,8 +12124,7 @@ function bindEventProp(el, eventProp) {
|
|
|
12093
12124
|
var richlistItemDirective = ({ props, renderSlot }) => {
|
|
12094
12125
|
const li = document.createElement("li");
|
|
12095
12126
|
li.className = "nr-richlist__item";
|
|
12096
|
-
|
|
12097
|
-
if (props.style) li.setAttribute("style", props.style);
|
|
12127
|
+
applyBaseProps(li, props);
|
|
12098
12128
|
if (props.image) {
|
|
12099
12129
|
const thumb = document.createElement("div");
|
|
12100
12130
|
thumb.className = "nr-richlist__thumb";
|
|
@@ -12156,36 +12186,20 @@ var richlistItemDirective = ({ props, renderSlot }) => {
|
|
|
12156
12186
|
var richlistDirective = ({ props, renderSlot }) => {
|
|
12157
12187
|
const ul = document.createElement("ul");
|
|
12158
12188
|
ul.className = "nr-richlist";
|
|
12159
|
-
|
|
12160
|
-
if (props.style) ul.setAttribute("style", props.style);
|
|
12189
|
+
applyBaseProps(ul, props);
|
|
12161
12190
|
ul.appendChild(renderSlot("default"));
|
|
12162
12191
|
return ul;
|
|
12163
12192
|
};
|
|
12164
12193
|
var richlist_default = richlistDirective;
|
|
12165
12194
|
|
|
12166
12195
|
// vanilla/directives/stat.ts
|
|
12167
|
-
var STAT_THEME_TOKENS = /* @__PURE__ */ new Set([
|
|
12168
|
-
"primary",
|
|
12169
|
-
"secondary",
|
|
12170
|
-
"info",
|
|
12171
|
-
"success",
|
|
12172
|
-
"warning",
|
|
12173
|
-
"error"
|
|
12174
|
-
]);
|
|
12175
|
-
function isArbitraryColor2(value) {
|
|
12176
|
-
if (STAT_THEME_TOKENS.has(value)) return false;
|
|
12177
|
-
if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(value)) return true;
|
|
12178
|
-
if (/^[a-zA-Z]+$/.test(value)) return true;
|
|
12179
|
-
return false;
|
|
12180
|
-
}
|
|
12181
12196
|
var statDirective = ({ props }) => {
|
|
12182
|
-
const
|
|
12183
|
-
const colorClass =
|
|
12197
|
+
const statIsThemeToken = isThemeToken(props.color);
|
|
12198
|
+
const colorClass = statIsThemeToken ? ` nr-stat--${props.color}` : "";
|
|
12184
12199
|
const stat = document.createElement("div");
|
|
12185
12200
|
stat.className = `nr-stat${colorClass}`;
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
const useInlineColor = props.color && isArbitraryColor2(props.color) && !isThemeToken;
|
|
12201
|
+
applyBaseProps(stat, props);
|
|
12202
|
+
const useInlineColor = props.color && isArbitraryColor(props.color) && !statIsThemeToken;
|
|
12189
12203
|
if (props.icon) {
|
|
12190
12204
|
const figure = document.createElement("div");
|
|
12191
12205
|
figure.className = "nr-stat__figure";
|
|
@@ -12278,9 +12292,12 @@ function renderHtmlString(html) {
|
|
|
12278
12292
|
processedContent = processedContent.replace(
|
|
12279
12293
|
/<style(?:\s+[^>]*)?>([\s\S]*?)<\/style>/gi,
|
|
12280
12294
|
(_match, cssContent) => {
|
|
12295
|
+
const trimmed = cssContent.trim();
|
|
12296
|
+
const existing = document.head.querySelector("style[data-nr-global]");
|
|
12297
|
+
if (existing && existing.textContent === trimmed) return "";
|
|
12281
12298
|
const styleEl = document.createElement("style");
|
|
12282
12299
|
styleEl.setAttribute("data-nr-global", "");
|
|
12283
|
-
styleEl.textContent =
|
|
12300
|
+
styleEl.textContent = trimmed;
|
|
12284
12301
|
document.head.appendChild(styleEl);
|
|
12285
12302
|
return "";
|
|
12286
12303
|
}
|
|
@@ -12350,19 +12367,14 @@ function renderElement(element, ctx, allElements) {
|
|
|
12350
12367
|
switch (element.type) {
|
|
12351
12368
|
case "header": {
|
|
12352
12369
|
const tag = `h${element.level}`;
|
|
12353
|
-
let text = element.text;
|
|
12354
|
-
const alignCenter = text.match(/^->\s*(.+?)\s*<-\s*$/);
|
|
12355
|
-
const alignRight = text.match(/^->\s*(.+?)\s*->\s*$/);
|
|
12356
|
-
if (alignCenter) text = alignCenter[1];
|
|
12357
|
-
else if (alignRight) text = alignRight[1];
|
|
12358
12370
|
const h = document.createElement(tag);
|
|
12359
12371
|
h.id = element.id;
|
|
12360
12372
|
let cls = `md-h${element.level}`;
|
|
12361
|
-
if (
|
|
12362
|
-
if (
|
|
12373
|
+
if (element.align === "center") cls += " text-center";
|
|
12374
|
+
else if (element.align === "right") cls += " text-right";
|
|
12363
12375
|
if (element.classes) cls += ` ${element.classes}`;
|
|
12364
12376
|
h.className = cls;
|
|
12365
|
-
h.appendChild(renderInline(text));
|
|
12377
|
+
h.appendChild(renderInline(element.text));
|
|
12366
12378
|
return h;
|
|
12367
12379
|
}
|
|
12368
12380
|
case "paragraph": {
|
|
@@ -12705,7 +12717,7 @@ var guideData = [
|
|
|
12705
12717
|
"title": "Introducci\xF3n",
|
|
12706
12718
|
"icon": "menu_book",
|
|
12707
12719
|
"order": 1,
|
|
12708
|
-
"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
|
|
12720
|
+
"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.'
|
|
12709
12721
|
},
|
|
12710
12722
|
{
|
|
12711
12723
|
"id": "titulos",
|
|
@@ -12921,7 +12933,7 @@ var guideData = [
|
|
|
12921
12933
|
"title": "Modal",
|
|
12922
12934
|
"icon": "open_in_full",
|
|
12923
12935
|
"order": 2,
|
|
12924
|
-
"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 (
|
|
12936
|
+
"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.'
|
|
12925
12937
|
},
|
|
12926
12938
|
{
|
|
12927
12939
|
"id": "button",
|
|
@@ -12929,7 +12941,7 @@ var guideData = [
|
|
|
12929
12941
|
"title": "Button",
|
|
12930
12942
|
"icon": "touch_app",
|
|
12931
12943
|
"order": 3,
|
|
12932
|
-
"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 `
|
|
12944
|
+
"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"`) |'
|
|
12933
12945
|
},
|
|
12934
12946
|
{
|
|
12935
12947
|
"id": "slide",
|
|
@@ -12946,6 +12958,14 @@ var guideData = [
|
|
|
12946
12958
|
"icon": "code_off",
|
|
12947
12959
|
"order": 1,
|
|
12948
12960
|
"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.'
|
|
12961
|
+
},
|
|
12962
|
+
{
|
|
12963
|
+
"id": "wrapper-directives",
|
|
12964
|
+
"category": "Layout",
|
|
12965
|
+
"title": "Wrapper Directives",
|
|
12966
|
+
"icon": "crop_free",
|
|
12967
|
+
"order": 1,
|
|
12968
|
+
"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```'
|
|
12949
12969
|
}
|
|
12950
12970
|
];
|
|
12951
12971
|
|