@dogsbay/render-html 0.2.0-beta.122 → 0.2.0-beta.124

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/README.md CHANGED
@@ -9,17 +9,19 @@ markup and Tailwind classes of the Dogsbay Astro components.
9
9
 
10
10
  ```ts
11
11
  import { dogsbayMdToTree } from "@dogsbay/format-dogsbay-md/browser";
12
- import { renderBlocks, type RenderContext } from "@dogsbay/render-html";
13
-
14
- const ctx: RenderContext = {
15
- link: (href) => href,
16
- asset: (src) => src,
17
- headings: [], ids: new Set(), unknown: new Set(), seq: 0,
18
- t: (key) => key,
12
+ import { createRenderContext, renderBlocks } from "@dogsbay/render-html";
13
+
14
+ // One context per page. Pass only what you choose; the renderer's own state
15
+ // (headings, ids, …) is created for you, and UI strings default to English.
16
+ const ctx = createRenderContext({
17
+ // link: (href) => …, // default: unchanged
18
+ // asset: (src) => …, // default: unchanged
19
+ // t: (key) => myStrings[key], // empty answers fall back to UI_STRINGS
19
20
  // highlighter: await createHighlighter(), // @dogsbay/highlight
20
21
  // math: katexMath, // @dogsbay/render-html/math (needs katex)
21
- };
22
+ });
22
23
  const html = renderBlocks(dogsbayMdToTree(markdown).tree, ctx);
24
+ // ctx.headings: the h2/h3 for a table of contents; ctx.unknown: node types it did not know
23
25
  ```
24
26
 
25
27
  The output uses Tailwind utility classes and the theme tokens. Styling it needs the Dogsbay
package/css/docs.css CHANGED
@@ -51,8 +51,9 @@
51
51
  looked like a colour bug in one button rather than a cascade bug in both.
52
52
  (No backticks in this comment: the whole stylesheet is a template
53
53
  literal.) */
54
- & a:not(.dba-api *):not([data-variant]) { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }
55
- & a:hover:not(.dba-api *):not([data-variant]) { opacity: 0.8; }
54
+ /* Not a whole-card link (LinkCard, the video card: `a.not-prose`): its underline ran under every line of the card */
55
+ & a:not(.dba-api *):not([data-variant]):not(.not-prose) { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }
56
+ & a:hover:not(.dba-api *):not([data-variant]):not(.not-prose) { opacity: 0.8; }
56
57
 
57
58
  & strong:not(.dba-api *) { font-weight: 600; }
58
59
  & code:not(.dba-api *) { font-size: 0.875em; padding: 0.15em 0.35em; border-radius: 0.25rem; background: var(--muted); font-family: var(--font-code, ui-monospace, monospace); }
@@ -66,6 +67,9 @@
66
67
  & ol:not(.dba-api *) { list-style: decimal; padding-left: 1.5rem; margin: 0.75rem 0; }
67
68
  & li:not(.dba-api *) { margin: 0.25rem 0; }
68
69
  & li > ul:not(.dba-api *), & li > ol:not(.dba-api *) { margin: 0.25rem 0; }
70
+ /* A file tree draws its own folder and file icons (files/markup.ts): the list rules above gave it bullets too */
71
+ & [data-component="files"] ul:not(.dba-api *) { list-style: none; padding-left: 0; }
72
+ & [data-component="files"] li > ul:not(.dba-api *) { padding-left: 1rem; }
69
73
 
70
74
  & blockquote:not(.dba-api *) { border-left: 4px solid var(--border); padding-left: 1rem; color: var(--muted-foreground); font-style: italic; margin: 1rem 0; }
71
75
 
@@ -28,6 +28,8 @@ export const BADGE_VARIANTS = {
28
28
  };
29
29
  /** The class list for a variant; an unknown variant gets the base classes only. */
