@batterai/block-sdk 0.1.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE +21 -0
  3. package/README.md +22 -0
  4. package/dist/base-element.d.ts +37 -0
  5. package/dist/base-element.d.ts.map +1 -0
  6. package/dist/base-element.js +46 -0
  7. package/dist/base-element.js.map +1 -0
  8. package/dist/blocks/callout.css +1 -0
  9. package/dist/blocks/callout.d.ts +13 -0
  10. package/dist/blocks/callout.d.ts.map +1 -0
  11. package/dist/blocks/callout.js +106 -0
  12. package/dist/blocks/callout.js.map +1 -0
  13. package/dist/blocks/first-party.d.ts +3 -0
  14. package/dist/blocks/first-party.d.ts.map +1 -0
  15. package/dist/blocks/first-party.js +7 -0
  16. package/dist/blocks/first-party.js.map +1 -0
  17. package/dist/blocks/form.css +1 -0
  18. package/dist/blocks/form.d.ts +67 -0
  19. package/dist/blocks/form.d.ts.map +1 -0
  20. package/dist/blocks/form.js +199 -0
  21. package/dist/blocks/form.js.map +1 -0
  22. package/dist/blocks/image.css +1 -0
  23. package/dist/blocks/image.d.ts +49 -0
  24. package/dist/blocks/image.d.ts.map +1 -0
  25. package/dist/blocks/image.js +238 -0
  26. package/dist/blocks/image.js.map +1 -0
  27. package/dist/define.d.ts +9 -0
  28. package/dist/define.d.ts.map +1 -0
  29. package/dist/define.js +12 -0
  30. package/dist/define.js.map +1 -0
  31. package/dist/html-package.d.ts +16 -0
  32. package/dist/html-package.d.ts.map +1 -0
  33. package/dist/html-package.js +104 -0
  34. package/dist/html-package.js.map +1 -0
  35. package/dist/i18n.d.ts +88 -0
  36. package/dist/i18n.d.ts.map +1 -0
  37. package/dist/i18n.js +93 -0
  38. package/dist/i18n.js.map +1 -0
  39. package/dist/index.d.ts +16 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +16 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/render-to-dsd.d.ts +18 -0
  44. package/dist/render-to-dsd.d.ts.map +1 -0
  45. package/dist/render-to-dsd.js +72 -0
  46. package/dist/render-to-dsd.js.map +1 -0
  47. package/dist/tag.d.ts +14 -0
  48. package/dist/tag.d.ts.map +1 -0
  49. package/dist/tag.js +25 -0
  50. package/dist/tag.js.map +1 -0
  51. package/package.json +43 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # @batterai/block-sdk
