@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.
@@ -0,0 +1,407 @@
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
+
329
+ // src/registry.ts
330
+ var BLOCK_REGISTRY = {
331
+ heading: {
332
+ component: Heading,
333
+ label: "Heading",
334
+ icon: "type"
335
+ },
336
+ text: {
337
+ component: Text,
338
+ label: "Text",
339
+ icon: "align-left"
340
+ },
341
+ image: {
342
+ component: Image,
343
+ label: "Image",
344
+ icon: "image"
345
+ },
346
+ button: {
347
+ component: Button,
348
+ label: "Button",
349
+ icon: "square"
350
+ },
351
+ spacer: {
352
+ component: Spacer,
353
+ label: "Spacer",
354
+ icon: "minus"
355
+ },
356
+ columns: {
357
+ component: Columns,
358
+ label: "Columns",
359
+ icon: "columns"
360
+ },
361
+ video: {
362
+ component: Video,
363
+ label: "Video",
364
+ icon: "play"
365
+ },
366
+ section: {
367
+ component: Section,
368
+ label: "Section",
369
+ icon: "layout"
370
+ },
371
+ navbar: {
372
+ component: Navbar,
373
+ label: "Navbar",
374
+ icon: "menu"
375
+ },
376
+ footer: {
377
+ component: Footer,
378
+ label: "Footer",
379
+ icon: "panel-bottom"
380
+ },
381
+ slider: {
382
+ component: Slider,
383
+ label: "Slider",
384
+ icon: "gallery-horizontal"
385
+ },
386
+ tabs: {
387
+ component: Tabs,
388
+ label: "Tabs",
389
+ icon: "folder"
390
+ },
391
+ component: {
392
+ component: ComponentInstance,
393
+ label: "Component",
394
+ icon: "component"
395
+ },
396
+ form: {
397
+ component: FormPlaceholder,
398
+ label: "Form",
399
+ icon: "clipboard-list"
400
+ }
401
+ };
402
+ var BLOCK_TYPES = Object.keys(BLOCK_REGISTRY);
403
+ export {
404
+ BLOCK_REGISTRY,
405
+ BLOCK_TYPES
406
+ };
407
+ //# sourceMappingURL=registry.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","../src/registry.ts"],"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","import type { ContentBlock, BlockType } from \"@bettercms-ai/types\";\nimport { Heading } from \"./blocks/Heading\";\nimport { Text } from \"./blocks/Text\";\nimport { Image } from \"./blocks/Image\";\nimport { Button } from \"./blocks/Button\";\nimport { Spacer } from \"./blocks/Spacer\";\nimport { Columns } from \"./blocks/Columns\";\nimport { Video } from \"./blocks/Video\";\nimport { Section } from \"./blocks/Section\";\nimport { Navbar } from \"./blocks/Navbar\";\nimport { Footer } from \"./blocks/Footer\";\nimport { Slider } from \"./blocks/Slider\";\nimport { Tabs } from \"./blocks/Tabs\";\nimport { ComponentInstance, FormPlaceholder } from \"./blocks/Placeholders\";\n\n/**\n * Block registry entry — maps a block type to its React component\n * and metadata for the block library UI.\n */\nexport interface BlockRegistryEntry {\n component: React.ComponentType<Record<string, unknown>>;\n label: string;\n icon: string;\n}\n\nexport const BLOCK_REGISTRY: Record<BlockType, BlockRegistryEntry> = {\n heading: {\n component: Heading as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Heading\",\n icon: \"type\",\n },\n text: {\n component: Text as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Text\",\n icon: \"align-left\",\n },\n image: {\n component: Image as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Image\",\n icon: \"image\",\n },\n button: {\n component: Button as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Button\",\n icon: \"square\",\n },\n spacer: {\n component: Spacer as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Spacer\",\n icon: \"minus\",\n },\n columns: {\n component: Columns as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Columns\",\n icon: \"columns\",\n },\n video: {\n component: Video as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Video\",\n icon: \"play\",\n },\n section: {\n component: Section as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Section\",\n icon: \"layout\",\n },\n navbar: {\n component: Navbar as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Navbar\",\n icon: \"menu\",\n },\n footer: {\n component: Footer as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Footer\",\n icon: \"panel-bottom\",\n },\n slider: {\n component: Slider as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Slider\",\n icon: \"gallery-horizontal\",\n },\n tabs: {\n component: Tabs as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Tabs\",\n icon: \"folder\",\n },\n component: {\n component: ComponentInstance as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Component\",\n icon: \"component\",\n },\n form: {\n component: FormPlaceholder as unknown as React.ComponentType<Record<string, unknown>>,\n label: \"Form\",\n icon: \"clipboard-list\",\n },\n} as const;\n\nexport const BLOCK_TYPES = Object.keys(BLOCK_REGISTRY) as BlockType[];\n\nexport type { ContentBlock, BlockType };\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,18 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ContentBlock } from '@bettercms-ai/types';
3
+ import React from 'react';
4
+
5
+ interface BlockRendererProps {
6
+ block: ContentBlock;
7
+ className?: string;
8
+ renderBlock?: (block: ContentBlock) => React.ReactNode;
9
+ }
10
+ declare function BlockRenderer({ block, className, renderBlock, }: BlockRendererProps): react_jsx_runtime.JSX.Element;
11
+ interface BlocksRendererProps {
12
+ blocks: ContentBlock[];
13
+ className?: string;
14
+ renderBlock?: (block: ContentBlock) => React.ReactNode;
15
+ }
16
+ declare function BlocksRenderer({ blocks, className, renderBlock, }: BlocksRendererProps): react_jsx_runtime.JSX.Element | null;
17
+
18
+ export { BlockRenderer, BlocksRenderer };