@cube-drone/marquee-html-renderer 0.9.0 → 0.9.1
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/effects.d.ts +47 -0
- package/dist/effects.js +252 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/render.js +127 -175
- package/package.json +5 -5
- package/src/effects.ts +316 -0
- package/src/index.ts +1 -0
- package/src/render.ts +138 -207
package/dist/render.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// vocabulary shrugs (children survive, effect doesn't); comments render
|
|
5
5
|
// nothing; invalid constructs render inert placeholders.
|
|
6
6
|
import { bareWebProfile } from "./profile.js";
|
|
7
|
+
import { effectLook, splitPieces } from "./effects.js";
|
|
7
8
|
export function render(node, profile = bareWebProfile) {
|
|
8
9
|
return renderNode(node, { profile, note: { n: 0, pending: [] } });
|
|
9
10
|
}
|
|
@@ -154,8 +155,24 @@ export function usedFontTokens(html) {
|
|
|
154
155
|
for (const m of html.matchAll(/mq-font-([a-z0-9-]+)/g)) {
|
|
155
156
|
used.add(m[1]);
|
|
156
157
|
}
|
|
158
|
+
// A scheme that wears a grab-bag face of its own needs that face shipped.
|
|
159
|
+
for (const m of html.matchAll(/mq-scheme-([a-z0-9-]+)/g)) {
|
|
160
|
+
for (const [scheme, token] of SCHEME_FONTS) {
|
|
161
|
+
if (m[1] === scheme || m[1].startsWith(`${scheme}-`)) {
|
|
162
|
+
used.add(token);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
157
166
|
return [...used].sort();
|
|
158
167
|
}
|
|
168
|
+
/** Schemes (and their `-flavor` variants) that wear a grab-bag face by
|
|
169
|
+
* default. Kept in lockstep with marquee.css and the Rust renderer. */
|
|
170
|
+
const SCHEME_FONTS = [
|
|
171
|
+
["earthbound", "press-start"],
|
|
172
|
+
["crosscode", "vt323"],
|
|
173
|
+
["ff6", "vt323"],
|
|
174
|
+
["chronotrigger", "vt323"],
|
|
175
|
+
];
|
|
159
176
|
/** One rung of the font-element seven-step dial: presentational floor
|
|
160
177
|
* (works with no stylesheet, under any CSP), stylesheet class as ceiling.
|
|
161
178
|
* The named rungs - teeny, tiny, huge, enormous - are unnecessary
|
|
@@ -266,6 +283,11 @@ function styleVarList(attrs, profile) {
|
|
|
266
283
|
else if (isColorValue(bg)) {
|
|
267
284
|
vars.push(`--mq-bg:${bg}`);
|
|
268
285
|
}
|
|
286
|
+
// A scheme's signature color - the thing its game let you customize (an
|
|
287
|
+
// EarthBound frame, an FF6 window). Schemes without one ignore it.
|
|
288
|
+
if (isColorValue(attrs["accent"])) {
|
|
289
|
+
vars.push(`--mq-accent:${attrs["accent"]}`);
|
|
290
|
+
}
|
|
269
291
|
return vars.join(";");
|
|
270
292
|
}
|
|
271
293
|
function styleVars(attrs, profile) {
|
|
@@ -293,6 +315,14 @@ function fontClass(attrs) {
|
|
|
293
315
|
}
|
|
294
316
|
function directive(name, attrs, nodes, ctx) {
|
|
295
317
|
const { profile } = ctx;
|
|
318
|
+
// The profile hook sees the children rendered; built-ins that lay their
|
|
319
|
+
// children out themselves (table, stack) render them again, so rewind the
|
|
320
|
+
// aside numbering first - or a note inside counts twice.
|
|
321
|
+
const saved = { n: ctx.note.n, pending: [...ctx.note.pending] };
|
|
322
|
+
const rewind = () => {
|
|
323
|
+
ctx.note.n = saved.n;
|
|
324
|
+
ctx.note.pending = [...saved.pending];
|
|
325
|
+
};
|
|
296
326
|
const inner = children(nodes, ctx);
|
|
297
327
|
const custom = profile.directive(name, attrs, inner);
|
|
298
328
|
if (custom !== null) {
|
|
@@ -332,7 +362,15 @@ function directive(name, attrs, nodes, ctx) {
|
|
|
332
362
|
return `<div class="mq-media"${style}>${inner}</div>`;
|
|
333
363
|
}
|
|
334
364
|
case "table":
|
|
365
|
+
rewind();
|
|
335
366
|
return renderTable(attrs, nodes, ctx);
|
|
367
|
+
case "stack":
|
|
368
|
+
rewind();
|
|
369
|
+
return renderStack(attrs, nodes, ctx);
|
|
370
|
+
case "layer":
|
|
371
|
+
// Outside a stack a layer is just a section-like container: its style
|
|
372
|
+
// knobs apply, place/backing mean nothing.
|
|
373
|
+
return `<div class="mq-layer${schemeClass(attrs)}${fontClass(attrs)}"${styleVars(attrs, profile)}>${inner}</div>`;
|
|
336
374
|
case "center":
|
|
337
375
|
case "right":
|
|
338
376
|
case "left":
|
|
@@ -422,17 +460,81 @@ function renderTable(attrs, nodes, ctx) {
|
|
|
422
460
|
// Cell sidenotes land just below the table, like a paragraph's would.
|
|
423
461
|
return flushNotes(ctx, `<table class="mq-table">${rows.join("")}</table>`);
|
|
424
462
|
}
|
|
463
|
+
/** A stack paints at most this many layers; the rest flow below the box. */
|
|
464
|
+
const MAX_LAYERS = 8;
|
|
465
|
+
const PLACES = new Set([
|
|
466
|
+
"fill", "top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right",
|
|
467
|
+
]);
|
|
468
|
+
/** The `aspect` vocabulary as CSS aspect-ratio values. */
|
|
469
|
+
const STACK_ASPECTS = {
|
|
470
|
+
"16:9": "16/9",
|
|
471
|
+
"4:3": "4/3",
|
|
472
|
+
"3:2": "3/2",
|
|
473
|
+
"1:1": "1/1",
|
|
474
|
+
card: "5/7",
|
|
475
|
+
};
|
|
476
|
+
/** :::stack (SPEC.md, "Stacks"): every direct child is a layer, source order
|
|
477
|
+
* is z-order. The stylesheet puts every layer in one grid cell, so the box
|
|
478
|
+
* is as big as its biggest layer needs and paint order is DOM order: no
|
|
479
|
+
* z-index, no absolute positioning, nothing clipped. Layers past the cap
|
|
480
|
+
* render in flow below the box. */
|
|
481
|
+
function renderStack(attrs, nodes, ctx) {
|
|
482
|
+
const vars = [];
|
|
483
|
+
const aspect = Object.hasOwn(STACK_ASPECTS, attrs["aspect"] ?? "") ? STACK_ASPECTS[attrs["aspect"]] : undefined;
|
|
484
|
+
if (aspect !== undefined) {
|
|
485
|
+
vars.push(`--mq-stack-aspect:${aspect}`);
|
|
486
|
+
}
|
|
487
|
+
const w = mediaSize(attrs["width"]);
|
|
488
|
+
if (w !== null) {
|
|
489
|
+
vars.push(`--mq-stack-w:${w}`);
|
|
490
|
+
}
|
|
491
|
+
const style = vars.length === 0 ? "" : ` style="${vars.join(";")}"`;
|
|
492
|
+
const layers = nodes.slice(0, MAX_LAYERS).map((n) => renderLayer(n, ctx)).join("");
|
|
493
|
+
const rest = nodes.slice(MAX_LAYERS);
|
|
494
|
+
const restHtml = rest.length === 0 ? "" : `<div class="mq-stack-rest">${children(rest, ctx)}</div>`;
|
|
495
|
+
// The class tells the stylesheet a cover base fills the box rather than
|
|
496
|
+
// sizing it.
|
|
497
|
+
const cls = aspect === undefined ? "mq-stack" : "mq-stack mq-stack-aspect";
|
|
498
|
+
return `<div class="${cls}"${style}>${layers}</div>${restHtml}`;
|
|
499
|
+
}
|
|
500
|
+
/** One layer of a stack: a `:::layer` child carries knobs; any other child
|
|
501
|
+
* block is a layer with the defaults (`fill`, no backing). */
|
|
502
|
+
function renderLayer(node, ctx) {
|
|
503
|
+
const isLayer = node.type === "directive" && node.name === "layer";
|
|
504
|
+
const attrs = isLayer ? node.attrs : {};
|
|
505
|
+
const content = isLayer ? node.children : [node];
|
|
506
|
+
const place = PLACES.has(attrs["place"] ?? "") ? attrs["place"] : "fill";
|
|
507
|
+
const backing = attrs["backing"] === "box" || attrs["backing"] === "outline" ? ` mq-backing-${attrs["backing"]}` : "";
|
|
508
|
+
// A fill layer that is exactly one embed is that media covering the box -
|
|
509
|
+
// the one crop the spec permits, of pictures, never of words.
|
|
510
|
+
const only = content.length === 1 ? content[0] : undefined;
|
|
511
|
+
const cover = place === "fill" && only?.type === "paragraph" && only.children.length === 1 && only.children[0].type === "embed"
|
|
512
|
+
? " mq-layer-cover"
|
|
513
|
+
: "";
|
|
514
|
+
const inner = children(content, ctx);
|
|
515
|
+
return `<div class="mq-layer mq-place-${place}${backing}${cover}${schemeClass(attrs)}${fontClass(attrs)}"${styleVars(attrs, ctx.profile)}>${inner}</div>`;
|
|
516
|
+
}
|
|
425
517
|
/** Effect/typographic spans. The `<font>` tag is deliberate: presentational
|
|
426
518
|
* attributes are outside CSP's jurisdiction and are implemented by the
|
|
427
519
|
* browser itself, so color survives with no stylesheet and no style
|
|
428
520
|
* attributes - the floor of the degradation ladder. The --mq-color slot is
|
|
429
521
|
* the stylesheet-era ceiling on the same element. */
|
|
430
522
|
function span(name, attrs, nodes, ctx) {
|
|
523
|
+
const saved = { n: ctx.note.n, pending: [...ctx.note.pending] };
|
|
431
524
|
const inner = children(nodes, ctx);
|
|
432
525
|
const custom = ctx.profile.span(name, attrs, inner);
|
|
433
526
|
if (custom !== null) {
|
|
434
527
|
return custom;
|
|
435
528
|
}
|
|
529
|
+
const look = effectLook(name, attrs, nodes);
|
|
530
|
+
if (look !== null) {
|
|
531
|
+
if (look.units !== null) {
|
|
532
|
+
// A split renders its children again: rewind the aside numbering.
|
|
533
|
+
ctx.note.n = saved.n;
|
|
534
|
+
ctx.note.pending = [...saved.pending];
|
|
535
|
+
}
|
|
536
|
+
return renderEffect(name, look, nodes, inner, ctx);
|
|
537
|
+
}
|
|
436
538
|
switch (name) {
|
|
437
539
|
case "sup":
|
|
438
540
|
return `<sup>${inner}</sup>`;
|
|
@@ -492,194 +594,44 @@ function span(name, attrs, nodes, ctx) {
|
|
|
492
594
|
ctx.note.pending.push(`<span class="mq-note-num">${ctx.note.n}</span>${inner}`);
|
|
493
595
|
return `<sup class="mq-noteref">${ctx.note.n}</sup>`;
|
|
494
596
|
}
|
|
495
|
-
case "marquee": {
|
|
496
|
-
const dir = isToken(attrs["direction"]) ? ` data-direction="${attrs["direction"]}"` : "";
|
|
497
|
-
const speed = attrs["speed"] !== undefined && COUNT.test(attrs["speed"])
|
|
498
|
-
? ` style="--mq-speed:${attrs["speed"]}"`
|
|
499
|
-
: "";
|
|
500
|
-
return `<span class="mq-marquee"${dir}${speed}><span class="mq-marquee-inner">${inner}</span></span>`;
|
|
501
|
-
}
|
|
502
|
-
case "blink": {
|
|
503
|
-
const rate = attrs["rate"] !== undefined && COUNT.test(attrs["rate"])
|
|
504
|
-
? ` style="--mq-rate:${attrs["rate"]}"`
|
|
505
|
-
: "";
|
|
506
|
-
if (attrs["by"] === "letter" || attrs["by"] === "word") {
|
|
507
|
-
// Split blink: ramp is theater-marquee chase lights, scatter is
|
|
508
|
-
// twinkle. The rate var rides the container; units inherit it.
|
|
509
|
-
return bySegments(name, attrs["by"], attrs["phase"], nodes, ctx, rate);
|
|
510
|
-
}
|
|
511
|
-
return `<span class="mq-blink"${rate}>${inner}</span>`;
|
|
512
|
-
}
|
|
513
|
-
case "rainbow":
|
|
514
|
-
case "bounce":
|
|
515
|
-
case "jitter":
|
|
516
|
-
case "wave":
|
|
517
|
-
case "rubber":
|
|
518
|
-
if (attrs["by"] === "letter" || attrs["by"] === "word") {
|
|
519
|
-
return bySegments(name, attrs["by"], attrs["phase"], nodes, ctx);
|
|
520
|
-
}
|
|
521
|
-
return `<span class="mq-${name}">${inner}</span>`;
|
|
522
|
-
case "typewriter": {
|
|
523
|
-
// Inherently per-unit: the reveal IS a by=letter effect (by=word for
|
|
524
|
-
// word-at-a-time). speed= is units per second; the container carries
|
|
525
|
-
// the per-unit delay step, each unit its ordinal in --mq-o.
|
|
526
|
-
const by = attrs["by"] === "word" ? "word" : "letter";
|
|
527
|
-
const step = revealStep(attrs["speed"], 14);
|
|
528
|
-
return bySegments(name, by, attrs["phase"], nodes, ctx, ` style="--mq-tw-step:${step}s"`);
|
|
529
|
-
}
|
|
530
|
-
case "fadein": {
|
|
531
|
-
// The ghostly reveal. Bare [fadein] fades the whole run in once;
|
|
532
|
-
// by=letter / by=word drift units in on staggered starts (same
|
|
533
|
-
// one-shot family as typewriter: sequential ordinals, high cap);
|
|
534
|
-
// phase=scatter is apparition weather.
|
|
535
|
-
if (attrs["by"] === "letter" || attrs["by"] === "word") {
|
|
536
|
-
const step = revealStep(attrs["speed"], 16);
|
|
537
|
-
return bySegments(name, attrs["by"], attrs["phase"], nodes, ctx, ` style="--mq-fi-step:${step}s"`);
|
|
538
|
-
}
|
|
539
|
-
return `<span class="mq-fadein">${inner}</span>`;
|
|
540
|
-
}
|
|
541
597
|
}
|
|
542
598
|
return inner; // unknown span: pure shrug, children as plain content
|
|
543
599
|
}
|
|
544
|
-
// --
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
};
|
|
552
|
-
/** DOM-weight discipline: past this many units, the run animates whole.
|
|
553
|
-
* Loopers pay a live animation per element forever, so they cap low;
|
|
554
|
-
* typewriter's units are 1ms one-shots (finished animations cost nothing)
|
|
555
|
-
* and its natural material is long text, so it caps high. */
|
|
556
|
-
const MAX_SPLIT_UNITS = 400;
|
|
557
|
-
const MAX_REVEAL_UNITS = 2000;
|
|
558
|
-
function bySegments(effect, by, phaseAttr, nodes, ctx, containerStyle = "") {
|
|
559
|
-
// Each effect has a natural phase order (jitter scatters, the rest sweep);
|
|
560
|
-
// the knob overrides it either way. Invalid values degrade to the default.
|
|
561
|
-
const phase = phaseAttr === "scatter" || phaseAttr === "ramp"
|
|
562
|
-
? phaseAttr
|
|
563
|
-
: effect === "jitter"
|
|
564
|
-
? "scatter"
|
|
565
|
-
: "ramp";
|
|
566
|
-
const state = { effect, by, phase, i: 0, total: 0 };
|
|
567
|
-
state.total = countUnits(nodes, by);
|
|
568
|
-
const cap = isReveal(effect) ? MAX_REVEAL_UNITS : MAX_SPLIT_UNITS;
|
|
569
|
-
if (state.total === 0 || state.total > cap) {
|
|
570
|
-
return `<span class="mq-${effect}">${children(nodes, ctx)}</span>`;
|
|
600
|
+
// -- effects: the look (classes, knobs, per-unit split) comes from
|
|
601
|
+
// effects.ts, shared with every other surface that draws effects.
|
|
602
|
+
function renderEffect(name, look, nodes, inner, ctx) {
|
|
603
|
+
const data = look.data.map(([k, v]) => ` data-${k}="${escapeAttr(v)}"`).join("");
|
|
604
|
+
const style = look.vars.length === 0 ? "" : ` style="${look.vars.map(([k, v]) => `${k}:${escapeAttr(v)}`).join(";")}"`;
|
|
605
|
+
if (name === "marquee") {
|
|
606
|
+
return `<span class="${look.className}"${data}${style}><span class="mq-marquee-inner">${inner}</span></span>`;
|
|
571
607
|
}
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
*
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
// looping effects replay. phase=scatter reveals in a
|
|
587
|
-
// scrambled-but-deterministic order: a stride at the run's golden-ratio
|
|
588
|
-
// point, nudged coprime with the total, walks a well-spread permutation
|
|
589
|
-
// at EVERY length. (A fixed prime stride is a trap: 7919 mod 40 = 39 =
|
|
590
|
-
// -1, so forty-unit runs typed in backwards.)
|
|
591
|
-
if (isReveal(state.effect)) {
|
|
592
|
-
const o = state.phase === "scatter"
|
|
593
|
-
? (state.i * scatterStride(state.total)) % state.total
|
|
594
|
-
: state.i;
|
|
595
|
-
return String(o);
|
|
596
|
-
}
|
|
597
|
-
let o;
|
|
598
|
-
if (state.phase === "scatter") {
|
|
599
|
-
o = ((state.i * 7919) % 101) / 101;
|
|
600
|
-
}
|
|
601
|
-
else {
|
|
602
|
-
switch (state.effect) {
|
|
603
|
-
case "rainbow":
|
|
604
|
-
o = state.i / state.total; // gradient across the whole run
|
|
605
|
-
break;
|
|
606
|
-
case "wave":
|
|
607
|
-
o = (state.i % 8) / 8; // fixed ripple wavelength
|
|
608
|
-
break;
|
|
609
|
-
case "bounce":
|
|
610
|
-
o = (state.i % 6) / 6;
|
|
611
|
-
break;
|
|
612
|
-
default:
|
|
613
|
-
o = (state.i % 8) / 8; // jitter in ramp mode: a rippling shudder
|
|
614
|
-
break;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
return String(Math.round(o * 1000) / 1000);
|
|
618
|
-
}
|
|
619
|
-
/** speed= (units per second, a COUNT) into a per-unit delay step in
|
|
620
|
-
* seconds; invalid or absent falls to the effect's default rate. */
|
|
621
|
-
function revealStep(speedAttr, dflt) {
|
|
622
|
-
const speed = speedAttr !== undefined && COUNT.test(speedAttr) && Number(speedAttr) > 0
|
|
623
|
-
? Number(speedAttr)
|
|
624
|
-
: dflt;
|
|
625
|
-
return Math.round(1000 / speed) / 1000;
|
|
626
|
-
}
|
|
627
|
-
/** The one-shot reveals: sequential ordinals, the high unit cap. */
|
|
628
|
-
function isReveal(effect) {
|
|
629
|
-
return effect === "typewriter" || effect === "fadein";
|
|
630
|
-
}
|
|
631
|
-
function gcd(a, b) {
|
|
632
|
-
return b === 0 ? a : gcd(b, a % b);
|
|
633
|
-
}
|
|
634
|
-
/** The smallest stride >= ~61.8% of total that's coprime with it (falls
|
|
635
|
-
* back to 1 for degenerate totals - a 1- or 2-unit "scramble" is fate). */
|
|
636
|
-
function scatterStride(total) {
|
|
637
|
-
let stride = Math.max(1, Math.round(total * 0.618));
|
|
638
|
-
while (stride < total && gcd(stride, total) !== 1) {
|
|
639
|
-
stride += 1;
|
|
640
|
-
}
|
|
641
|
-
return gcd(stride, total) === 1 ? stride : 1;
|
|
642
|
-
}
|
|
643
|
-
function countUnits(nodes, by) {
|
|
644
|
-
let n = 0;
|
|
645
|
-
for (const node of nodes) {
|
|
646
|
-
if (node.type === "text") {
|
|
647
|
-
for (const seg of SEGMENTERS[by].segment(node.value)) {
|
|
648
|
-
if (isUnit(seg, by)) {
|
|
649
|
-
n += 1;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
else if (node.type === "emphasis" ||
|
|
654
|
-
node.type === "strong" ||
|
|
655
|
-
node.type === "strikethrough") {
|
|
656
|
-
n += countUnits(node.children, by);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
return n;
|
|
660
|
-
}
|
|
661
|
-
function splitRender(nodes, ctx, state) {
|
|
608
|
+
const body = look.units === null ? inner : splitRender(nodes, ctx, look);
|
|
609
|
+
return `<span class="${look.className}"${data}${style}>${body}</span>`;
|
|
610
|
+
}
|
|
611
|
+
/** Each unit in its own span with its phase offset; spaces and punctuation
|
|
612
|
+
* between units ride along as plain text; each word's units sit in a group
|
|
613
|
+
* that wraps as one. */
|
|
614
|
+
function splitRender(nodes, ctx, look) {
|
|
615
|
+
const pieces = (list) => list
|
|
616
|
+
.map((p) => p.kind === "text"
|
|
617
|
+
? escapeText(p.text)
|
|
618
|
+
: p.kind === "unit"
|
|
619
|
+
? `<span class="mq-l" style="--mq-o:${p.offset}">${escapeText(p.text)}</span>`
|
|
620
|
+
: `<span class="mq-w">${pieces(p.pieces)}</span>`)
|
|
621
|
+
.join("");
|
|
662
622
|
let out = "";
|
|
663
623
|
for (const node of nodes) {
|
|
664
624
|
if (node.type === "text") {
|
|
665
|
-
|
|
666
|
-
if (!isUnit(seg, state.by)) {
|
|
667
|
-
out += escapeText(seg.segment); // spaces/punctuation ride along
|
|
668
|
-
continue;
|
|
669
|
-
}
|
|
670
|
-
const o = unitOffset(state);
|
|
671
|
-
state.i += 1;
|
|
672
|
-
out += `<span class="mq-l" style="--mq-o:${o}">${escapeText(seg.segment)}</span>`;
|
|
673
|
-
}
|
|
625
|
+
out += pieces(splitPieces(node, look));
|
|
674
626
|
}
|
|
675
627
|
else if (node.type === "emphasis") {
|
|
676
|
-
out += `<em>${splitRender(node.children, ctx,
|
|
628
|
+
out += `<em>${splitRender(node.children, ctx, look)}</em>`;
|
|
677
629
|
}
|
|
678
630
|
else if (node.type === "strong") {
|
|
679
|
-
out += `<strong>${splitRender(node.children, ctx,
|
|
631
|
+
out += `<strong>${splitRender(node.children, ctx, look)}</strong>`;
|
|
680
632
|
}
|
|
681
633
|
else if (node.type === "strikethrough") {
|
|
682
|
-
out += `<del>${splitRender(node.children, ctx,
|
|
634
|
+
out += `<del>${splitRender(node.children, ctx, look)}</del>`;
|
|
683
635
|
}
|
|
684
636
|
else {
|
|
685
637
|
out += renderNode(node, ctx); // anything else renders whole, un-split
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cube-drone/marquee-html-renderer",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Reference static HTML renderer for the Marquee markup language",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"prepack": "npm run build"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@cube-drone/marquee-parser": "^0.9.
|
|
38
|
+
"@cube-drone/marquee-parser": "^0.9.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@cube-drone/marquee-css": "^0.9.
|
|
42
|
-
"@cube-drone/marquee-fonts": "^0.9.
|
|
43
|
-
"@cube-drone/marquee-turbolink": "^0.9.
|
|
41
|
+
"@cube-drone/marquee-css": "^0.9.1",
|
|
42
|
+
"@cube-drone/marquee-fonts": "^0.9.1",
|
|
43
|
+
"@cube-drone/marquee-turbolink": "^0.9.1",
|
|
44
44
|
"@types/node": "^24.0.0",
|
|
45
45
|
"typescript": "^5.9.0"
|
|
46
46
|
}
|