@frontlit/page-builder 0.1.0-alpha.2 → 0.1.0-alpha.4
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 +32 -0
- package/dist/blocks/index.d.ts +33 -21
- package/dist/blocks/index.js +3 -3
- package/dist/builder/index.d.ts +7 -8
- package/dist/builder/index.js +6 -5
- package/dist/{button-Bzt1GDO-.d.ts → button-OLKN3wPf.d.ts} +2 -2
- package/dist/{chunk-H4P5MFJI.js → chunk-36QHCIPM.js} +205 -251
- package/dist/chunk-36QHCIPM.js.map +1 -0
- package/dist/chunk-BBI7UHOA.js +56 -0
- package/dist/chunk-BBI7UHOA.js.map +1 -0
- package/dist/{chunk-KQKSLI3L.js → chunk-GIKTOAQS.js} +335 -122
- package/dist/chunk-GIKTOAQS.js.map +1 -0
- package/dist/chunk-HWOVSHIW.js +4 -0
- package/dist/{chunk-RUYOL7JZ.js.map → chunk-HWOVSHIW.js.map} +1 -1
- package/dist/{chunk-HDINUNI2.js → chunk-IU4KATI2.js} +69 -96
- package/dist/chunk-IU4KATI2.js.map +1 -0
- package/dist/{chunk-SGNRWWG3.js → chunk-J7Z4UW45.js} +530 -135
- package/dist/chunk-J7Z4UW45.js.map +1 -0
- package/dist/{chunk-UO7XGBGM.js → chunk-K4WCLHMS.js} +1182 -1033
- package/dist/chunk-K4WCLHMS.js.map +1 -0
- package/dist/components/index.d.ts +33 -8
- package/dist/components/index.js +42 -2
- package/dist/components/index.js.map +1 -1
- package/dist/data-slots.d.ts +3 -3
- package/dist/fonts/archivo/archivo-latin-variable.woff2 +0 -0
- package/dist/fonts/hanken-grotesk/hanken-grotesk-latin-variable.woff2 +0 -0
- package/dist/fonts/jetbrains-mono/jetbrains-mono-latin-variable.woff2 +0 -0
- package/dist/fonts/spline-sans-mono/spline-sans-mono-latin-variable.woff2 +0 -0
- package/dist/heading-DQCxQt38.d.ts +20 -0
- package/dist/image-Bk8kPXwP.d.ts +52 -0
- package/dist/index.d.ts +17 -10
- package/dist/index.js +7 -6
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +1 -1
- package/dist/{page-W3hQga4w.d.ts → page-B5Gmm-Ys.d.ts} +1 -1
- package/dist/primitives/index.d.ts +44 -9
- package/dist/primitives/index.js +1 -1
- package/dist/renderer/index.d.ts +12 -8
- package/dist/renderer/index.js +5 -4
- package/dist/{section-background-MsdE40Rk.d.ts → section-background-6V_LCi5e.d.ts} +1 -1
- package/dist/server/index.d.ts +103 -0
- package/dist/server/index.js +2649 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/islands/code-snippet.d.ts +17 -0
- package/dist/server/islands/code-snippet.js +72 -0
- package/dist/server/islands/code-snippet.js.map +1 -0
- package/dist/server/islands/email-form.d.ts +50 -0
- package/dist/server/islands/email-form.js +406 -0
- package/dist/server/islands/email-form.js.map +1 -0
- package/dist/server/islands/header-mobile-menu.d.ts +22 -0
- package/dist/server/islands/header-mobile-menu.js +422 -0
- package/dist/server/islands/header-mobile-menu.js.map +1 -0
- package/dist/server/islands/inline-embed.d.ts +28 -0
- package/dist/server/islands/inline-embed.js +84 -0
- package/dist/server/islands/inline-embed.js.map +1 -0
- package/dist/server/islands/marquee-track.d.ts +18 -0
- package/dist/server/islands/marquee-track.js +67 -0
- package/dist/server/islands/marquee-track.js.map +1 -0
- package/dist/server/islands/nav-link.d.ts +37 -0
- package/dist/server/islands/nav-link.js +67 -0
- package/dist/server/islands/nav-link.js.map +1 -0
- package/dist/server/islands/support-form.d.ts +17 -0
- package/dist/server/islands/support-form.js +469 -0
- package/dist/server/islands/support-form.js.map +1 -0
- package/dist/server/islands/theme-mode-switcher.d.ts +38 -0
- package/dist/server/islands/theme-mode-switcher.js +169 -0
- package/dist/server/islands/theme-mode-switcher.js.map +1 -0
- package/dist/server/islands/video-with-preview.d.ts +13 -0
- package/dist/server/islands/video-with-preview.js +269 -0
- package/dist/server/islands/video-with-preview.js.map +1 -0
- package/dist/server/primitives.d.ts +200 -0
- package/dist/server/primitives.js +888 -0
- package/dist/server/primitives.js.map +1 -0
- package/dist/server/schema.d.ts +11308 -0
- package/dist/server/schema.js +6179 -0
- package/dist/server/schema.js.map +1 -0
- package/dist/server/theme-CF3fIKvw.d.ts +9 -0
- package/dist/server/theme-style-5_AGy-4V.d.ts +183 -0
- package/dist/server/theme-style-BPaMwk88.d.ts +183 -0
- package/dist/server/theme.d.ts +28 -0
- package/dist/server/theme.js +1671 -0
- package/dist/server/theme.js.map +1 -0
- package/dist/server/widget-YH9BrOwY.d.ts +77 -0
- package/dist/styles.css +121 -15
- package/dist/{theme-style-Cbl7NM-T.d.ts → theme-style-BVd5tOsc.d.ts} +20 -0
- package/dist/theme.css +12 -0
- package/dist/{widget-B_RoG6se.d.ts → widget-CpE2HdgU.d.ts} +17 -14
- package/package.json +60 -12
- package/schema/page.v1.json +3855 -0
- package/schema/site.v1.json +3811 -0
- package/dist/alignment-dZDzN96G.d.ts +0 -5
- package/dist/chunk-H4P5MFJI.js.map +0 -1
- package/dist/chunk-HDINUNI2.js.map +0 -1
- package/dist/chunk-KQKSLI3L.js.map +0 -1
- package/dist/chunk-RUYOL7JZ.js +0 -4
- package/dist/chunk-SGNRWWG3.js.map +0 -1
- package/dist/chunk-UO7XGBGM.js.map +0 -1
- package/dist/image-DAWVx1zQ.d.ts +0 -31
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
// src/blocks/header/mobile-menu.tsx
|
|
5
|
+
import { useState as useState2 } from "react";
|
|
6
|
+
import { MenuIcon } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
// src/components/nav-link.tsx
|
|
9
|
+
import * as React from "react";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
var LINK_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("@frontlit/page-builder/link-context");
|
|
12
|
+
var globalRegistry = globalThis;
|
|
13
|
+
var PageBuilderLinkContext = globalRegistry[LINK_CONTEXT_KEY] ?? (globalRegistry[LINK_CONTEXT_KEY] = React.createContext(null));
|
|
14
|
+
function usePageBuilderLinkComponent() {
|
|
15
|
+
return React.useContext(PageBuilderLinkContext);
|
|
16
|
+
}
|
|
17
|
+
function NavLink({
|
|
18
|
+
href,
|
|
19
|
+
children,
|
|
20
|
+
openInSameTab = true,
|
|
21
|
+
style,
|
|
22
|
+
className = "",
|
|
23
|
+
onClick
|
|
24
|
+
}) {
|
|
25
|
+
const LinkComponent = usePageBuilderLinkComponent();
|
|
26
|
+
const isInternal = Boolean(href && href.startsWith("/"));
|
|
27
|
+
const isInPageNavigation = Boolean(href && href.startsWith("#"));
|
|
28
|
+
const target = openInSameTab ? void 0 : "_blank";
|
|
29
|
+
const rel = target === "_blank" ? "noopener noreferrer" : void 0;
|
|
30
|
+
const handleClick = () => {
|
|
31
|
+
onClick?.();
|
|
32
|
+
};
|
|
33
|
+
if (!isInPageNavigation && isInternal && LinkComponent) {
|
|
34
|
+
return /* @__PURE__ */ jsx(
|
|
35
|
+
LinkComponent,
|
|
36
|
+
{
|
|
37
|
+
href,
|
|
38
|
+
style,
|
|
39
|
+
className,
|
|
40
|
+
onClick: handleClick,
|
|
41
|
+
target,
|
|
42
|
+
rel,
|
|
43
|
+
children
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return /* @__PURE__ */ jsx(
|
|
48
|
+
"a",
|
|
49
|
+
{
|
|
50
|
+
href,
|
|
51
|
+
style,
|
|
52
|
+
className,
|
|
53
|
+
target,
|
|
54
|
+
rel,
|
|
55
|
+
onClick: handleClick,
|
|
56
|
+
children
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/primitives/lib/utils.ts
|
|
62
|
+
import { clsx } from "clsx";
|
|
63
|
+
import { twMerge } from "tailwind-merge";
|
|
64
|
+
function cn(...inputs) {
|
|
65
|
+
return twMerge(clsx(inputs));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/primitives/components/ui/button.tsx
|
|
69
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
70
|
+
import { cva } from "class-variance-authority";
|
|
71
|
+
import * as React2 from "react";
|
|
72
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
73
|
+
var buttonVariants = cva(
|
|
74
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
75
|
+
{
|
|
76
|
+
variants: {
|
|
77
|
+
variant: {
|
|
78
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
79
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
80
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
81
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
82
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
83
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
84
|
+
},
|
|
85
|
+
size: {
|
|
86
|
+
default: "h-10 px-4 py-2",
|
|
87
|
+
sm: "h-9 rounded-md px-3",
|
|
88
|
+
lg: "h-11 rounded-md px-8",
|
|
89
|
+
icon: "h-10 w-10"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
defaultVariants: {
|
|
93
|
+
variant: "default",
|
|
94
|
+
size: "default"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
var Button = React2.forwardRef(
|
|
99
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
100
|
+
const Comp = asChild ? Slot : "button";
|
|
101
|
+
return /* @__PURE__ */ jsx2(
|
|
102
|
+
Comp,
|
|
103
|
+
{
|
|
104
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
105
|
+
ref,
|
|
106
|
+
...props
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
Button.displayName = "Button";
|
|
112
|
+
|
|
113
|
+
// src/primitives/button.tsx
|
|
114
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
115
|
+
var Button2 = ({
|
|
116
|
+
variant = "default",
|
|
117
|
+
size = "default",
|
|
118
|
+
disabled = false,
|
|
119
|
+
children,
|
|
120
|
+
className = "",
|
|
121
|
+
theme,
|
|
122
|
+
...props
|
|
123
|
+
}) => {
|
|
124
|
+
const buttonStyles = theme?.interactives?.button;
|
|
125
|
+
const typographyStyles = theme?.typography?.button;
|
|
126
|
+
const isIcon = size === "icon";
|
|
127
|
+
const classes = cn(
|
|
128
|
+
// Base styles
|
|
129
|
+
"",
|
|
130
|
+
// Theme typography
|
|
131
|
+
typographyStyles?.fontFamily,
|
|
132
|
+
typographyStyles?.fontSize,
|
|
133
|
+
typographyStyles?.fontWeight,
|
|
134
|
+
typographyStyles?.lineHeight,
|
|
135
|
+
typographyStyles?.letterSpacing,
|
|
136
|
+
typographyStyles?.textTransform,
|
|
137
|
+
typographyStyles?.textDecoration,
|
|
138
|
+
typographyStyles?.textOverflow,
|
|
139
|
+
// Theme interactivity. Icon buttons stay square — CTA padding
|
|
140
|
+
// would stretch them off the size="icon" box.
|
|
141
|
+
!isIcon && buttonStyles?.padding?.x,
|
|
142
|
+
!isIcon && buttonStyles?.padding?.y,
|
|
143
|
+
buttonStyles?.border?.width,
|
|
144
|
+
buttonStyles?.border?.radius,
|
|
145
|
+
buttonStyles?.border?.style,
|
|
146
|
+
// buttonStyles?.border?.color,
|
|
147
|
+
buttonStyles?.shadow,
|
|
148
|
+
// Theme disabled states
|
|
149
|
+
disabled && buttonStyles?.disabled?.opacity,
|
|
150
|
+
disabled && buttonStyles?.disabled?.cursor,
|
|
151
|
+
disabled && buttonStyles?.disabled?.color,
|
|
152
|
+
disabled && buttonStyles?.disabled?.background,
|
|
153
|
+
disabled && buttonStyles?.disabled?.border,
|
|
154
|
+
// User overrides
|
|
155
|
+
buttonStyles?.custom,
|
|
156
|
+
className
|
|
157
|
+
);
|
|
158
|
+
return /* @__PURE__ */ jsx3(
|
|
159
|
+
Button,
|
|
160
|
+
{
|
|
161
|
+
variant,
|
|
162
|
+
size,
|
|
163
|
+
disabled,
|
|
164
|
+
className: classes,
|
|
165
|
+
...props,
|
|
166
|
+
children
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/primitives/drawer.tsx
|
|
172
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
173
|
+
|
|
174
|
+
// src/primitives/components/ui/sheet.tsx
|
|
175
|
+
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
176
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
177
|
+
import { X } from "lucide-react";
|
|
178
|
+
import * as React3 from "react";
|
|
179
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
180
|
+
var Sheet = SheetPrimitive.Root;
|
|
181
|
+
var SheetTrigger = SheetPrimitive.Trigger;
|
|
182
|
+
var SheetPortal = SheetPrimitive.Portal;
|
|
183
|
+
var SheetOverlay = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
184
|
+
SheetPrimitive.Overlay,
|
|
185
|
+
{
|
|
186
|
+
className: cn(
|
|
187
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
188
|
+
className
|
|
189
|
+
),
|
|
190
|
+
...props,
|
|
191
|
+
ref
|
|
192
|
+
}
|
|
193
|
+
));
|
|
194
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
195
|
+
var sheetVariants = cva2(
|
|
196
|
+
"fixed z-50 gap-4 bg-background p-6 text-foreground shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
197
|
+
{
|
|
198
|
+
variants: {
|
|
199
|
+
side: {
|
|
200
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
201
|
+
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
202
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
203
|
+
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
defaultVariants: {
|
|
207
|
+
side: "right"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
var SheetContent = React3.forwardRef(({ side = "right", className, children, container, ...props }, ref) => /* @__PURE__ */ jsxs(SheetPortal, { container: container ?? void 0, children: [
|
|
212
|
+
/* @__PURE__ */ jsx4(SheetOverlay, {}),
|
|
213
|
+
/* @__PURE__ */ jsxs(
|
|
214
|
+
SheetPrimitive.Content,
|
|
215
|
+
{
|
|
216
|
+
ref,
|
|
217
|
+
className: cn(sheetVariants({ side }), className),
|
|
218
|
+
...props,
|
|
219
|
+
children: [
|
|
220
|
+
children,
|
|
221
|
+
/* @__PURE__ */ jsxs(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
|
|
222
|
+
/* @__PURE__ */ jsx4(X, { className: "h-4 w-4" }),
|
|
223
|
+
/* @__PURE__ */ jsx4("span", { className: "sr-only", children: "Close" })
|
|
224
|
+
] })
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
] }));
|
|
229
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
230
|
+
var SheetHeader = ({ className, ...props }) => /* @__PURE__ */ jsx4(
|
|
231
|
+
"div",
|
|
232
|
+
{
|
|
233
|
+
className: cn("flex flex-col space-y-2 text-center sm:text-left", className),
|
|
234
|
+
...props
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
SheetHeader.displayName = "SheetHeader";
|
|
238
|
+
var SheetFooter = ({ className, ...props }) => /* @__PURE__ */ jsx4(
|
|
239
|
+
"div",
|
|
240
|
+
{
|
|
241
|
+
className: cn(
|
|
242
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
243
|
+
className
|
|
244
|
+
),
|
|
245
|
+
...props
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
SheetFooter.displayName = "SheetFooter";
|
|
249
|
+
var SheetTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
250
|
+
SheetPrimitive.Title,
|
|
251
|
+
{
|
|
252
|
+
ref,
|
|
253
|
+
className: cn("text-lg font-semibold text-foreground", className),
|
|
254
|
+
...props
|
|
255
|
+
}
|
|
256
|
+
));
|
|
257
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
258
|
+
var SheetDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
259
|
+
SheetPrimitive.Description,
|
|
260
|
+
{
|
|
261
|
+
ref,
|
|
262
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
263
|
+
...props
|
|
264
|
+
}
|
|
265
|
+
));
|
|
266
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
267
|
+
|
|
268
|
+
// src/primitives/drawer.tsx
|
|
269
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
270
|
+
function Drawer({
|
|
271
|
+
trigger,
|
|
272
|
+
children,
|
|
273
|
+
side = "left",
|
|
274
|
+
open,
|
|
275
|
+
setOpen,
|
|
276
|
+
style,
|
|
277
|
+
className = "",
|
|
278
|
+
theme: _theme
|
|
279
|
+
}) {
|
|
280
|
+
const triggerWrapRef = useRef(null);
|
|
281
|
+
const [container, setContainer] = useState(null);
|
|
282
|
+
useLayoutEffect(() => {
|
|
283
|
+
const root = triggerWrapRef.current?.closest(
|
|
284
|
+
"[data-pb-theme], .pb-theme"
|
|
285
|
+
);
|
|
286
|
+
setContainer(root ?? null);
|
|
287
|
+
}, []);
|
|
288
|
+
return /* @__PURE__ */ jsxs2(Sheet, { open, onOpenChange: setOpen, children: [
|
|
289
|
+
/* @__PURE__ */ jsx5(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx5("span", { ref: triggerWrapRef, children: trigger }) }),
|
|
290
|
+
/* @__PURE__ */ jsx5(
|
|
291
|
+
SheetContent,
|
|
292
|
+
{
|
|
293
|
+
side,
|
|
294
|
+
style,
|
|
295
|
+
container,
|
|
296
|
+
className: cn(
|
|
297
|
+
"bg-background text-foreground",
|
|
298
|
+
!container && "pb-theme",
|
|
299
|
+
className
|
|
300
|
+
),
|
|
301
|
+
children
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
] });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/primitives/link.tsx
|
|
308
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
309
|
+
var Link = ({
|
|
310
|
+
children,
|
|
311
|
+
className = "",
|
|
312
|
+
theme,
|
|
313
|
+
disabled = false,
|
|
314
|
+
style,
|
|
315
|
+
...props
|
|
316
|
+
}) => {
|
|
317
|
+
const typographyStyles = theme?.typography?.link;
|
|
318
|
+
const linkStyles = theme?.interactives?.link;
|
|
319
|
+
const classes = cn(
|
|
320
|
+
// Base styles
|
|
321
|
+
"font-medium cursor-pointer",
|
|
322
|
+
// Theme typography
|
|
323
|
+
typographyStyles?.fontFamily,
|
|
324
|
+
typographyStyles?.fontSize,
|
|
325
|
+
typographyStyles?.fontWeight,
|
|
326
|
+
typographyStyles?.lineHeight,
|
|
327
|
+
typographyStyles?.letterSpacing,
|
|
328
|
+
typographyStyles?.textTransform,
|
|
329
|
+
typographyStyles?.textDecoration,
|
|
330
|
+
typographyStyles?.textOverflow,
|
|
331
|
+
// Theme interactivity
|
|
332
|
+
linkStyles?.padding?.x,
|
|
333
|
+
linkStyles?.padding?.y,
|
|
334
|
+
linkStyles?.border?.width,
|
|
335
|
+
linkStyles?.border?.radius,
|
|
336
|
+
linkStyles?.border?.style,
|
|
337
|
+
// Theme disabled states
|
|
338
|
+
disabled && linkStyles?.disabled?.color,
|
|
339
|
+
disabled && linkStyles?.disabled?.background,
|
|
340
|
+
disabled && linkStyles?.disabled?.border,
|
|
341
|
+
disabled && linkStyles?.disabled?.opacity,
|
|
342
|
+
disabled && linkStyles?.disabled?.cursor,
|
|
343
|
+
// User overrides
|
|
344
|
+
linkStyles?.custom,
|
|
345
|
+
className
|
|
346
|
+
);
|
|
347
|
+
return /* @__PURE__ */ jsx6(
|
|
348
|
+
"span",
|
|
349
|
+
{
|
|
350
|
+
className: classes,
|
|
351
|
+
style: {
|
|
352
|
+
...style,
|
|
353
|
+
textShadow: linkStyles?.textShadow || void 0
|
|
354
|
+
},
|
|
355
|
+
...props,
|
|
356
|
+
children
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// src/blocks/header/header-link.tsx
|
|
362
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
363
|
+
function HeaderLink({
|
|
364
|
+
link,
|
|
365
|
+
theme,
|
|
366
|
+
onClick,
|
|
367
|
+
fullWidth = false
|
|
368
|
+
}) {
|
|
369
|
+
if (link.isButton) {
|
|
370
|
+
return /* @__PURE__ */ jsx7(NavLink, { href: link.href, onClick, children: /* @__PURE__ */ jsx7(
|
|
371
|
+
Button2,
|
|
372
|
+
{
|
|
373
|
+
size: fullWidth ? void 0 : "sm",
|
|
374
|
+
theme,
|
|
375
|
+
className: fullWidth ? "w-full" : void 0,
|
|
376
|
+
children: link.label
|
|
377
|
+
}
|
|
378
|
+
) });
|
|
379
|
+
}
|
|
380
|
+
return /* @__PURE__ */ jsx7(NavLink, { href: link.href, onClick, className: "no-underline", children: /* @__PURE__ */ jsx7(Link, { theme, className: "no-underline", children: link.label }) });
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/blocks/header/mobile-menu.tsx
|
|
384
|
+
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
385
|
+
function HeaderMobileMenu({
|
|
386
|
+
links,
|
|
387
|
+
ctaLabel,
|
|
388
|
+
ctaHref,
|
|
389
|
+
theme
|
|
390
|
+
}) {
|
|
391
|
+
const [open, setOpen] = useState2(false);
|
|
392
|
+
return /* @__PURE__ */ jsx8(
|
|
393
|
+
Drawer,
|
|
394
|
+
{
|
|
395
|
+
open,
|
|
396
|
+
setOpen,
|
|
397
|
+
side: "right",
|
|
398
|
+
theme,
|
|
399
|
+
trigger: /* @__PURE__ */ jsxs3(Button2, { variant: "outline", size: "sm", theme, children: [
|
|
400
|
+
/* @__PURE__ */ jsx8(MenuIcon, { className: "h-4 w-4" }),
|
|
401
|
+
/* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Toggle menu" })
|
|
402
|
+
] }),
|
|
403
|
+
children: /* @__PURE__ */ jsxs3("div", { className: "mt-6 flex flex-col gap-4", children: [
|
|
404
|
+
links.map((link) => /* @__PURE__ */ jsx8(
|
|
405
|
+
HeaderLink,
|
|
406
|
+
{
|
|
407
|
+
link,
|
|
408
|
+
theme,
|
|
409
|
+
onClick: () => setOpen(false),
|
|
410
|
+
fullWidth: true
|
|
411
|
+
},
|
|
412
|
+
link.id
|
|
413
|
+
)),
|
|
414
|
+
ctaLabel && ctaHref && /* @__PURE__ */ jsx8(NavLink, { href: ctaHref, onClick: () => setOpen(false), children: /* @__PURE__ */ jsx8(Button2, { theme, className: "w-full", children: ctaLabel }) })
|
|
415
|
+
] })
|
|
416
|
+
}
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
export {
|
|
420
|
+
HeaderMobileMenu
|
|
421
|
+
};
|
|
422
|
+
//# sourceMappingURL=header-mobile-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/header/mobile-menu.tsx","../../../src/components/nav-link.tsx","../../../src/primitives/lib/utils.ts","../../../src/primitives/components/ui/button.tsx","../../../src/primitives/button.tsx","../../../src/primitives/drawer.tsx","../../../src/primitives/components/ui/sheet.tsx","../../../src/primitives/link.tsx","../../../src/blocks/header/header-link.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { MenuIcon } from \"lucide-react\";\nimport type { ThemeStyle } from \"../../models\";\nimport type { HeaderNavLink } from \"./settings\";\nimport { NavLink } from \"../../components/nav-link\";\nimport { Button, Drawer } from \"../../primitives\";\nimport { HeaderLink } from \"./header-link\";\n\n/**\n * The header's mobile drawer. It is the only interactive part of the header,\n * so it is the only part sent to the browser on server-rendered pages.\n */\nexport function HeaderMobileMenu({\n links,\n ctaLabel,\n ctaHref,\n theme,\n}: {\n links: HeaderNavLink[];\n ctaLabel?: string;\n ctaHref?: string;\n theme: ThemeStyle;\n}) {\n const [open, setOpen] = useState(false);\n\n return (\n <Drawer\n open={open}\n setOpen={setOpen}\n side=\"right\"\n theme={theme}\n trigger={\n <Button variant=\"outline\" size=\"sm\" theme={theme}>\n <MenuIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">Toggle menu</span>\n </Button>\n }\n >\n <div className=\"mt-6 flex flex-col gap-4\">\n {links.map((link) => (\n <HeaderLink\n key={link.id}\n link={link}\n theme={theme}\n onClick={() => setOpen(false)}\n fullWidth\n />\n ))}\n {ctaLabel && ctaHref && (\n <NavLink href={ctaHref} onClick={() => setOpen(false)}>\n <Button theme={theme} className=\"w-full\">\n {ctaLabel}\n </Button>\n </NavLink>\n )}\n </div>\n </Drawer>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nexport interface PageBuilderLinkProps {\n href: string;\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n onClick?: React.MouseEventHandler<HTMLAnchorElement>;\n target?: string;\n rel?: string;\n}\n\n/**\n * Optional host-supplied link. Next.js apps can pass `next/link`; Vite / Remix\n * / plain React hosts can omit it and NavLink will render a native `<a>`.\n */\nexport type PageBuilderLinkComponent = React.ComponentType<PageBuilderLinkProps>;\n\n// Server-rendered pages load this module more than once (each client island is\n// bundled on its own), so the context is shared through the global registry\n// rather than created per copy. Otherwise a provider from one copy would be\n// invisible to a NavLink from another.\nconst LINK_CONTEXT_KEY = Symbol.for(\"@frontlit/page-builder/link-context\");\nconst globalRegistry = globalThis as typeof globalThis & {\n [LINK_CONTEXT_KEY]?: React.Context<PageBuilderLinkComponent | null>;\n};\nconst PageBuilderLinkContext = (globalRegistry[LINK_CONTEXT_KEY] ??=\n React.createContext<PageBuilderLinkComponent | null>(null));\n\nexport function PageBuilderLinkProvider({\n component,\n children,\n}: {\n component?: PageBuilderLinkComponent | null;\n children: React.ReactNode;\n}) {\n return (\n <PageBuilderLinkContext.Provider value={component ?? null}>\n {children}\n </PageBuilderLinkContext.Provider>\n );\n}\n\nexport function usePageBuilderLinkComponent() {\n return React.useContext(PageBuilderLinkContext);\n}\n\ninterface NavLinkProps {\n href: string;\n children?: React.ReactNode;\n openInSameTab?: boolean;\n style?: React.CSSProperties;\n className?: string;\n onClick?: () => void;\n}\n\n/**\n * A navigation-aware link used inside block widgets. In-page anchors scroll\n * to the target. Internal paths (`/...`) use the host `linkComponent` when\n * one is provided (e.g. Next.js `Link`); everything else is a native `<a>`.\n */\nexport function NavLink({\n href,\n children,\n openInSameTab = true,\n style,\n className = \"\",\n onClick,\n}: NavLinkProps) {\n const LinkComponent = usePageBuilderLinkComponent();\n const isInternal = Boolean(href && href.startsWith(\"/\"));\n const isInPageNavigation = Boolean(href && href.startsWith(\"#\"));\n const target = openInSameTab ? undefined : \"_blank\";\n const rel = target === \"_blank\" ? \"noopener noreferrer\" : undefined;\n const handleClick: React.MouseEventHandler<HTMLAnchorElement> = () => {\n onClick?.();\n };\n\n if (!isInPageNavigation && isInternal && LinkComponent) {\n return (\n <LinkComponent\n href={href}\n style={style}\n className={className}\n onClick={handleClick}\n target={target}\n rel={rel}\n >\n {children}\n </LinkComponent>\n );\n }\n\n return (\n <a\n href={href}\n style={style}\n className={className}\n target={target}\n rel={rel}\n onClick={handleClick}\n >\n {children}\n </a>\n );\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n ref={ref}\n {...props}\n />\n );\n },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import type React from \"react\";\nimport type { ThemeStyle } from \"../models\";\nimport {\n Button as ShadcnButton,\n type ButtonProps as ShadcnButtonProps,\n} from \"./components/ui/button\";\nimport { cn } from \"./lib/utils\";\n\nexport interface ButtonProps extends ShadcnButtonProps {\n theme?: ThemeStyle;\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = \"default\",\n size = \"default\",\n disabled = false,\n children,\n className = \"\",\n theme,\n ...props\n}) => {\n const buttonStyles = theme?.interactives?.button;\n const typographyStyles = theme?.typography?.button;\n const isIcon = size === \"icon\";\n\n const classes = cn(\n // Base styles\n \"\",\n // Theme typography\n typographyStyles?.fontFamily,\n typographyStyles?.fontSize,\n typographyStyles?.fontWeight,\n typographyStyles?.lineHeight,\n typographyStyles?.letterSpacing,\n typographyStyles?.textTransform,\n typographyStyles?.textDecoration,\n typographyStyles?.textOverflow,\n // Theme interactivity. Icon buttons stay square — CTA padding\n // would stretch them off the size=\"icon\" box.\n !isIcon && buttonStyles?.padding?.x,\n !isIcon && buttonStyles?.padding?.y,\n buttonStyles?.border?.width,\n buttonStyles?.border?.radius,\n buttonStyles?.border?.style,\n // buttonStyles?.border?.color,\n buttonStyles?.shadow,\n // Theme disabled states\n disabled && buttonStyles?.disabled?.opacity,\n disabled && buttonStyles?.disabled?.cursor,\n disabled && buttonStyles?.disabled?.color,\n disabled && buttonStyles?.disabled?.background,\n disabled && buttonStyles?.disabled?.border,\n // User overrides\n buttonStyles?.custom,\n className,\n );\n\n return (\n <ShadcnButton\n variant={variant}\n size={size}\n disabled={disabled}\n className={classes}\n {...props}\n >\n {children}\n </ShadcnButton>\n );\n};\n","\"use client\";\n\nimport { type ReactNode, useLayoutEffect, useRef, useState } from \"react\";\nimport type { ThemeStyle } from \"../models\";\nimport { Sheet, SheetContent, SheetTrigger } from \"./components/ui/sheet\";\nimport { cn } from \"./lib/utils\";\n\ninterface DrawerProps {\n trigger: ReactNode;\n children: ReactNode;\n side?: \"left\" | \"right\" | \"top\" | \"bottom\";\n open: boolean;\n setOpen: (open: boolean) => void;\n style?: React.CSSProperties;\n className?: string;\n theme?: ThemeStyle;\n}\n\nexport function Drawer({\n trigger,\n children,\n side = \"left\",\n open,\n setOpen,\n style,\n className = \"\",\n theme: _theme,\n}: DrawerProps) {\n const triggerWrapRef = useRef<HTMLSpanElement>(null);\n const [container, setContainer] = useState<HTMLElement | null>(null);\n\n useLayoutEffect(() => {\n const root = triggerWrapRef.current?.closest<HTMLElement>(\n \"[data-pb-theme], .pb-theme\",\n );\n // Not `instanceof HTMLElement`: inside the builder's preview iframe the\n // root belongs to the iframe's realm, so that check always fails and the\n // sheet would open over the whole editor instead of the preview.\n setContainer(root ?? null);\n }, []);\n\n return (\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger asChild>\n <span ref={triggerWrapRef}>{trigger}</span>\n </SheetTrigger>\n <SheetContent\n side={side}\n style={style}\n container={container}\n className={cn(\n \"bg-background text-foreground\",\n !container && \"pb-theme\",\n className,\n )}\n >\n {children}\n </SheetContent>\n </Sheet>\n );\n}\n","import * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst Sheet = SheetPrimitive.Root;\n\nconst SheetTrigger = SheetPrimitive.Trigger;\n\nconst SheetClose = SheetPrimitive.Close;\n\nconst SheetPortal = SheetPrimitive.Portal;\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName;\n\nconst sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 text-foreground shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n {\n variants: {\n side: {\n top: \"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n },\n);\n\ninterface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n /** Mount the overlay and panel here so scoped theme tokens still apply. */\n container?: HTMLElement | null;\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = \"right\", className, children, container, ...props }, ref) => (\n <SheetPortal container={container ?? undefined}>\n <SheetOverlay />\n <SheetPrimitive.Content\n ref={ref}\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPortal>\n));\nSheetContent.displayName = SheetPrimitive.Content.displayName;\n\nconst SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\"flex flex-col space-y-2 text-center sm:text-left\", className)}\n {...props}\n />\n);\nSheetHeader.displayName = \"SheetHeader\";\n\nconst SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nSheetFooter.displayName = \"SheetFooter\";\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold text-foreground\", className)}\n {...props}\n />\n));\nSheetTitle.displayName = SheetPrimitive.Title.displayName;\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nSheetDescription.displayName = SheetPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n};\n","import type React from \"react\";\nimport type { ThemeStyle } from \"../models\";\nimport { cn } from \"./lib/utils\";\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n children: React.ReactNode;\n className?: string;\n theme?: ThemeStyle;\n disabled?: boolean;\n style?: React.CSSProperties;\n}\n\nexport const Link: React.FC<LinkProps> = ({\n children,\n className = \"\",\n theme,\n disabled = false,\n style,\n ...props\n}) => {\n const typographyStyles = theme?.typography?.link;\n const linkStyles = theme?.interactives?.link;\n const classes = cn(\n // Base styles\n \"font-medium cursor-pointer\",\n // Theme typography\n typographyStyles?.fontFamily,\n typographyStyles?.fontSize,\n typographyStyles?.fontWeight,\n typographyStyles?.lineHeight,\n typographyStyles?.letterSpacing,\n typographyStyles?.textTransform,\n typographyStyles?.textDecoration,\n typographyStyles?.textOverflow,\n // Theme interactivity\n linkStyles?.padding?.x,\n linkStyles?.padding?.y,\n linkStyles?.border?.width,\n linkStyles?.border?.radius,\n linkStyles?.border?.style,\n // Theme disabled states\n disabled && linkStyles?.disabled?.color,\n disabled && linkStyles?.disabled?.background,\n disabled && linkStyles?.disabled?.border,\n disabled && linkStyles?.disabled?.opacity,\n disabled && linkStyles?.disabled?.cursor,\n // User overrides\n linkStyles?.custom,\n className,\n );\n\n return (\n <span\n className={classes}\n style={{\n ...style,\n textShadow: linkStyles?.textShadow || undefined,\n }}\n {...props}\n >\n {children}\n </span>\n );\n};\n","import type { ThemeStyle } from \"../../models\";\nimport type { HeaderNavLink } from \"./settings\";\nimport { NavLink } from \"../../components/nav-link\";\nimport { Button, Link as PrimitiveLink } from \"../../primitives\";\n\nexport function HeaderLink({\n link,\n theme,\n onClick,\n fullWidth = false,\n}: {\n link: HeaderNavLink;\n theme?: ThemeStyle;\n onClick?: () => void;\n /** Mobile menu: button links span the sheet, like the CTA. */\n fullWidth?: boolean;\n}) {\n if (link.isButton) {\n return (\n <NavLink href={link.href} onClick={onClick}>\n <Button\n size={fullWidth ? undefined : \"sm\"}\n theme={theme}\n className={fullWidth ? \"w-full\" : undefined}\n >\n {link.label}\n </Button>\n </NavLink>\n );\n }\n\n return (\n <NavLink href={link.href} onClick={onClick} className=\"no-underline\">\n <PrimitiveLink theme={theme} className=\"no-underline\">\n {link.label}\n </PrimitiveLink>\n </NavLink>\n );\n}\n"],"mappings":"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","names":["useState","React","jsx","jsx","Button","cva","React","jsx","jsx","cva","jsx","jsxs","jsx","jsx","Button","jsx","jsxs","useState","Button"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
|
|
3
|
+
interface InlineEmbedProps {
|
|
4
|
+
content: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
style?: React__default.CSSProperties;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Snippets are usually written as a standalone document (they used to live in
|
|
10
|
+
* an iframe). Recreate that inside the shadow root: the host plays `html` and
|
|
11
|
+
* is a size container, a wrapper plays `body`, and viewport units and width
|
|
12
|
+
* media queries are rewritten to measure the embed (as they measured the
|
|
13
|
+
* iframe) instead of the browser window. "Fill the frame" heights are dropped,
|
|
14
|
+
* as are scripts that only synced state with `window.parent`, which the shadow
|
|
15
|
+
* host handles itself.
|
|
16
|
+
*/
|
|
17
|
+
declare function prepareEmbed(content: string): {
|
|
18
|
+
links: string;
|
|
19
|
+
body: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Renders a raw HTML snippet inline, inside a declarative shadow root. The
|
|
23
|
+
* markup is part of the server-rendered page (so crawlers index it) while its
|
|
24
|
+
* styles stay isolated from the site's in both directions.
|
|
25
|
+
*/
|
|
26
|
+
declare const InlineEmbed: ({ content, className, style }: InlineEmbedProps) => React__default.JSX.Element;
|
|
27
|
+
|
|
28
|
+
export { InlineEmbed, prepareEmbed };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
// src/components/inline-embed.tsx
|
|
5
|
+
import { useEffect, useRef } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
var HOISTED_LINK = /<link\b[^>]*(?:rel=["']?(?:preconnect|dns-prefetch|preload)|href=["'][^"']*fonts?\.)[^>]*>/gi;
|
|
8
|
+
function prepareEmbed(content) {
|
|
9
|
+
const links = content.match(HOISTED_LINK)?.join("") ?? "";
|
|
10
|
+
const markup = content.replace(HOISTED_LINK, "").replace(/<!doctype[^>]*>|<\/?(?:html|head|body)\b[^>]*>/gi, "").replace(
|
|
11
|
+
/<script\b[^>]*>(?:(?!<\/script>)[\s\S])*window\.parent[\s\S]*?<\/script>/gi,
|
|
12
|
+
""
|
|
13
|
+
).replace(
|
|
14
|
+
/<style\b([^>]*)>([\s\S]*?)<\/style>/gi,
|
|
15
|
+
(_, attrs, css) => {
|
|
16
|
+
const scoped = css.replace(/:root\b/g, ":host").replace(/(^|[\s,{}])html\.dark\b/g, "$1:host(.dark)").replace(/(^|[\s,{}])html(?=[\s,{:.[>~+])/g, "$1:host").replace(/(^|[\s,{}])body(?=[\s,{:.[>~+])/g, "$1[data-embed-body]").replace(/min-height\s*:\s*100d?vh/gi, "min-height:0").replace(/(\d*\.?\d+)vw\b/gi, "$1cqw").replace(
|
|
17
|
+
/@media\s+(?:only\s+)?(?:screen\s+and\s+)?(\([^{]*\bwidth\b[^{]*)\{/gi,
|
|
18
|
+
"@container $1{"
|
|
19
|
+
);
|
|
20
|
+
return `<style${attrs}>${scoped}</style>`;
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
const body = `<style>:host{display:block;container-type:inline-size;overflow-x:clip}</style><div data-embed-body>${markup}</div>`;
|
|
24
|
+
return { links, body };
|
|
25
|
+
}
|
|
26
|
+
function runScripts(root) {
|
|
27
|
+
for (const old of root.querySelectorAll("script")) {
|
|
28
|
+
const script = document.createElement("script");
|
|
29
|
+
for (const { name, value } of old.attributes) script.setAttribute(name, value);
|
|
30
|
+
script.textContent = old.textContent;
|
|
31
|
+
old.replaceWith(script);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var InlineEmbed = ({ content, className, style }) => {
|
|
35
|
+
const hostRef = useRef(null);
|
|
36
|
+
const appliedRef = useRef(null);
|
|
37
|
+
const { links, body } = prepareEmbed(content);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const host = hostRef.current;
|
|
40
|
+
if (!host) return;
|
|
41
|
+
const root = host.shadowRoot ?? host.attachShadow({ mode: "open" });
|
|
42
|
+
if (appliedRef.current === body) return;
|
|
43
|
+
if (appliedRef.current !== null || !root.hasChildNodes()) {
|
|
44
|
+
root.innerHTML = body;
|
|
45
|
+
runScripts(root);
|
|
46
|
+
}
|
|
47
|
+
appliedRef.current = body;
|
|
48
|
+
}, [body]);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const host = hostRef.current;
|
|
51
|
+
if (!host) return;
|
|
52
|
+
const sync = () => host.classList.toggle(
|
|
53
|
+
"dark",
|
|
54
|
+
!!host.parentElement?.closest(".dark") || document.documentElement.classList.contains("dark")
|
|
55
|
+
);
|
|
56
|
+
sync();
|
|
57
|
+
const observer = new MutationObserver(sync);
|
|
58
|
+
observer.observe(document.documentElement, {
|
|
59
|
+
attributes: true,
|
|
60
|
+
attributeFilter: ["class"],
|
|
61
|
+
subtree: true
|
|
62
|
+
});
|
|
63
|
+
return () => observer.disconnect();
|
|
64
|
+
}, []);
|
|
65
|
+
return /* @__PURE__ */ jsx(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
ref: hostRef,
|
|
69
|
+
className,
|
|
70
|
+
style,
|
|
71
|
+
suppressHydrationWarning: true,
|
|
72
|
+
dangerouslySetInnerHTML: {
|
|
73
|
+
// Only the HTML parser turns the template into a shadow root; on the
|
|
74
|
+
// client the effect attaches it instead.
|
|
75
|
+
__html: typeof window === "undefined" ? `${links}<template shadowrootmode="open">${body}</template>` : links
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
export {
|
|
81
|
+
InlineEmbed,
|
|
82
|
+
prepareEmbed
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=inline-embed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/inline-embed.tsx"],"sourcesContent":["\"use client\";\n\nimport type React from \"react\";\nimport { useEffect, useRef } from \"react\";\n\ninterface InlineEmbedProps {\n content: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// Font stylesheets and connection hints only work at document level (a\n// shadow root ignores @font-face), so these links are hoisted out of it.\nconst HOISTED_LINK =\n /<link\\b[^>]*(?:rel=[\"']?(?:preconnect|dns-prefetch|preload)|href=[\"'][^\"']*fonts?\\.)[^>]*>/gi;\n\n/**\n * Snippets are usually written as a standalone document (they used to live in\n * an iframe). Recreate that inside the shadow root: the host plays `html` and\n * is a size container, a wrapper plays `body`, and viewport units and width\n * media queries are rewritten to measure the embed (as they measured the\n * iframe) instead of the browser window. \"Fill the frame\" heights are dropped,\n * as are scripts that only synced state with `window.parent`, which the shadow\n * host handles itself.\n */\nexport function prepareEmbed(content: string) {\n const links = content.match(HOISTED_LINK)?.join(\"\") ?? \"\";\n const markup = content\n .replace(HOISTED_LINK, \"\")\n .replace(/<!doctype[^>]*>|<\\/?(?:html|head|body)\\b[^>]*>/gi, \"\")\n .replace(\n /<script\\b[^>]*>(?:(?!<\\/script>)[\\s\\S])*window\\.parent[\\s\\S]*?<\\/script>/gi,\n \"\",\n )\n .replace(\n /<style\\b([^>]*)>([\\s\\S]*?)<\\/style>/gi,\n (_, attrs: string, css: string) => {\n const scoped = css\n .replace(/:root\\b/g, \":host\")\n .replace(/(^|[\\s,{}])html\\.dark\\b/g, \"$1:host(.dark)\")\n .replace(/(^|[\\s,{}])html(?=[\\s,{:.[>~+])/g, \"$1:host\")\n .replace(/(^|[\\s,{}])body(?=[\\s,{:.[>~+])/g, \"$1[data-embed-body]\")\n .replace(/min-height\\s*:\\s*100d?vh/gi, \"min-height:0\")\n .replace(/(\\d*\\.?\\d+)vw\\b/gi, \"$1cqw\")\n .replace(\n /@media\\s+(?:only\\s+)?(?:screen\\s+and\\s+)?(\\([^{]*\\bwidth\\b[^{]*)\\{/gi,\n \"@container $1{\",\n );\n return `<style${attrs}>${scoped}</style>`;\n },\n );\n\n const body = `<style>:host{display:block;container-type:inline-size;overflow-x:clip}</style><div data-embed-body>${markup}</div>`;\n return { links, body };\n}\n\nfunction runScripts(root: ShadowRoot) {\n for (const old of root.querySelectorAll(\"script\")) {\n const script = document.createElement(\"script\");\n for (const { name, value } of old.attributes) script.setAttribute(name, value);\n script.textContent = old.textContent;\n old.replaceWith(script);\n }\n}\n\n/**\n * Renders a raw HTML snippet inline, inside a declarative shadow root. The\n * markup is part of the server-rendered page (so crawlers index it) while its\n * styles stay isolated from the site's in both directions.\n */\nexport const InlineEmbed = ({ content, className, style }: InlineEmbedProps) => {\n const hostRef = useRef<HTMLDivElement>(null);\n const appliedRef = useRef<string | null>(null);\n const { links, body } = prepareEmbed(content);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n // A server-rendered host already has its shadow root from the HTML\n // parser; a client-rendered one (editor, client navigation) does not,\n // because innerHTML ignores declarative shadow roots.\n const root = host.shadowRoot ?? host.attachShadow({ mode: \"open\" });\n if (appliedRef.current === body) return;\n // The HTML parser already ran the scripts of a server-rendered shadow\n // root; only markup set through innerHTML (which never runs scripts)\n // needs them re-created, or they'd run twice.\n if (appliedRef.current !== null || !root.hasChildNodes()) {\n root.innerHTML = body;\n runScripts(root);\n }\n appliedRef.current = body;\n }, [body]);\n\n // Mirror the site's color mode onto the host so snippets can use\n // `:host(.dark)`.\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n const sync = () =>\n host.classList.toggle(\n \"dark\",\n !!host.parentElement?.closest(\".dark\") ||\n document.documentElement.classList.contains(\"dark\"),\n );\n sync();\n const observer = new MutationObserver(sync);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n subtree: true,\n });\n return () => observer.disconnect();\n }, []);\n\n return (\n <div\n ref={hostRef}\n className={className}\n style={style}\n suppressHydrationWarning\n dangerouslySetInnerHTML={{\n // Only the HTML parser turns the template into a shadow root; on the\n // client the effect attaches it instead.\n __html:\n typeof window === \"undefined\"\n ? `${links}<template shadowrootmode=\"open\">${body}</template>`\n : links,\n }}\n />\n );\n};\n"],"mappings":";;;;AAGA,SAAS,WAAW,cAAc;AAiH9B;AAvGJ,IAAM,eACJ;AAWK,SAAS,aAAa,SAAiB;AAC5C,QAAM,QAAQ,QAAQ,MAAM,YAAY,GAAG,KAAK,EAAE,KAAK;AACvD,QAAM,SAAS,QACZ,QAAQ,cAAc,EAAE,EACxB,QAAQ,oDAAoD,EAAE,EAC9D;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA,CAAC,GAAG,OAAe,QAAgB;AACjC,YAAM,SAAS,IACZ,QAAQ,YAAY,OAAO,EAC3B,QAAQ,4BAA4B,gBAAgB,EACpD,QAAQ,oCAAoC,SAAS,EACrD,QAAQ,oCAAoC,qBAAqB,EACjE,QAAQ,8BAA8B,cAAc,EACpD,QAAQ,qBAAqB,OAAO,EACpC;AAAA,QACC;AAAA,QACA;AAAA,MACF;AACF,aAAO,SAAS,KAAK,IAAI,MAAM;AAAA,IACjC;AAAA,EACF;AAEF,QAAM,OAAO,sGAAsG,MAAM;AACzH,SAAO,EAAE,OAAO,KAAK;AACvB;AAEA,SAAS,WAAW,MAAkB;AACpC,aAAW,OAAO,KAAK,iBAAiB,QAAQ,GAAG;AACjD,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,eAAW,EAAE,MAAM,MAAM,KAAK,IAAI,WAAY,QAAO,aAAa,MAAM,KAAK;AAC7E,WAAO,cAAc,IAAI;AACzB,QAAI,YAAY,MAAM;AAAA,EACxB;AACF;AAOO,IAAM,cAAc,CAAC,EAAE,SAAS,WAAW,MAAM,MAAwB;AAC9E,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,aAAa,OAAsB,IAAI;AAC7C,QAAM,EAAE,OAAO,KAAK,IAAI,aAAa,OAAO;AAE5C,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AAKX,UAAM,OAAO,KAAK,cAAc,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAClE,QAAI,WAAW,YAAY,KAAM;AAIjC,QAAI,WAAW,YAAY,QAAQ,CAAC,KAAK,cAAc,GAAG;AACxD,WAAK,YAAY;AACjB,iBAAW,IAAI;AAAA,IACjB;AACA,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,IAAI,CAAC;AAIT,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,OAAO,MACX,KAAK,UAAU;AAAA,MACb;AAAA,MACA,CAAC,CAAC,KAAK,eAAe,QAAQ,OAAO,KACnC,SAAS,gBAAgB,UAAU,SAAS,MAAM;AAAA,IACtD;AACF,SAAK;AACL,UAAM,WAAW,IAAI,iBAAiB,IAAI;AAC1C,aAAS,QAAQ,SAAS,iBAAiB;AAAA,MACzC,YAAY;AAAA,MACZ,iBAAiB,CAAC,OAAO;AAAA,MACzB,SAAS;AAAA,IACX,CAAC;AACD,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,0BAAwB;AAAA,MACxB,yBAAyB;AAAA;AAAA;AAAA,QAGvB,QACE,OAAO,WAAW,cACd,GAAG,KAAK,mCAAmC,IAAI,gBAC/C;AAAA,MACR;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Infinite horizontal scroller. Measures the width of one copy of the
|
|
5
|
+
* content, then renders enough duplicate copies to always cover at least
|
|
6
|
+
* twice the container's width, and animates a translateX loop across
|
|
7
|
+
* exactly one content-width — because the duplicates repeat the same
|
|
8
|
+
* sequence, the loop point is visually seamless regardless of how the
|
|
9
|
+
* content width compares to the container width.
|
|
10
|
+
*/
|
|
11
|
+
declare function MarqueeTrack({ children, speed, direction, pauseOnHover, }: {
|
|
12
|
+
children: React__default.ReactNode;
|
|
13
|
+
speed: number;
|
|
14
|
+
direction: "left" | "right";
|
|
15
|
+
pauseOnHover?: boolean;
|
|
16
|
+
}): React__default.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { MarqueeTrack };
|