@diagrammo/dgmo 0.45.0 → 0.47.0
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/advanced.cjs +31 -25
- package/dist/advanced.d.cts +3 -855
- package/dist/advanced.d.ts +3 -855
- package/dist/advanced.js +541 -70101
- package/dist/analyzer-UYKBXAKR.js +15 -0
- package/dist/auto.cjs +500 -341
- package/dist/auto.css +342 -159
- package/dist/auto.d.cts +10 -8
- package/dist/auto.d.ts +10 -8
- package/dist/auto.js +373 -265
- package/dist/auto.mjs +500 -341
- package/dist/block.cjs +31 -25
- package/dist/block.js +83 -69411
- package/dist/calculator-LDYQCDDY.js +11 -0
- package/dist/charts-d3-QOZHKTCT.js +25 -0
- package/dist/chunk-2DXMZRWJ.js +800 -0
- package/dist/chunk-2LACINWN.js +786 -0
- package/dist/chunk-33LCUH4H.js +893 -0
- package/dist/chunk-3CIOJ5YJ.js +35 -0
- package/dist/chunk-3HDBAXF5.js +86 -0
- package/dist/chunk-3JLKYGBQ.js +290 -0
- package/dist/chunk-3MQQNXPD.js +415 -0
- package/dist/chunk-3R5POCTZ.js +967 -0
- package/dist/chunk-3SMGIJDD.js +112 -0
- package/dist/chunk-44CM72SQ.js +409 -0
- package/dist/chunk-4GRI7MEB.js +1604 -0
- package/dist/chunk-4OHACBGX.js +606 -0
- package/dist/chunk-5DH3KYFH.js +21 -0
- package/dist/chunk-5MLYVTYM.js +76 -0
- package/dist/chunk-5QXL4NYS.js +553 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-6EK55ART.js +117 -0
- package/dist/chunk-6FZYCKXB.js +2065 -0
- package/dist/chunk-6HO5ZTXK.js +277 -0
- package/dist/chunk-6KFWC4CO.js +7 -0
- package/dist/chunk-6MTWIQVO.js +121 -0
- package/dist/chunk-6NYWYNBI.js +329 -0
- package/dist/chunk-6SM5NJQH.js +620 -0
- package/dist/chunk-725LDASD.js +422 -0
- package/dist/chunk-76OWZ3BA.js +130 -0
- package/dist/chunk-7JEGTRLD.js +338 -0
- package/dist/chunk-A44USUV7.js +923 -0
- package/dist/chunk-A4GOY3PE.js +25 -0
- package/dist/chunk-A4VFQH5G.js +251 -0
- package/dist/chunk-AELOBFW5.js +375 -0
- package/dist/chunk-AN2MOO5T.js +522 -0
- package/dist/chunk-BMR4CIEO.js +41 -0
- package/dist/chunk-BS7SV7C3.js +51 -0
- package/dist/chunk-BUPDIHML.js +613 -0
- package/dist/chunk-BUVJFRPY.js +887 -0
- package/dist/chunk-C3Z4DX3V.js +112 -0
- package/dist/chunk-CI2G3OEB.js +1818 -0
- package/dist/chunk-CKNVO24D.js +54 -0
- package/dist/chunk-CUVHQHZ7.js +391 -0
- package/dist/chunk-CXK4DZH3.js +114 -0
- package/dist/chunk-DKEPS5LH.js +315 -0
- package/dist/chunk-DU7W62N5.js +487 -0
- package/dist/chunk-DZAQBW35.js +751 -0
- package/dist/chunk-EB6FPQUP.js +316 -0
- package/dist/chunk-EMS2SK26.js +376 -0
- package/dist/chunk-ERLBPDGU.js +510 -0
- package/dist/chunk-EVCVDTXE.js +732 -0
- package/dist/chunk-FCIIHT24.js +384 -0
- package/dist/chunk-FFUN5D66.js +97 -0
- package/dist/chunk-FITOLXSX.js +714 -0
- package/dist/chunk-FMDSF3OV.js +68 -0
- package/dist/chunk-FNB3PNGF.js +410 -0
- package/dist/chunk-G2H74XJZ.js +2104 -0
- package/dist/chunk-GMR5MFHJ.js +339 -0
- package/dist/chunk-H6PI3KJT.js +305 -0
- package/dist/chunk-I46X5VUA.js +59 -0
- package/dist/chunk-I5IGB56C.js +255 -0
- package/dist/chunk-IH6ZMVQ5.js +3950 -0
- package/dist/chunk-IJZFN3HM.js +463 -0
- package/dist/chunk-IPWPWM6R.js +3079 -0
- package/dist/chunk-IYULMRBE.js +23 -0
- package/dist/chunk-IZMRON6C.js +167 -0
- package/dist/chunk-J5FIXQRT.js +813 -0
- package/dist/chunk-JED6ZDEE.js +73 -0
- package/dist/chunk-JEUJOX5X.js +136 -0
- package/dist/chunk-JM4LEPY3.js +436 -0
- package/dist/chunk-L3UHP6TD.js +101 -0
- package/dist/chunk-L66GEFB6.js +524 -0
- package/dist/chunk-LIOHW36Z.js +469 -0
- package/dist/chunk-LP7EC4MI.js +16 -0
- package/dist/chunk-MITI6NOL.js +548 -0
- package/dist/chunk-MO5YHHMQ.js +168 -0
- package/dist/chunk-MZSBFAPJ.js +885 -0
- package/dist/chunk-NNAAJVBU.js +9 -0
- package/dist/chunk-NOTA6TEI.js +47 -0
- package/dist/chunk-NURGB5Z4.js +335 -0
- package/dist/chunk-NX4EQS3U.js +1062 -0
- package/dist/chunk-NXMESY4J.js +1 -0
- package/dist/chunk-OJR3MQYV.js +1458 -0
- package/dist/chunk-OURHMODR.js +454 -0
- package/dist/chunk-P235SVAH.js +1057 -0
- package/dist/chunk-P4RH4OSP.js +1038 -0
- package/dist/chunk-P6T66CCZ.js +226 -0
- package/dist/chunk-PBAHEPLQ.js +223 -0
- package/dist/chunk-PBHE5UG6.js +1530 -0
- package/dist/chunk-PDKUANDZ.js +35 -0
- package/dist/chunk-PWIHZ6NJ.js +296 -0
- package/dist/chunk-QEBUY5NY.js +1685 -0
- package/dist/chunk-QLCCJEJI.js +253 -0
- package/dist/chunk-QOOUC2J5.js +52 -0
- package/dist/chunk-QYTPPDAO.js +402 -0
- package/dist/chunk-R3XI2VC7.js +801 -0
- package/dist/chunk-RCERWOJR.js +154 -0
- package/dist/chunk-RJE5JTVK.js +362 -0
- package/dist/chunk-RTLBSQ3G.js +1155 -0
- package/dist/chunk-RUNNI6VE.js +448 -0
- package/dist/chunk-RVMRZAPB.js +354 -0
- package/dist/chunk-RYEGFMUO.js +955 -0
- package/dist/chunk-RZCF2VVM.js +528 -0
- package/dist/chunk-SML67VPV.js +1025 -0
- package/dist/chunk-SQ7IY53Q.js +44 -0
- package/dist/chunk-SQAG3UXH.js +161 -0
- package/dist/chunk-SRTU6HMQ.js +1851 -0
- package/dist/chunk-T2OE3YQB.js +550 -0
- package/dist/chunk-T3UBLACL.js +299 -0
- package/dist/chunk-TLVIHFRO.js +296 -0
- package/dist/chunk-TYS6CSS5.js +52 -0
- package/dist/chunk-U6EQI3U6.js +130 -0
- package/dist/chunk-UJ4FJLBF.js +86 -0
- package/dist/chunk-ULOEATBZ.js +347 -0
- package/dist/chunk-UNCCZ3NU.js +127 -0
- package/dist/chunk-USZW2HHU.js +197 -0
- package/dist/chunk-UWN33VNX.js +1610 -0
- package/dist/chunk-UZ7EZW3B.js +40 -0
- package/dist/chunk-VOKGH627.js +37 -0
- package/dist/chunk-WBRZJOEC.js +204 -0
- package/dist/chunk-WCSOJFU3.js +380 -0
- package/dist/chunk-WCT3NYCV.js +160 -0
- package/dist/chunk-WVAJFAIA.js +529 -0
- package/dist/chunk-X5LCYCL5.js +394 -0
- package/dist/chunk-XAKEUMEJ.js +1256 -0
- package/dist/chunk-Y2ZE3MSG.js +590 -0
- package/dist/chunk-Y3J7VR52.js +646 -0
- package/dist/chunk-Y5QGVTVC.js +33 -0
- package/dist/chunk-YAA6IID3.js +548 -0
- package/dist/chunk-YGJTDXVR.js +692 -0
- package/dist/chunk-YRYKTYMQ.js +186 -0
- package/dist/chunk-YYVTBZZC.js +61 -0
- package/dist/chunk-Z5CGSFJB.js +647 -0
- package/dist/chunk-Z72XRXD4.js +787 -0
- package/dist/chunk-ZGR7ULFJ.js +978 -0
- package/dist/chunk-ZJEL4H2R.js +851 -0
- package/dist/chunk-ZO27FGJS.js +554 -0
- package/dist/cli.cjs +112 -112
- package/dist/collapse-CLPJD2RL.js +11 -0
- package/dist/collapse-SLINJQW6.js +9 -0
- package/dist/collapse-ZWUFFCK2.js +9 -0
- package/dist/compute-G55RG53N.js +8 -0
- package/dist/dgmo-router-DZCIDUO5.js +73 -0
- package/dist/dimensions-J3FHIMJ6.js +22 -0
- package/dist/element.cjs +492 -325
- package/dist/element.js +367 -259
- package/dist/element.mjs +492 -325
- package/dist/flowchart-parser-ZNSKIBVR.js +21 -0
- package/dist/flowchart-renderer-ZAEOL4DX.js +35 -0
- package/dist/index.cjs +34 -28
- package/dist/index.d.cts +3 -469
- package/dist/index.d.ts +3 -469
- package/dist/index.js +137 -69679
- package/dist/layout-46N4JJYK.js +17 -0
- package/dist/layout-5RA6QWR6.js +26 -0
- package/dist/layout-5T6RH5M6.js +14 -0
- package/dist/layout-7QXCNOVS.js +13 -0
- package/dist/layout-EE6GE46Y.js +17 -0
- package/dist/layout-G23F7LDH.js +9 -0
- package/dist/layout-HRBZPFCN.js +23 -0
- package/dist/layout-HWDSRX5E.js +20 -0
- package/dist/layout-HYZPWAK5.js +18 -0
- package/dist/layout-N76NR4ZO.js +19 -0
- package/dist/layout-OB3RI63S.js +14 -0
- package/dist/layout-S2QBYSK2.js +15 -0
- package/dist/layout-UM5F4DJB.js +15 -0
- package/dist/layout-search-OYV77HHS.js +1655 -0
- package/dist/load-data-EHDDZ5ZS.js +8 -0
- package/dist/palettes-PRJ2RI6D.js +56 -0
- package/dist/parser-2MFP2H2E.js +11 -0
- package/dist/parser-3STE62GB.js +21 -0
- package/dist/parser-4FL2CMDG.js +18 -0
- package/dist/parser-4OGOBJJ4.js +13 -0
- package/dist/parser-6BTRLKRZ.js +15 -0
- package/dist/parser-AQETEVRW.js +21 -0
- package/dist/parser-CFZD5IBL.js +12 -0
- package/dist/parser-FUSKFGZN.js +16 -0
- package/dist/parser-I6KXEYFK.js +13 -0
- package/dist/parser-IXSZZQHY.js +18 -0
- package/dist/parser-JAL2HD4I.js +13 -0
- package/dist/parser-KNSQSKQO.js +20 -0
- package/dist/parser-N5O4IHUN.js +13 -0
- package/dist/parser-NGU3ETO6.js +16 -0
- package/dist/parser-NRAI6O25.js +19 -0
- package/dist/parser-O5J4VBII.js +11 -0
- package/dist/parser-OV7NOBW6.js +21 -0
- package/dist/parser-PQ3POX45.js +23 -0
- package/dist/parser-TFZFBVWN.js +11 -0
- package/dist/parser-TRTHDFPP.js +18 -0
- package/dist/parser-VQP2UJ6W.js +11 -0
- package/dist/parser-XDVELHRK.js +13 -0
- package/dist/parser-XKRP7QKP.js +11 -0
- package/dist/parser-Y6WTBU76.js +14 -0
- package/dist/parser-ZSDPZYQP.js +12 -0
- package/dist/renderer-2XQQQ6QR.js +28 -0
- package/dist/renderer-5NDVNDAZ.js +26 -0
- package/dist/renderer-6EEZHMH4.js +26 -0
- package/dist/renderer-6W5462RB.js +43 -0
- package/dist/renderer-7MVLWWQD.js +22 -0
- package/dist/renderer-AWWAF6XD.js +33 -0
- package/dist/renderer-BYCNMBF7.js +34 -0
- package/dist/renderer-CLJHQPBJ.js +29 -0
- package/dist/renderer-GHPZMFU2.js +15 -0
- package/dist/renderer-JGBKUCZD.js +16 -0
- package/dist/renderer-KQB7UGDS.js +19 -0
- package/dist/renderer-PGX2TKVS.js +24 -0
- package/dist/renderer-QIWVHWZO.js +15 -0
- package/dist/renderer-RPOA5YPZ.js +35 -0
- package/dist/renderer-SMIBCRVB.js +24 -0
- package/dist/renderer-T7YKC5VP.js +28 -0
- package/dist/renderer-TOCOVLHS.js +37 -0
- package/dist/renderer-UWA5XS74.js +39 -0
- package/dist/renderer-VACVQYML.js +25 -0
- package/dist/renderer-W4M6QLIJ.js +37 -0
- package/dist/renderer-WZRREQ2P.js +23 -0
- package/dist/renderer-YY2OSF6E.js +27 -0
- package/dist/renderer-Z7I3W2PP.js +24 -0
- package/dist/renderer-ZGNTUWC4.js +22 -0
- package/dist/renderer-ZTR3DER3.js +19 -0
- package/dist/renderer-radial-C32GPJQ7.js +21 -0
- package/dist/resolver-NOAA7ID7.js +13 -0
- package/dist/state-collapse-HCGD6IVJ.js +8 -0
- package/dist/state-parser-Z2V23ATR.js +18 -0
- package/dist/state-renderer-RFYHSP4K.js +34 -0
- package/dist/themes-1-CuKpeH.d.cts +908 -0
- package/dist/themes-1-CuKpeH.d.ts +908 -0
- package/package.json +1 -1
- package/src/auto/index.ts +55 -57
- package/src/auto/shared.ts +142 -142
- package/src/auto/styles.ts +44 -199
- package/src/c4/renderer.ts +2 -2
- package/src/element/index.ts +29 -21
- package/src/infra/renderer.ts +1 -1
- package/src/render.ts +34 -14
- package/src/sitemap/renderer.ts +1 -1
- package/src/timeline/renderer.ts +1 -1
- package/src/utils/hover-styles.ts +6 -1
- package/src/utils/legend-d3.ts +1 -4
- package/src/utils/legend-svg.ts +1 -1
package/package.json
CHANGED
package/src/auto/index.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Drop a `<script src="…/auto.js">` on any page; on `DOMContentLoaded`
|
|
5
5
|
* this module scans for `.dgmo, .language-dgmo`, runs `render()`, and
|
|
6
|
-
* replaces each match with
|
|
7
|
-
*
|
|
8
|
-
* "Open in editor" actions.
|
|
6
|
+
* replaces each match with the standard DGMO embed block (BL-114,
|
|
7
|
+
* `figure.dgmo.dgmo-rendered`) — the diagram plus a hover-reveal icon
|
|
8
|
+
* toolbar with view-source, Copy, and "Open in editor" actions.
|
|
9
9
|
*
|
|
10
10
|
* Public API: frozen `window.dgmo` and alias `window.diagrammo` with
|
|
11
11
|
* `{ initialize, run, version }`. Configuration is read from the
|
|
@@ -24,8 +24,8 @@ import {
|
|
|
24
24
|
resolveTheme,
|
|
25
25
|
ensureStyles,
|
|
26
26
|
deriveAriaLabel,
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
buildRenderedBlock,
|
|
28
|
+
buildErrorBlock,
|
|
29
29
|
buildShareUrl,
|
|
30
30
|
} from './shared';
|
|
31
31
|
|
|
@@ -59,7 +59,7 @@ let activeConfig: Required<AutoConfig> = { ...DEFAULTS };
|
|
|
59
59
|
|
|
60
60
|
// Track wrappers so we can re-render on theme changes / re-runs.
|
|
61
61
|
interface TrackedWrapper {
|
|
62
|
-
wrapper:
|
|
62
|
+
wrapper: HTMLElement;
|
|
63
63
|
source: string;
|
|
64
64
|
perElementShowSource: boolean | null;
|
|
65
65
|
}
|
|
@@ -220,7 +220,28 @@ function determineReplaceTarget(matched: Element): Element {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
interface ProcessOutcome {
|
|
223
|
-
wrapper?:
|
|
223
|
+
wrapper?: HTMLElement;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Swap a failing source element for the standard `.dgmo--error` card (which
|
|
228
|
+
* carries the message AND the offending source — unified error shape across
|
|
229
|
+
* every embed surface). The card is marked `data-dgmo-processed` so a
|
|
230
|
+
* follow-up run() doesn't loop on it; users wanting to retry after editing
|
|
231
|
+
* should insert a fresh source element.
|
|
232
|
+
*/
|
|
233
|
+
function replaceWithErrorCard(
|
|
234
|
+
el: Element,
|
|
235
|
+
source: string,
|
|
236
|
+
opts: {
|
|
237
|
+
message: string;
|
|
238
|
+
severity?: string;
|
|
239
|
+
line?: number;
|
|
240
|
+
column?: number;
|
|
241
|
+
}
|
|
242
|
+
): void {
|
|
243
|
+
const card = buildErrorBlock({ ...opts, source });
|
|
244
|
+
determineReplaceTarget(el).replaceWith(card);
|
|
224
245
|
}
|
|
225
246
|
|
|
226
247
|
async function processElement(el: Element): Promise<ProcessOutcome> {
|
|
@@ -237,15 +258,10 @@ async function processElement(el: Element): Promise<ProcessOutcome> {
|
|
|
237
258
|
const source = el.textContent || '';
|
|
238
259
|
const sourceBytes = new TextEncoder().encode(source).byteLength;
|
|
239
260
|
if (sourceBytes > SOURCE_BYTE_CAP) {
|
|
240
|
-
el
|
|
241
|
-
// Keep `data-dgmo-processed` set so a follow-up run() doesn't loop on
|
|
242
|
-
// the same broken source. Users wanting to retry after editing should
|
|
243
|
-
// clear the attribute manually or replace the element. // un-hide so user can see the source
|
|
244
|
-
const banner = buildErrorBanner({
|
|
261
|
+
replaceWithErrorCard(el, source, {
|
|
245
262
|
message: `DGMO source too large to render — ${SOURCE_BYTE_CAP / 1024} KB max`,
|
|
246
263
|
severity: 'error',
|
|
247
264
|
});
|
|
248
|
-
el.parentElement?.insertBefore(banner, el);
|
|
249
265
|
warn('source exceeds 256 KB cap');
|
|
250
266
|
return {};
|
|
251
267
|
}
|
|
@@ -281,59 +297,40 @@ async function processElement(el: Element): Promise<ProcessOutcome> {
|
|
|
281
297
|
palette: cfg.palette,
|
|
282
298
|
});
|
|
283
299
|
} catch (err) {
|
|
284
|
-
el.style.visibility = '';
|
|
285
|
-
// Keep `data-dgmo-processed` set so a follow-up run() doesn't loop on
|
|
286
|
-
// the same broken source. Users wanting to retry after editing should
|
|
287
|
-
// clear the attribute manually or replace the element.
|
|
288
300
|
const message =
|
|
289
301
|
err instanceof Error ? err.message : 'Render failed unexpectedly';
|
|
290
|
-
|
|
291
|
-
el.parentElement?.insertBefore(banner, el);
|
|
302
|
+
replaceWithErrorCard(el, source, { message, severity: 'error' });
|
|
292
303
|
warn('render() rejected:', err);
|
|
293
304
|
return {};
|
|
294
305
|
}
|
|
295
306
|
|
|
296
307
|
if (result.diagnostics && result.diagnostics.length > 0) {
|
|
297
|
-
el.style.visibility = '';
|
|
298
|
-
// Keep `data-dgmo-processed` set so a follow-up run() doesn't loop on
|
|
299
|
-
// the same broken source. Users wanting to retry after editing should
|
|
300
|
-
// clear the attribute manually or replace the element.
|
|
301
308
|
const d = result.diagnostics[0]!; // In-bounds by length > 0 check above.
|
|
302
309
|
// d may have shape { severity, message, line, column } from diagnostics.ts
|
|
303
|
-
|
|
310
|
+
replaceWithErrorCard(el, source, {
|
|
304
311
|
message: d.message,
|
|
305
312
|
severity: d.severity,
|
|
306
313
|
line: d.line,
|
|
307
314
|
...(d.column !== undefined && { column: d.column }),
|
|
308
315
|
});
|
|
309
|
-
el.parentElement?.insertBefore(banner, el);
|
|
310
316
|
warn('diagnostic:', d.message, d.line, d.column);
|
|
311
317
|
return {};
|
|
312
318
|
}
|
|
313
319
|
|
|
314
320
|
if (!result.svg) {
|
|
315
|
-
el
|
|
316
|
-
// Keep `data-dgmo-processed` set so a follow-up run() doesn't loop on
|
|
317
|
-
// the same broken source. Users wanting to retry after editing should
|
|
318
|
-
// clear the attribute manually or replace the element.
|
|
319
|
-
const banner = buildErrorBanner({
|
|
321
|
+
replaceWithErrorCard(el, source, {
|
|
320
322
|
message: 'Empty SVG returned from renderer',
|
|
321
323
|
severity: 'error',
|
|
322
324
|
});
|
|
323
|
-
el.parentElement?.insertBefore(banner, el);
|
|
324
325
|
return {};
|
|
325
326
|
}
|
|
326
327
|
|
|
327
|
-
// Build wrapper.
|
|
328
|
-
const wrapper = document.createElement('div');
|
|
329
328
|
const themeClass =
|
|
330
329
|
resolvedTheme === 'dark'
|
|
331
330
|
? 'dgmo-theme-dark'
|
|
332
331
|
: resolvedTheme === 'transparent'
|
|
333
332
|
? 'dgmo-theme-transparent'
|
|
334
333
|
: 'dgmo-theme-light';
|
|
335
|
-
wrapper.className = `dgmo-rendered ${themeClass}`;
|
|
336
|
-
wrapper.dataset['dgmoProcessed'] = 'true';
|
|
337
334
|
|
|
338
335
|
// Insert SVG via a detached holder + post-insertion sanitization. The
|
|
339
336
|
// spec said "never assign user-supplied content to innerHTML"; we treat
|
|
@@ -349,15 +346,10 @@ async function processElement(el: Element): Promise<ProcessOutcome> {
|
|
|
349
346
|
svgHolder.innerHTML = result.svg;
|
|
350
347
|
const svgEl = svgHolder.querySelector('svg');
|
|
351
348
|
if (!svgEl) {
|
|
352
|
-
el
|
|
353
|
-
// Keep `data-dgmo-processed` set so a follow-up run() doesn't loop on
|
|
354
|
-
// the same broken source. Users wanting to retry after editing should
|
|
355
|
-
// clear the attribute manually or replace the element.
|
|
356
|
-
const banner = buildErrorBanner({
|
|
349
|
+
replaceWithErrorCard(el, source, {
|
|
357
350
|
message: 'Empty SVG returned from renderer',
|
|
358
351
|
severity: 'error',
|
|
359
352
|
});
|
|
360
|
-
el.parentElement?.insertBefore(banner, el);
|
|
361
353
|
return {};
|
|
362
354
|
}
|
|
363
355
|
sanitizeSvgInPlace(svgEl);
|
|
@@ -366,24 +358,30 @@ async function processElement(el: Element): Promise<ProcessOutcome> {
|
|
|
366
358
|
// control/bidi-strip filter rather than relying on renderer output).
|
|
367
359
|
svgEl.setAttribute('role', 'img');
|
|
368
360
|
svgEl.setAttribute('aria-label', ariaLabel);
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
utmSource: 'auto-embed',
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
const panel = buildSourcePanel(source, shareUrl, cfg.showEditorLink);
|
|
384
|
-
wrapper.appendChild(panel);
|
|
361
|
+
|
|
362
|
+
// Build share URL for the "Open in editor" toolbar action.
|
|
363
|
+
let shareUrl: string | null = null;
|
|
364
|
+
if (showSource && cfg.showEditorLink) {
|
|
365
|
+
shareUrl = buildShareUrl(source, {
|
|
366
|
+
palette: cfg.palette,
|
|
367
|
+
theme: resolvedTheme === 'dark' ? 'dark' : 'light',
|
|
368
|
+
editorBase: EDITOR_BASE_URL,
|
|
369
|
+
campaign: VERSION,
|
|
370
|
+
utmSource: 'auto-embed',
|
|
371
|
+
});
|
|
385
372
|
}
|
|
386
373
|
|
|
374
|
+
// Standard embed block (BL-114): canonical chrome from src/embed.
|
|
375
|
+
const wrapper = buildRenderedBlock({
|
|
376
|
+
source,
|
|
377
|
+
svgEl,
|
|
378
|
+
themeClass,
|
|
379
|
+
showSource,
|
|
380
|
+
showEditorLink: cfg.showEditorLink,
|
|
381
|
+
shareUrl,
|
|
382
|
+
});
|
|
383
|
+
wrapper.dataset['dgmoProcessed'] = 'true';
|
|
384
|
+
|
|
387
385
|
// Track wrapper so re-runs / theme changes can update it. Only persist
|
|
388
386
|
// the explicit 'true'/'false' values; treat any other value as null so
|
|
389
387
|
// the global default applies on re-render (matches first-render behavior).
|
package/src/auto/shared.ts
CHANGED
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
* Shared browser-embed helpers for the `@diagrammo/dgmo` client-side
|
|
3
3
|
* drop-ins (`./auto` script-tag renderer and `./element` custom element).
|
|
4
4
|
*
|
|
5
|
-
* These are the SVG sanitizer, theme resolver,
|
|
6
|
-
*
|
|
7
|
-
* and share-URL builder — factored
|
|
8
|
-
*
|
|
9
|
-
* public `window.dgmo` surface is
|
|
5
|
+
* These are the SVG sanitizer, theme resolver, the standard-block DOM
|
|
6
|
+
* assembler (canonical chrome from `src/embed` — BL-114), the error card,
|
|
7
|
+
* aria-label derivation, style injection, and share-URL builder — factored
|
|
8
|
+
* out of `auto/index.ts` so the two entries share one implementation rather
|
|
9
|
+
* than diverging copies. The `auto` entry's public `window.dgmo` surface is
|
|
10
|
+
* unaffected; it imports from here.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
import { encodeDiagramUrl } from '../sharing';
|
|
13
|
-
import {
|
|
14
|
+
import { buildDgmoBlockHtml, errorBlockHtml } from '../embed';
|
|
14
15
|
import { CSS } from './styles';
|
|
15
16
|
import { safeHref } from '../utils/safe-href';
|
|
16
17
|
|
|
@@ -22,10 +23,10 @@ export const VERSION: string =
|
|
|
22
23
|
(typeof __DGMO_VERSION__ === 'string' && __DGMO_VERSION__) || 'dev';
|
|
23
24
|
|
|
24
25
|
/** Default hosted editor used by "Open in editor" share links. */
|
|
25
|
-
export
|
|
26
|
+
export { EDITOR_BASE_URL } from '../embed';
|
|
26
27
|
|
|
27
28
|
const ARIA_LABEL_MAX = 200;
|
|
28
|
-
const COPIED_INTERACTION_MS =
|
|
29
|
+
const COPIED_INTERACTION_MS = 1500;
|
|
29
30
|
const LOG_PREFIX = '[dgmo]';
|
|
30
31
|
|
|
31
32
|
// Bidi override + control char strip for aria-label sanitization. The regex
|
|
@@ -148,156 +149,149 @@ export function deriveAriaLabel(source: string): string {
|
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
// ============================================================
|
|
151
|
-
//
|
|
152
|
+
// Standard block assembly (canonical chrome from src/embed — BL-114)
|
|
152
153
|
// ============================================================
|
|
153
154
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return frag;
|
|
155
|
+
export interface RenderedBlockOptions {
|
|
156
|
+
/** Trimmed DGMO source (copy payload + highlighted panel content). */
|
|
157
|
+
source: string;
|
|
158
|
+
/** Already-rendered AND sanitized SVG element to mount as the diagram. */
|
|
159
|
+
svgEl: Element;
|
|
160
|
+
/** `dgmo-theme-light` / `dgmo-theme-dark` / `dgmo-theme-transparent`. */
|
|
161
|
+
themeClass: string;
|
|
162
|
+
/** Emit the source disclosure + toolbar (showcase) or diagram-only. */
|
|
163
|
+
showSource: boolean;
|
|
164
|
+
/** Emit the open-in-editor toolbar link at all. */
|
|
165
|
+
showEditorLink: boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Pre-built share URL (with the surface's UTM params) for the
|
|
168
|
+
* open-in-editor link. `null` (encode failed / too large) drops the link.
|
|
169
|
+
*/
|
|
170
|
+
shareUrl: string | null;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Assemble the standard DGMO embed block (`figure.dgmo` + hover-reveal icon
|
|
175
|
+
* toolbar + native `<details>` source panel) around an already-sanitized SVG
|
|
176
|
+
* node, and bind the toolbar's copy/open click handling.
|
|
177
|
+
*
|
|
178
|
+
* The markup comes from the canonical `buildDgmoBlockHtml` in `src/embed`;
|
|
179
|
+
* this wrapper only (1) mounts the live SVG node into the `.dgmo-svg` slot,
|
|
180
|
+
* (2) swaps the open-in-editor href for the surface's UTM-tagged share URL,
|
|
181
|
+
* and (3) attaches the click handler that `<details>` can't provide (copy).
|
|
182
|
+
*/
|
|
183
|
+
export function buildRenderedBlock(opts: RenderedBlockOptions): HTMLElement {
|
|
184
|
+
const html = buildDgmoBlockHtml(opts.source, '<div class="dgmo-svg"></div>', {
|
|
185
|
+
mode: opts.showSource ? 'showcase' : 'diagram',
|
|
186
|
+
showOpenInEditor: opts.showSource && opts.showEditorLink,
|
|
187
|
+
// Keep the legacy `.dgmo-rendered` + theme hooks so the anti-flash CSS,
|
|
188
|
+
// idempotency filters, and theme-scoped token colors keep working.
|
|
189
|
+
legacyClassNames: ['dgmo-rendered', opts.themeClass],
|
|
190
|
+
});
|
|
191
|
+
const holder = document.createElement('div');
|
|
192
|
+
// buildDgmoBlockHtml output is author-controlled markup with all
|
|
193
|
+
// user-supplied strings escaped; the SVG slot is empty at this point.
|
|
194
|
+
holder.innerHTML = html;
|
|
195
|
+
const wrapper = holder.firstElementChild as HTMLElement;
|
|
196
|
+
|
|
197
|
+
// Mount the sanitized SVG node directly (no serialize/re-parse round trip).
|
|
198
|
+
wrapper.querySelector('.dgmo-svg')?.appendChild(opts.svgEl);
|
|
199
|
+
|
|
200
|
+
// The canonical builder encodes a bare share URL; the browser surfaces
|
|
201
|
+
// carry UTM attribution, so swap in the pre-built URL (or drop the link
|
|
202
|
+
// when encoding failed — copy remains as the fallback affordance).
|
|
203
|
+
const open = wrapper.querySelector<HTMLAnchorElement>('a.dgmo-open');
|
|
204
|
+
if (open) {
|
|
205
|
+
if (opts.shareUrl) open.href = opts.shareUrl;
|
|
206
|
+
else open.remove();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
bindBlockToolbar(wrapper);
|
|
210
|
+
return wrapper;
|
|
184
211
|
}
|
|
185
212
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
chevron.setAttribute('aria-hidden', 'true');
|
|
201
|
-
chevron.textContent = '▸';
|
|
202
|
-
toggle.appendChild(chevron);
|
|
203
|
-
const label = document.createElement('span');
|
|
204
|
-
label.textContent = 'DGMO source';
|
|
205
|
-
toggle.appendChild(label);
|
|
206
|
-
|
|
207
|
-
const body = document.createElement('div');
|
|
208
|
-
body.className = 'dgmo-source-body';
|
|
209
|
-
const pre = document.createElement('pre');
|
|
210
|
-
pre.className = 'dgmo-source-pre';
|
|
211
|
-
pre.appendChild(buildHighlightedSource(source));
|
|
212
|
-
body.appendChild(pre);
|
|
213
|
-
|
|
214
|
-
const actions = document.createElement('div');
|
|
215
|
-
actions.className = 'dgmo-source-actions';
|
|
216
|
-
|
|
217
|
-
const copyBtn = document.createElement('button');
|
|
218
|
-
copyBtn.type = 'button';
|
|
219
|
-
copyBtn.className = 'dgmo-btn dgmo-btn-copy';
|
|
220
|
-
copyBtn.setAttribute('aria-label', 'Copy DGMO source');
|
|
221
|
-
copyBtn.title = 'Copy source';
|
|
222
|
-
setIcon(copyBtn, COPY_ICON_SVG);
|
|
223
|
-
copyBtn.addEventListener('click', () => {
|
|
224
|
-
void copySource(source, copyBtn);
|
|
213
|
+
/**
|
|
214
|
+
* Click handling for the standard block toolbar (mirrors remark-dgmo's
|
|
215
|
+
* `bindDgmo` reference implementation, but bound per-wrapper because these
|
|
216
|
+
* surfaces build their DOM imperatively).
|
|
217
|
+
*
|
|
218
|
+
* The toolbar is the `<summary>` of the source `<details>`: clicks on the
|
|
219
|
+
* `</>` toggle keep the native default (toggling), while clicks on
|
|
220
|
+
* `.dgmo-toolbar-btn` (copy / open) must preventDefault so they don't ALSO
|
|
221
|
+
* toggle — which cancels an anchor's navigation, hence the manual
|
|
222
|
+
* `window.open`.
|
|
223
|
+
*/
|
|
224
|
+
function bindBlockToolbar(wrapper: HTMLElement): void {
|
|
225
|
+
wrapper.addEventListener('click', (e) => {
|
|
226
|
+
void handleToolbarClick(e);
|
|
225
227
|
});
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function handleToolbarClick(e: Event): Promise<void> {
|
|
231
|
+
const target = e.target as Element | null;
|
|
232
|
+
if (!target || typeof target.closest !== 'function') return;
|
|
233
|
+
const btn = target.closest('.dgmo-toolbar-btn') as HTMLElement | null;
|
|
234
|
+
if (!btn) return;
|
|
235
|
+
|
|
236
|
+
const insideSummary = !!btn.closest('summary');
|
|
237
|
+
if (insideSummary) e.preventDefault();
|
|
238
|
+
|
|
239
|
+
if (btn.matches('button.dgmo-copy')) {
|
|
240
|
+
const copied = await copyText(btn.dataset['dgmoSource'] ?? '');
|
|
241
|
+
if (copied) {
|
|
242
|
+
btn.classList.add('dgmo-copy--success');
|
|
243
|
+
setTimeout(
|
|
244
|
+
() => btn.classList.remove('dgmo-copy--success'),
|
|
245
|
+
COPIED_INTERACTION_MS
|
|
246
|
+
);
|
|
238
247
|
} else {
|
|
239
|
-
|
|
240
|
-
editorBtn.title =
|
|
241
|
-
'Diagram too large for share link; copy source and paste into editor';
|
|
242
|
-
editorBtn.addEventListener('click', (e) => e.preventDefault());
|
|
248
|
+
sharedWarn('clipboard write failed');
|
|
243
249
|
}
|
|
244
|
-
|
|
250
|
+
return;
|
|
245
251
|
}
|
|
246
252
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
253
|
+
if (insideSummary && btn.matches('a.dgmo-open')) {
|
|
254
|
+
const anchor = btn as HTMLAnchorElement;
|
|
255
|
+
if (anchor.href) {
|
|
256
|
+
window.open(
|
|
257
|
+
anchor.href,
|
|
258
|
+
anchor.target || '_blank',
|
|
259
|
+
'noopener,noreferrer'
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
257
263
|
}
|
|
258
264
|
|
|
259
|
-
async function
|
|
260
|
-
source: string,
|
|
261
|
-
btn: HTMLButtonElement
|
|
262
|
-
): Promise<void> {
|
|
263
|
-
let copied = false;
|
|
265
|
+
async function copyText(text: string): Promise<boolean> {
|
|
264
266
|
try {
|
|
265
267
|
if (navigator?.clipboard?.writeText) {
|
|
266
|
-
await navigator.clipboard.writeText(
|
|
267
|
-
|
|
268
|
+
await navigator.clipboard.writeText(text);
|
|
269
|
+
return true;
|
|
268
270
|
}
|
|
269
271
|
} catch {
|
|
270
272
|
// fallthrough to execCommand
|
|
271
273
|
}
|
|
272
|
-
if (
|
|
274
|
+
if (typeof document !== 'undefined') {
|
|
273
275
|
try {
|
|
274
276
|
const ta = document.createElement('textarea');
|
|
275
|
-
ta.value =
|
|
277
|
+
ta.value = text;
|
|
276
278
|
ta.setAttribute('readonly', '');
|
|
277
279
|
ta.style.position = 'absolute';
|
|
278
280
|
ta.style.left = '-9999px';
|
|
279
281
|
document.body.appendChild(ta);
|
|
280
282
|
ta.select();
|
|
281
|
-
copied = document.execCommand('copy');
|
|
283
|
+
const copied = document.execCommand('copy');
|
|
282
284
|
document.body.removeChild(ta);
|
|
285
|
+
return copied;
|
|
283
286
|
} catch {
|
|
284
|
-
|
|
287
|
+
return false;
|
|
285
288
|
}
|
|
286
289
|
}
|
|
287
|
-
|
|
288
|
-
setIcon(btn, CHECK_ICON_SVG);
|
|
289
|
-
btn.classList.add('dgmo-btn-copied');
|
|
290
|
-
setTimeout(() => {
|
|
291
|
-
setIcon(btn, COPY_ICON_SVG);
|
|
292
|
-
btn.classList.remove('dgmo-btn-copied');
|
|
293
|
-
}, COPIED_INTERACTION_MS);
|
|
294
|
-
} else {
|
|
295
|
-
sharedWarn('clipboard write failed');
|
|
296
|
-
}
|
|
290
|
+
return false;
|
|
297
291
|
}
|
|
298
292
|
|
|
299
293
|
// ============================================================
|
|
300
|
-
// Error
|
|
294
|
+
// Error card (canonical errorBlockHtml from src/embed)
|
|
301
295
|
// ============================================================
|
|
302
296
|
|
|
303
297
|
export interface BannerOptions {
|
|
@@ -307,26 +301,32 @@ export interface BannerOptions {
|
|
|
307
301
|
column?: number;
|
|
308
302
|
}
|
|
309
303
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Build the standard `.dgmo--error` card as a live DOM element. Message +
|
|
306
|
+
* location are folded into one line; the offending source is shown inside
|
|
307
|
+
* the card (canonical shape — same as remark-dgmo and the other adopters).
|
|
308
|
+
*/
|
|
309
|
+
export function buildErrorBlock(
|
|
310
|
+
opts: BannerOptions & { source: string }
|
|
311
|
+
): HTMLElement {
|
|
312
|
+
let message =
|
|
313
|
+
opts.severity && opts.severity !== 'error'
|
|
314
|
+
? `${opts.severity}: ${opts.message}`
|
|
315
|
+
: opts.message;
|
|
320
316
|
if (opts.line !== undefined && opts.line > 0) {
|
|
321
|
-
|
|
322
|
-
loc.className = 'dgmo-error-banner-loc';
|
|
323
|
-
loc.textContent =
|
|
317
|
+
message +=
|
|
324
318
|
opts.column !== undefined
|
|
325
|
-
? `at ${opts.line}:${opts.column}`
|
|
326
|
-
: `at line ${opts.line}`;
|
|
327
|
-
banner.appendChild(loc);
|
|
319
|
+
? ` (at ${opts.line}:${opts.column})`
|
|
320
|
+
: ` (at line ${opts.line})`;
|
|
328
321
|
}
|
|
329
|
-
|
|
322
|
+
const holder = document.createElement('div');
|
|
323
|
+
// errorBlockHtml escapes both message and source.
|
|
324
|
+
holder.innerHTML = errorBlockHtml(new Error(message), opts.source);
|
|
325
|
+
const card = holder.firstElementChild as HTMLElement;
|
|
326
|
+
// Mark processed so the auto surface's selectors never re-scan the card
|
|
327
|
+
// (its root carries the `.dgmo` class the scanner matches on).
|
|
328
|
+
card.setAttribute('data-dgmo-processed', 'true');
|
|
329
|
+
return card;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
// ============================================================
|