@bettercms-ai/convert 0.20.1 → 0.22.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/CHANGELOG.md +23 -0
- package/dist/cli.js +178 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +176 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @bettercms-ai/convert
|
|
2
2
|
|
|
3
|
+
## 0.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c0afef4: The emitted helper (v11) paints the same section design keys as `blockStyleToCss`: `theme`, `bg`/`bgCustom`, `bgImage` (http(s) or root-relative only), `corner`, `shadow`, `fullHeight`, `opacity`, `borderTop`/`borderBottom` and the px padding sliders. A converted section root's `data-bcms-style` promise, that its inline style is `blockStyleToCss(block.style)`, holds again for sections styled in the visual editor. Helpers at v10 and older are recognised and upgraded. The content column (`contentWidth`) is still not drawn on converted roots.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [c0afef4]
|
|
12
|
+
- Updated dependencies [5c6db8e]
|
|
13
|
+
- @bettercms-ai/types@1.30.0
|
|
14
|
+
|
|
15
|
+
## 0.21.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- a99b2c3: A site's own section root can now declare that it applies the section's style. `sectionRootAttrs(block)` from `@bettercms-ai/astro` and `@bettercms-ai/next` returns `data-bcms-block`, `data-bcms-style` and the block's `blockStyleToCss(block.style)` as `style`. Spread it on the root: `<section {...sectionRootAttrs(block)}>`. When the block has no style there is no `style` attribute, but the marker is still there. The BetterCMS editor shows a section's spacing handles on a site-rendered page only when every section root it finds carries the marker. `bettercms-convert --componentize` now stamps the marker and the placement's style on every section root it extracts: the helper (v10) inlines the same declarations, and the registry passes each placement's `block.style` down as `blockStyle`. A root that already has its own `style` attribute, or a spread, is left unmarked.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [d84d241]
|
|
24
|
+
- @bettercms-ai/types@1.29.0
|
|
25
|
+
|
|
3
26
|
## 0.20.1
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -4190,7 +4190,7 @@ async function bindImages(ctx, targets) {
|
|
|
4190
4190
|
|
|
4191
4191
|
// src/helper.ts
|
|
4192
4192
|
import { createHash as createHash2 } from "crypto";
|
|
4193
|
-
var HELPER_VERSION =
|
|
4193
|
+
var HELPER_VERSION = 11;
|
|
4194
4194
|
var HEADER = "// @bettercms-ai/convert helper v";
|
|
4195
4195
|
var HELPER_PATH = Object.fromEntries(
|
|
4196
4196
|
Object.keys(DIALECT_RULES).map((d) => [d, DIALECT_RULES[d].helper])
|
|
@@ -4514,6 +4514,144 @@ export function bcmsFields(
|
|
|
4514
4514
|
return (own ? undefined : moved(key, rest.slice(key?.length ?? 0))) ?? lane + rest;
|
|
4515
4515
|
};
|
|
4516
4516
|
}
|
|
4517
|
+
|
|
4518
|
+
/**
|
|
4519
|
+
* C3/C4 \u2014 a section's \`block.style\` as the inline CSS the BetterCMS SDK draws for it.
|
|
4520
|
+
*
|
|
4521
|
+
* A converted section root carries \`data-bcms-style\` beside \`data-bcms-block\`, which is the
|
|
4522
|
+
* site's promise to the editor that "this root's inline style is \`blockStyleToCss(block.style)\`"
|
|
4523
|
+
* \u2014 and the editor only offers a section's spacing handles where every stamped root makes it.
|
|
4524
|
+
* This is \`blockStyleToCss\` from \`@bettercms-ai/types\`, INLINED for the same reason \`readPath\`
|
|
4525
|
+
* is (zero dependencies); \`helper.test.ts\` runs it against the original over a token table.
|
|
4526
|
+
*/
|
|
4527
|
+
const STYLE_SPACE_PX: Record<string, string> = { none: "0", xs: "4px", sm: "8px", md: "16px", lg: "32px", xl: "64px" };
|
|
4528
|
+
const STYLE_FONT_SIZE_REM: Record<string, string> = {
|
|
4529
|
+
sm: "0.875rem",
|
|
4530
|
+
base: "1rem",
|
|
4531
|
+
lg: "1.25rem",
|
|
4532
|
+
xl: "1.5rem",
|
|
4533
|
+
"2xl": "2rem",
|
|
4534
|
+
"3xl": "2.25rem",
|
|
4535
|
+
"4xl": "3rem",
|
|
4536
|
+
"5xl": "4rem",
|
|
4537
|
+
};
|
|
4538
|
+
const STYLE_WEIGHT: Record<string, number> = { normal: 400, medium: 500, semibold: 600, bold: 700 };
|
|
4539
|
+
const STYLE_RADIUS_PX: Record<string, string> = { none: "0", sm: "4px", md: "8px", lg: "16px", full: "9999px" };
|
|
4540
|
+
const STYLE_COLOR_HEX: Record<string, string> = { white: "#ffffff", black: "#111111", muted: "#6b7280", mutedBg: "#f3f4f6", primary: "#111111", accent: "#4f46e5" };
|
|
4541
|
+
const STYLE_SPACE_TOKEN_PX: Record<string, string> = {
|
|
4542
|
+
"section-space-none": "0px",
|
|
4543
|
+
"section-space-small": "32px",
|
|
4544
|
+
"section-space-medium": "64px",
|
|
4545
|
+
"section-space-large": "96px",
|
|
4546
|
+
"section-space-xlarge": "144px",
|
|
4547
|
+
"section-space-nav-overlap": "-72px",
|
|
4548
|
+
"space-none": "0px",
|
|
4549
|
+
"space-s": "8px",
|
|
4550
|
+
"space-m": "16px",
|
|
4551
|
+
"space-l": "32px",
|
|
4552
|
+
"space-xl": "64px",
|
|
4553
|
+
};
|
|
4554
|
+
|
|
4555
|
+
const STYLE_THEME: Record<string, { colorScheme: string; background: string; color: string }> = {
|
|
4556
|
+
light: { colorScheme: "light", background: "#ffffff", color: "#111111" },
|
|
4557
|
+
dark: { colorScheme: "dark", background: "#0b0b0d", color: "#f7f8f8" },
|
|
4558
|
+
};
|
|
4559
|
+
const STYLE_BG: Record<string, string> = {
|
|
4560
|
+
surface: "var(--bcms-bg-surface,#ffffff)",
|
|
4561
|
+
muted: "var(--bcms-bg-muted,#f3f4f6)",
|
|
4562
|
+
accent: "var(--bcms-bg-accent,#4f46e5)",
|
|
4563
|
+
dark: "var(--bcms-bg-dark,#0b0b0d)",
|
|
4564
|
+
};
|
|
4565
|
+
const STYLE_CORNER_PX: Record<string, string> = { "0": "0", s: "4px", m: "8px", l: "16px", xl: "24px", "2xl": "32px" };
|
|
4566
|
+
const STYLE_SHADOW: Record<string, string> = {
|
|
4567
|
+
"0": "none",
|
|
4568
|
+
s: "0 1px 2px rgba(0,0,0,.06)",
|
|
4569
|
+
m: "0 4px 12px rgba(0,0,0,.08)",
|
|
4570
|
+
l: "0 10px 24px rgba(0,0,0,.10)",
|
|
4571
|
+
xl: "0 24px 48px rgba(0,0,0,.14)",
|
|
4572
|
+
};
|
|
4573
|
+
const STYLE_HAIRLINE = "1px solid rgba(0,0,0,.10)";
|
|
4574
|
+
|
|
4575
|
+
/** A map entry by OWN key only, so a token like \`constructor\` never reaches CSS. */
|
|
4576
|
+
function styleOwn<T>(map: Record<string, T>, key: unknown): T | undefined {
|
|
4577
|
+
return typeof key === "string" && Object.prototype.hasOwnProperty.call(map, key) ? map[key] : undefined;
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4580
|
+
/** An http(s) or root-relative url with nothing that could end \`url(\u2026)\`; "" for anything else. */
|
|
4581
|
+
function styleSafeUrl(raw: unknown): string {
|
|
4582
|
+
if (typeof raw !== "string") return "";
|
|
4583
|
+
const url = raw.trim();
|
|
4584
|
+
if (!url || url.length > 2000) return "";
|
|
4585
|
+
if (/["'()\\;]|\\s/.test(url)) return "";
|
|
4586
|
+
if (url.startsWith("//")) return "";
|
|
4587
|
+
if (url.startsWith("/")) return url;
|
|
4588
|
+
return /^https?:\\/\\//i.test(url) ? url : "";
|
|
4589
|
+
}
|
|
4590
|
+
|
|
4591
|
+
function styleClamp(n: number, lo: number, hi: number): number {
|
|
4592
|
+
return Math.min(hi, Math.max(lo, n));
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4595
|
+
function styleSpaceToken(token: unknown): string {
|
|
4596
|
+
const px = typeof token === "string" ? STYLE_SPACE_TOKEN_PX[token] : undefined;
|
|
4597
|
+
return px ? "var(--bcms-" + token + "," + px + ")" : "";
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4600
|
+
/** The declarations as a React-style object (camelCase), or undefined when there are none. */
|
|
4601
|
+
export function bcmsSectionStyle(style: unknown): Record<string, string | number> | undefined {
|
|
4602
|
+
if (!style || typeof style !== "object") return undefined;
|
|
4603
|
+
const s = style as Record<string, string>;
|
|
4604
|
+
const css: Record<string, string | number> = {};
|
|
4605
|
+
if (s.paddingY && STYLE_SPACE_PX[s.paddingY] != null) { css.paddingTop = STYLE_SPACE_PX[s.paddingY]!; css.paddingBottom = STYLE_SPACE_PX[s.paddingY]!; }
|
|
4606
|
+
if (s.paddingX && STYLE_SPACE_PX[s.paddingX] != null) { css.paddingLeft = STYLE_SPACE_PX[s.paddingX]!; css.paddingRight = STYLE_SPACE_PX[s.paddingX]!; }
|
|
4607
|
+
const top = styleSpaceToken(s.spaceTop);
|
|
4608
|
+
// A negative band that pulls content under the nav makes sense at the TOP only (SPACE_BOTTOM_TOKENS).
|
|
4609
|
+
const bottom = /^section-space-(none|small|medium|large|xlarge)$/.test(String(s.spaceBottom)) ? styleSpaceToken(s.spaceBottom) : "";
|
|
4610
|
+
const sides = styleSpaceToken(s.spaceSides);
|
|
4611
|
+
const navOverlap = s.spaceTop === "section-space-nav-overlap";
|
|
4612
|
+
if (top && !navOverlap) css.paddingTop = top;
|
|
4613
|
+
if (bottom) css.paddingBottom = bottom;
|
|
4614
|
+
if (sides) { css.paddingLeft = sides; css.paddingRight = sides; }
|
|
4615
|
+
if (s.marginTop && STYLE_SPACE_PX[s.marginTop] != null) css.marginTop = STYLE_SPACE_PX[s.marginTop]!;
|
|
4616
|
+
if (top && navOverlap) { css.marginTop = top; css.paddingTop = "calc(-1 * " + top + ")"; }
|
|
4617
|
+
if (s.marginBottom && STYLE_SPACE_PX[s.marginBottom] != null) css.marginBottom = STYLE_SPACE_PX[s.marginBottom]!;
|
|
4618
|
+
if (s.background && STYLE_COLOR_HEX[s.background]) css.background = STYLE_COLOR_HEX[s.background]!;
|
|
4619
|
+
if (s.textColor && STYLE_COLOR_HEX[s.textColor]) css.color = STYLE_COLOR_HEX[s.textColor]!;
|
|
4620
|
+
if (s.align === "left" || s.align === "center" || s.align === "right") css.textAlign = s.align;
|
|
4621
|
+
if (s.fontSize && STYLE_FONT_SIZE_REM[s.fontSize]) css.fontSize = STYLE_FONT_SIZE_REM[s.fontSize]!;
|
|
4622
|
+
if (s.weight && STYLE_WEIGHT[s.weight] != null) css.fontWeight = STYLE_WEIGHT[s.weight]!;
|
|
4623
|
+
if (s.radius && STYLE_RADIUS_PX[s.radius] != null) css.borderRadius = STYLE_RADIUS_PX[s.radius]!;
|
|
4624
|
+
const theme = styleOwn(STYLE_THEME, s.theme);
|
|
4625
|
+
if (theme) { css.colorScheme = theme.colorScheme; css.background = theme.background; css.color = theme.color; }
|
|
4626
|
+
if (s.bg === "custom") { if (/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(s.bgCustom ?? "")) css.background = s.bgCustom!; }
|
|
4627
|
+
else if (styleOwn(STYLE_BG, s.bg)) css.background = styleOwn(STYLE_BG, s.bg)!;
|
|
4628
|
+
const bgImage = styleSafeUrl(s.bgImage);
|
|
4629
|
+
if (bgImage) { css.backgroundImage = "url(" + bgImage + ")"; css.backgroundSize = "cover"; css.backgroundPosition = "center"; }
|
|
4630
|
+
const n = style as Record<string, unknown>;
|
|
4631
|
+
if (!top && typeof n.paddingTop === "number") css.paddingTop = styleClamp(n.paddingTop, 0, 240) + "px";
|
|
4632
|
+
if (!bottom && typeof n.paddingBottom === "number") css.paddingBottom = styleClamp(n.paddingBottom, 0, 240) + "px";
|
|
4633
|
+
if (!sides && typeof n.paddingSides === "number") {
|
|
4634
|
+
const px = styleClamp(n.paddingSides, 0, 240) + "px";
|
|
4635
|
+
css.paddingLeft = px; css.paddingRight = px;
|
|
4636
|
+
}
|
|
4637
|
+
if (n.fullHeight === true) { css.minHeight = "100vh"; css.display = "flex"; css.flexDirection = "column"; css.justifyContent = "center"; }
|
|
4638
|
+
if (typeof n.opacity === "number") css.opacity = styleClamp(n.opacity, 0, 100) / 100;
|
|
4639
|
+
if (styleOwn(STYLE_CORNER_PX, s.corner) != null) { css.borderRadius = styleOwn(STYLE_CORNER_PX, s.corner)!; css.overflow = "hidden"; }
|
|
4640
|
+
if (styleOwn(STYLE_SHADOW, s.shadow)) css.boxShadow = styleOwn(STYLE_SHADOW, s.shadow)!;
|
|
4641
|
+
if (n.borderTop === true) css.borderTop = STYLE_HAIRLINE;
|
|
4642
|
+
if (n.borderBottom === true) css.borderBottom = STYLE_HAIRLINE;
|
|
4643
|
+
if ((style as { border?: unknown }).border === true) css.border = "1px solid currentColor";
|
|
4644
|
+
return Object.keys(css).length ? css : undefined;
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4647
|
+
/** The same declarations as an Astro \`style\` string (kebab-case, \`;\`-joined), or undefined. */
|
|
4648
|
+
export function bcmsSectionStyleText(style: unknown): string | undefined {
|
|
4649
|
+
const css = bcmsSectionStyle(style);
|
|
4650
|
+
if (!css) return undefined;
|
|
4651
|
+
return Object.entries(css)
|
|
4652
|
+
.map(([k, v]) => k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()) + ":" + v)
|
|
4653
|
+
.join(";");
|
|
4654
|
+
}
|
|
4517
4655
|
`;
|
|
4518
4656
|
}
|
|
4519
4657
|
var HISTORICAL = {
|
|
@@ -4525,7 +4663,9 @@ var HISTORICAL = {
|
|
|
4525
4663
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4526
4664
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4527
4665
|
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4528
|
-
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4666
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9",
|
|
4667
|
+
9: "d6441db2ff4578c3c5d4b7d461f3374b89247ef6ba9e0d535791e840d803e4f3",
|
|
4668
|
+
10: "ffcb59862972b15a67c5951e9f3b94ce5b8b50345e6aac2bfa5789cfc3136910"
|
|
4529
4669
|
},
|
|
4530
4670
|
"src/lib/bcms-content.ts": {
|
|
4531
4671
|
1: "ae72ae14d706943d481c880d70da5789b4816ba1ba319a10fbc63ded4d0b42f2",
|
|
@@ -4535,7 +4675,9 @@ var HISTORICAL = {
|
|
|
4535
4675
|
5: "c8c93655320fa65664611ba84541f3fa7bfa292cc9a2fd655373440b99049fba",
|
|
4536
4676
|
6: "63f1fa29e47e70c5193b81ee24addb238ba100247124d55bc17713102d587df5",
|
|
4537
4677
|
7: "ed92fb88de953d9951abbe6a1edae1d048f4050eaf6fb607ac08167f94d8bcc7",
|
|
4538
|
-
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5"
|
|
4678
|
+
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5",
|
|
4679
|
+
9: "eee9fb1635ae7d6f8f33676a1f390600ca24a62ee992775252273c73a011c494",
|
|
4680
|
+
10: "35bb7c0e30f5c41fe68e52259ec4764de6de2734064fa0e1521f3338eef0a09e"
|
|
4539
4681
|
},
|
|
4540
4682
|
"composables/bcms-content.ts": {
|
|
4541
4683
|
1: "c272412532efed7db64b6cf313b2bed4291f9951430412289c8a588b7f565407",
|
|
@@ -4545,7 +4687,9 @@ var HISTORICAL = {
|
|
|
4545
4687
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4546
4688
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4547
4689
|
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4548
|
-
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4690
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9",
|
|
4691
|
+
9: "d6441db2ff4578c3c5d4b7d461f3374b89247ef6ba9e0d535791e840d803e4f3",
|
|
4692
|
+
10: "ffcb59862972b15a67c5951e9f3b94ce5b8b50345e6aac2bfa5789cfc3136910"
|
|
4549
4693
|
}
|
|
4550
4694
|
};
|
|
4551
4695
|
var sha256 = (value) => createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -8303,7 +8447,9 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8303
8447
|
]);
|
|
8304
8448
|
const fieldsName = introduced.get("bcmsFields");
|
|
8305
8449
|
const fieldName = introduced.get("bcmsField");
|
|
8306
|
-
const
|
|
8450
|
+
const styleReader = dialect === "astro" ? "bcmsSectionStyleText" : "bcmsSectionStyle";
|
|
8451
|
+
const styled = rootStyleIsFree(content, resolved.root) && !reserved.has("blockStyle") && !reserved.has(styleReader);
|
|
8452
|
+
const { markup, bound, duplicates } = sectionMarkup(content, resolved.root, fieldName, styled ? styleReader : null);
|
|
8307
8453
|
if (duplicates.length > 0) return { content: "", free: [], duplicates, unconvertible: [] };
|
|
8308
8454
|
const groupKey = resolved.section.groupKey;
|
|
8309
8455
|
const locals = helperLocals(parsed, dialect, fromFile);
|
|
@@ -8314,7 +8460,8 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8314
8460
|
.../* @__PURE__ */ new Set([
|
|
8315
8461
|
...helperNames.map((h) => alias(h.name, h.local)),
|
|
8316
8462
|
flat3 ? "bcmsSectionPaths" : "bcmsSection",
|
|
8317
|
-
...bound > 0 ? [alias("bcmsFields", fieldsName)] : []
|
|
8463
|
+
...bound > 0 ? [alias("bcmsFields", fieldsName)] : [],
|
|
8464
|
+
...styled ? [styleReader] : []
|
|
8318
8465
|
])
|
|
8319
8466
|
].sort();
|
|
8320
8467
|
const helperSpecifier = relativeImport(path, HELPER_PATH[dialect]).replace(/\.tsx?$/, "");
|
|
@@ -8363,9 +8510,11 @@ interface Props {
|
|
|
8363
8510
|
/** The instance's own copy, when an editor gave it any. Wins over the bound group. */
|
|
8364
8511
|
overrides?: Record<string, unknown>;
|
|
8365
8512
|
/** The page snapshot, so one component can serve every page whose group has this shape. */
|
|
8366
|
-
page?: unknown
|
|
8513
|
+
page?: unknown;${styled ? `
|
|
8514
|
+
/** The placement's \`block.style\` \u2014 painted on the root, which says so with \`data-bcms-style\`. */
|
|
8515
|
+
blockStyle?: Record<string, unknown>;` : ""}
|
|
8367
8516
|
}
|
|
8368
|
-
const { blockId, bind, bindPaths, overrides, page } = Astro.props;
|
|
8517
|
+
const { blockId, bind, bindPaths, overrides, page${styled ? ", blockStyle" : ""} } = Astro.props;
|
|
8369
8518
|
${carriedDeclarations}${declared}
|
|
8370
8519
|
---
|
|
8371
8520
|
${markup}
|
|
@@ -8377,7 +8526,7 @@ ${styles}
|
|
|
8377
8526
|
${[...carried, `import { ${helpers.join(", ")} } from "${helperSpecifier}";`, `import type { BcmsSectionProps } from "${relativeImport(path, SECTIONS_LIB).replace(/\.tsx?$/, "")}";`].join("\n")}
|
|
8378
8527
|
${carriedDeclarations === "" ? "" : `
|
|
8379
8528
|
${carriedDeclarations}`}
|
|
8380
|
-
export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page }: BcmsSectionProps) {
|
|
8529
|
+
export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page${styled ? ", blockStyle" : ""} }: BcmsSectionProps) {
|
|
8381
8530
|
${declared.split("\n").join("\n ")}
|
|
8382
8531
|
return (
|
|
8383
8532
|
${markup}
|
|
@@ -8385,13 +8534,21 @@ export default function ${resolved.name}({ blockId, bind, bindPaths, overrides,
|
|
|
8385
8534
|
}
|
|
8386
8535
|
` };
|
|
8387
8536
|
}
|
|
8388
|
-
function
|
|
8537
|
+
function rootStyleIsFree(content, root) {
|
|
8538
|
+
return root.attrs.every((attr) => {
|
|
8539
|
+
if (attr.name === "style") return false;
|
|
8540
|
+
const open = attr.expressionRange ? content.slice(attr.expressionRange.start, attr.expressionRange.end).trimStart() : "";
|
|
8541
|
+
return !open.startsWith("{...");
|
|
8542
|
+
});
|
|
8543
|
+
}
|
|
8544
|
+
function sectionMarkup(content, root, fieldName, styleReader = null) {
|
|
8389
8545
|
const slice = new MagicString5(content.slice(root.start, root.end));
|
|
8390
8546
|
const at = (offset) => offset - root.start;
|
|
8547
|
+
const stamp = styleReader ? `data-bcms-block={blockId} data-bcms-style="" style={${styleReader}(blockStyle)}` : "data-bcms-block={blockId}";
|
|
8391
8548
|
const stamps = root.attrs.filter((attr) => attr.name === "data-bcms-block");
|
|
8392
|
-
if (stamps.length === 0) slice.appendLeft(at(root.attrInsertAt),
|
|
8549
|
+
if (stamps.length === 0) slice.appendLeft(at(root.attrInsertAt), ` ${stamp}`);
|
|
8393
8550
|
else {
|
|
8394
|
-
slice.overwrite(at(stamps[0].range.start), at(stamps[0].range.end),
|
|
8551
|
+
slice.overwrite(at(stamps[0].range.start), at(stamps[0].range.end), stamp);
|
|
8395
8552
|
for (const extra of stamps.slice(1)) {
|
|
8396
8553
|
let from = extra.range.start;
|
|
8397
8554
|
while (from > root.start && /\s/.test(content[from - 1])) from--;
|
|
@@ -8742,6 +8899,8 @@ export interface BcmsSectionProps {
|
|
|
8742
8899
|
bindPaths?: Record<string, string>;
|
|
8743
8900
|
overrides?: Record<string, unknown>;
|
|
8744
8901
|
page?: unknown;
|
|
8902
|
+
/** The placement's \`block.style\`, which the section root paints (\`data-bcms-style\`). */
|
|
8903
|
+
blockStyle?: Record<string, unknown>;
|
|
8745
8904
|
}
|
|
8746
8905
|
|
|
8747
8906
|
/** One placement on one page: which component, bound to which page field group. */
|
|
@@ -8752,6 +8911,8 @@ export interface BcmsPlacement {
|
|
|
8752
8911
|
/** A locale copy's own field path for each prop, when its keys differ from the component's. */
|
|
8753
8912
|
bindPaths?: Record<string, string>;
|
|
8754
8913
|
overrides?: Record<string, unknown>;
|
|
8914
|
+
/** The placement's \`block.style\` \u2014 what the editor's section spacing and style controls write. */
|
|
8915
|
+
style?: Record<string, unknown>;
|
|
8755
8916
|
}
|
|
8756
8917
|
|
|
8757
8918
|
/** The page's own snapshot \u2014 the copy every placement on it reads through \`bind\`. */
|
|
@@ -8813,6 +8974,7 @@ export function pageSections(pageSlug: string): BcmsPlacement[] {
|
|
|
8813
8974
|
bind: typeof props.bind === "string" ? props.bind : undefined,
|
|
8814
8975
|
bindPaths: isRecord(props.bindPaths) ? (props.bindPaths as Record<string, string>) : undefined,
|
|
8815
8976
|
overrides: isRecord(props.overrides) ? props.overrides : undefined,
|
|
8977
|
+
style: isRecord(block.style) ? block.style : undefined,
|
|
8816
8978
|
});
|
|
8817
8979
|
}
|
|
8818
8980
|
return out;
|
|
@@ -8879,6 +9041,7 @@ const snapshot = pageSnapshot(page);
|
|
|
8879
9041
|
bind={placement.bind}
|
|
8880
9042
|
bindPaths={placement.bindPaths}
|
|
8881
9043
|
overrides={placement.overrides}
|
|
9044
|
+
blockStyle={placement.style}
|
|
8882
9045
|
page={snapshot}
|
|
8883
9046
|
/>
|
|
8884
9047
|
) : null;
|
|
@@ -8902,6 +9065,7 @@ export default function Sections({ page }: { page: string }) {
|
|
|
8902
9065
|
bind={placement.bind}
|
|
8903
9066
|
bindPaths={placement.bindPaths}
|
|
8904
9067
|
overrides={placement.overrides}
|
|
9068
|
+
blockStyle={placement.style}
|
|
8905
9069
|
page={snapshot}
|
|
8906
9070
|
/>
|
|
8907
9071
|
) : null;
|
|
@@ -10176,7 +10340,7 @@ function styleEdits(before, after) {
|
|
|
10176
10340
|
// package.json
|
|
10177
10341
|
var package_default = {
|
|
10178
10342
|
name: "@bettercms-ai/convert",
|
|
10179
|
-
version: "0.
|
|
10343
|
+
version: "0.22.0",
|
|
10180
10344
|
type: "module",
|
|
10181
10345
|
description: "Deterministic codemod that turns an imported site's text-matched bindings into declared ones \u2014 parser offsets in, one magic-string pass out, plus a receipt of everything it could not do.",
|
|
10182
10346
|
bin: {
|
|
@@ -10209,7 +10373,7 @@ var package_default = {
|
|
|
10209
10373
|
dependencies: {
|
|
10210
10374
|
"@astrojs/compiler": "^2.13.1",
|
|
10211
10375
|
"@babel/parser": "^7.29.2",
|
|
10212
|
-
"@bettercms-ai/types": "^1.
|
|
10376
|
+
"@bettercms-ai/types": "^1.30.0",
|
|
10213
10377
|
"@vue/compiler-sfc": "^3.5.0",
|
|
10214
10378
|
"magic-string": "^0.30.21",
|
|
10215
10379
|
parse5: "^7.3.0",
|