30
30
  export function badgeClass(variant) {
31
- const v = BADGE_VARIANTS[(variant ?? "default")];
31
+ // Own keys only: `toString` or `__proto__` must not read Object.prototype
32
+ const key = variant ?? "default";
33
+ const v = Object.prototype.hasOwnProperty.call(BADGE_VARIANTS, key) ? BADGE_VARIANTS[key] : undefined;
32
34
  return v ? `${BADGE_BASE} ${v}` : BADGE_BASE;
33
35
  }
@@ -43,6 +43,9 @@ export const RENDER_HTML_CAPABILITIES = [
43
43
  { feature: "callout", support: "full", rendersAs: "Alert markup (12 variants, aliases mapped); collapsible → CollapsibleAlert `<details>`" },
44
44
  { feature: "details", support: "full", rendersAs: "CollapsibleAlert `<details>`, as the Astro serializer" },
45
45
  { feature: "details-sheet", support: "full", rendersAs: "`<db-details-sheet>` around the CollapsibleAlert `<details>` (a right-hand native `<dialog>` when the element script runs; a collapsible block with `js: none`)" },
46
+ { feature: "theme", support: "full", rendersAs: "a `<div class=\"dark …\" data-theme>` (THEME_SCOPES); an unknown name keeps the content and is reported" },
47
+ { feature: "tabs-variant", support: "full", rendersAs: "the variant's complete list and trigger classes in place of the base ones (TAB_VARIANTS)" },
48
+ { feature: "tone", support: "full", rendersAs: "each card's border and tint from the tone (CARD_TONE_CLASSES)" },
46
49
  {
47
50
  feature: "tabs",
48
51
  support: "full",
@@ -57,6 +60,7 @@ export const RENDER_HTML_CAPABILITIES = [
57
60
  { feature: "cards", support: "full", rendersAs: "a responsive card grid `<div>`" },
58
61
  { feature: "card", support: "full", rendersAs: "Card.astro markup; icon, title, description, body; linked when `href` is set" },
59
62
  { feature: "link-card", support: "full", rendersAs: "LinkCard.astro markup; a body of several blocks renders as a linked Card" },
63
+ { feature: "files", support: "full", rendersAs: "FileTree's markup: folder and file icons, nested" },
60
64
  { feature: "grid", support: "full", rendersAs: "a 1–6 column grid; grid-item spans and placeholder cells" },
61
65
  { feature: "link-button", support: "full", rendersAs: "an `<a>` with Button.astro's classes and variant" },
62
66
  { feature: "related", support: "full", rendersAs: "`<nav class=\"related-resources\">`" },
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A RenderContext with defaults. RenderContext mixes what a host chooses
3
+ * (links, assets, highlighter, math, icons, strings) with the renderer's own
4
+ * per-page state (headings, ids, seq, unknown …); hosts built it by hand,
5
+ * reading render.d.ts to get the internals right, and a new internal field
6
+ * broke every host silently. Build it here instead: pass only what you choose.
7
+ */
8
+ import type { RenderContext } from "./render.js";
9
+ /** The UI strings the renderer asks for (ctx.t), in English. */
10
+ export declare const UI_STRINGS: Readonly<Record<string, string>>;
11
+ /** The per-page state the renderer keeps in the context: always fresh, never passed. */
12
+ type Internal = "headings" | "ids" | "unknown" | "seq" | "t" | "fnRefs" | "usedMath" | "inLink" | "lastHeadingLevel" | "apiParentLevel" | "missingIcons" | "unsafeUrls";
13
+ export type RenderContextOptions = Partial<Omit<RenderContext, Internal>> & {
14
+ /**
15
+ * Localised UI strings. An empty or missing answer falls back to English
16
+ * (UI_STRINGS), then to the renderer's own label (callout titles).
17
+ */
18
+ t?: (key: string) => string | undefined;
19
+ /** Ids the page already uses outside the rendered content (a skip link's target): generated ids avoid them. */
20
+ reservedIds?: Iterable<string>;
21
+ };
22
+ /** A fresh context for one page: identity links and assets, English strings, empty state. */
23
+ export declare function createRenderContext(options?: RenderContextOptions): RenderContext;
24
+ export {};
@@ -0,0 +1,25 @@
1
+ /** The UI strings the renderer asks for (ctx.t), in English. */
2
+ export const UI_STRINGS = {
3
+ backToContent: "Back to content",
4
+ close: "Close",
5
+ copyCode: "Copy code",
6
+ details: "Details",
7
+ related: "Related links",
8
+ };
9
+ /** A fresh context for one page: identity links and assets, English strings, empty state. */
10
+ export function createRenderContext(options = {}) {
11
+ const { t, reservedIds, ...chosen } = options;
12
+ return {
13
+ ...chosen,
14
+ // An explicit `link: undefined` must not remove the default
15
+ link: chosen.link ?? ((href) => href),
16
+ asset: chosen.asset ?? ((src) => src),
17
+ headings: [],
18
+ ids: new Set(reservedIds ?? []),
19
+ unknown: new Set(),
20
+ missingIcons: new Set(),
21
+ unsafeUrls: new Set(),
22
+ seq: 0,
23
+ t: (key) => t?.(key) || UI_STRINGS[key] || "",
24
+ };
25
+ }
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  * imports neither, so it carries no Shiki, KaTeX or Node built-ins.
7
7
  */
8
8
  export * from "./render.js";
9
+ export { createRenderContext, UI_STRINGS, type RenderContextOptions } from "./context.js";
9
10
  export * from "./lines.js";
10
11
  export { esc, attrs, passthrough, slugify, unesc } from "./html.js";
11
12
  export { icon, hasIcon, CALLOUTS } from "./icons.js";
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * imports neither, so it carries no Shiki, KaTeX or Node built-ins.
7
7
  */
8
8
  export * from "./render.js";
9
+ export { createRenderContext, UI_STRINGS } from "./context.js";
9
10
  export * from "./lines.js";
10
11
  export { esc, attrs, passthrough, slugify, unesc } from "./html.js";
11
12
  export { icon, hasIcon, CALLOUTS } from "./icons.js";
package/dist/render.d.ts CHANGED
@@ -136,4 +136,4 @@ export interface TabItem {
136
136
  body: () => string;
137
137
  }
138
138
  /** A `db-tabs` group with Tabs.astro's markup, the first tab selected. */
139
- export declare function tabGroup(items: TabItem[], ctx: RenderContext, rootAttrs: Record<string, unknown>, syncKey?: string): string;
139
+ export declare function tabGroup(items: TabItem[], ctx: RenderContext, rootAttrs: Record<string, unknown>, syncKey?: string, variant?: string): string;
package/dist/render.js CHANGED
@@ -10,7 +10,7 @@ import { attrs, esc, FOREIGN_END, FOREIGN_START, passthrough, slugify, unesc } f
10
10
  import { CALLOUTS, hasIcon, icon } from "./icons.js";
11
11
  import { badgeClass } from "./badge-variants.js";
12
12
  import { KBD_CLASS } from "./kbd-variants.js";
13
- import { TONE_CLASSES } from "./tone-classes.js";
13
+ import { CARD_TONE_CLASSES, TAB_VARIANTS, THEME_SCOPES, TONE_CLASSES, lookup } from "./tone-classes.js";
14
14
  import { fileTreeHtml } from "./file-tree.js";
15
15
  import { stripMarkersForCopy } from "./code-markers.js";
16
16
  import { icons as ALERT_ICONS, chevronSvg as ALERT_CHEVRON } from "./alert-icons.js";
@@ -101,7 +101,7 @@ function inline(n, ctx) {
101
101
  const variant = n.button ? buttonVariant(n.button.variant) : undefined;
102
102
  const a = {
103
103
  // Button.astro's small size, whose text-xs replaces the base text-sm (tailwind-merge in tv()).
104
- ...passthrough(n.attrs, variant ? `${BUTTON_BASE.split(" ").filter((c) => c !== "text-sm").join(" ")} ${BUTTON_VARIANTS[variant] ?? BUTTON_VARIANTS.default} h-9 px-3 text-xs no-underline` : undefined),
104
+ ...passthrough(n.attrs, variant ? `${BUTTON_BASE.split(" ").filter((c) => c !== "text-sm").join(" ")} ${lookup(BUTTON_VARIANTS, variant) ?? BUTTON_VARIANTS.default} h-9 px-3 text-xs no-underline` : undefined),
105
105
  href,
106
106
  title: n.title,
107
107
  "data-variant": variant,
@@ -253,9 +253,27 @@ function proseHeadings(html, ctx) {
253
253
  });
254
254
  }
255
255
  // ─── Blocks ──────────────────────────────────────────────────────────
256
+ /**
257
+ * The heading ids a page will use, collected on the first (outermost)
258
+ * renderBlocks call for a context: a side sheet's title id must yield to a
259
+ * heading of the same name even when the sheet comes first, or the heading's
260
+ * TOC entry and links would open the sheet instead (#101).
261
+ */
262
+ const plannedHeadingIds = new WeakMap();
263
+ function planHeadingIds(nodes, out) {
264
+ for (const n of nodes) {
265
+ if (n.type === "heading")
266
+ out.add(str(n.props?.id) ?? str(n.props?.slug) ?? slugify(inlineText(n.inline)));
267
+ if (n.children)
268
+ planHeadingIds(n.children, out);
269
+ }
270
+ return out;
271
+ }
256
272
  export function renderBlocks(nodes, ctx) {
257
273
  if (!nodes)
258
274
  return "";
275
+ if (!plannedHeadingIds.has(ctx))
276
+ plannedHeadingIds.set(ctx, planHeadingIds(nodes, new Set()));
259
277
  let out = "";
260
278
  for (const n of nodes)
261
279
  out += block(n, ctx);
@@ -389,8 +407,21 @@ function block(n, ctx) {
389
407
  return avatar(p, ctx);
390
408
  case "example":
391
409
  return example(n, ctx);
392
- case "cards":
393
- return `<div${attrs(passthrough(p, "not-prose my-4 grid grid-cols-1 gap-4 sm:grid-cols-2"))}>${renderBlocks(n.children, ctx)}</div>\n`;
410
+ case "cards": {
411
+ // A group tone applies to every card that has none of its own
412
+ const tone = str(p.tone);
413
+ const kids = tone ? (n.children ?? []).map((c) => (c.type === "card" && !c.props?.tone ? { ...c, props: { ...c.props, tone } } : c)) : n.children;
414
+ return `<div${attrs(passthrough(p, "not-prose my-4 grid grid-cols-1 gap-4 sm:grid-cols-2"))}>${renderBlocks(kids, ctx)}</div>\n`;
415
+ }
416
+ // A scoped theme: `.dark` re-declares the tokens for its subtree (THEME_SCOPES)
417
+ case "theme": {
418
+ const scope = lookup(THEME_SCOPES, str(p.name));
419
+ if (!scope) {
420
+ ctx.unknown.add(`theme "${str(p.name) ?? ""}"`);
421
+ return renderBlocks(n.children, ctx);
422
+ }
423
+ return `<div${attrs({ ...passthrough(p, scope), "data-theme": str(p.name) })}>${renderBlocks(n.children, ctx)}</div>\n`;
424
+ }
394
425
  case "card":
395
426
  return card(n, ctx);
396
427
  case "link-card":
@@ -406,7 +437,7 @@ function block(n, ctx) {
406
437
  // `label` draws a placeholder cell in the `tone` colours, as GridItem does in the Astro pipeline.
407
438
  const label = str(p.label);
408
439
  const inner = label !== undefined
409
- ? `<div class="flex h-full min-h-16 items-center justify-center rounded-lg font-mono text-sm font-medium ${TONE_CLASSES[str(p.tone) ?? "primary-light"] ?? TONE_CLASSES["primary-light"]}">${esc(label)}</div>`
440
+ ? `<div class="flex h-full min-h-16 items-center justify-center rounded-lg font-mono text-sm font-medium ${lookup(TONE_CLASSES, str(p.tone)) ?? TONE_CLASSES["primary-light"]}">${esc(label)}</div>`
410
441
  : renderBlocks(n.children, ctx);
411
442
  const { label: _l, tone: _t, rowSpan: _r, ...rest } = p;
412
443
  const pass = passthrough(rest);
@@ -430,7 +461,7 @@ function block(n, ctx) {
430
461
  const href = str(p.href);
431
462
  const variant = buttonVariant(str(p.variant));
432
463
  const label = insideLink(true, ctx, () => (n.children?.length === 1 && n.children[0].type === "paragraph" ? renderInline(n.children[0].inline, ctx) : renderBlocks(n.children, ctx)));
433
- return `<p><a${attrs({ ...passthrough(p, `${BUTTON_BASE} ${BUTTON_VARIANTS[variant] ?? BUTTON_VARIANTS.default} h-10 px-4 py-2 no-underline`), "data-variant": variant, "data-size": "default", href: href ? linkUrl(href, ctx) : undefined })}>${label}</a></p>\n`;
464
+ return `<p><a${attrs({ ...passthrough(p, `${BUTTON_BASE} ${lookup(BUTTON_VARIANTS, variant) ?? BUTTON_VARIANTS.default} h-10 px-4 py-2 no-underline`), "data-variant": variant, "data-size": "default", href: href ? linkUrl(href, ctx) : undefined })}>${label}</a></p>\n`;
434
465
  }
435
466
  case "youtube": {
436
467
  // A card linking to the video, not an embed: the page must work offline, with no request to YouTube
@@ -752,10 +783,12 @@ function tabs(n, ctx) {
752
783
  return { value: v, label: esc(str(k.props?.label) ?? `Tab ${i + 1}`), body: () => renderBlocks(k.children, ctx) };
753
784
  });
754
785
  const syncKey = str(p.syncKey) ?? str(p["sync-key"]) ?? str(p.group);
755
- return tabGroup(items, ctx, passthrough(p, "my-4 w-full overflow-hidden rounded-lg border border-border"), syncKey);
786
+ return tabGroup(items, ctx, passthrough(p, "my-4 w-full overflow-hidden rounded-lg border border-border"), syncKey, str(p.variant));
756
787
  }
757
788
  /** A `db-tabs` group with Tabs.astro's markup, the first tab selected. */
758
- export function tabGroup(items, ctx, rootAttrs, syncKey) {
789
+ export function tabGroup(items, ctx, rootAttrs, syncKey, variant) {
790
+ // A variant's class strings are complete: they replace the base ones (TAB_VARIANTS)
791
+ const v = lookup(TAB_VARIANTS, variant);
759
792
  const group = ++ctx.seq;
760
793
  let list = "";
761
794
  let panels = "";
@@ -763,10 +796,10 @@ export function tabGroup(items, ctx, rootAttrs, syncKey) {
763
796
  const tid = `tab-${group}-${i + 1}`;
764
797
  const pid = `tabpanel-${group}-${i + 1}`;
765
798
  const sel = i === 0;
766
- list += `<button data-part="trigger" data-value="${esc(it.value)}" role="tab" type="button" id="${tid}" aria-controls="${pid}" aria-selected="${sel}" tabindex="${sel ? 0 : -1}"${sel ? ' data-state="active"' : ""} class="${TAB_TRIGGER}">${it.label}</button>`;
799
+ list += `<button data-part="trigger" data-value="${esc(it.value)}" role="tab" type="button" id="${tid}" aria-controls="${pid}" aria-selected="${sel}" tabindex="${sel ? 0 : -1}"${sel ? ' data-state="active"' : ""} class="${v?.trigger ?? TAB_TRIGGER}">${it.label}</button>`;
767
800
  panels += `<div data-part="content" data-value="${esc(it.value)}" role="tabpanel" id="${pid}" aria-labelledby="${tid}" tabindex="0"${sel ? ' data-state="active"' : " hidden"} class="${TAB_CONTENT}">${it.body()}</div>`;
768
801
  });
769
- return `<db-tabs${attrs({ ...rootAttrs, "default-value": items[0]?.value, "sync-key": syncKey })}><div data-part="list" role="tablist" aria-orientation="horizontal" class="flex items-center border-b border-border bg-muted p-1 text-muted-foreground">${list}</div>${panels}</db-tabs>\n`;
802
+ return `<db-tabs${attrs({ ...rootAttrs, "default-value": items[0]?.value, "sync-key": syncKey })}><div data-part="list" role="tablist" aria-orientation="horizontal" class="${v?.list ?? "flex items-center border-b border-border bg-muted p-1 text-muted-foreground"}">${list}</div>${panels}</db-tabs>\n`;
770
803
  }
771
804
  // ─── Accordion (Accordion*.astro + db-accordion) ────────────────────
772
805
  function accordion(n, ctx) {
@@ -794,7 +827,19 @@ function accordion(n, ctx) {
794
827
  }
795
828
  // `:::details` renders as a CollapsibleAlert, as in the Astro serializer.
796
829
  function details(n, ctx) {
797
- const p = (n.props ?? {});
830
+ let p = (n.props ?? {});
831
+ // A side sheet with no id takes one from its title, so a link written as for
832
+ // a heading opens it (#101; extractHeadings does the same for a site build)
833
+ if (isDetailsSheet(p) && !str(p.id)) {
834
+ const base = slugify(str(p.title) ?? str(p.summary) ?? "");
835
+ if (base) {
836
+ const planned = plannedHeadingIds.get(ctx);
837
+ let id = base;
838
+ for (let k = 2; planned?.has(id) || ctx.ids.has(id); k++)
839
+ id = `${base}-${k}`;
840
+ p = { ...p, id: uniqueId(ctx, id) };
841
+ }
842
+ }
798
843
  const title = str(p.title) ?? str(p.summary) ?? ctx.t("details");
799
844
  // `variant` as documented, then `type`, as the Astro pipeline reads it.
800
845
  const type = (str(p.variant) ?? str(p.type) ?? "").toLowerCase();
@@ -869,7 +914,9 @@ function card(n, ctx) {
869
914
  (desc ? `<p class="m-0 mt-1 text-sm text-muted-foreground [text-decoration:none]">${renderInline(parseInline(desc), ctx)}</p>` : "") +
870
915
  // Body blocks in the same description wrapper as the Astro pipeline's card (a <div>: they carry their own <p>).
871
916
  (n.children?.length ? `<div class="text-sm text-muted-foreground mt-1 [text-decoration:none]">${renderBlocks(n.children, ctx)}</div>` : ""));
872
- const cls = `rounded-lg border bg-card p-4 text-card-foreground shadow-sm${href ? " transition-colors hover:border-foreground/20" : ""}`;
917
+ // A tone (TONES) replaces the card's background and border colour
918
+ const toned = lookup(CARD_TONE_CLASSES, str(p.tone));
919
+ const cls = `rounded-lg border ${toned ?? "bg-card"} p-4 text-card-foreground shadow-sm${href ? ` transition-colors ${toned ? "hover:shadow-md" : "hover:border-foreground/20"}` : ""}`;
873
920
  return href
874
921
  ? `<div${attrs(passthrough(p, cls))}><div class="p-0"><a href="${esc(linkUrl(href, ctx))}" class="block text-foreground [text-decoration:none]">${inner}</a></div></div>`
875
922
  : `<div${attrs(passthrough(p, cls))}><div class="p-0">${inner}</div></div>`;
@@ -1 +1,9 @@
1
1
  export declare const TONE_CLASSES: Record<string, string>;
2
+ export declare const TONES: readonly ["info", "success", "warning", "danger"];
3
+ export declare const CARD_TONE_CLASSES: Record<string, string>;
4
+ export declare const TAB_VARIANTS: Record<string, {
5
+ list: string;
6
+ trigger: string;
7
+ }>;
8
+ export declare const THEME_SCOPES: Record<string, string>;
9
+ export declare function lookup<T>(table: Record<string, T>, key: unknown): T | undefined;
@@ -1,4 +1,4 @@
1
- // Generated by packages/render-html/scripts/sync-sources.mjs from @dogsbay/format-astro TONE_CLASSES. Do not edit.
1
+ // Generated by packages/render-html/scripts/sync-sources.mjs from @dogsbay/format-astro tone-classes.ts. Do not edit.
2
2
  export const TONE_CLASSES = {
3
3
  "primary": "bg-primary text-primary-foreground",
4
4
  "primary-strong": "bg-primary/80 text-primary-foreground",
@@ -13,3 +13,26 @@ export const TONE_CLASSES = {
13
13
  "purple": "bg-purple-500/15 text-purple-700 dark:text-purple-300",
14
14
  "red": "bg-red-500/15 text-red-700 dark:text-red-300"
15
15
  };
16
+ export const TONES = ["info", "success", "warning", "danger"];
17
+ export const CARD_TONE_CLASSES = {
18
+ "info": "border-info/50 bg-info/5",
19
+ "success": "border-success/50 bg-success/5",
20
+ "warning": "border-warning/50 bg-warning/5",
21
+ "danger": "border-danger/50 bg-danger/5"
22
+ };
23
+ export const TAB_VARIANTS = {
24
+ "pills": {
25
+ "list": "flex flex-wrap items-center gap-2 border-b-0 border-transparent bg-transparent p-0 px-3 pt-3 pb-1 text-muted-foreground",
26
+ "trigger": "inline-flex items-center justify-center whitespace-nowrap rounded-full border border-border px-4 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-selected:border-primary aria-selected:bg-primary aria-selected:text-primary-foreground aria-selected:shadow-none"
27
+ },
28
+ "underline": {
29
+ "list": "flex items-center gap-6 border-b border-border bg-transparent p-0 px-4 text-muted-foreground",
30
+ "trigger": "-mb-px inline-flex items-center justify-center whitespace-nowrap rounded-none border-b-2 border-transparent p-0 px-0.5 pt-3 pb-2 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:text-foreground aria-selected:border-primary aria-selected:bg-transparent aria-selected:text-foreground aria-selected:shadow-none"
31
+ }
32
+ };
33
+ export const THEME_SCOPES = {
34
+ "dark": "dark my-6 rounded-xl border border-border bg-background p-6 text-foreground [&>:first-child]:mt-0! [&>:last-child]:mb-0!"
35
+ };
36
+ export function lookup(table, key) {
37
+ return typeof key === "string" && Object.prototype.hasOwnProperty.call(table, key) ? table[key] : undefined;
38
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dogsbay/render-html",
3
- "version": "0.2.0-beta.122",
3
+ "version": "0.2.0-beta.124",
4
4
  "description": "Dogsbay MD TreeNode → HTML with the Astro components' markup and classes. No highlighter, math or CSS compiler unless you pass one; Worker- and browser-safe",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,9 +30,9 @@
30
30
  "dependencies": {
31
31
  "htmlparser2": "^10.1.0",
32
32
  "markdown-it": "^14.3.0",
33
- "@dogsbay/format-dogsbay-md": "0.2.0-beta.122",
34
- "@dogsbay/serialize-core": "0.2.0-beta.122",
35
- "@dogsbay/types": "0.2.0-beta.122"
33
+ "@dogsbay/format-dogsbay-md": "0.2.0-beta.124",
34
+ "@dogsbay/serialize-core": "0.2.0-beta.124",
35
+ "@dogsbay/types": "0.2.0-beta.124"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "katex": "^0.16.0"