@bettercms-ai/astro 0.24.0 → 0.26.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.
@@ -1,44 +1,44 @@
1
- ---
2
- /**
3
- * <BcmsButton> — render a `button` field ({ label, href, variant?, size?, arrow?, icon?,
4
- * newTab? }) as one editable button, the way the BetterCMS visual editor and in-place publishing
5
- * expect to find it:
6
- *
7
- * <a data-bcms-button="<path>" data-variant data-size href [target rel] data-bcms-props="<path>.href|url|href">
8
- * [<svg class="bcms-btn-icon">]<span data-bcms-field="<path>.label">Label</span>[<svg class="bcms-btn-arrow">]
9
- * </a>
10
- *
11
- * Style it by `data-variant` (primary · secondary · tertiary · brand · dark · light · outline ·
12
- * link) and `data-size` (sm · md · lg) in your own CSS: the editor repaints those attributes as the
13
- * author picks, and publishing writes them into the live page, so your stylesheet decides what a
14
- * look looks like. `class` is passed through untouched.
15
- *
16
- * <BcmsButton path="hero.cta" value={page.hero.cta} class="btn" />
17
- */
18
- import { formatPropsAttribute, readButtonValue, buttonIconSvg } from "@bettercms-ai/types";
19
-
20
- interface Props {
21
- /** The field path in the editor grammar, e.g. `cta` or `hero.cta`. */
22
- path: string;
23
- /** The stored value. Missing keys render as the defaults (Primary, medium, no arrow, no icon). */
24
- value: unknown;
25
- class?: string;
26
- }
27
- const { path, value, class: className } = Astro.props;
28
- const b = readButtonValue(value);
29
- ---
30
- {b.label && (
31
- <a
32
- class={className}
33
- href={b.href || "#"}
34
- data-bcms-button={path}
35
- data-variant={b.variant}
36
- data-size={b.size}
37
- data-bcms-props={formatPropsAttribute([{ address: `${path}.href`, kind: "url", attr: "href" }])}
38
- {...(b.newTab ? { target: "_blank", rel: "noopener noreferrer" } : {})}
39
- >
40
- {b.icon && <Fragment set:html={buttonIconSvg(b.icon, "bcms-btn-icon")} />}
41
- <span data-bcms-field={`${path}.label`} data-bcms-kind="text">{b.label}</span>
42
- {b.arrow && <Fragment set:html={buttonIconSvg("arrow-right", "bcms-btn-arrow")} />}
43
- </a>
44
- )}
1
+ ---
2
+ /**
3
+ * <BcmsButton> — render a `button` field ({ label, href, variant?, size?, arrow?, icon?,
4
+ * newTab? }) as one editable button, the way the BetterCMS visual editor and in-place publishing
5
+ * expect to find it:
6
+ *
7
+ * <a data-bcms-button="<path>" data-variant data-size href [target rel] data-bcms-props="<path>.href|url|href">
8
+ * [<svg class="bcms-btn-icon">]<span data-bcms-field="<path>.label">Label</span>[<svg class="bcms-btn-arrow">]
9
+ * </a>
10
+ *
11
+ * Style it by `data-variant` (primary · secondary · tertiary · brand · dark · light · outline ·
12
+ * link) and `data-size` (sm · md · lg) in your own CSS: the editor repaints those attributes as the
13
+ * author picks, and publishing writes them into the live page, so your stylesheet decides what a
14
+ * look looks like. `class` is passed through untouched.
15
+ *
16
+ * <BcmsButton path="hero.cta" value={page.hero.cta} class="btn" />
17
+ */
18
+ import { formatPropsAttribute, readButtonValue, buttonIconSvg } from "@bettercms-ai/types";
19
+
20
+ interface Props {
21
+ /** The field path in the editor grammar, e.g. `cta` or `hero.cta`. */
22
+ path: string;
23
+ /** The stored value. Missing keys render as the defaults (Primary, medium, no arrow, no icon). */
24
+ value: unknown;
25
+ class?: string;
26
+ }
27
+ const { path, value, class: className } = Astro.props;
28
+ const b = readButtonValue(value);
29
+ ---
30
+ {b.label && (
31
+ <a
32
+ class={className}
33
+ href={b.href || "#"}
34
+ data-bcms-button={path}
35
+ data-variant={b.variant}
36
+ data-size={b.size}
37
+ data-bcms-props={formatPropsAttribute([{ address: `${path}.href`, kind: "url", attr: "href" }])}
38
+ {...(b.newTab ? { target: "_blank", rel: "noopener noreferrer" } : {})}
39
+ >
40
+ {b.icon && <Fragment set:html={buttonIconSvg(b.icon, "bcms-btn-icon")} />}
41
+ <span data-bcms-field={`${path}.label`} data-bcms-kind="text">{b.label}</span>
42
+ {b.arrow && <Fragment set:html={buttonIconSvg("arrow-right", "bcms-btn-arrow")} />}
43
+ </a>
44
+ )}
@@ -1,30 +1,39 @@
1
- ---
2
- /**
3
- * <BcmsField> — tag an entry field's rendered value with its identity so the
4
- * BetterCMS visual editor can bind click-to-edit deterministically (mirrors
5
- * Sanity's `data-sanity` / BaseHub's `data-basehub`). Entry-backed templates
6
- * hand-render field values (`f.title`, `f.body.html`), so the field `path` is
7
- * declared here by the author — the delivery payload carries no source-map.
8
- *
9
- * By default wraps the slot in a `display:contents` span, invisible to
10
- * layout/GSAP; pass `as` to carry the attributes on a real element instead.
11
- *
12
- * `path` follows the editor grammar: `title` · `hero.title` · `columns[0].links[2].href`
13
- * (dotted keys and any number of `[n]` indices). For images, put the attributes on the
14
- * `<img>` itself (`kind="image"` reflection patches `.src`), not on a wrapper:
15
- * <img src={f.cover.url} data-bcms-field="cover" data-bcms-kind="image" />
16
- */
17
- interface Props {
18
- /** Field path in the editor grammar, e.g. `title` or `facts[2].label`. */
19
- path: string;
20
- /** Kind hint the editor's reflection branches on. Omit for plain text/number. */
21
- kind?: "richtext" | "image";
22
- /** Wrapper element. Defaults to a `display:contents` span. */
23
- as?: string;
24
- }
25
- const { path, kind, as } = Astro.props;
26
- const Tag = (as ?? "span") as keyof HTMLElementTagNameMap;
27
- ---
28
- <Tag data-bcms-field={path} data-bcms-kind={kind} style={as ? undefined : "display:contents"}>
29
- <slot />
30
- </Tag>
1
+ ---
2
+ /**
3
+ * <BcmsField> — tag an entry field's rendered value with its identity so the
4
+ * BetterCMS visual editor can bind click-to-edit deterministically (mirrors
5
+ * Sanity's `data-sanity` / BaseHub's `data-basehub`). Entry-backed templates
6
+ * hand-render field values (`f.title`, `f.body.html`), so the field `path` is
7
+ * declared here by the author — the delivery payload carries no source-map.
8
+ *
9
+ * When the slot is ONE element, the attributes go on that element and nothing is added to
10
+ * the page: `.hero > h1` and every animation target stay what the author wrote. Text, or
11
+ * several elements, are wrapped in a `display:contents` span as before; pass `as` to carry
12
+ * the attributes on a real wrapper instead.
13
+ *
14
+ * `path` follows the editor grammar: `title` · `hero.title` · `columns[0].links[2].href`
15
+ * (dotted keys and any number of `[n]` indices). For images, put the attributes on the
16
+ * `<img>` itself (`kind="image"` reflection patches `.src`), not on a wrapper:
17
+ * <img src={f.cover.url} data-bcms-field="cover" data-bcms-kind="image" />
18
+ */
19
+ interface Props {
20
+ /** Field path in the editor grammar, e.g. `title` or `facts[2].label`. */
21
+ path: string;
22
+ /** Kind hint the editor's reflection branches on. Omit for plain text/number. */
23
+ kind?: "richtext" | "image";
24
+ /** Wrapper element. Without it: no wrapper around a single element, a `display:contents` span around anything else. */
25
+ as?: string;
26
+ }
27
+ import { stampSoleElement } from "../dist/bindings.js";
28
+
29
+ const { path, kind, as } = Astro.props;
30
+ const Tag = (as ?? "span") as keyof HTMLElementTagNameMap;
31
+ // Rendered once, here: the same markup is either stamped or wrapped below.
32
+ const slot = await Astro.slots.render("default");
33
+ const sole = as ? null : stampSoleElement(slot, { "data-bcms-field": path, "data-bcms-kind": kind });
34
+ ---
35
+ {sole !== null ? <Fragment set:html={sole} /> : (
36
+ <Tag data-bcms-field={path} data-bcms-kind={kind} style={as ? undefined : "display:contents"}>
37
+ <Fragment set:html={slot} />
38
+ </Tag>
39
+ )}