2
+
3
+ ## 0.1.0
4
+
5
+ - Baseline web-component block SDK with first-party callout, form, image, and DSD render helpers.
6
+ - Ships as Node-compatible ESM with declaration files under `dist/`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Batterai.eu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # @batterai/block-sdk
2
+
3
+ Framework-neutral block registration and server-rendering helpers for Battery blocks.
4
+
5
+ ## What It Provides
6
+
7
+ - `defineBlock` and tag helpers for block packages.
8
+ - A Lit-based base element for browser rendering.
9
+ - Declarative Shadow DOM server rendering utilities.
10
+ - Built-in callout, form, and image block examples.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @batterai/block-sdk
16
+ ```
17
+
18
+ Requires Node.js `>=20.11`.
19
+
20
+ ## Boundary
21
+
22
+ Blocks receive resolved props and host-supplied data. They do not own page persistence; the host CMS remains the durable source of truth.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * BatteryBlockElement — the Lit base class for block elements.
3
+ * - pure function of the `config` PROPERTY (host-assigned; contract §3)
4
+ * - DSD adoption: with `@lit-labs/ssr-client`'s hydrate support loaded FIRST
5
+ * (invariant A), an existing server shadow root is adopted, never re-rendered
6
+ * - emits be-ready on connect; helpers for be-edit / be-intent
7
+ * - editingRegion contract (plan §5.1): subclasses call `suppressedRegion()`
8
+ * to render an identical-box placeholder while that region is overlay-edited
9
+ */
10
+ import { LitElement } from "lit";
11
+ import { type BeEditDetail, type BeIntentDetail, type BlockConfig } from "@batterai/contract";
12
+ export declare class BatteryBlockElement extends LitElement {
13
+ /** `config` is BOTH a property (host mount path) and a JSON attribute (the
14
+ * SSR path): HTML cannot serialize JS properties into DSD, so the server
15
+ * binds the attribute and the upgraded client element parses it — giving
16
+ * hydration the IDENTICAL data the server rendered with (invariant A;
17
+ * spike-proven; the research memo's "DSD property-binding gap"). */
18
+ static properties: {
19
+ config: {
20
+ attribute: string;
21
+ type: ObjectConstructor;
22
+ };
23
+ };
24
+ config: BlockConfig | null;
25
+ /** Set by defineBlock() so be-ready carries identity without subclass code. */
26
+ static blockType: string;
27
+ static blockVersion: string;
28
+ constructor();
29
+ connectedCallback(): void;
30
+ protected emitEdit(detail: BeEditDetail): void;
31
+ protected emitIntent(detail: BeIntentDetail): void;
32
+ /** True when `regionId` must render as a stable-box placeholder because the
33
+ * host's overlay is editing it (editMode only; renderToDSD paths never see
34
+ * an editingRegion — invariant L). */
35
+ protected suppressedRegion(regionId: string): boolean;
36
+ }
37
+ //# sourceMappingURL=base-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-element.d.ts","sourceRoot":"","sources":["../src/base-element.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,mBAAoB,SAAQ,UAAU;IACjD;;;;wEAIoE;IACpE,MAAM,CAAC,UAAU;;;;;MAEf;IAEM,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAEnC,+EAA+E;IAC/E,MAAM,CAAC,SAAS,SAAM;IACtB,MAAM,CAAC,YAAY,SAAM;;IAOhB,iBAAiB,IAAI,IAAI;IAMlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAI9C,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIlD;;0CAEsC;IACtC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAGtD"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * BatteryBlockElement — the Lit base class for block elements.
3
+ * - pure function of the `config` PROPERTY (host-assigned; contract §3)
4
+ * - DSD adoption: with `@lit-labs/ssr-client`'s hydrate support loaded FIRST
5
+ * (invariant A), an existing server shadow root is adopted, never re-rendered
6
+ * - emits be-ready on connect; helpers for be-edit / be-intent
7
+ * - editingRegion contract (plan §5.1): subclasses call `suppressedRegion()`
8
+ * to render an identical-box placeholder while that region is overlay-edited
9
+ */
10
+ import { LitElement } from "lit";
11
+ import { BE_READY, emitBlockEvent, } from "@batterai/contract";
12
+ export class BatteryBlockElement extends LitElement {
13
+ /** `config` is BOTH a property (host mount path) and a JSON attribute (the
14
+ * SSR path): HTML cannot serialize JS properties into DSD, so the server
15
+ * binds the attribute and the upgraded client element parses it — giving
16
+ * hydration the IDENTICAL data the server rendered with (invariant A;
17
+ * spike-proven; the research memo's "DSD property-binding gap"). */
18
+ static properties = {
19
+ config: { attribute: "config", type: Object },
20
+ };
21
+ /** Set by defineBlock() so be-ready carries identity without subclass code. */
22
+ static blockType = "";
23
+ static blockVersion = "";
24
+ constructor() {
25
+ super();
26
+ this.config = null;
27
+ }
28
+ connectedCallback() {
29
+ super.connectedCallback();
30
+ const ctor = this.constructor;
31
+ emitBlockEvent(this, BE_READY, { type: ctor.blockType, version: ctor.blockVersion });
32
+ }
33
+ emitEdit(detail) {
34
+ emitBlockEvent(this, "be-edit", detail);
35
+ }
36
+ emitIntent(detail) {
37
+ emitBlockEvent(this, "be-intent", detail);
38
+ }
39
+ /** True when `regionId` must render as a stable-box placeholder because the
40
+ * host's overlay is editing it (editMode only; renderToDSD paths never see
41
+ * an editingRegion — invariant L). */
42
+ suppressedRegion(regionId) {
43
+ return this.config?.context.editMode === true && this.config.context.editingRegion === regionId;
44
+ }
45
+ }
46
+ //# sourceMappingURL=base-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-element.js","sourceRoot":"","sources":["../src/base-element.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,cAAc,GAIf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,OAAO,mBAAoB,SAAQ,UAAU;IACjD;;;;wEAIoE;IACpE,MAAM,CAAC,UAAU,GAAG;QAClB,MAAM,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;KAC9C,CAAC;IAIF,+EAA+E;IAC/E,MAAM,CAAC,SAAS,GAAG,EAAE,CAAC;IACtB,MAAM,CAAC,YAAY,GAAG,EAAE,CAAC;IAEzB;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAEQ,iBAAiB;QACxB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAyC,CAAC;QAC5D,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IACvF,CAAC;IAES,QAAQ,CAAC,MAAoB;QACrC,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IAES,UAAU,CAAC,MAAsB;QACzC,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED;;0CAEsC;IAC5B,gBAAgB,CAAC,QAAgB;QACzC,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,KAAK,QAAQ,CAAC;IAClG,CAAC"}
@@ -0,0 +1 @@
1
+ be-battery-callout-v1 { display: block; }
@@ -0,0 +1,13 @@
1
+ import { type Locale } from "@batterai/contract";
2
+ import type { BlockManifest, BlockPackage } from "@batterai/contract";
3
+ import { BatteryBlockElement } from "../base-element";
4
+ export declare function createCalloutManifest(locale?: Locale | string): BlockManifest;
5
+ export declare const calloutManifest: BlockManifest;
6
+ export declare class BatteryCallout extends BatteryBlockElement {
7
+ static styles: import("lit").CSSResult;
8
+ private regionClick;
9
+ render(): import("lit").TemplateResult<1>;
10
+ }
11
+ export declare function createCalloutPackage(locale?: Locale | string): BlockPackage;
12
+ export declare const calloutPackage: BlockPackage;
13
+ //# sourceMappingURL=callout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callout.d.ts","sourceRoot":"","sources":["../../src/blocks/callout.ts"],"names":[],"mappings":"AAOA,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAwBtD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAoB7E;AAED,eAAO,MAAM,eAAe,EAAE,aAA2C,CAAC;AAE1E,qBAAa,cAAe,SAAQ,mBAAmB;IACrD,MAAM,CAAC,MAAM,0BASX;IAEF,OAAO,CAAC,WAAW;IAQV,MAAM;CAsBhB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAO3E;AAED,eAAO,MAAM,cAAc,EAAE,YAAyC,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * First-party proof block `battery.callout` (Tier 2, contract §10 example
3
+ * generalized): title + body with an accent bar; both regions inline-editable
4
+ * via be-intent{edit-region} in editMode; pure function of RESOLVED props.
5
+ * Used by the Phase-4 gate specs and every later phase's fixtures.
6
+ */
7
+ import { css, html, nothing } from "lit";
8
+ import { fieldName } from "@batterai/contract";
9
+ import { MULTILINE_TEXT_COMPONENT } from "@batterai/contract";
10
+ import { BatteryBlockElement } from "../base-element.js";
11
+ import { defineBlock } from "../define.js";
12
+ import { blockSdkMessage } from "../i18n.js";
13
+ function fields(locale) {
14
+ return [
15
+ {
16
+ name: fieldName("title"),
17
+ label: blockSdkMessage(locale, "callout.field.title.label"),
18
+ valueType: "string",
19
+ cardinality: "one",
20
+ bindable: true,
21
+ },
22
+ {
23
+ name: fieldName("body"),
24
+ label: blockSdkMessage(locale, "callout.field.body.label"),
25
+ valueType: "string",
26
+ cardinality: "one",
27
+ bindable: true,
28
+ render: { component: MULTILINE_TEXT_COMPONENT },
29
+ },
30
+ ];
31
+ }
32
+ export function createCalloutManifest(locale) {
33
+ return {
34
+ type: "battery.callout",
35
+ version: "1.0.0",
36
+ source: "battery",
37
+ label: blockSdkMessage(locale, "callout.manifest.label"),
38
+ summary: blockSdkMessage(locale, "callout.manifest.summary"),
39
+ category: "content",
40
+ icon: "text",
41
+ fields: fields(locale),
42
+ defaultProps: {
43
+ title: blockSdkMessage(locale, "callout.default.title"),
44
+ body: blockSdkMessage(locale, "callout.default.body"),
45
+ },
46
+ editableRegions: [
47
+ { regionId: "title", field: "title", target: "[data-edit='title']", kind: "rich" },
48
+ { regionId: "body", field: "body", target: "[data-edit='body']", kind: "rich", multiline: true },
49
+ ],
50
+ capabilities: { ssr: true, hydration: "partial" },
51
+ };
52
+ }
53
+ export const calloutManifest = createCalloutManifest("en");
54
+ export class BatteryCallout extends BatteryBlockElement {
55
+ static styles = css `
56
+ .bar {
57
+ border-left: 4px solid var(--be-color-accent, rebeccapurple);
58
+ padding: 8px 16px;
59
+ font-family: system-ui, sans-serif;
60
+ }
61
+ h3 { margin: 0 0 4px; font-size: 20px; line-height: 1.3; }
62
+ p { margin: 0; font-size: 16px; line-height: 1.5; }
63
+ .be-region-placeholder { visibility: hidden; }
64
+ `;
65
+ regionClick(field, regionId, e) {
66
+ if (!this.config?.context.editMode)
67
+ return;
68
+ this.emitIntent({
69
+ action: "edit-region",
70
+ payload: { field, regionId, clientX: e.clientX, clientY: e.clientY },
71
+ });
72
+ }
73
+ render() {
74
+ const c = this.config;
75
+ if (!c)
76
+ return html `<p class="be-unconfigured">${blockSdkMessage(undefined, "block.unconfigured")}</p>`;
77
+ const title = typeof c.props.title === "string" ? c.props.title : "";
78
+ const body = typeof c.props.body === "string" ? c.props.body : "";
79
+ return html `<article class="bar">
80
+ <h3
81
+ data-edit="title"
82
+ class=${this.suppressedRegion("title") ? "be-region-placeholder" : nothing}
83
+ @click=${(e) => this.regionClick("title", "title", e)}
84
+ >
85
+ ${title}
86
+ </h3>
87
+ <p
88
+ data-edit="body"
89
+ class=${this.suppressedRegion("body") ? "be-region-placeholder" : nothing}
90
+ @click=${(e) => this.regionClick("body", "body", e)}
91
+ >
92
+ ${body}
93
+ </p>
94
+ </article>`;
95
+ }
96
+ }
97
+ export function createCalloutPackage(locale) {
98
+ const manifest = createCalloutManifest(locale);
99
+ return {
100
+ manifest,
101
+ stylesheets: [new URL("./callout.css", import.meta.url).href],
102
+ defineElement: defineBlock(manifest, BatteryCallout),
103
+ };
104
+ }
105
+ export const calloutPackage = createCalloutPackage("en");
106
+ //# sourceMappingURL=callout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/blocks/callout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAE,SAAS,EAA2B,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,SAAS,MAAM,CAAC,MAAwB;IACtC,OAAO;QACP;YACE,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC;YACxB,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,2BAA2B,CAAC;YAC3D,SAAS,EAAE,QAAQ;YACnB,WAAW,EAAE,KAAK;YAClB,QAAQ,EAAE,IAAI;SACf;QACD;YACE,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;YACvB,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,0BAA0B,CAAC;YAC1D,SAAS,EAAE,QAAQ;YACnB,WAAW,EAAE,KAAK;YAClB,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,EAAE,SAAS,EAAE,wBAAwB,EAAE;SAChD;KACA,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAwB;IAC5D,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,OAAO;QAChB,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,wBAAwB,CAAC;QACxD,OAAO,EAAE,eAAe,CAAC,MAAM,EAAE,0BAA0B,CAAC;QAC5D,QAAQ,EAAE,SAAS;QACnB,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACtB,YAAY,EAAE;YACZ,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,uBAAuB,CAAC;YACvD,IAAI,EAAE,eAAe,CAAC,MAAM,EAAE,sBAAsB,CAAC;SACtD;QACD,eAAe,EAAE;YACf,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE;YAClF,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;SACjG;QACD,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE;KAClD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAkB,qBAAqB,CAAC,IAAI,CAAC,CAAC;AAE1E,MAAM,OAAO,cAAe,SAAQ,mBAAmB;IACrD,MAAM,CAAC,MAAM,GAAG,GAAG,CAAA;;;;;;;;;GASlB,CAAC;IAEM,WAAW,CAAC,KAAa,EAAE,QAAgB,EAAE,CAAa;QAChE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ;YAAE,OAAO;QAC3C,IAAI,CAAC,UAAU,CAAC;YACd,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;SACrE,CAAC,CAAC;IACL,CAAC;IAEQ,MAAM;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA,8BAA8B,eAAe,CAAC,SAAS,EAAE,oBAAoB,CAAC,MAAM,CAAC;QACxG,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,OAAO,IAAI,CAAA;;;gBAGC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO;iBACjE,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;;UAE/D,KAAK;;;;gBAIC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO;iBAChE,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;;UAE7D,IAAI;;eAEC,CAAC;IACd,CAAC;;AAGH,MAAM,UAAU,oBAAoB,CAAC,MAAwB;IAC3D,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO;QACL,QAAQ;QACR,WAAW,EAAE,CAAC,IAAI,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QAC7D,aAAa,EAAE,WAAW,CAAC,QAAQ,EAAE,cAAc,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAiB,oBAAoB,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { BlockManifest, Locale } from "@batterai/contract";
2
+ export declare function createFirstPartyBlockManifests(locale?: Locale | string): readonly BlockManifest[];
3
+ //# sourceMappingURL=first-party.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-party.d.ts","sourceRoot":"","sources":["../../src/blocks/first-party.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKhE,wBAAgB,8BAA8B,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,aAAa,EAAE,CAEjG"}
@@ -0,0 +1,7 @@
1
+ import { createCalloutManifest } from "./callout.js";
2
+ import { createFormManifest } from "./form.js";
3
+ import { createImageManifest } from "./image.js";
4
+ export function createFirstPartyBlockManifests(locale) {
5
+ return [createCalloutManifest(locale), createImageManifest(locale), createFormManifest(locale)];
6
+ }
7
+ //# sourceMappingURL=first-party.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-party.js","sourceRoot":"","sources":["../../src/blocks/first-party.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,UAAU,8BAA8B,CAAC,MAAwB;IACrE,OAAO,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;AAClG,CAAC"}
@@ -0,0 +1 @@
1
+ be-battery-form-v1 { display: block; }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * First-party `battery.form` (Tier 3, hydration "partial") — the v1 form
3
+ * block posts to a host action endpoint, which routes through HostApi.mutate:
4
+ * - fields render from a literal `fieldsJson` spec (name/label/required/
5
+ * multiline) — SSR'd, so the form is usable at first paint;
6
+ * - the write TARGET is never wire-authored: the block posts only
7
+ * { formId, instanceId, idempotencyKey, values } to the host `action`
8
+ * endpoint; the host maps formId -> registered target server-side and
9
+ * runs checkWriteAuthz (tenant-scoped, invariant D order);
10
+ * - client-side required validation shows a visible inline error and does
11
+ * NOT submit; server errors render verbatim in a role=alert region;
12
+ * - idempotency: one key per user INTENT (minted at mount and after each
13
+ * success), constant across retries of a failed submit — the host dedupes;
14
+ * - visible states throughout: pending disables the button, success is a
15
+ * role=status message, failure a role=alert — never a silent outcome.
16
+ */
17
+ import { type TemplateResult } from "lit";
18
+ import { type BlockManifest, type BlockPackage, type Locale } from "@batterai/contract";
19
+ import { BatteryBlockElement } from "../base-element";
20
+ export declare function createFormManifest(locale?: Locale | string): BlockManifest;
21
+ export declare const formManifest: BlockManifest;
22
+ export interface FormFieldSpec {
23
+ readonly name: string;
24
+ readonly label: string;
25
+ readonly required?: boolean;
26
+ readonly multiline?: boolean;
27
+ }
28
+ /** Parse the literal fieldsJson prop; malformed JSON is a VISIBLE config
29
+ * error, not a silently empty form. */
30
+ export declare function parseFormFields(raw: unknown, locale?: Locale | string): FormFieldSpec[] | Error;
31
+ type Status = {
32
+ kind: "idle";
33
+ } | {
34
+ kind: "pending";
35
+ } | {
36
+ kind: "success";
37
+ message: string;
38
+ } | {
39
+ kind: "error";
40
+ message: string;
41
+ };
42
+ export declare class BatteryForm extends BatteryBlockElement {
43
+ static styles: import("lit").CSSResult;
44
+ static properties: {
45
+ status: {
46
+ state: boolean;
47
+ };
48
+ fieldErrors: {
49
+ state: boolean;
50
+ };
51
+ config: {
52
+ attribute: string;
53
+ type: ObjectConstructor;
54
+ };
55
+ };
56
+ status: Status;
57
+ fieldErrors: Record<string, string>;
58
+ /** One key per user INTENT: constant across retries, rotated on success. */
59
+ private idempotencyKey;
60
+ constructor();
61
+ private submit;
62
+ render(): TemplateResult;
63
+ }
64
+ export declare function createFormPackage(locale?: Locale | string): BlockPackage;
65
+ export declare const formPackage: BlockPackage;
66
+ export {};
67
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/blocks/form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAC9D,OAAO,EAAa,KAAK,aAAa,EAAE,KAAK,YAAY,EAAc,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC/G,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAsBtD,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAoB1E;AAED,eAAO,MAAM,YAAY,EAAE,aAAwC,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;uCACuC;AACvC,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,EAAE,GAAG,KAAK,CAc/F;AAED,KAAK,MAAM,GACP;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,qBAAa,WAAY,SAAQ,mBAAmB;IAClD,MAAM,CAAC,MAAM,0BASX;IAEF,MAAM,CAAC,UAAU;;;;;;;;;;;MAIf;IAEM,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,4EAA4E;IAC5E,OAAO,CAAC,cAAc,CAAuB;;YAQ/B,MAAM;IAgDX,MAAM,IAAI,cAAc;CAoClC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAOxE;AAED,eAAO,MAAM,WAAW,EAAE,YAAsC,CAAC"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * First-party `battery.form` (Tier 3, hydration "partial") — the v1 form
3
+ * block posts to a host action endpoint, which routes through HostApi.mutate:
4
+ * - fields render from a literal `fieldsJson` spec (name/label/required/
5
+ * multiline) — SSR'd, so the form is usable at first paint;
6
+ * - the write TARGET is never wire-authored: the block posts only
7
+ * { formId, instanceId, idempotencyKey, values } to the host `action`
8
+ * endpoint; the host maps formId -> registered target server-side and
9
+ * runs checkWriteAuthz (tenant-scoped, invariant D order);
10
+ * - client-side required validation shows a visible inline error and does
11
+ * NOT submit; server errors render verbatim in a role=alert region;
12
+ * - idempotency: one key per user INTENT (minted at mount and after each
13
+ * success), constant across retries of a failed submit — the host dedupes;
14
+ * - visible states throughout: pending disables the button, success is a
15
+ * role=status message, failure a role=alert — never a silent outcome.
16
+ */
17
+ import { css, html, nothing } from "lit";
18
+ import { fieldName } from "@batterai/contract";
19
+ import { BatteryBlockElement } from "../base-element.js";
20
+ import { defineBlock } from "../define.js";
21
+ import { blockSdkMessage } from "../i18n.js";
22
+ function fields(locale) {
23
+ return [
24
+ { name: fieldName("title"), label: blockSdkMessage(locale, "form.field.title.label"), valueType: "string", cardinality: "one", bindable: true },
25
+ {
26
+ name: fieldName("fieldsJson"),
27
+ label: blockSdkMessage(locale, "form.field.fieldsJson.label"),
28
+ help: blockSdkMessage(locale, "form.field.fieldsJson.help"),
29
+ valueType: "json",
30
+ cardinality: "one",
31
+ bindable: false,
32
+ },
33
+ { name: fieldName("submitLabel"), label: blockSdkMessage(locale, "form.field.submitLabel.label"), valueType: "string", cardinality: "one", bindable: false },
34
+ { name: fieldName("successMessage"), label: blockSdkMessage(locale, "form.field.successMessage.label"), valueType: "string", cardinality: "one", bindable: false },
35
+ { name: fieldName("action"), label: blockSdkMessage(locale, "form.field.action.label"), valueType: "string", cardinality: "one", bindable: false },
36
+ { name: fieldName("formId"), label: blockSdkMessage(locale, "form.field.formId.label"), valueType: "string", cardinality: "one", bindable: false },
37
+ ];
38
+ }
39
+ export function createFormManifest(locale) {
40
+ return {
41
+ type: "battery.form",
42
+ version: "1.0.0",
43
+ source: "battery",
44
+ label: blockSdkMessage(locale, "form.manifest.label"),
45
+ summary: blockSdkMessage(locale, "form.manifest.summary"),
46
+ category: "input",
47
+ icon: "form",
48
+ fields: fields(locale),
49
+ defaultProps: {
50
+ title: "",
51
+ fieldsJson: "[]",
52
+ submitLabel: blockSdkMessage(locale, "form.default.submitLabel"),
53
+ successMessage: blockSdkMessage(locale, "form.default.successMessage"),
54
+ action: "/__form",
55
+ formId: "",
56
+ },
57
+ capabilities: { ssr: true, hydration: "partial" },
58
+ };
59
+ }
60
+ export const formManifest = createFormManifest("en");
61
+ /** Parse the literal fieldsJson prop; malformed JSON is a VISIBLE config
62
+ * error, not a silently empty form. */
63
+ export function parseFormFields(raw, locale) {
64
+ if (typeof raw !== "string")
65
+ return new Error(blockSdkMessage(locale, "form.parse.missing"));
66
+ try {
67
+ const parsed = JSON.parse(raw);
68
+ if (!Array.isArray(parsed))
69
+ return new Error(blockSdkMessage(locale, "form.parse.list"));
70
+ for (const f of parsed) {
71
+ if (typeof f?.name !== "string" || !f.name || typeof f?.label !== "string") {
72
+ return new Error(blockSdkMessage(locale, "form.parse.field"));
73
+ }
74
+ }
75
+ return parsed;
76
+ }
77
+ catch {
78
+ return new Error(blockSdkMessage(locale, "form.parse.invalidJson"));
79
+ }
80
+ }
81
+ export class BatteryForm extends BatteryBlockElement {
82
+ static styles = css `
83
+ form { font-family: system-ui, sans-serif; display: grid; gap: 8px; max-width: 480px; }
84
+ label { display: grid; gap: 2px; font-size: 14px; }
85
+ input, textarea { font: inherit; padding: 6px 8px; border: 1px solid #bbb; border-radius: 4px; }
86
+ button { justify-self: start; font: inherit; padding: 6px 16px; border-radius: 4px; border: 1px solid #666; cursor: pointer; }
87
+ button[disabled] { opacity: 0.6; cursor: wait; }
88
+ .be-form-error { background: #f7c1c1; padding: 6px 10px; border-radius: 4px; font-size: 14px; }
89
+ .be-form-success { background: #c9ecc9; padding: 6px 10px; border-radius: 4px; font-size: 14px; }
90
+ .be-field-error { color: #a4262c; font-size: 12px; }
91
+ `;
92
+ static properties = {
93
+ ...BatteryBlockElement.properties,
94
+ status: { state: true },
95
+ fieldErrors: { state: true },
96
+ };
97
+ /** One key per user INTENT: constant across retries, rotated on success. */
98
+ idempotencyKey = crypto.randomUUID();
99
+ constructor() {
100
+ super();
101
+ this.status = { kind: "idle" };
102
+ this.fieldErrors = {};
103
+ }
104
+ async submit(e) {
105
+ e.preventDefault();
106
+ const c = this.config;
107
+ if (!c || this.status.kind === "pending")
108
+ return;
109
+ const specs = parseFormFields(c.props.fieldsJson, c.context.locale);
110
+ if (specs instanceof Error)
111
+ return;
112
+ const form = e.target;
113
+ const values = {};
114
+ const errors = {};
115
+ for (const spec of specs) {
116
+ const el = form.elements.namedItem(spec.name);
117
+ const value = el?.value?.trim() ?? "";
118
+ if (spec.required && !value) {
119
+ errors[spec.name] = blockSdkMessage(c.context.locale, "form.validation.required", { label: spec.label });
120
+ }
121
+ values[spec.name] = value;
122
+ }
123
+ this.fieldErrors = errors;
124
+ if (Object.keys(errors).length > 0)
125
+ return; // visible inline, no request
126
+ this.status = { kind: "pending" };
127
+ try {
128
+ const res = await fetch(String(c.props.action ?? "/__form"), {
129
+ method: "POST",
130
+ headers: { "Content-Type": "application/json" },
131
+ body: JSON.stringify({
132
+ formId: String(c.props.formId ?? ""),
133
+ instanceId: c.data.instanceId,
134
+ idempotencyKey: this.idempotencyKey,
135
+ values,
136
+ }),
137
+ });
138
+ if (res.ok) {
139
+ this.idempotencyKey = crypto.randomUUID(); // next intent = next key
140
+ this.status = {
141
+ kind: "success",
142
+ message: String(c.props.successMessage ?? blockSdkMessage(c.context.locale, "form.status.processed")),
143
+ };
144
+ form.reset();
145
+ }
146
+ else {
147
+ this.status = { kind: "error", message: await res.text() };
148
+ }
149
+ }
150
+ catch {
151
+ this.status = { kind: "error", message: blockSdkMessage(c.context.locale, "form.status.connectionFailed") };
152
+ }
153
+ }
154
+ render() {
155
+ const c = this.config;
156
+ if (!c)
157
+ return html `<p class="be-unconfigured">${blockSdkMessage(undefined, "block.unconfigured")}</p>`;
158
+ const title = typeof c.props.title === "string" ? c.props.title : "";
159
+ const specs = parseFormFields(c.props.fieldsJson, c.context.locale);
160
+ if (specs instanceof Error) {
161
+ return html `<p class="be-form-error" role="alert">
162
+ ${blockSdkMessage(c.context.locale, "form.config.invalid", { message: specs.message })}
163
+ </p>`;
164
+ }
165
+ return html `<form @submit=${(e) => void this.submit(e)} novalidate>
166
+ ${title ? html `<h3>${title}</h3>` : nothing}
167
+ ${specs.map((spec) => html `<label>
168
+ ${spec.label}${spec.required ? " *" : ""}
169
+ ${spec.multiline
170
+ ? html `<textarea name=${spec.name} rows="3"></textarea>`
171
+ : html `<input name=${spec.name} type="text" />`}
172
+ ${this.fieldErrors[spec.name]
173
+ ? html `<span class="be-field-error" role="alert">${this.fieldErrors[spec.name]}</span>`
174
+ : nothing}
175
+ </label>`)}
176
+ <button type="submit" ?disabled=${this.status.kind === "pending"}>
177
+ ${this.status.kind === "pending"
178
+ ? blockSdkMessage(c.context.locale, "form.status.pending")
179
+ : String(c.props.submitLabel ?? blockSdkMessage(c.context.locale, "form.default.submitLabel"))}
180
+ </button>
181
+ ${this.status.kind === "success"
182
+ ? html `<p class="be-form-success" role="status">${this.status.message}</p>`
183
+ : nothing}
184
+ ${this.status.kind === "error"
185
+ ? html `<p class="be-form-error" role="alert">${this.status.message}</p>`
186
+ : nothing}
187
+ </form>`;
188
+ }
189
+ }
190
+ export function createFormPackage(locale) {
191
+ const manifest = createFormManifest(locale);
192
+ return {
193
+ manifest,
194
+ stylesheets: [new URL("./form.css", import.meta.url).href],
195
+ defineElement: defineBlock(manifest, BatteryForm),
196
+ };
197
+ }
198
+ export const formPackage = createFormPackage("en");
199
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../../src/blocks/form.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ be-battery-image-v1 { display: block; }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * First-party `battery.image` (Tier 1, hydration "none" — 0 kb client JS):
3
+ * a bound image through @batterai/media (plan §8 Phase 7). The block is a pure
4
+ * function of RESOLVED props + host-supplied media data:
5
+ * - `assetId`/`alt`/`caption` props are bindable like any other prop;
6
+ * - the HOST resolves assetId -> src/srcset/dimensions via its MediaStore and
7
+ * injects the result as `config.data.media` (blocks never do I/O — the
8
+ * media lookup is host render machinery, shared by page + fragment +
9
+ * canvas so all three agree, invariant A);
10
+ * - an assetId without media data renders a VISIBLE diagnostic (`be-media-
11
+ * missing`, role=alert) — never a broken <img>, never a silent gap;
12
+ * - alt precedence: bound/authored `alt` prop, else the asset's own alt (the
13
+ * store validates alt at upload, so the floor is never empty).
14
+ */
15
+ import { type TemplateResult } from "lit";
16
+ import { type BlockManifest, type BlockPackage, type Locale } from "@batterai/contract";
17
+ import { BatteryBlockElement } from "../base-element";
18
+ export declare function createImageManifest(locale?: Locale | string): BlockManifest;
19
+ export declare const imageManifest: BlockManifest;
20
+ export type ImageView = "single" | "carousel" | "grid";
21
+ /** The host-injected media payload (`config.data.media` or `.images`). */
22
+ export interface ImageMediaData {
23
+ readonly src: string;
24
+ readonly srcset?: string;
25
+ readonly width: number;
26
+ readonly height: number;
27
+ readonly alt: string;
28
+ readonly title?: string;
29
+ readonly caption?: string;
30
+ readonly href?: string;
31
+ readonly focal?: {
32
+ readonly x: number;
33
+ readonly y: number;
34
+ };
35
+ readonly aspectRatio?: string;
36
+ readonly sizing?: {
37
+ readonly width?: string;
38
+ readonly height?: string;
39
+ readonly objectFit?: "cover" | "contain" | "fill";
40
+ };
41
+ readonly opacity?: number;
42
+ }
43
+ export declare class BatteryImage extends BatteryBlockElement {
44
+ static styles: import("lit").CSSResult;
45
+ render(): TemplateResult;
46
+ }
47
+ export declare function createImagePackage(locale?: Locale | string): BlockPackage;
48
+ export declare const imagePackage: BlockPackage;
49
+ //# sourceMappingURL=image.d.ts.map