@bettercms-ai/ui 0.3.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/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @bettercms-ai/ui
2
+
3
+ > **Status: Scaffolded** — Not yet published to npm.
4
+
5
+ Shared page-builder block components for BetterCMS. Contains presentation-only React components for the 7 core block types: **Heading**, **Text**, **Image**, **Button**, **Spacer**, **Columns**, and **Video**.
6
+
7
+ These components are intentionally **dumb** (presentational only) — no selection state, no toolbar, no inline editing. That logic lives in the admin app (`bettercms-admin`).
8
+
9
+ ## Design Philosophy
10
+
11
+ This package follows the **shadcn/ui studio** model:
12
+
13
+ - Each block has **multiple style variants** and **animation presets** that can be composed.
14
+ - Components are owned by you — copy, modify, extend freely.
15
+ - The package is a **starting point**, not a locked dependency.
16
+ - Animation and style variation work ships **post-MVP**.
17
+
18
+ ## Block Types
19
+
20
+ | Type | Component | Purpose |
21
+ |------|-----------|---------|
22
+ | `heading` | `Heading` | H1–H3 text headings |
23
+ | `text` | `Text` | Rich text / HTML content |
24
+ | `image` | `Image` | Images with alt text & caption |
25
+ | `button` | `Button` | CTA buttons with variants |
26
+ | `spacer` | `Spacer` | Vertical spacing blocks |
27
+ | `columns` | `Columns` | Multi-column layouts with nested blocks |
28
+ | `video` | `Video` | YouTube, Vimeo, or native video embeds |
29
+
30
+ ## Usage
31
+
32
+ ```tsx
33
+ import { BlocksRenderer } from "@bettercms-ai/ui";
34
+ import type { ContentBlock } from "@bettercms-ai/types";
35
+
36
+ // Use with @bettercms-ai/types block JSON
37
+ const blocks: ContentBlock[] = [
38
+ { type: "heading", id: "1", props: { text: "Hello", level: 1 } },
39
+ { type: "text", id: "2", props: { html: "<p>Welcome!</p>" } },
40
+ ];
41
+
42
+ export function Page() {
43
+ return <BlocksRenderer blocks={blocks} />;
44
+ }
45
+ ```
46
+
47
+ ## With a custom block renderer (e.g., admin app adds selection state)
48
+
49
+ ```tsx
50
+ import { BlockRenderer } from "@bettercms-ai/ui";
51
+
52
+ function AdminCanvas({ block, isSelected, onSelect }) {
53
+ return (
54
+ <div
55
+ onClick={() => onSelect(block.id)}
56
+ className={isSelected ? "ring-2 ring-primary" : ""}
57
+ >
58
+ <BlockRenderer block={block} />
59
+ </div>
60
+ );
61
+ }
62
+ ```
63
+
64
+ ## Adding new blocks
65
+
66
+ 1. Create `src/blocks/MyBlock.tsx`
67
+ 2. Export from `src/blocks/index.ts`
68
+ 3. Add entry to `src/registry.ts`
69
+ 4. Update `src/index.ts`
70
+
71
+ ## Adding animation variants (post-MVP)
72
+
73
+ Each block should eventually expose:
74
+
75
+ - `animation` prop (e.g., `"fade-in"`, `"slide-up"`, `"stagger"`)
76
+ - `duration` prop (ms)
77
+ - `delay` prop (ms)
78
+
79
+ These are pre-defined via Tailwind keyframes in `tailwind.config.ts`.
80
+
81
+ ## Development
82
+
83
+ ```bash
84
+ # Install dependencies (run from backend root)
85
+ bun install
86
+
87
+ # Type-check
88
+ bun run --filter @bettercms-ai/ui typecheck
89
+
90
+ # Add a new shadcn/ui component
91
+ cd packages/ui && npx shadcn@latest add -p ../../ button
92
+ ```
93
+
94
+ ## Note on npm publishing
95
+
96
+ This package is **not yet published** to npm. Admin and web repos use their own local shadcn/ui copies for non-page-builder UI (Dialog, Sheet, Table, etc.). The `@bettercms-ai/ui` blocks are consumed via workspace references during local development, and will be published after MVP when the block variants and animation system are finalized.
@@ -0,0 +1,45 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { HeadingProps, TextProps, ImageProps, ButtonProps, SpacerProps, ColumnsProps, ContentBlock, VideoProps } from '@betttercms/types';
3
+ import React from 'react';
4
+
5
+ interface HeadingBlockProps extends HeadingProps {
6
+ className?: string;
7
+ align?: "left" | "center" | "right";
8
+ }
9
+ declare function Heading({ text, level, align, className, }: HeadingBlockProps): react_jsx_runtime.JSX.Element;
10
+
11
+ interface TextBlockProps extends TextProps {
12
+ className?: string;
13
+ align?: "left" | "center" | "right";
14
+ }
15
+ declare function Text({ html, align, className }: TextBlockProps): react_jsx_runtime.JSX.Element;
16
+
17
+ interface ImageBlockProps extends ImageProps {
18
+ className?: string;
19
+ sizes?: string;
20
+ }
21
+ declare function Image({ src, alt, width, height, caption, className, sizes, }: ImageBlockProps): react_jsx_runtime.JSX.Element;
22
+
23
+ interface ButtonBlockProps extends ButtonProps {
24
+ className?: string;
25
+ align?: "left" | "center" | "right";
26
+ }
27
+ declare function Button({ text, href, variant, align, className, }: ButtonBlockProps): react_jsx_runtime.JSX.Element;
28
+
29
+ interface SpacerBlockProps extends SpacerProps {
30
+ className?: string;
31
+ }
32
+ declare function Spacer({ height, className }: SpacerBlockProps): react_jsx_runtime.JSX.Element;
33
+
34
+ interface ColumnsBlockProps extends ColumnsProps {
35
+ className?: string;
36
+ renderBlock?: (block: ContentBlock) => React.ReactNode;
37
+ }
38
+ declare function Columns({ columns, gap, className, renderBlock, }: ColumnsBlockProps): react_jsx_runtime.JSX.Element;
39
+
40
+ interface VideoBlockProps extends VideoProps {
41
+ className?: string;
42
+ }
43
+ declare function Video({ url, poster, autoplay, loop, className, }: VideoBlockProps): react_jsx_runtime.JSX.Element;
44
+
45
+ export { Button as B, Columns as C, Heading as H, Image as I, Spacer as S, Text as T, Video as V };
@@ -0,0 +1,48 @@
1
+ export { B as Button, C as Columns, H as Heading, I as Image, S as Spacer, T as Text, V as Video } from './Video-Dd3TLlXA.js';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import { SectionProps, ContentBlock, NavbarProps, FooterProps, SliderProps, TabsProps, ComponentProps, FormProps } from '@betttercms/types';
4
+ import React from 'react';
5
+
6
+ interface SectionBlockProps extends SectionProps {
7
+ className?: string;
8
+ renderBlock?: (block: ContentBlock) => React.ReactNode;
9
+ }
10
+ declare function Section({ children, background, paddingY, maxWidth, className, renderBlock, }: SectionBlockProps): react_jsx_runtime.JSX.Element;
11
+
12
+ interface NavbarBlockProps extends NavbarProps {
13
+ className?: string;
14
+ }
15
+ declare function Navbar({ logo, links, cta, className }: NavbarBlockProps): react_jsx_runtime.JSX.Element;
16
+
17
+ interface FooterBlockProps extends FooterProps {
18
+ className?: string;
19
+ }
20
+ declare function Footer({ columns, copyright, className }: FooterBlockProps): react_jsx_runtime.JSX.Element;
21
+
22
+ interface SliderBlockProps extends SliderProps {
23
+ className?: string;
24
+ renderBlock?: (block: ContentBlock) => React.ReactNode;
25
+ }
26
+ declare function Slider({ slides, className, renderBlock }: SliderBlockProps): react_jsx_runtime.JSX.Element;
27
+
28
+ interface TabsBlockProps extends TabsProps {
29
+ className?: string;
30
+ renderBlock?: (block: ContentBlock) => React.ReactNode;
31
+ }
32
+ declare function Tabs({ tabs, className, renderBlock }: TabsBlockProps): react_jsx_runtime.JSX.Element;
33
+
34
+ /**
35
+ * Builder-preview placeholder for a `component` instance. Live instance resolution
36
+ * (definition lookup + override merge) happens server-side in the delivery renderer
37
+ * and in the page-builder, which pass a resolver — the standalone library preview
38
+ * just shows what's referenced.
39
+ */
40
+ declare function ComponentInstance({ componentId, className, }: ComponentProps & {
41
+ className?: string;
42
+ }): react_jsx_runtime.JSX.Element;
43
+ /** Builder-preview placeholder for a `form` block (rendered live by @betttercms/next). */
44
+ declare function FormPlaceholder({ formId, className }: FormProps & {
45
+ className?: string;
46
+ }): react_jsx_runtime.JSX.Element;
47
+
48
+ export { ComponentInstance, Footer, FormPlaceholder, Navbar, Section, Slider, Tabs };
package/dist/blocks.js ADDED
@@ -0,0 +1,344 @@
1
+ "use client";
2
+
3
+ // src/blocks/Heading.tsx
4
+ import { jsx } from "react/jsx-runtime";
5
+ function Heading({
6
+ text,
7
+ level = 2,
8
+ align = "left",
9
+ className = ""
10
+ }) {
11
+ const alignClass = {
12
+ left: "text-left",
13
+ center: "text-center",
14
+ right: "text-right"
15
+ }[align];
16
+ const classNames = `font-heading font-bold tracking-tight text-foreground ${alignClass} ${className}`;
17
+ switch (level) {
18
+ case 1:
19
+ return /* @__PURE__ */ jsx("h1", { className: classNames, children: text });
20
+ case 2:
21
+ return /* @__PURE__ */ jsx("h2", { className: classNames, children: text });
22
+ case 3:
23
+ return /* @__PURE__ */ jsx("h3", { className: classNames, children: text });
24
+ default:
25
+ return /* @__PURE__ */ jsx("h2", { className: classNames, children: text });
26
+ }
27
+ }
28
+
29
+ // src/blocks/Text.tsx
30
+ import { jsx as jsx2 } from "react/jsx-runtime";
31
+ function Text({ html, align = "left", className = "" }) {
32
+ const alignClass = {
33
+ left: "text-left",
34
+ center: "text-center",
35
+ right: "text-right"
36
+ }[align];
37
+ return /* @__PURE__ */ jsx2(
38
+ "div",
39
+ {
40
+ className: `text-muted-foreground leading-relaxed ${alignClass} ${className}`,
41
+ dangerouslySetInnerHTML: { __html: html }
42
+ }
43
+ );
44
+ }
45
+
46
+ // src/lib/utils.ts
47
+ import { clsx } from "clsx";
48
+ import { twMerge } from "tailwind-merge";
49
+ function cn(...inputs) {
50
+ return twMerge(clsx(inputs));
51
+ }
52
+
53
+ // src/blocks/Image.tsx
54
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
55
+ function Image({
56
+ src,
57
+ alt,
58
+ width,
59
+ height,
60
+ caption,
61
+ className = "",
62
+ sizes
63
+ }) {
64
+ return /* @__PURE__ */ jsxs("figure", { className: cn("w-full", className), children: [
65
+ /* @__PURE__ */ jsx3(
66
+ "img",
67
+ {
68
+ src,
69
+ alt,
70
+ width,
71
+ height,
72
+ sizes,
73
+ className: "w-full h-auto rounded-md object-cover",
74
+ loading: "lazy"
75
+ }
76
+ ),
77
+ caption && /* @__PURE__ */ jsx3("figcaption", { className: "mt-2 text-sm text-muted-foreground text-center italic", children: caption })
78
+ ] });
79
+ }
80
+
81
+ // src/blocks/Button.tsx
82
+ import { jsx as jsx4 } from "react/jsx-runtime";
83
+ function Button({
84
+ text,
85
+ href,
86
+ variant = "primary",
87
+ align = "left",
88
+ className = ""
89
+ }) {
90
+ const baseStyles = "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50";
91
+ const variantStyles = {
92
+ primary: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
93
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80"
94
+ };
95
+ const alignClass = {
96
+ left: "justify-start",
97
+ center: "justify-center",
98
+ right: "justify-end"
99
+ }[align];
100
+ return /* @__PURE__ */ jsx4(
101
+ "a",
102
+ {
103
+ href,
104
+ className: cn(baseStyles, variantStyles[variant], alignClass, "px-4 py-2", className),
105
+ children: text
106
+ }
107
+ );
108
+ }
109
+
110
+ // src/blocks/Spacer.tsx
111
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
112
+ function Spacer({ height = 32, className = "" }) {
113
+ return /* @__PURE__ */ jsx5(
114
+ "div",
115
+ {
116
+ className: `w-full border border-dashed border-muted-foreground/20 rounded flex items-center justify-center ${className}`,
117
+ style: { height: `${height}px` },
118
+ "aria-hidden": "true",
119
+ children: /* @__PURE__ */ jsxs2("span", { className: "text-xs text-muted-foreground/40 select-none", children: [
120
+ height,
121
+ "px"
122
+ ] })
123
+ }
124
+ );
125
+ }
126
+
127
+ // src/blocks/Columns.tsx
128
+ import "react";
129
+ import { jsx as jsx6 } from "react/jsx-runtime";
130
+ function Columns({
131
+ columns,
132
+ gap = 16,
133
+ className = "",
134
+ renderBlock
135
+ }) {
136
+ return /* @__PURE__ */ jsx6(
137
+ "div",
138
+ {
139
+ className: cn("grid w-full", className),
140
+ style: {
141
+ gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))`,
142
+ gap: `${gap}px`
143
+ },
144
+ children: columns.map((columnBlocks, colIndex) => /* @__PURE__ */ jsx6("div", { className: "flex flex-col gap-4 min-w-0", children: columnBlocks.map((block) => /* @__PURE__ */ jsx6("span", { children: renderBlock ? renderBlock(block) : null }, block.id)) }, colIndex))
145
+ }
146
+ );
147
+ }
148
+
149
+ // src/blocks/Video.tsx
150
+ import { useState } from "react";
151
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
152
+ function getEmbedUrl(url) {
153
+ const ytMatch = url.match(
154
+ /(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/
155
+ );
156
+ if (ytMatch) {
157
+ return {
158
+ embedUrl: `https://www.youtube.com/embed/${ytMatch[1]}`,
159
+ provider: "youtube"
160
+ };
161
+ }
162
+ const vimeoMatch = url.match(/vimeo\.com\/(\d+)/);
163
+ if (vimeoMatch) {
164
+ return {
165
+ embedUrl: `https://player.vimeo.com/video/${vimeoMatch[1]}`,
166
+ provider: "vimeo"
167
+ };
168
+ }
169
+ return { embedUrl: url, provider: "unknown" };
170
+ }
171
+ function Video({
172
+ url,
173
+ poster,
174
+ autoplay = false,
175
+ loop = false,
176
+ className = ""
177
+ }) {
178
+ const [isLoaded, setIsLoaded] = useState(false);
179
+ const { embedUrl, provider } = getEmbedUrl(url);
180
+ if (provider === "unknown") {
181
+ return /* @__PURE__ */ jsx7(
182
+ "video",
183
+ {
184
+ src: url,
185
+ poster,
186
+ autoPlay: autoplay,
187
+ loop,
188
+ controls: true,
189
+ className,
190
+ playsInline: true
191
+ }
192
+ );
193
+ }
194
+ return /* @__PURE__ */ jsxs3("div", { className: cn("w-full overflow-hidden rounded-md bg-black aspect-video", className), children: [
195
+ !isLoaded && poster && // eslint-disable-next-line @next/next/no-img-element
196
+ /* @__PURE__ */ jsx7(
197
+ "img",
198
+ {
199
+ src: poster,
200
+ alt: "Video thumbnail",
201
+ className: "w-full h-full object-cover absolute inset-0"
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx7(
205
+ "iframe",
206
+ {
207
+ src: `${embedUrl}?autoplay=${autoplay ? 1 : 0}&loop=${loop ? 1 : 0}&mute=${autoplay ? 1 : 0}`,
208
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
209
+ allowFullScreen: true,
210
+ loading: "lazy",
211
+ onLoad: () => setIsLoaded(true),
212
+ className: "w-full h-full"
213
+ }
214
+ )
215
+ ] });
216
+ }
217
+
218
+ // src/blocks/Section.tsx
219
+ import "react";
220
+ import { jsx as jsx8 } from "react/jsx-runtime";
221
+ function Section({
222
+ children,
223
+ background,
224
+ paddingY,
225
+ maxWidth,
226
+ className = "",
227
+ renderBlock
228
+ }) {
229
+ const inner = (children ?? []).map((block) => /* @__PURE__ */ jsx8("span", { children: renderBlock ? renderBlock(block) : null }, block.id));
230
+ return /* @__PURE__ */ jsx8(
231
+ "section",
232
+ {
233
+ className: cn("w-full", className),
234
+ style: { background, paddingTop: paddingY, paddingBottom: paddingY },
235
+ children: maxWidth ? /* @__PURE__ */ jsx8("div", { style: { maxWidth, marginInline: "auto" }, children: inner }) : inner
236
+ }
237
+ );
238
+ }
239
+
240
+ // src/blocks/Navbar.tsx
241
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
242
+ function Navbar({ logo, links, cta, className = "" }) {
243
+ return /* @__PURE__ */ jsxs4("nav", { className: cn("flex items-center gap-6 py-4", className), children: [
244
+ logo?.src ? /* @__PURE__ */ jsx9("a", { href: logo.href ?? "/", className: "shrink-0", children: /* @__PURE__ */ jsx9("img", { src: logo.src, alt: logo.alt, className: "h-8 w-auto" }) }) : null,
245
+ /* @__PURE__ */ jsx9("div", { className: "flex flex-1 gap-5", children: (links ?? []).map((l, i) => /* @__PURE__ */ jsx9("a", { href: l.href, className: "text-inherit no-underline", children: l.label }, i)) }),
246
+ cta ? /* @__PURE__ */ jsx9(
247
+ "a",
248
+ {
249
+ href: cta.href,
250
+ className: "rounded-lg bg-black px-4 py-2 font-semibold text-white no-underline",
251
+ children: cta.text
252
+ }
253
+ ) : null
254
+ ] });
255
+ }
256
+
257
+ // src/blocks/Footer.tsx
258
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
259
+ function Footer({ columns, copyright, className = "" }) {
260
+ return /* @__PURE__ */ jsxs5("footer", { className: cn("mt-12 border-t pt-8", className), children: [
261
+ /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-12", children: (columns ?? []).map((col, i) => /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1.5", children: [
262
+ col.heading ? /* @__PURE__ */ jsx10("h4", { className: "mb-2 font-semibold", children: col.heading }) : null,
263
+ (col.links ?? []).map((l, j) => /* @__PURE__ */ jsx10("a", { href: l.href, className: "text-neutral-500 no-underline", children: l.label }, j))
264
+ ] }, i)) }),
265
+ copyright ? /* @__PURE__ */ jsx10("p", { className: "mt-6 text-sm text-neutral-500", children: copyright }) : null
266
+ ] });
267
+ }
268
+
269
+ // src/blocks/Slider.tsx
270
+ import { useState as useState2 } from "react";
271
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
272
+ function Slider({ slides, className = "", renderBlock }) {
273
+ const [i, setI] = useState2(0);
274
+ const list = slides ?? [];
275
+ const go = (n) => setI((n + list.length) % (list.length || 1));
276
+ const btn = "absolute top-1/2 -translate-y-1/2 flex h-9 w-9 items-center justify-center rounded-full border-0 bg-black/50 text-white cursor-pointer";
277
+ return /* @__PURE__ */ jsxs6("div", { className: cn("relative w-full", className), children: [
278
+ list.map((s, idx) => /* @__PURE__ */ jsx11("div", { hidden: idx !== i, className: "flex flex-col gap-4", children: (s.children ?? []).map((b) => /* @__PURE__ */ jsx11("span", { children: renderBlock ? renderBlock(b) : null }, b.id)) }, s.id)),
279
+ /* @__PURE__ */ jsx11("button", { type: "button", "aria-label": "Previous", onClick: () => go(i - 1), className: cn(btn, "left-2"), children: "\u2039" }),
280
+ /* @__PURE__ */ jsx11("button", { type: "button", "aria-label": "Next", onClick: () => go(i + 1), className: cn(btn, "right-2"), children: "\u203A" })
281
+ ] });
282
+ }
283
+
284
+ // src/blocks/Tabs.tsx
285
+ import { useState as useState3 } from "react";
286
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
287
+ function Tabs({ tabs, className = "", renderBlock }) {
288
+ const [active, setActive] = useState3(0);
289
+ const list = tabs ?? [];
290
+ return /* @__PURE__ */ jsxs7("div", { className: cn("w-full", className), children: [
291
+ /* @__PURE__ */ jsx12("div", { role: "tablist", className: "mb-4 flex gap-1 border-b", children: list.map((t, idx) => /* @__PURE__ */ jsx12(
292
+ "button",
293
+ {
294
+ role: "tab",
295
+ type: "button",
296
+ "aria-selected": idx === active,
297
+ onClick: () => setActive(idx),
298
+ className: cn(
299
+ "cursor-pointer border-b-2 border-transparent bg-transparent px-4 py-2",
300
+ idx === active && "border-black font-semibold"
301
+ ),
302
+ children: t.label
303
+ },
304
+ t.id
305
+ )) }),
306
+ list.map((t, idx) => /* @__PURE__ */ jsx12("div", { role: "tabpanel", hidden: idx !== active, className: "flex flex-col gap-4", children: (t.children ?? []).map((b) => /* @__PURE__ */ jsx12("span", { children: renderBlock ? renderBlock(b) : null }, b.id)) }, t.id))
307
+ ] });
308
+ }
309
+
310
+ // src/blocks/Placeholders.tsx
311
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
312
+ var box = "rounded border border-dashed border-neutral-300 bg-neutral-50 p-4 text-sm text-neutral-500";
313
+ function ComponentInstance({
314
+ componentId,
315
+ className = ""
316
+ }) {
317
+ return /* @__PURE__ */ jsxs8("div", { className: cn(box, className), children: [
318
+ "Component instance: ",
319
+ /* @__PURE__ */ jsx13("code", { children: componentId })
320
+ ] });
321
+ }
322
+ function FormPlaceholder({ formId, className = "" }) {
323
+ return /* @__PURE__ */ jsxs8("div", { className: cn(box, className), children: [
324
+ "Form: ",
325
+ /* @__PURE__ */ jsx13("code", { children: formId })
326
+ ] });
327
+ }
328
+ export {
329
+ Button,
330
+ Columns,
331
+ ComponentInstance,
332
+ Footer,
333
+ FormPlaceholder,
334
+ Heading,
335
+ Image,
336
+ Navbar,
337
+ Section,
338
+ Slider,
339
+ Spacer,
340
+ Tabs,
341
+ Text,
342
+ Video
343
+ };
344
+ //# sourceMappingURL=blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blocks/Heading.tsx","../src/blocks/Text.tsx","../src/lib/utils.ts","../src/blocks/Image.tsx","../src/blocks/Button.tsx","../src/blocks/Spacer.tsx","../src/blocks/Columns.tsx","../src/blocks/Video.tsx","../src/blocks/Section.tsx","../src/blocks/Navbar.tsx","../src/blocks/Footer.tsx","../src/blocks/Slider.tsx","../src/blocks/Tabs.tsx","../src/blocks/Placeholders.tsx"],"sourcesContent":["import type { HeadingProps } from \"@betttercms/types\";\n\ninterface HeadingBlockProps extends HeadingProps {\n className?: string;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport function Heading({\n text,\n level = 2,\n align = \"left\",\n className = \"\",\n}: HeadingBlockProps) {\n const alignClass = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n }[align];\n\n const classNames = `font-heading font-bold tracking-tight text-foreground ${alignClass} ${className}`;\n\n switch (level) {\n case 1:\n return <h1 className={classNames}>{text}</h1>;\n case 2:\n return <h2 className={classNames}>{text}</h2>;\n case 3:\n return <h3 className={classNames}>{text}</h3>;\n default:\n return <h2 className={classNames}>{text}</h2>;\n }\n}\n","import type { TextProps } from \"@betttercms/types\";\n\ninterface TextBlockProps extends TextProps {\n className?: string;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport function Text({ html, align = \"left\", className = \"\" }: TextBlockProps) {\n const alignClass = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n }[align];\n\n return (\n <div\n className={`text-muted-foreground leading-relaxed ${alignClass} ${className}`}\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: html }}\n />\n );\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { ImageProps } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\n\ninterface ImageBlockProps extends ImageProps {\n className?: string;\n sizes?: string;\n}\n\nexport function Image({\n src,\n alt,\n width,\n height,\n caption,\n className = \"\",\n sizes,\n}: ImageBlockProps) {\n return (\n <figure className={cn(\"w-full\", className)}>\n <img\n src={src}\n alt={alt}\n width={width}\n height={height}\n sizes={sizes}\n className=\"w-full h-auto rounded-md object-cover\"\n loading=\"lazy\"\n />\n {caption && (\n <figcaption className=\"mt-2 text-sm text-muted-foreground text-center italic\">\n {caption}\n </figcaption>\n )}\n </figure>\n );\n}\n","import type { ButtonProps } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\n\ninterface ButtonBlockProps extends ButtonProps {\n className?: string;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport function Button({\n text,\n href,\n variant = \"primary\",\n align = \"left\",\n className = \"\",\n}: ButtonBlockProps) {\n const baseStyles =\n \"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\";\n\n const variantStyles = {\n primary:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n };\n\n const alignClass = {\n left: \"justify-start\",\n center: \"justify-center\",\n right: \"justify-end\",\n }[align];\n\n return (\n <a\n href={href}\n className={cn(baseStyles, variantStyles[variant], alignClass, \"px-4 py-2\", className)}\n >\n {text}\n </a>\n );\n}\n","import type { SpacerProps } from \"@betttercms/types\";\n\ninterface SpacerBlockProps extends SpacerProps {\n className?: string;\n}\n\nexport function Spacer({ height = 32, className = \"\" }: SpacerBlockProps) {\n return (\n <div\n className={`w-full border border-dashed border-muted-foreground/20 rounded flex items-center justify-center ${className}`}\n style={{ height: `${height}px` }}\n aria-hidden=\"true\"\n >\n <span className=\"text-xs text-muted-foreground/40 select-none\">\n {height}px\n </span>\n </div>\n );\n}\n","import type { ColumnsProps, ContentBlock } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\nimport React from \"react\";\n\ninterface ColumnsBlockProps extends ColumnsProps {\n className?: string;\n renderBlock?: (block: ContentBlock) => React.ReactNode;\n}\n\nexport function Columns({\n columns,\n gap = 16,\n className = \"\",\n renderBlock,\n}: ColumnsBlockProps) {\n return (\n <div\n className={cn(\"grid w-full\", className)}\n style={{\n gridTemplateColumns: `repeat(${columns.length}, minmax(0, 1fr))`,\n gap: `${gap}px`,\n }}\n >\n {columns.map((columnBlocks, colIndex) => (\n <div key={colIndex} className=\"flex flex-col gap-4 min-w-0\">\n {columnBlocks.map((block) => (\n <span key={block.id}>\n {renderBlock ? renderBlock(block) : null}\n </span>\n ))}\n </div>\n ))}\n </div>\n );\n}\n","import type { VideoProps } from \"@betttercms/types\";\nimport { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\n\ninterface VideoBlockProps extends VideoProps {\n className?: string;\n}\n\nfunction getEmbedUrl(url: string): { embedUrl: string; provider: \"youtube\" | \"vimeo\" | \"unknown\" } {\n // YouTube\n const ytMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n );\n if (ytMatch) {\n return {\n embedUrl: `https://www.youtube.com/embed/${ytMatch[1]}`,\n provider: \"youtube\",\n };\n }\n\n // Vimeo\n const vimeoMatch = url.match(/vimeo\\.com\\/(\\d+)/);\n if (vimeoMatch) {\n return {\n embedUrl: `https://player.vimeo.com/video/${vimeoMatch[1]}`,\n provider: \"vimeo\",\n };\n }\n\n return { embedUrl: url, provider: \"unknown\" };\n}\n\nexport function Video({\n url,\n poster,\n autoplay = false,\n loop = false,\n className = \"\",\n}: VideoBlockProps) {\n const [isLoaded, setIsLoaded] = useState(false);\n const { embedUrl, provider } = getEmbedUrl(url);\n\n // If not a recognized embed, render a native video tag\n if (provider === \"unknown\") {\n return (\n <video\n src={url}\n poster={poster}\n autoPlay={autoplay}\n loop={loop}\n controls\n className={className}\n playsInline\n />\n );\n }\n\n return (\n <div className={cn(\"w-full overflow-hidden rounded-md bg-black aspect-video\", className)}>\n {!isLoaded && poster && (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={poster}\n alt=\"Video thumbnail\"\n className=\"w-full h-full object-cover absolute inset-0\"\n />\n )}\n <iframe\n src={`${embedUrl}?autoplay=${autoplay ? 1 : 0}&loop=${loop ? 1 : 0}&mute=${autoplay ? 1 : 0}`}\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n allowFullScreen\n loading=\"lazy\"\n onLoad={() => setIsLoaded(true)}\n className=\"w-full h-full\"\n />\n </div>\n );\n}\n","import type { SectionProps, ContentBlock } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\nimport React from \"react\";\n\ninterface SectionBlockProps extends SectionProps {\n className?: string;\n renderBlock?: (block: ContentBlock) => React.ReactNode;\n}\n\nexport function Section({\n children,\n background,\n paddingY,\n maxWidth,\n className = \"\",\n renderBlock,\n}: SectionBlockProps) {\n const inner = (children ?? []).map((block) => (\n <span key={block.id}>{renderBlock ? renderBlock(block) : null}</span>\n ));\n return (\n <section\n className={cn(\"w-full\", className)}\n style={{ background, paddingTop: paddingY, paddingBottom: paddingY }}\n >\n {maxWidth ? <div style={{ maxWidth, marginInline: \"auto\" }}>{inner}</div> : inner}\n </section>\n );\n}\n","import type { NavbarProps } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\n\ninterface NavbarBlockProps extends NavbarProps {\n className?: string;\n}\n\nexport function Navbar({ logo, links, cta, className = \"\" }: NavbarBlockProps) {\n return (\n <nav className={cn(\"flex items-center gap-6 py-4\", className)}>\n {logo?.src ? (\n <a href={logo.href ?? \"/\"} className=\"shrink-0\">\n <img src={logo.src} alt={logo.alt} className=\"h-8 w-auto\" />\n </a>\n ) : null}\n <div className=\"flex flex-1 gap-5\">\n {(links ?? []).map((l, i) => (\n <a key={i} href={l.href} className=\"text-inherit no-underline\">\n {l.label}\n </a>\n ))}\n </div>\n {cta ? (\n <a\n href={cta.href}\n className=\"rounded-lg bg-black px-4 py-2 font-semibold text-white no-underline\"\n >\n {cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n","import type { FooterProps } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\n\ninterface FooterBlockProps extends FooterProps {\n className?: string;\n}\n\nexport function Footer({ columns, copyright, className = \"\" }: FooterBlockProps) {\n return (\n <footer className={cn(\"mt-12 border-t pt-8\", className)}>\n <div className=\"flex flex-wrap gap-12\">\n {(columns ?? []).map((col, i) => (\n <div key={i} className=\"flex flex-col gap-1.5\">\n {col.heading ? <h4 className=\"mb-2 font-semibold\">{col.heading}</h4> : null}\n {(col.links ?? []).map((l, j) => (\n <a key={j} href={l.href} className=\"text-neutral-500 no-underline\">\n {l.label}\n </a>\n ))}\n </div>\n ))}\n </div>\n {copyright ? <p className=\"mt-6 text-sm text-neutral-500\">{copyright}</p> : null}\n </footer>\n );\n}\n","\"use client\";\n\nimport type { SliderProps, ContentBlock } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\nimport React, { useState } from \"react\";\n\ninterface SliderBlockProps extends SliderProps {\n className?: string;\n renderBlock?: (block: ContentBlock) => React.ReactNode;\n}\n\nexport function Slider({ slides, className = \"\", renderBlock }: SliderBlockProps) {\n const [i, setI] = useState(0);\n const list = slides ?? [];\n const go = (n: number) => setI((n + list.length) % (list.length || 1));\n const btn =\n \"absolute top-1/2 -translate-y-1/2 flex h-9 w-9 items-center justify-center rounded-full border-0 bg-black/50 text-white cursor-pointer\";\n return (\n <div className={cn(\"relative w-full\", className)}>\n {list.map((s, idx) => (\n <div key={s.id} hidden={idx !== i} className=\"flex flex-col gap-4\">\n {(s.children ?? []).map((b) => (\n <span key={b.id}>{renderBlock ? renderBlock(b) : null}</span>\n ))}\n </div>\n ))}\n <button type=\"button\" aria-label=\"Previous\" onClick={() => go(i - 1)} className={cn(btn, \"left-2\")}>\n &#8249;\n </button>\n <button type=\"button\" aria-label=\"Next\" onClick={() => go(i + 1)} className={cn(btn, \"right-2\")}>\n &#8250;\n </button>\n </div>\n );\n}\n","\"use client\";\n\nimport type { TabsProps, ContentBlock } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\nimport React, { useState } from \"react\";\n\ninterface TabsBlockProps extends TabsProps {\n className?: string;\n renderBlock?: (block: ContentBlock) => React.ReactNode;\n}\n\nexport function Tabs({ tabs, className = \"\", renderBlock }: TabsBlockProps) {\n const [active, setActive] = useState(0);\n const list = tabs ?? [];\n return (\n <div className={cn(\"w-full\", className)}>\n <div role=\"tablist\" className=\"mb-4 flex gap-1 border-b\">\n {list.map((t, idx) => (\n <button\n key={t.id}\n role=\"tab\"\n type=\"button\"\n aria-selected={idx === active}\n onClick={() => setActive(idx)}\n className={cn(\n \"cursor-pointer border-b-2 border-transparent bg-transparent px-4 py-2\",\n idx === active && \"border-black font-semibold\",\n )}\n >\n {t.label}\n </button>\n ))}\n </div>\n {list.map((t, idx) => (\n <div key={t.id} role=\"tabpanel\" hidden={idx !== active} className=\"flex flex-col gap-4\">\n {(t.children ?? []).map((b) => (\n <span key={b.id}>{renderBlock ? renderBlock(b) : null}</span>\n ))}\n </div>\n ))}\n </div>\n );\n}\n","import type { ComponentProps as BcmsComponentProps, FormProps } from \"@betttercms/types\";\nimport { cn } from \"../lib/utils\";\n\nconst box =\n \"rounded border border-dashed border-neutral-300 bg-neutral-50 p-4 text-sm text-neutral-500\";\n\n/**\n * Builder-preview placeholder for a `component` instance. Live instance resolution\n * (definition lookup + override merge) happens server-side in the delivery renderer\n * and in the page-builder, which pass a resolver — the standalone library preview\n * just shows what's referenced.\n */\nexport function ComponentInstance({\n componentId,\n className = \"\",\n}: BcmsComponentProps & { className?: string }) {\n return (\n <div className={cn(box, className)}>\n Component instance: <code>{componentId}</code>\n </div>\n );\n}\n\n/** Builder-preview placeholder for a `form` block (rendered live by @betttercms/next). */\nexport function FormPlaceholder({ formId, className = \"\" }: FormProps & { className?: string }) {\n return (\n <div className={cn(box, className)}>\n Form: <code>{formId}</code>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsx","jsxs","jsx","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs"]}
@@ -0,0 +1,12 @@
1
+ export { B as Button, C as Columns, H as Heading, I as Image, S as Spacer, T as Text, V as Video } from './Video-Dd3TLlXA.js';
2
+ export { BLOCK_REGISTRY, BLOCK_TYPES, BlockRegistryEntry } from './registry.js';
3
+ export { BlockRenderer, BlocksRenderer } from './renderer.js';
4
+ import { ClassValue } from 'clsx';
5
+ import 'react/jsx-runtime';
6
+ import '@betttercms/types';
7
+ import 'react';
8
+ import '@bettercms-ai/types';
9
+
10
+ declare function cn(...inputs: ClassValue[]): string;
11
+
12
+ export { cn };