@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 +96 -0
- package/dist/Video-Dd3TLlXA.d.ts +45 -0
- package/dist/blocks.d.ts +48 -0
- package/dist/blocks.js +344 -0
- package/dist/blocks.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +514 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +16 -0
- package/dist/registry.js +407 -0
- package/dist/registry.js.map +1 -0
- package/dist/renderer.d.ts +18 -0
- package/dist/renderer.js +504 -0
- package/dist/renderer.js.map +1 -0
- package/dist/resolve.d.ts +40 -0
- package/dist/resolve.js +58 -0
- package/dist/resolve.js.map +1 -0
- package/package.json +79 -0
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 };
|
package/dist/blocks.d.ts
ADDED
|
@@ -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 ‹\n </button>\n <button type=\"button\" aria-label=\"Next\" onClick={() => go(i + 1)} className={cn(btn, \"right-2\")}>\n ›\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"]}
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|