@bettercms-ai/convert 0.20.1 → 0.21.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 +11 -0
- package/dist/cli.js +116 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +114 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -955,7 +955,7 @@ declare function attrsFor(path: string, kind: string, props?: AttrBinding[], sco
|
|
|
955
955
|
declare function propsAttribute(props: AttrBinding[]): string;
|
|
956
956
|
|
|
957
957
|
/** Bumped whenever the emitted source changes. `isKnownHelper` upgrades anything older. */
|
|
958
|
-
declare const HELPER_VERSION =
|
|
958
|
+
declare const HELPER_VERSION = 10;
|
|
959
959
|
/** Where each dialect's helper lives. Null = this dialect reads nothing at build time. */
|
|
960
960
|
declare const HELPER_PATH: Record<Dialect, string | null>;
|
|
961
961
|
/** The directory the snapshots live in, at the repository root. */
|
package/dist/index.js
CHANGED
|
@@ -4187,7 +4187,7 @@ async function bindImages(ctx, targets) {
|
|
|
4187
4187
|
|
|
4188
4188
|
// src/helper.ts
|
|
4189
4189
|
import { createHash as createHash2 } from "crypto";
|
|
4190
|
-
var HELPER_VERSION =
|
|
4190
|
+
var HELPER_VERSION = 10;
|
|
4191
4191
|
var HEADER = "// @bettercms-ai/convert helper v";
|
|
4192
4192
|
var HELPER_PATH = Object.fromEntries(
|
|
4193
4193
|
Object.keys(DIALECT_RULES).map((d) => [d, DIALECT_RULES[d].helper])
|
|
@@ -4511,6 +4511,85 @@ export function bcmsFields(
|
|
|
4511
4511
|
return (own ? undefined : moved(key, rest.slice(key?.length ?? 0))) ?? lane + rest;
|
|
4512
4512
|
};
|
|
4513
4513
|
}
|
|
4514
|
+
|
|
4515
|
+
/**
|
|
4516
|
+
* C3/C4 \u2014 a section's \`block.style\` as the inline CSS the BetterCMS SDK draws for it.
|
|
4517
|
+
*
|
|
4518
|
+
* A converted section root carries \`data-bcms-style\` beside \`data-bcms-block\`, which is the
|
|
4519
|
+
* site's promise to the editor that "this root's inline style is \`blockStyleToCss(block.style)\`"
|
|
4520
|
+
* \u2014 and the editor only offers a section's spacing handles where every stamped root makes it.
|
|
4521
|
+
* This is \`blockStyleToCss\` from \`@bettercms-ai/types\`, INLINED for the same reason \`readPath\`
|
|
4522
|
+
* is (zero dependencies); \`helper.test.ts\` runs it against the original over a token table.
|
|
4523
|
+
*/
|
|
4524
|
+
const STYLE_SPACE_PX: Record<string, string> = { none: "0", xs: "4px", sm: "8px", md: "16px", lg: "32px", xl: "64px" };
|
|
4525
|
+
const STYLE_FONT_SIZE_REM: Record<string, string> = {
|
|
4526
|
+
sm: "0.875rem",
|
|
4527
|
+
base: "1rem",
|
|
4528
|
+
lg: "1.25rem",
|
|
4529
|
+
xl: "1.5rem",
|
|
4530
|
+
"2xl": "2rem",
|
|
4531
|
+
"3xl": "2.25rem",
|
|
4532
|
+
"4xl": "3rem",
|
|
4533
|
+
"5xl": "4rem",
|
|
4534
|
+
};
|
|
4535
|
+
const STYLE_WEIGHT: Record<string, number> = { normal: 400, medium: 500, semibold: 600, bold: 700 };
|
|
4536
|
+
const STYLE_RADIUS_PX: Record<string, string> = { none: "0", sm: "4px", md: "8px", lg: "16px", full: "9999px" };
|
|
4537
|
+
const STYLE_COLOR_HEX: Record<string, string> = { white: "#ffffff", black: "#111111", muted: "#6b7280", mutedBg: "#f3f4f6", primary: "#111111", accent: "#4f46e5" };
|
|
4538
|
+
const STYLE_SPACE_TOKEN_PX: Record<string, string> = {
|
|
4539
|
+
"section-space-none": "0px",
|
|
4540
|
+
"section-space-small": "32px",
|
|
4541
|
+
"section-space-medium": "64px",
|
|
4542
|
+
"section-space-large": "96px",
|
|
4543
|
+
"section-space-xlarge": "144px",
|
|
4544
|
+
"section-space-nav-overlap": "-72px",
|
|
4545
|
+
"space-none": "0px",
|
|
4546
|
+
"space-s": "8px",
|
|
4547
|
+
"space-m": "16px",
|
|
4548
|
+
"space-l": "32px",
|
|
4549
|
+
"space-xl": "64px",
|
|
4550
|
+
};
|
|
4551
|
+
|
|
4552
|
+
function styleSpaceToken(token: unknown): string {
|
|
4553
|
+
const px = typeof token === "string" ? STYLE_SPACE_TOKEN_PX[token] : undefined;
|
|
4554
|
+
return px ? "var(--bcms-" + token + "," + px + ")" : "";
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4557
|
+
/** The declarations as a React-style object (camelCase), or undefined when there are none. */
|
|
4558
|
+
export function bcmsSectionStyle(style: unknown): Record<string, string | number> | undefined {
|
|
4559
|
+
if (!style || typeof style !== "object") return undefined;
|
|
4560
|
+
const s = style as Record<string, string>;
|
|
4561
|
+
const css: Record<string, string | number> = {};
|
|
4562
|
+
if (s.paddingY && STYLE_SPACE_PX[s.paddingY] != null) { css.paddingTop = STYLE_SPACE_PX[s.paddingY]!; css.paddingBottom = STYLE_SPACE_PX[s.paddingY]!; }
|
|
4563
|
+
if (s.paddingX && STYLE_SPACE_PX[s.paddingX] != null) { css.paddingLeft = STYLE_SPACE_PX[s.paddingX]!; css.paddingRight = STYLE_SPACE_PX[s.paddingX]!; }
|
|
4564
|
+
const top = styleSpaceToken(s.spaceTop);
|
|
4565
|
+
// A negative band that pulls content under the nav makes sense at the TOP only (SPACE_BOTTOM_TOKENS).
|
|
4566
|
+
const bottom = /^section-space-(none|small|medium|large|xlarge)$/.test(String(s.spaceBottom)) ? styleSpaceToken(s.spaceBottom) : "";
|
|
4567
|
+
const sides = styleSpaceToken(s.spaceSides);
|
|
4568
|
+
const navOverlap = s.spaceTop === "section-space-nav-overlap";
|
|
4569
|
+
if (top && !navOverlap) css.paddingTop = top;
|
|
4570
|
+
if (bottom) css.paddingBottom = bottom;
|
|
4571
|
+
if (sides) { css.paddingLeft = sides; css.paddingRight = sides; }
|
|
4572
|
+
if (s.marginTop && STYLE_SPACE_PX[s.marginTop] != null) css.marginTop = STYLE_SPACE_PX[s.marginTop]!;
|
|
4573
|
+
if (top && navOverlap) { css.marginTop = top; css.paddingTop = "calc(-1 * " + top + ")"; }
|
|
4574
|
+
if (s.marginBottom && STYLE_SPACE_PX[s.marginBottom] != null) css.marginBottom = STYLE_SPACE_PX[s.marginBottom]!;
|
|
4575
|
+
if (s.background && STYLE_COLOR_HEX[s.background]) css.background = STYLE_COLOR_HEX[s.background]!;
|
|
4576
|
+
if (s.textColor && STYLE_COLOR_HEX[s.textColor]) css.color = STYLE_COLOR_HEX[s.textColor]!;
|
|
4577
|
+
if (s.align === "left" || s.align === "center" || s.align === "right") css.textAlign = s.align;
|
|
4578
|
+
if (s.fontSize && STYLE_FONT_SIZE_REM[s.fontSize]) css.fontSize = STYLE_FONT_SIZE_REM[s.fontSize]!;
|
|
4579
|
+
if (s.weight && STYLE_WEIGHT[s.weight] != null) css.fontWeight = STYLE_WEIGHT[s.weight]!;
|
|
4580
|
+
if (s.radius && STYLE_RADIUS_PX[s.radius] != null) css.borderRadius = STYLE_RADIUS_PX[s.radius]!;
|
|
4581
|
+
if ((style as { border?: unknown }).border === true) css.border = "1px solid currentColor";
|
|
4582
|
+
return Object.keys(css).length ? css : undefined;
|
|
4583
|
+
}
|
|
4584
|
+
|
|
4585
|
+
/** The same declarations as an Astro \`style\` string (kebab-case, \`;\`-joined), or undefined. */
|
|
4586
|
+
export function bcmsSectionStyleText(style: unknown): string | undefined {
|
|
4587
|
+
const css = bcmsSectionStyle(style);
|
|
4588
|
+
if (!css) return undefined;
|
|
4589
|
+
return Object.entries(css)
|
|
4590
|
+
.map(([k, v]) => k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()) + ":" + v)
|
|
4591
|
+
.join(";");
|
|
4592
|
+
}
|
|
4514
4593
|
`;
|
|
4515
4594
|
}
|
|
4516
4595
|
var HISTORICAL = {
|
|
@@ -4522,7 +4601,8 @@ var HISTORICAL = {
|
|
|
4522
4601
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4523
4602
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4524
4603
|
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4525
|
-
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4604
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9",
|
|
4605
|
+
9: "d6441db2ff4578c3c5d4b7d461f3374b89247ef6ba9e0d535791e840d803e4f3"
|
|
4526
4606
|
},
|
|
4527
4607
|
"src/lib/bcms-content.ts": {
|
|
4528
4608
|
1: "ae72ae14d706943d481c880d70da5789b4816ba1ba319a10fbc63ded4d0b42f2",
|
|
@@ -4532,7 +4612,8 @@ var HISTORICAL = {
|
|
|
4532
4612
|
5: "c8c93655320fa65664611ba84541f3fa7bfa292cc9a2fd655373440b99049fba",
|
|
4533
4613
|
6: "63f1fa29e47e70c5193b81ee24addb238ba100247124d55bc17713102d587df5",
|
|
4534
4614
|
7: "ed92fb88de953d9951abbe6a1edae1d048f4050eaf6fb607ac08167f94d8bcc7",
|
|
4535
|
-
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5"
|
|
4615
|
+
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5",
|
|
4616
|
+
9: "eee9fb1635ae7d6f8f33676a1f390600ca24a62ee992775252273c73a011c494"
|
|
4536
4617
|
},
|
|
4537
4618
|
"composables/bcms-content.ts": {
|
|
4538
4619
|
1: "c272412532efed7db64b6cf313b2bed4291f9951430412289c8a588b7f565407",
|
|
@@ -4542,7 +4623,8 @@ var HISTORICAL = {
|
|
|
4542
4623
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4543
4624
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4544
4625
|
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4545
|
-
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4626
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9",
|
|
4627
|
+
9: "d6441db2ff4578c3c5d4b7d461f3374b89247ef6ba9e0d535791e840d803e4f3"
|
|
4546
4628
|
}
|
|
4547
4629
|
};
|
|
4548
4630
|
var sha256 = (value) => createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -8320,7 +8402,9 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8320
8402
|
]);
|
|
8321
8403
|
const fieldsName = introduced.get("bcmsFields");
|
|
8322
8404
|
const fieldName = introduced.get("bcmsField");
|
|
8323
|
-
const
|
|
8405
|
+
const styleReader = dialect === "astro" ? "bcmsSectionStyleText" : "bcmsSectionStyle";
|
|
8406
|
+
const styled = rootStyleIsFree(content, resolved.root) && !reserved.has("blockStyle") && !reserved.has(styleReader);
|
|
8407
|
+
const { markup, bound, duplicates } = sectionMarkup(content, resolved.root, fieldName, styled ? styleReader : null);
|
|
8324
8408
|
if (duplicates.length > 0) return { content: "", free: [], duplicates, unconvertible: [] };
|
|
8325
8409
|
const groupKey = resolved.section.groupKey;
|
|
8326
8410
|
const locals = helperLocals(parsed, dialect, fromFile);
|
|
@@ -8331,7 +8415,8 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8331
8415
|
.../* @__PURE__ */ new Set([
|
|
8332
8416
|
...helperNames.map((h) => alias(h.name, h.local)),
|
|
8333
8417
|
flat3 ? "bcmsSectionPaths" : "bcmsSection",
|
|
8334
|
-
...bound > 0 ? [alias("bcmsFields", fieldsName)] : []
|
|
8418
|
+
...bound > 0 ? [alias("bcmsFields", fieldsName)] : [],
|
|
8419
|
+
...styled ? [styleReader] : []
|
|
8335
8420
|
])
|
|
8336
8421
|
].sort();
|
|
8337
8422
|
const helperSpecifier = relativeImport(path, HELPER_PATH[dialect]).replace(/\.tsx?$/, "");
|
|
@@ -8380,9 +8465,11 @@ interface Props {
|
|
|
8380
8465
|
/** The instance's own copy, when an editor gave it any. Wins over the bound group. */
|
|
8381
8466
|
overrides?: Record<string, unknown>;
|
|
8382
8467
|
/** The page snapshot, so one component can serve every page whose group has this shape. */
|
|
8383
|
-
page?: unknown
|
|
8468
|
+
page?: unknown;${styled ? `
|
|
8469
|
+
/** The placement's \`block.style\` \u2014 painted on the root, which says so with \`data-bcms-style\`. */
|
|
8470
|
+
blockStyle?: Record<string, unknown>;` : ""}
|
|
8384
8471
|
}
|
|
8385
|
-
const { blockId, bind, bindPaths, overrides, page } = Astro.props;
|
|
8472
|
+
const { blockId, bind, bindPaths, overrides, page${styled ? ", blockStyle" : ""} } = Astro.props;
|
|
8386
8473
|
${carriedDeclarations}${declared}
|
|
8387
8474
|
---
|
|
8388
8475
|
${markup}
|
|
@@ -8394,7 +8481,7 @@ ${styles}
|
|
|
8394
8481
|
${[...carried, `import { ${helpers.join(", ")} } from "${helperSpecifier}";`, `import type { BcmsSectionProps } from "${relativeImport(path, SECTIONS_LIB).replace(/\.tsx?$/, "")}";`].join("\n")}
|
|
8395
8482
|
${carriedDeclarations === "" ? "" : `
|
|
8396
8483
|
${carriedDeclarations}`}
|
|
8397
|
-
export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page }: BcmsSectionProps) {
|
|
8484
|
+
export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page${styled ? ", blockStyle" : ""} }: BcmsSectionProps) {
|
|
8398
8485
|
${declared.split("\n").join("\n ")}
|
|
8399
8486
|
return (
|
|
8400
8487
|
${markup}
|
|
@@ -8402,13 +8489,21 @@ export default function ${resolved.name}({ blockId, bind, bindPaths, overrides,
|
|
|
8402
8489
|
}
|
|
8403
8490
|
` };
|
|
8404
8491
|
}
|
|
8405
|
-
function
|
|
8492
|
+
function rootStyleIsFree(content, root) {
|
|
8493
|
+
return root.attrs.every((attr) => {
|
|
8494
|
+
if (attr.name === "style") return false;
|
|
8495
|
+
const open = attr.expressionRange ? content.slice(attr.expressionRange.start, attr.expressionRange.end).trimStart() : "";
|
|
8496
|
+
return !open.startsWith("{...");
|
|
8497
|
+
});
|
|
8498
|
+
}
|
|
8499
|
+
function sectionMarkup(content, root, fieldName, styleReader = null) {
|
|
8406
8500
|
const slice = new MagicString5(content.slice(root.start, root.end));
|
|
8407
8501
|
const at = (offset) => offset - root.start;
|
|
8502
|
+
const stamp = styleReader ? `data-bcms-block={blockId} data-bcms-style="" style={${styleReader}(blockStyle)}` : "data-bcms-block={blockId}";
|
|
8408
8503
|
const stamps = root.attrs.filter((attr) => attr.name === "data-bcms-block");
|
|
8409
|
-
if (stamps.length === 0) slice.appendLeft(at(root.attrInsertAt),
|
|
8504
|
+
if (stamps.length === 0) slice.appendLeft(at(root.attrInsertAt), ` ${stamp}`);
|
|
8410
8505
|
else {
|
|
8411
|
-
slice.overwrite(at(stamps[0].range.start), at(stamps[0].range.end),
|
|
8506
|
+
slice.overwrite(at(stamps[0].range.start), at(stamps[0].range.end), stamp);
|
|
8412
8507
|
for (const extra of stamps.slice(1)) {
|
|
8413
8508
|
let from = extra.range.start;
|
|
8414
8509
|
while (from > root.start && /\s/.test(content[from - 1])) from--;
|
|
@@ -8759,6 +8854,8 @@ export interface BcmsSectionProps {
|
|
|
8759
8854
|
bindPaths?: Record<string, string>;
|
|
8760
8855
|
overrides?: Record<string, unknown>;
|
|
8761
8856
|
page?: unknown;
|
|
8857
|
+
/** The placement's \`block.style\`, which the section root paints (\`data-bcms-style\`). */
|
|
8858
|
+
blockStyle?: Record<string, unknown>;
|
|
8762
8859
|
}
|
|
8763
8860
|
|
|
8764
8861
|
/** One placement on one page: which component, bound to which page field group. */
|
|
@@ -8769,6 +8866,8 @@ export interface BcmsPlacement {
|
|
|
8769
8866
|
/** A locale copy's own field path for each prop, when its keys differ from the component's. */
|
|
8770
8867
|
bindPaths?: Record<string, string>;
|
|
8771
8868
|
overrides?: Record<string, unknown>;
|
|
8869
|
+
/** The placement's \`block.style\` \u2014 what the editor's section spacing and style controls write. */
|
|
8870
|
+
style?: Record<string, unknown>;
|
|
8772
8871
|
}
|
|
8773
8872
|
|
|
8774
8873
|
/** The page's own snapshot \u2014 the copy every placement on it reads through \`bind\`. */
|
|
@@ -8830,6 +8929,7 @@ export function pageSections(pageSlug: string): BcmsPlacement[] {
|
|
|
8830
8929
|
bind: typeof props.bind === "string" ? props.bind : undefined,
|
|
8831
8930
|
bindPaths: isRecord(props.bindPaths) ? (props.bindPaths as Record<string, string>) : undefined,
|
|
8832
8931
|
overrides: isRecord(props.overrides) ? props.overrides : undefined,
|
|
8932
|
+
style: isRecord(block.style) ? block.style : undefined,
|
|
8833
8933
|
});
|
|
8834
8934
|
}
|
|
8835
8935
|
return out;
|
|
@@ -8896,6 +8996,7 @@ const snapshot = pageSnapshot(page);
|
|
|
8896
8996
|
bind={placement.bind}
|
|
8897
8997
|
bindPaths={placement.bindPaths}
|
|
8898
8998
|
overrides={placement.overrides}
|
|
8999
|
+
blockStyle={placement.style}
|
|
8899
9000
|
page={snapshot}
|
|
8900
9001
|
/>
|
|
8901
9002
|
) : null;
|
|
@@ -8919,6 +9020,7 @@ export default function Sections({ page }: { page: string }) {
|
|
|
8919
9020
|
bind={placement.bind}
|
|
8920
9021
|
bindPaths={placement.bindPaths}
|
|
8921
9022
|
overrides={placement.overrides}
|
|
9023
|
+
blockStyle={placement.style}
|
|
8922
9024
|
page={snapshot}
|
|
8923
9025
|
/>
|
|
8924
9026
|
) : null;
|