@dogsbay/format-astro 0.2.0-beta.128 → 0.2.0-beta.129
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/capabilities.js +2 -2
- package/dist/serialize.js +67 -6
- package/package.json +7 -7
package/dist/capabilities.js
CHANGED
|
@@ -27,8 +27,8 @@ export const ASTRO_CAPABILITIES = [
|
|
|
27
27
|
{ feature: "diagram", support: "full", rendersAs: "`<Diagram>` (source + pre-rendered SVG)" },
|
|
28
28
|
{ feature: "youtube", support: "full", rendersAs: "`<YouTube>`" },
|
|
29
29
|
// ── Components ───────────────────────────────────────────
|
|
30
|
-
{ feature: "callout", support: "full", rendersAs: "`<Alert variant>` with the authored type kept as `data-type`" },
|
|
31
|
-
{ feature: "details", support: "full", rendersAs: "`<CollapsibleAlert variant title open icon>` (`title`, or its alias `summary`)" },
|
|
30
|
+
{ feature: "callout", support: "full", rendersAs: "`<Alert variant icon>` with the authored type kept as `data-type`; `collapsed`/`collapsible` → `<CollapsibleAlert>` (a `<details>`), as render-html; the title is inline Markdown" },
|
|
31
|
+
{ feature: "details", support: "full", rendersAs: "`<CollapsibleAlert variant title open icon>` (`title`, or its alias `summary`, inline Markdown in a `title` slot)" },
|
|
32
32
|
{ feature: "details-sheet", support: "full", rendersAs: "`<DetailsSheet>` around the CollapsibleAlert: `<db-details-sheet>` opens it as a right-hand native `<dialog>`; without the script it stays a collapsible block" },
|
|
33
33
|
{ feature: "theme", support: "full", rendersAs: "a `<div class=\"dark …\" data-theme>`: the theme re-declares its tokens on `.dark`, so the subtree turns dark" },
|
|
34
34
|
{ feature: "tabs-variant", support: "full", rendersAs: "TabsList/TabsTrigger given the variant's classes (TAB_VARIANTS), merged over their base" },
|
package/dist/serialize.js
CHANGED
|
@@ -875,13 +875,54 @@ function calloutToAstro(node, ctx) {
|
|
|
875
875
|
"type", "variant", "title", "icon", "class",
|
|
876
876
|
]);
|
|
877
877
|
const inner = childrenToAstro(node, ctx);
|
|
878
|
+
// An authored title is inline Markdown (`Before \`harbor init\``), as render-html reads it (MD-002);
|
|
879
|
+
// the default label is text
|
|
880
|
+
const titleNodes = explicitTitle && explicitTitle.length > 0 ? titleInline(title) : [{ type: "text", text: title }];
|
|
881
|
+
const plainTitle = isPlainCaption(titleNodes);
|
|
882
|
+
// `collapsed` / `collapsible`: a disclosure, as render-html draws it (MD-001)
|
|
883
|
+
if (isCollapsibleCallout(node.props)) {
|
|
884
|
+
ctx.imports.add("details");
|
|
885
|
+
const attrs = [`variant="${escapeAttr(collapsibleVariant(variant))}"`, componentAttr("title", plainTitle ? captionText(titleNodes) : title).trimStart()];
|
|
886
|
+
if (calloutStartsOpen(node.props))
|
|
887
|
+
attrs.push("open");
|
|
888
|
+
const slot = plainTitle ? "" : `\n <Fragment slot="title">${renderInline(titleNodes, ctx)}</Fragment>`;
|
|
889
|
+
const collapsiblePassthrough = renderPassthroughAttrs(node.props, ["type", "variant", "title", "icon", "class", "collapsed", "collapsible", "open"]);
|
|
890
|
+
return `<CollapsibleAlert ${attrs.join(" ")}${iconAttr}${classAttr}${collapsiblePassthrough}>${slot}
|
|
891
|
+
${indentStr(inner, 2)}
|
|
892
|
+
</CollapsibleAlert>`;
|
|
893
|
+
}
|
|
878
894
|
return `<Alert variant="${escapeAttr(variant)}"${iconAttr}${classAttr}${passthrough}>
|
|
879
|
-
<AlertTitle>${escapeTemplate(
|
|
895
|
+
<AlertTitle>${plainTitle ? escapeTemplate(captionText(titleNodes)) : renderInline(titleNodes, ctx)}</AlertTitle>
|
|
880
896
|
<AlertDescription>
|
|
881
897
|
${indentStr(inner, 4)}
|
|
882
898
|
</AlertDescription>
|
|
883
899
|
</Alert>`;
|
|
884
900
|
}
|
|
901
|
+
/**
|
|
902
|
+
* A presence flag: `open`, `open=""`, `open="true"` and `true` are on; absent, `false` and `"false"` are
|
|
903
|
+
* off. A bare `{open}` parses as "" (falsy), and "false" is truthy, so a plain truth test got both wrong
|
|
904
|
+
* (MD-003). render-html reads flags with the same rule (`flagOn`).
|
|
905
|
+
*/
|
|
906
|
+
function flagOn(v) {
|
|
907
|
+
return v !== undefined && v !== null && v !== false && v !== "false";
|
|
908
|
+
}
|
|
909
|
+
/** CollapsibleAlert's variants; `plain` is chrome (no tint, icon or role). */
|
|
910
|
+
const COLLAPSIBLE_VARIANTS = new Set(["plain", "destructive", "note", "abstract", "info", "tip", "success", "question", "warning", "failure", "danger", "bug", "example", "quote"]);
|
|
911
|
+
/** A disclosure's variant: lower-cased, aliases mapped, anything CollapsibleAlert does not draw → note. */
|
|
912
|
+
function collapsibleVariant(raw) {
|
|
913
|
+
const v = raw.toLowerCase();
|
|
914
|
+
const mapped = CALLOUT_VARIANT_MAP[v] ?? v;
|
|
915
|
+
return COLLAPSIBLE_VARIANTS.has(mapped) ? mapped : "note";
|
|
916
|
+
}
|
|
917
|
+
/** A callout with `collapsible` on or any `collapsed` is a disclosure (render-html's `callout`). */
|
|
918
|
+
function isCollapsibleCallout(props) {
|
|
919
|
+
return flagOn(props?.collapsible) || (props?.collapsed !== undefined && props?.collapsed !== null);
|
|
920
|
+
}
|
|
921
|
+
/** It starts open when `collapsed` is off (`collapsed="false"`) or `open` is on. */
|
|
922
|
+
function calloutStartsOpen(props) {
|
|
923
|
+
const c = props?.collapsed;
|
|
924
|
+
return c === false || c === "false" || flagOn(props?.open);
|
|
925
|
+
}
|
|
885
926
|
/**
|
|
886
927
|
* Merge a default class string with an optional user-provided class string.
|
|
887
928
|
* Concatenates (user classes appended) so utility frameworks like Tailwind
|
|
@@ -1022,13 +1063,17 @@ function genericContainerToAstro(node, ctx) {
|
|
|
1022
1063
|
function detailsToAstro(node, ctx) {
|
|
1023
1064
|
ctx.imports.add("details");
|
|
1024
1065
|
// `variant` as documented; `type` as dogsbay-ssg (and callouts) read it.
|
|
1025
|
-
|
|
1066
|
+
// Aliases (`caution` → danger) and unknown names (→ note) as render-html maps them
|
|
1067
|
+
const variant = collapsibleVariant(node.props?.variant ?? node.props?.type ?? "note");
|
|
1026
1068
|
// `summary` is dogsbay-md's alias for the title (`:::details{summary="…"}`)
|
|
1027
1069
|
const title = node.props?.title ?? node.props?.summary ?? "Details";
|
|
1028
|
-
const open = node.props?.open;
|
|
1070
|
+
const open = flagOn(node.props?.open);
|
|
1029
1071
|
const icon = node.props?.icon;
|
|
1030
1072
|
const inner = childrenToAstro(node, ctx);
|
|
1031
|
-
|
|
1073
|
+
// The title is inline Markdown, as in render-html: plain text stays the `title` prop
|
|
1074
|
+
const titleNodes = titleInline(title);
|
|
1075
|
+
const plainTitle = isPlainCaption(titleNodes);
|
|
1076
|
+
const attrs = [`variant="${escapeAttr(variant)}"`, componentAttr("title", plainTitle ? captionText(titleNodes) : title).trimStart()];
|
|
1032
1077
|
if (open)
|
|
1033
1078
|
attrs.push("open");
|
|
1034
1079
|
if (icon)
|
|
@@ -1037,7 +1082,8 @@ function detailsToAstro(node, ctx) {
|
|
|
1037
1082
|
const passthrough = renderPassthroughAttrs(node.props, [
|
|
1038
1083
|
"variant", "type", "title", "open", "icon", "class", "summary", "sheet",
|
|
1039
1084
|
]);
|
|
1040
|
-
const
|
|
1085
|
+
const slot = plainTitle ? "" : `\n <Fragment slot="title">${renderInline(titleNodes, ctx)}</Fragment>`;
|
|
1086
|
+
const alert = `<CollapsibleAlert ${attrs.join(" ")}${classAttr}${passthrough}>${slot}
|
|
1041
1087
|
${indentStr(inner, 2)}
|
|
1042
1088
|
</CollapsibleAlert>`;
|
|
1043
1089
|
// `sheet`: the same details, opened as a side sheet by <db-details-sheet>
|
|
@@ -1123,10 +1169,25 @@ function captionInline(caption) {
|
|
|
1123
1169
|
return parseInline(caption);
|
|
1124
1170
|
}
|
|
1125
1171
|
const isPlainCaption = (nodes) => nodes.every((n) => n.type === "text" && !n.bold && !n.italic && !n.strikethrough);
|
|
1172
|
+
/**
|
|
1173
|
+
* Formatting tags with no attributes, the HTML a title keeps (a raw `<details><summary><code>x</code>`
|
|
1174
|
+
* becomes the title `<code>x</code>`). render-html has the same list.
|
|
1175
|
+
*/
|
|
1176
|
+
const TITLE_TAG = /^<\/?(?:code|kbd|b|strong|i|em|s|del|mark|sub|sup|br)\s*\/?>$/i;
|
|
1177
|
+
/**
|
|
1178
|
+
* A callout or details title: inline Markdown, and any other raw HTML is TEXT. Importers write
|
|
1179
|
+
* plain-text titles with angle brackets (`Map<K, V>`, `List<String>`), which as HTML dropped words,
|
|
1180
|
+
* and a title with `<img onerror=…>` ran a script in the summary. render-html reads titles the same way.
|
|
1181
|
+
*/
|
|
1182
|
+
function titleInline(title) {
|
|
1183
|
+
return captionInline(title).map((n) => (n.type === "html-inline" && !TITLE_TAG.test(n.html.trim()) ? { type: "text", text: n.html } : n));
|
|
1184
|
+
}
|
|
1185
|
+
/** A plain caption's text (escapes undone by the parse). */
|
|
1186
|
+
const captionText = (nodes) => nodes.map((n) => (n.type === "text" ? n.text : "")).join("");
|
|
1126
1187
|
function captionToAstro(caption, ctx) {
|
|
1127
1188
|
const nodes = captionInline(caption);
|
|
1128
1189
|
return isPlainCaption(nodes)
|
|
1129
|
-
? escapeTemplate(nodes
|
|
1190
|
+
? escapeTemplate(captionText(nodes))
|
|
1130
1191
|
: renderInline(nodes, ctx);
|
|
1131
1192
|
}
|
|
1132
1193
|
function tableToAstro(node, ctx) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/format-astro",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.129",
|
|
4
4
|
"description": "Astro format plugin for Dogsbay — export TreeNode[] to Astro component markup",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"markdown-it": "^14.3.0",
|
|
35
|
-
"@dogsbay/format-dogsbay-md": "0.2.0-beta.
|
|
36
|
-
"@dogsbay/
|
|
37
|
-
"@dogsbay/
|
|
38
|
-
"@dogsbay/site-files": "0.2.0-beta.
|
|
39
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
40
|
-
"@dogsbay/ui": "0.2.0-beta.
|
|
35
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.129",
|
|
36
|
+
"@dogsbay/serialize-core": "0.2.0-beta.129",
|
|
37
|
+
"@dogsbay/render-html": "0.2.0-beta.129",
|
|
38
|
+
"@dogsbay/site-files": "0.2.0-beta.129",
|
|
39
|
+
"@dogsbay/types": "0.2.0-beta.129",
|
|
40
|
+
"@dogsbay/ui": "0.2.0-beta.129"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|