raffel 1.1.16 → 1.1.18
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/docs/ui/assets/raffel-docs.css +192 -1
- package/dist/docs/ui/assets/raffel-docs.js +229 -3
- package/dist/docs/ui/client-script/index.d.ts +1 -1
- package/dist/docs/ui/client-script/index.d.ts.map +1 -1
- package/dist/docs/ui/client-script/index.js +3 -2
- package/dist/docs/ui/client-script/index.js.map +1 -1
- package/dist/docs/ui/html-builder.d.ts.map +1 -1
- package/dist/docs/ui/html-builder.js +26 -1
- package/dist/docs/ui/html-builder.js.map +1 -1
- package/dist/docs/ui/runtime/index.js +229 -3
- package/dist/docs/ui/runtime/index.js.map +1 -1
- package/dist/docs/ui/style-sections/content.d.ts +1 -1
- package/dist/docs/ui/style-sections/content.d.ts.map +1 -1
- package/dist/docs/ui/style-sections/content.js +162 -1
- package/dist/docs/ui/style-sections/content.js.map +1 -1
- package/dist/docs/ui/style-sections/shell.d.ts.map +1 -1
- package/dist/docs/ui/style-sections/shell.js +30 -0
- package/dist/docs/ui/style-sections/shell.js.map +1 -1
- package/dist/docs/ui/types.d.ts +25 -0
- package/dist/docs/ui/types.d.ts.map +1 -1
- package/dist/ui/docs/ui/client-script/index.d.ts +1 -1
- package/dist/ui/docs/ui/client-script/index.d.ts.map +1 -1
- package/dist/ui/docs/ui/html-builder.d.ts.map +1 -1
- package/dist/ui/docs/ui/style-sections/content.d.ts +1 -1
- package/dist/ui/docs/ui/style-sections/content.d.ts.map +1 -1
- package/dist/ui/docs/ui/style-sections/shell.d.ts.map +1 -1
- package/dist/ui/docs/ui/types.d.ts +25 -0
- package/dist/ui/docs/ui/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -31,6 +31,8 @@ const docsAssetBasePath = String(data.docsAssetBasePath ?? '');
|
|
|
31
31
|
const footerMarkdown = data.footerMarkdown ?? null;
|
|
32
32
|
const tocConfig = data.tocConfig ?? {};
|
|
33
33
|
const markdownConfig = data.markdownConfig ?? {};
|
|
34
|
+
const mermaidConfig = data.mermaidConfig ?? { enabled: true, src: 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js', viewer: true };
|
|
35
|
+
let mermaidLoadPromise = null;
|
|
34
36
|
const docsRepoConfig = (data.docsRepoConfig ?? null);
|
|
35
37
|
const breadcrumbsConfig = (data.breadcrumbsConfig && typeof data.breadcrumbsConfig === 'object')
|
|
36
38
|
? data.breadcrumbsConfig
|
|
@@ -1490,15 +1492,52 @@ function scrollToActiveHeading() {
|
|
|
1490
1492
|
function scrollToEndpoint(id) {
|
|
1491
1493
|
byId(id)?.scrollIntoView?.({ behavior: 'smooth', block: 'start' });
|
|
1492
1494
|
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
+
/**
|
|
1496
|
+
* Lazy-load the Mermaid renderer the first time a page with diagrams is
|
|
1497
|
+
* visited. Cached: subsequent route transitions inside the SPA reuse the
|
|
1498
|
+
* same `<script>` injection. Pages without `.mermaid` blocks never trigger
|
|
1499
|
+
* the network request, so the ~3MB library stays off the critical path
|
|
1500
|
+
* for the 95% of docs pages that have no diagrams.
|
|
1501
|
+
*/
|
|
1502
|
+
function loadMermaidLibrary(src) {
|
|
1503
|
+
if (win.mermaid)
|
|
1504
|
+
return Promise.resolve(win.mermaid);
|
|
1505
|
+
if (mermaidLoadPromise)
|
|
1506
|
+
return mermaidLoadPromise;
|
|
1507
|
+
mermaidLoadPromise = new Promise((resolve, reject) => {
|
|
1508
|
+
const script = doc.createElement('script');
|
|
1509
|
+
script.src = src;
|
|
1510
|
+
script.defer = true;
|
|
1511
|
+
script.onload = () => resolve(win.mermaid);
|
|
1512
|
+
script.onerror = () => {
|
|
1513
|
+
mermaidLoadPromise = null;
|
|
1514
|
+
reject(new Error(`Failed to load Mermaid from ${src}`));
|
|
1515
|
+
};
|
|
1516
|
+
doc.head?.appendChild(script);
|
|
1517
|
+
});
|
|
1518
|
+
return mermaidLoadPromise;
|
|
1519
|
+
}
|
|
1520
|
+
async function renderMermaidDiagrams(root = doc) {
|
|
1495
1521
|
const diagrams = Array.from(root?.querySelectorAll?.('.mermaid:not([data-mermaid-rendered])') ?? []);
|
|
1496
1522
|
if (diagrams.length === 0)
|
|
1497
1523
|
return;
|
|
1498
|
-
if (
|
|
1524
|
+
if (mermaidConfig.enabled === false) {
|
|
1499
1525
|
diagrams.forEach(diagram => diagram.classList.add('mermaid-fallback'));
|
|
1500
1526
|
return;
|
|
1501
1527
|
}
|
|
1528
|
+
let mermaid = win.mermaid;
|
|
1529
|
+
if (!mermaid) {
|
|
1530
|
+
try {
|
|
1531
|
+
mermaid = await loadMermaidLibrary(mermaidConfig.src);
|
|
1532
|
+
}
|
|
1533
|
+
catch (error) {
|
|
1534
|
+
diagrams.forEach(diagram => {
|
|
1535
|
+
diagram.classList.add('mermaid-fallback', 'mermaid-error');
|
|
1536
|
+
diagram.setAttribute('title', error instanceof Error ? error.message : 'Unable to load Mermaid');
|
|
1537
|
+
});
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1502
1541
|
mermaid.initialize?.({ startOnLoad: false, securityLevel: 'strict' });
|
|
1503
1542
|
diagrams.forEach((diagram, index) => {
|
|
1504
1543
|
const source = diagram.getAttribute('data-mermaid-source') || diagram.textContent || '';
|
|
@@ -1509,6 +1548,8 @@ function renderMermaidDiagrams(root = doc) {
|
|
|
1509
1548
|
result?.bindFunctions?.(diagram);
|
|
1510
1549
|
diagram.dataset.mermaidRendered = 'true';
|
|
1511
1550
|
diagram.classList.remove('mermaid-fallback', 'mermaid-error');
|
|
1551
|
+
if (mermaidConfig.viewer !== false)
|
|
1552
|
+
mountMermaidViewer(diagram);
|
|
1512
1553
|
})
|
|
1513
1554
|
.catch((error) => {
|
|
1514
1555
|
diagram.dataset.mermaidRendered = 'error';
|
|
@@ -1517,6 +1558,191 @@ function renderMermaidDiagrams(root = doc) {
|
|
|
1517
1558
|
});
|
|
1518
1559
|
});
|
|
1519
1560
|
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Wrap a freshly rendered Mermaid SVG in a viewer overlay:
|
|
1563
|
+
* • toolbar (zoom in/out/reset/fullscreen) — fades in on hover
|
|
1564
|
+
* • drag-to-pan when zoomed in (scale > 1)
|
|
1565
|
+
* • wheel-zoom with Ctrl/⌘ pressed (so vertical scroll still works normally)
|
|
1566
|
+
* • fullscreen via <dialog>, with same controls
|
|
1567
|
+
*
|
|
1568
|
+
* Idempotent: skips diagrams already wrapped (data-mermaid-viewer-mounted).
|
|
1569
|
+
*/
|
|
1570
|
+
function mountMermaidViewer(diagram) {
|
|
1571
|
+
if (diagram.dataset.mermaidViewerMounted)
|
|
1572
|
+
return;
|
|
1573
|
+
const svg = diagram.querySelector?.('svg');
|
|
1574
|
+
if (!svg)
|
|
1575
|
+
return;
|
|
1576
|
+
const viewport = doc.createElement('div');
|
|
1577
|
+
viewport.className = 'mermaid-viewport';
|
|
1578
|
+
diagram.insertBefore(viewport, svg);
|
|
1579
|
+
viewport.appendChild(svg);
|
|
1580
|
+
const toolbar = doc.createElement('div');
|
|
1581
|
+
toolbar.className = 'mermaid-toolbar';
|
|
1582
|
+
toolbar.innerHTML = [
|
|
1583
|
+
'<button class="mermaid-btn" data-mermaid-action="zoom-in" aria-label="Zoom in" title="Zoom in">+</button>',
|
|
1584
|
+
'<button class="mermaid-btn" data-mermaid-action="zoom-out" aria-label="Zoom out" title="Zoom out">−</button>',
|
|
1585
|
+
'<button class="mermaid-btn" data-mermaid-action="reset" aria-label="Reset view" title="Reset view">⟲</button>',
|
|
1586
|
+
'<button class="mermaid-btn" data-mermaid-action="fullscreen" aria-label="Open fullscreen" title="Fullscreen">⛶</button>',
|
|
1587
|
+
].join('');
|
|
1588
|
+
diagram.appendChild(toolbar);
|
|
1589
|
+
const state = { scale: 1, tx: 0, ty: 0 };
|
|
1590
|
+
function apply() {
|
|
1591
|
+
svg.style.transform = `translate(${state.tx}px, ${state.ty}px) scale(${state.scale})`;
|
|
1592
|
+
svg.style.transformOrigin = 'center center';
|
|
1593
|
+
svg.style.transition = 'transform 0.18s cubic-bezier(0.16, 1, 0.3, 1)';
|
|
1594
|
+
viewport.style.cursor = state.scale > 1 ? 'grab' : '';
|
|
1595
|
+
}
|
|
1596
|
+
function reset() { state.scale = 1; state.tx = 0; state.ty = 0; apply(); }
|
|
1597
|
+
function zoomBy(factor) {
|
|
1598
|
+
state.scale = Math.max(0.5, Math.min(state.scale * factor, 8));
|
|
1599
|
+
if (state.scale === 1) {
|
|
1600
|
+
state.tx = 0;
|
|
1601
|
+
state.ty = 0;
|
|
1602
|
+
}
|
|
1603
|
+
apply();
|
|
1604
|
+
}
|
|
1605
|
+
toolbar.addEventListener('click', (ev) => {
|
|
1606
|
+
const action = ev.target?.dataset?.mermaidAction;
|
|
1607
|
+
if (action === 'zoom-in')
|
|
1608
|
+
zoomBy(1.25);
|
|
1609
|
+
else if (action === 'zoom-out')
|
|
1610
|
+
zoomBy(1 / 1.25);
|
|
1611
|
+
else if (action === 'reset')
|
|
1612
|
+
reset();
|
|
1613
|
+
else if (action === 'fullscreen')
|
|
1614
|
+
openMermaidFullscreen(svg.cloneNode(true));
|
|
1615
|
+
});
|
|
1616
|
+
let panning = false;
|
|
1617
|
+
let panStartX = 0;
|
|
1618
|
+
let panStartY = 0;
|
|
1619
|
+
let panStartTx = 0;
|
|
1620
|
+
let panStartTy = 0;
|
|
1621
|
+
viewport.addEventListener('mousedown', (ev) => {
|
|
1622
|
+
if (ev.button !== 0 || state.scale <= 1)
|
|
1623
|
+
return;
|
|
1624
|
+
panning = true;
|
|
1625
|
+
panStartX = ev.clientX;
|
|
1626
|
+
panStartY = ev.clientY;
|
|
1627
|
+
panStartTx = state.tx;
|
|
1628
|
+
panStartTy = state.ty;
|
|
1629
|
+
viewport.style.cursor = 'grabbing';
|
|
1630
|
+
ev.preventDefault();
|
|
1631
|
+
});
|
|
1632
|
+
doc.addEventListener('mousemove', (ev) => {
|
|
1633
|
+
if (!panning)
|
|
1634
|
+
return;
|
|
1635
|
+
state.tx = panStartTx + (ev.clientX - panStartX);
|
|
1636
|
+
state.ty = panStartTy + (ev.clientY - panStartY);
|
|
1637
|
+
svg.style.transform = `translate(${state.tx}px, ${state.ty}px) scale(${state.scale})`;
|
|
1638
|
+
});
|
|
1639
|
+
doc.addEventListener('mouseup', () => {
|
|
1640
|
+
if (!panning)
|
|
1641
|
+
return;
|
|
1642
|
+
panning = false;
|
|
1643
|
+
viewport.style.cursor = state.scale > 1 ? 'grab' : '';
|
|
1644
|
+
});
|
|
1645
|
+
viewport.addEventListener('wheel', (ev) => {
|
|
1646
|
+
if (!ev.ctrlKey && !ev.metaKey)
|
|
1647
|
+
return;
|
|
1648
|
+
ev.preventDefault();
|
|
1649
|
+
zoomBy(ev.deltaY < 0 ? 1.1 : 1 / 1.1);
|
|
1650
|
+
});
|
|
1651
|
+
diagram.dataset.mermaidViewerMounted = 'true';
|
|
1652
|
+
}
|
|
1653
|
+
function openMermaidFullscreen(svg) {
|
|
1654
|
+
const dialog = doc.createElement('dialog');
|
|
1655
|
+
dialog.className = 'mermaid-fullscreen-dialog';
|
|
1656
|
+
const close = doc.createElement('button');
|
|
1657
|
+
close.className = 'mermaid-fullscreen-close';
|
|
1658
|
+
close.setAttribute('aria-label', 'Close');
|
|
1659
|
+
close.textContent = '✕';
|
|
1660
|
+
close.addEventListener('click', () => dialog.close());
|
|
1661
|
+
const stage = doc.createElement('div');
|
|
1662
|
+
stage.className = 'mermaid-fullscreen-stage';
|
|
1663
|
+
svg.removeAttribute('style');
|
|
1664
|
+
stage.appendChild(svg);
|
|
1665
|
+
const fsState = { scale: 1, tx: 0, ty: 0 };
|
|
1666
|
+
function fsApply() {
|
|
1667
|
+
svg.style.transform = `translate(${fsState.tx}px, ${fsState.ty}px) scale(${fsState.scale})`;
|
|
1668
|
+
svg.style.transformOrigin = 'center center';
|
|
1669
|
+
stage.style.cursor = fsState.scale > 1 ? 'grab' : '';
|
|
1670
|
+
}
|
|
1671
|
+
function fsZoom(factor) {
|
|
1672
|
+
fsState.scale = Math.max(0.5, Math.min(fsState.scale * factor, 8));
|
|
1673
|
+
if (fsState.scale === 1) {
|
|
1674
|
+
fsState.tx = 0;
|
|
1675
|
+
fsState.ty = 0;
|
|
1676
|
+
}
|
|
1677
|
+
fsApply();
|
|
1678
|
+
}
|
|
1679
|
+
const toolbar = doc.createElement('div');
|
|
1680
|
+
toolbar.className = 'mermaid-toolbar mermaid-toolbar-fullscreen';
|
|
1681
|
+
toolbar.innerHTML = [
|
|
1682
|
+
'<button class="mermaid-btn" data-mermaid-action="zoom-in" aria-label="Zoom in" title="Zoom in">+</button>',
|
|
1683
|
+
'<button class="mermaid-btn" data-mermaid-action="zoom-out" aria-label="Zoom out" title="Zoom out">−</button>',
|
|
1684
|
+
'<button class="mermaid-btn" data-mermaid-action="reset" aria-label="Reset view" title="Reset view">⟲</button>',
|
|
1685
|
+
].join('');
|
|
1686
|
+
toolbar.addEventListener('click', (ev) => {
|
|
1687
|
+
const action = ev.target?.dataset?.mermaidAction;
|
|
1688
|
+
if (action === 'zoom-in')
|
|
1689
|
+
fsZoom(1.25);
|
|
1690
|
+
else if (action === 'zoom-out')
|
|
1691
|
+
fsZoom(1 / 1.25);
|
|
1692
|
+
else if (action === 'reset') {
|
|
1693
|
+
fsState.scale = 1;
|
|
1694
|
+
fsState.tx = 0;
|
|
1695
|
+
fsState.ty = 0;
|
|
1696
|
+
fsApply();
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
let fsPan = false;
|
|
1700
|
+
let fsStartX = 0;
|
|
1701
|
+
let fsStartY = 0;
|
|
1702
|
+
let fsStartTx = 0;
|
|
1703
|
+
let fsStartTy = 0;
|
|
1704
|
+
stage.addEventListener('mousedown', (ev) => {
|
|
1705
|
+
if (ev.button !== 0 || fsState.scale <= 1)
|
|
1706
|
+
return;
|
|
1707
|
+
fsPan = true;
|
|
1708
|
+
fsStartX = ev.clientX;
|
|
1709
|
+
fsStartY = ev.clientY;
|
|
1710
|
+
fsStartTx = fsState.tx;
|
|
1711
|
+
fsStartTy = fsState.ty;
|
|
1712
|
+
stage.style.cursor = 'grabbing';
|
|
1713
|
+
ev.preventDefault();
|
|
1714
|
+
});
|
|
1715
|
+
doc.addEventListener('mousemove', (ev) => {
|
|
1716
|
+
if (!fsPan)
|
|
1717
|
+
return;
|
|
1718
|
+
fsState.tx = fsStartTx + (ev.clientX - fsStartX);
|
|
1719
|
+
fsState.ty = fsStartTy + (ev.clientY - fsStartY);
|
|
1720
|
+
fsApply();
|
|
1721
|
+
});
|
|
1722
|
+
doc.addEventListener('mouseup', () => {
|
|
1723
|
+
if (!fsPan)
|
|
1724
|
+
return;
|
|
1725
|
+
fsPan = false;
|
|
1726
|
+
stage.style.cursor = fsState.scale > 1 ? 'grab' : '';
|
|
1727
|
+
});
|
|
1728
|
+
stage.addEventListener('wheel', (ev) => {
|
|
1729
|
+
ev.preventDefault();
|
|
1730
|
+
fsZoom(ev.deltaY < 0 ? 1.1 : 1 / 1.1);
|
|
1731
|
+
});
|
|
1732
|
+
dialog.appendChild(close);
|
|
1733
|
+
dialog.appendChild(toolbar);
|
|
1734
|
+
dialog.appendChild(stage);
|
|
1735
|
+
doc.body.appendChild(dialog);
|
|
1736
|
+
dialog.addEventListener('close', () => { try {
|
|
1737
|
+
doc.body.removeChild(dialog);
|
|
1738
|
+
}
|
|
1739
|
+
catch { } });
|
|
1740
|
+
dialog.addEventListener('keydown', (ev) => {
|
|
1741
|
+
if (ev.key === 'Escape')
|
|
1742
|
+
dialog.close();
|
|
1743
|
+
});
|
|
1744
|
+
dialog.showModal?.();
|
|
1745
|
+
}
|
|
1520
1746
|
function parseComponentProps(raw) {
|
|
1521
1747
|
const source = String(raw ?? '').trim();
|
|
1522
1748
|
if (!source)
|