@deneb-ui/ui 2.0.22 → 2.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +77 -155
  2. package/dist/DenebComponentStyles.d.ts +6 -0
  3. package/dist/DenebComponentStyles.js +84 -0
  4. package/dist/EditableCard.js +5 -1
  5. package/dist/EditableContactForm.js +1 -1
  6. package/dist/EditableFilterSidebar.js +12 -11
  7. package/dist/EditableFooter.js +1 -1
  8. package/dist/EditableGrid.js +15 -12
  9. package/dist/EditableNavbar.js +32 -19
  10. package/dist/EditablePricingCard.js +1 -1
  11. package/dist/EditableProductCard.js +4 -4
  12. package/dist/EditableProductDetail.js +2 -2
  13. package/dist/EditableProductGrid.js +1 -1
  14. package/dist/EditableSection.js +7 -10
  15. package/dist/EditableText.d.ts +1 -1
  16. package/dist/EditableText.js +8 -33
  17. package/dist/ResponsiveBaseStyles.d.ts +7 -0
  18. package/dist/ResponsiveBaseStyles.js +136 -0
  19. package/dist/SiteDataProvider.d.ts +2 -0
  20. package/dist/SiteDataProvider.js +22 -4
  21. package/dist/StickyMobileBar.js +1 -1
  22. package/dist/ThemeStyles.js +2 -1
  23. package/dist/TrustBadges.js +1 -1
  24. package/dist/contact/FloatingContactWidget.js +3 -2
  25. package/dist/fonts/FontLoader.d.ts +13 -0
  26. package/dist/fonts/FontLoader.js +43 -0
  27. package/dist/fonts/useDenebFonts.d.ts +6 -0
  28. package/dist/fonts/useDenebFonts.js +29 -0
  29. package/dist/hooks/useComponentStyle.d.ts +8 -0
  30. package/dist/hooks/useComponentStyle.js +46 -0
  31. package/dist/index.d.ts +8 -0
  32. package/dist/index.js +33 -1
  33. package/dist/utils/index.d.ts +1 -0
  34. package/dist/utils/index.js +1 -0
  35. package/dist/utils/responsive.d.ts +33 -0
  36. package/dist/utils/responsive.js +100 -0
  37. package/package.json +21 -8
  38. package/scripts/setup-fonts.cjs +26 -0
@@ -49,17 +49,17 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
49
49
  borderRadius: '14px',
50
50
  overflow: 'hidden',
51
51
  display: 'flex',
52
- flexDirection: 'row',
53
- alignItems: 'center',
52
+ flexDirection: 'column',
53
+ alignItems: 'stretch',
54
54
  },
55
55
  };
56
56
  return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, style: {
57
57
  ...variantStyles[cardVariant],
58
58
  ...style,
59
- }, className: `editable-product-card group ${className}`.trim(), ...props, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
59
+ }, className: `editable-product-card group ${isHorizontal ? 'is-horizontal' : ''} ${className}`.trim(), ...props, children: [(0, jsx_runtime_1.jsxs)("div", { className: "deneb-product-card-media", style: {
60
60
  position: 'relative',
61
61
  overflow: 'hidden',
62
- width: isHorizontal ? '38%' : '100%',
62
+ width: isHorizontal ? '100%' : '100%',
63
63
  flexShrink: 0,
64
64
  }, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.imageUrl`, src: imageUrl, fallbackSrc: imageFallback, alt: name, aspectRatio: isHorizontal ? 'square' : '4/3', fit: "cover", hoverZoom: true, style: { width: '100%', height: '100%', display: 'block' } }), badge && ((0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', top: '10px', left: '10px', zIndex: 10 }, children: (0, jsx_runtime_1.jsx)(EditableText_2.EditableBadge, { id: `${itemPath}.badge`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
65
65
  padding: '1.25rem',
@@ -42,11 +42,11 @@ function EditableProductDetail({ sectionPath = 'product', product, sizes = ['40'
42
42
  const resolvedWhatsappUrl = whatsappUrl || (product.whatsappNumber
43
43
  ? (0, urls_1.createWhatsAppUrl)(product.whatsappNumber, product.whatsappMessage || `Hi, I would like to order ${name} (${selectedSize}, ${selectedColor}) - ${price}`)
44
44
  : '');
45
- return ((0, jsx_runtime_1.jsx)("section", { "data-preview-page-key": sectionPath, className: `editable-product-detail max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-start", children: [(0, jsx_runtime_1.jsxs)("div", { className: "lg:col-span-7 flex flex-col-reverse md:flex-row gap-4", children: [images.length > 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex md:flex-col gap-3 overflow-x-auto md:overflow-y-auto max-h-[580px] pb-2 md:pb-0 scrollbar-none", children: images.map((img, idx) => ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveImage(img), className: `w-20 h-20 sm:w-24 sm:h-24 rounded-2xl overflow-hidden border-2 transition-all duration-200 flex-shrink-0 bg-slate-900/40 p-2 ${activeImage === img
45
+ return ((0, jsx_runtime_1.jsx)("section", { "data-preview-page-key": sectionPath, className: `editable-product-detail max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-start", children: [(0, jsx_runtime_1.jsxs)("div", { className: "lg:col-span-7 flex flex-col-reverse md:flex-row gap-4", children: [images.length > 1 && ((0, jsx_runtime_1.jsx)("div", { className: "deneb-product-detail-gallery flex md:flex-col gap-3 overflow-x-auto md:overflow-y-auto max-h-[580px] pb-2 md:pb-0 scrollbar-none", children: images.map((img, idx) => ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveImage(img), className: `w-20 h-20 sm:w-24 sm:h-24 rounded-2xl overflow-hidden border-2 transition-all duration-200 flex-shrink-0 bg-slate-900/40 p-2 ${activeImage === img
46
46
  ? 'border-brand-primary scale-98 shadow-md'
47
47
  : 'border-slate-800/80 opacity-60 hover:opacity-100 hover:border-slate-700'}`, children: (0, jsx_runtime_1.jsx)("img", { src: (0, utils_1.withBasePath)(img), alt: "", className: "w-full h-full object-contain" }) }, idx))) })), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex-1 aspect-square rounded-3xl bg-gradient-to-b from-slate-900/50 to-slate-950/80 border border-slate-800/80 p-8 flex items-center justify-center overflow-hidden group", children: [badge && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.badge`, className: "absolute top-6 left-6 z-10 px-3.5 py-1 text-xs font-black tracking-wider uppercase rounded-full bg-lime-400 text-slate-950 shadow-lg", children: badge })), (0, jsx_runtime_1.jsx)("img", { "data-preview-field-path": `${sectionPath}.featuredImage`, src: (0, utils_1.withBasePath)(activeImage), alt: name, className: "w-full h-full object-contain transition-transform duration-500 group-hover:scale-105" })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "lg:col-span-5 flex flex-col justify-between", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { "data-preview-field-path": `${sectionPath}.name`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-white leading-tight", children: name }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-baseline gap-3", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.price`, className: "text-3xl font-black text-lime-400 tracking-tight", children: price }), product.originalPrice ? ((0, jsx_runtime_1.jsx)("span", { className: "text-lg font-medium text-slate-500 line-through", children: String(product.originalPrice) })) : null] }), description && ((0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `${sectionPath}.description`, className: "mt-6 text-base text-slate-300 leading-relaxed", children: description })), colors.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-8", children: [(0, jsx_runtime_1.jsxs)("span", { className: "block text-xs font-bold uppercase tracking-wider text-slate-400 mb-3", children: ["Color \u2014 ", (0, jsx_runtime_1.jsx)("span", { className: "text-white", children: selectedColor })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex gap-3", children: colors.map((c) => ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedColor(c.name), className: `w-9 h-9 rounded-full border-2 transition-all p-0.5 ${selectedColor === c.name
48
48
  ? 'border-lime-400 ring-2 ring-lime-400/30 scale-105'
49
- : 'border-slate-700 hover:border-slate-500'}`, style: { backgroundColor: c.hex }, title: c.name, "aria-label": c.name }, c.name))) })] })), sizes.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-8", children: [(0, jsx_runtime_1.jsx)("span", { className: "block text-xs font-bold uppercase tracking-wider text-slate-400 mb-3", children: "Select Size" }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-4 sm:grid-cols-7 gap-2", children: sizes.map((s) => ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedSize(s), className: `py-2.5 rounded-xl font-bold text-sm transition-all duration-150 ${selectedSize === s
49
+ : 'border-slate-700 hover:border-slate-500'}`, style: { backgroundColor: c.hex }, title: c.name, "aria-label": c.name }, c.name))) })] })), sizes.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-8", children: [(0, jsx_runtime_1.jsx)("span", { className: "block text-xs font-bold uppercase tracking-wider text-slate-400 mb-3", children: "Select Size" }), (0, jsx_runtime_1.jsx)("div", { className: "deneb-product-detail-sizes grid grid-cols-4 sm:grid-cols-7 gap-2", children: sizes.map((s) => ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedSize(s), className: `py-2.5 rounded-xl font-bold text-sm transition-all duration-150 ${selectedSize === s
50
50
  ? 'bg-white text-slate-950 shadow-md font-extrabold scale-102'
51
51
  : 'bg-slate-900/60 text-slate-300 border border-slate-800 hover:bg-slate-800 hover:text-white'}`, children: s }, s))) })] })), (0, jsx_runtime_1.jsxs)("div", { className: "mt-8 flex flex-col gap-3", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => onAddToSelection?.(product, selectedSize, selectedColor), className: "w-full py-4 px-6 rounded-2xl font-black text-sm uppercase tracking-wider bg-lime-400 text-slate-950 hover:bg-lime-300 active:scale-98 transition-all duration-150 shadow-lg shadow-lime-400/20 flex items-center justify-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.addToSelectionLabel`, children: addToSelectionLabel }) }), resolvedWhatsappUrl && ((0, jsx_runtime_1.jsxs)("a", { href: resolvedWhatsappUrl, target: "_blank", rel: "noopener noreferrer", className: "w-full py-3.5 px-6 rounded-2xl font-bold text-sm bg-emerald-600/20 text-emerald-400 hover:bg-emerald-600/30 border border-emerald-500/30 transition-all duration-150 flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-5 h-5 fill-current", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { d: "M17.472 14.382c-.301-.15-1.78-.879-2.056-.98-.276-.1-.477-.15-.678.15-.201.3-.78 0.98-.956 1.18-.175.2-.351.226-.652.075-.301-.15-1.272-.469-2.423-1.496-.896-.799-1.501-1.787-1.677-2.088-.175-.301-.019-.464.132-.614.136-.135.301-.351.452-.527.15-.176.201-.301.301-.502.1-.2.05-.376-.025-.527-.075-.15-.678-1.635-.93-2.242-.244-.592-.493-.512-.678-.521-.175-.009-.376-.009-.577-.009-.201 0-.527.075-.803.376-.276.301-1.054 1.03-1.054 2.512 0 1.482 1.079 2.912 1.23 3.113.15.201 2.124 3.243 5.145 4.548.718.311 1.279.497 1.716.636.722.23 1.378.197 1.898.12.579-.087 1.78-.728 2.03-1.431.251-.703.251-1.305.176-1.431-.075-.126-.276-.201-.577-.351zM12.004 2C6.48 2 2 6.48 2 12c0 1.82.49 3.52 1.34 4.99L2 22l5.14-1.35c1.42.78 3.04 1.22 4.86 1.22 5.52 0 10-4.48 10-10S17.524 2 12.004 2z" }) }), (0, jsx_runtime_1.jsx)("span", { children: "Order Directly via WhatsApp" })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-10 border-t border-slate-800/80 pt-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex gap-6 border-b border-slate-800 pb-3 mb-4", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveTab('specs'), className: `text-sm font-bold tracking-wide transition-colors ${activeTab === 'specs' ? 'text-lime-400' : 'text-slate-400 hover:text-slate-200'}`, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.specsTitle`, children: specsTitle }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveTab('shipping'), className: `text-sm font-bold tracking-wide transition-colors ${activeTab === 'shipping' ? 'text-lime-400' : 'text-slate-400 hover:text-slate-200'}`, children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.shippingTitle`, children: shippingTitle }) })] }), activeTab === 'specs' ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: product.specs && product.specs.length > 0 ? (product.specs.map((spec, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-xs py-1 border-b border-slate-900", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-slate-400 font-medium", children: spec.label }), (0, jsx_runtime_1.jsx)("span", { className: "text-slate-200 font-semibold", children: spec.value })] }, i)))) : ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-slate-400 space-y-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between py-1 border-b border-slate-800/50", children: [(0, jsx_runtime_1.jsx)("span", { children: "Upper Material" }), (0, jsx_runtime_1.jsx)("span", { className: "text-slate-200 font-semibold", children: "Engineered breathable mesh" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between py-1 border-b border-slate-800/50", children: [(0, jsx_runtime_1.jsx)("span", { children: "Midsole Technology" }), (0, jsx_runtime_1.jsx)("span", { className: "text-slate-200 font-semibold", children: "Dual-density responsive foam" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between py-1 border-b border-slate-800/50", children: [(0, jsx_runtime_1.jsx)("span", { children: "Outsole Grip" }), (0, jsx_runtime_1.jsx)("span", { className: "text-slate-200 font-semibold", children: "High-abrasion tactical rubber" })] })] })) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-slate-300 space-y-3 leading-relaxed", children: [(0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `${sectionPath}.shippingSummary`, children: shippingSummary }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `${sectionPath}.shippingReturns`, className: "text-slate-400", children: shippingReturns })] }))] })] }) })] }) }));
52
52
  }
@@ -38,7 +38,7 @@ function EditableProductGrid({ sectionPath = 'home', title = 'Featured Collectio
38
38
  return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveCategory(cat), className: `px-4 py-2 rounded-xl text-xs font-bold transition-all duration-200 ${isActive
39
39
  ? 'bg-white text-slate-950 shadow-md scale-102 font-extrabold'
40
40
  : 'bg-slate-900/60 text-slate-400 hover:text-white border border-slate-800/80 hover:bg-slate-850'}`, children: cat }, cat));
41
- }) }))] }), filteredProducts.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: `grid ${gridColClasses} gap-6 sm:gap-8`, children: filteredProducts.map((product, idx) => {
41
+ }) }))] }), filteredProducts.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: `deneb-product-grid grid ${gridColClasses} gap-6 sm:gap-8`, children: filteredProducts.map((product, idx) => {
42
42
  const itemPath = `${sectionPath}.${cardPrefix}${idx + 1}`;
43
43
  return ((0, jsx_runtime_1.jsxs)("div", { className: "relative group", children: [(0, jsx_runtime_1.jsx)(EditableProductCard_1.EditableProductCard, { itemPath: itemPath, product: product, cardVariant: cardVariant, className: "h-full" }), onQuickView && ((0, jsx_runtime_1.jsx)("div", { className: "absolute top-4 right-4 z-20 opacity-0 group-hover:opacity-100 transition-opacity duration-200", children: (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => onQuickView(product, itemPath), className: "p-2.5 rounded-xl bg-slate-950/80 backdrop-blur-md text-white hover:bg-lime-400 hover:text-slate-950 shadow-lg transition-all active:scale-95", title: "Quick View", "aria-label": `Quick View ${product.name || product.title}`, children: (0, jsx_runtime_1.jsxs)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }), (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" })] }) }) }))] }, product.id || idx));
44
44
  }) })) : (
@@ -2,15 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EditableSection = EditableSection;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const SECTION_PADDING_MAP = {
6
- none: '0',
7
- xs: '1.5rem 0',
8
- sm: '2.5rem 0',
9
- md: '4rem 0',
10
- lg: '6rem 0',
11
- xl: '8rem 0',
12
- '2xl': '10rem 0',
13
- };
5
+ const useComponentStyle_1 = require("./hooks/useComponentStyle");
6
+ const responsive_1 = require("./utils/responsive");
7
+ const SECTION_PADDING_MAP = responsive_1.RESPONSIVE_SECTION_PADDING;
14
8
  /**
15
9
  * EditableSection standardizes section spacing and automatically applies the required
16
10
  * `data-design-section` marker for 100% fivora contract compliance.
@@ -22,13 +16,16 @@ function EditableSection({ as: Component = 'section', name, padding = 'lg', bg,
22
16
  : typeof border === 'string'
23
17
  ? border
24
18
  : undefined;
19
+ const stylePath = `${name}.section`;
20
+ const { cssVars: styleVars } = (0, useComponentStyle_1.useComponentStyle)(stylePath, 'section');
25
21
  const sectionStyle = {
26
22
  ...(resolvedPadding ? { padding: resolvedPadding } : {}),
27
23
  ...(bg ? { background: bg } : {}),
28
24
  ...(color ? { color } : {}),
29
25
  ...(maxWidth !== undefined ? { maxWidth, marginLeft: 'auto', marginRight: 'auto' } : {}),
30
26
  ...(resolvedBorder ? { borderBottom: resolvedBorder } : {}),
27
+ ...styleVars,
31
28
  ...style,
32
29
  };
33
- return ((0, jsx_runtime_1.jsx)(Component, { "data-design-section": name, className: `editable-section ${className}`.trim(), style: sectionStyle, ...props, children: children }));
30
+ return ((0, jsx_runtime_1.jsx)(Component, { "data-design-section": name, "data-preview-style-target": stylePath, "data-preview-style-type": "section", className: `deneb-section editable-section ${className}`.trim(), style: sectionStyle, ...props, children: children }));
34
31
  }
@@ -81,7 +81,7 @@ export interface EditableTextProps extends React.HTMLAttributes<HTMLElement> {
81
81
  * EditableText provides full typography controls (color, size, weight, line-height, alignment, transform, variants)
82
82
  * alongside strict Fivora visual editing bindings.
83
83
  */
84
- export declare function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, placeholder, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, ...props }: EditableTextProps): React.JSX.Element;
84
+ export declare function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, placeholder, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, className, ...props }: EditableTextProps): React.JSX.Element;
85
85
  export interface EditableHeadingProps extends Omit<EditableTextProps, 'variant'> {
86
86
  level?: 1 | 2 | 3 | 4 | 5 | 6;
87
87
  }
@@ -10,7 +10,7 @@ exports.EditableQuote = EditableQuote;
10
10
  exports.EditableLink = EditableLink;
11
11
  exports.EditableButton = EditableButton;
12
12
  const jsx_runtime_1 = require("react/jsx-runtime");
13
- const SiteDataProvider_1 = require("./SiteDataProvider");
13
+ const useComponentStyle_1 = require("./hooks/useComponentStyle");
14
14
  exports.SIZE_MAP = {
15
15
  xs: '0.75rem',
16
16
  sm: '0.875rem',
@@ -106,7 +106,7 @@ function toCssUnit(value) {
106
106
  * EditableText provides full typography controls (color, size, weight, line-height, alignment, transform, variants)
107
107
  * alongside strict Fivora visual editing bindings.
108
108
  */
109
- function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, placeholder, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, ...props }) {
109
+ function EditableText({ id, 'data-preview-field-path': previewFieldPath, defaultValue, placeholder, children, as: ComponentOverride, variant, color, size, weight, lineHeight, align, transform, letterSpacing, fontFamily, style, className = '', ...props }) {
110
110
  const path = previewFieldPath || id;
111
111
  const rawContent = children !== undefined ? children : defaultValue;
112
112
  const isContentEmpty = rawContent === undefined ||
@@ -114,7 +114,7 @@ function EditableText({ id, 'data-preview-field-path': previewFieldPath, default
114
114
  (typeof rawContent === 'string' && rawContent.trim() === '');
115
115
  const isPlaceholderActive = isContentEmpty && Boolean(placeholder);
116
116
  const displayContent = isPlaceholderActive ? placeholder : rawContent;
117
- const dynamicStyle = (0, SiteDataProvider_1.useFieldStyle)(path);
117
+ const { cssVars: styleVars } = (0, useComponentStyle_1.useComponentStyle)(path, 'text');
118
118
  const variantDefaults = variant ? exports.VARIANT_DEFAULTS[variant] : undefined;
119
119
  const Component = ComponentOverride || variantDefaults?.as || 'span';
120
120
  const effectiveColor = color || variantDefaults?.color;
@@ -134,24 +134,6 @@ function EditableText({ id, 'data-preview-field-path': previewFieldPath, default
134
134
  const resolvedFontFamily = effectiveFontFamily
135
135
  ? (exports.FONT_FAMILY_MAP[effectiveFontFamily] || effectiveFontFamily)
136
136
  : undefined;
137
- // Dynamic visual editor overrides
138
- const dynamicColor = dynamicStyle?.color
139
- ? (exports.COLOR_MAP[String(dynamicStyle.color)] || String(dynamicStyle.color))
140
- : undefined;
141
- const dynamicSize = dynamicStyle?.fontSize !== undefined && dynamicStyle?.fontSize !== ''
142
- ? (exports.SIZE_MAP[String(dynamicStyle.fontSize)] || toCssUnit(dynamicStyle.fontSize))
143
- : undefined;
144
- const dynamicLineHeight = dynamicStyle?.lineHeight !== undefined && dynamicStyle?.lineHeight !== ''
145
- ? (exports.LINE_HEIGHT_MAP[String(dynamicStyle.lineHeight)] || dynamicStyle.lineHeight)
146
- : undefined;
147
- const dynamicFontFamily = dynamicStyle?.fontFamily
148
- ? (exports.FONT_FAMILY_MAP[String(dynamicStyle.fontFamily)] || String(dynamicStyle.fontFamily))
149
- : undefined;
150
- const dynamicAlign = dynamicStyle?.textAlign;
151
- const dynamicMarginTop = toCssUnit(dynamicStyle?.spacingTop);
152
- const dynamicMarginBottom = toCssUnit(dynamicStyle?.spacingBottom);
153
- const dynamicMarginLeft = toCssUnit(dynamicStyle?.spacingLeft);
154
- const dynamicMarginRight = toCssUnit(dynamicStyle?.spacingRight);
155
137
  const typographyStyle = {
156
138
  // Minimum dimensions ensure empty/placeholder elements never collapse to 0x0 and remain 100% clickable in Fivora
157
139
  minHeight: '1.2em',
@@ -166,19 +148,10 @@ function EditableText({ id, 'data-preview-field-path': previewFieldPath, default
166
148
  ...(effectiveTransform ? { textTransform: effectiveTransform } : {}),
167
149
  ...(resolvedLetterSpacing ? { letterSpacing: resolvedLetterSpacing } : {}),
168
150
  ...(resolvedFontFamily ? { fontFamily: resolvedFontFamily } : {}),
151
+ ...styleVars,
169
152
  ...style,
170
- // Visual editor overrides take highest precedence:
171
- ...(dynamicColor ? { color: dynamicColor } : {}),
172
- ...(dynamicSize ? { fontSize: dynamicSize } : {}),
173
- ...(dynamicLineHeight ? { lineHeight: dynamicLineHeight } : {}),
174
- ...(dynamicAlign ? { textAlign: dynamicAlign } : {}),
175
- ...(dynamicFontFamily ? { fontFamily: dynamicFontFamily } : {}),
176
- ...(dynamicMarginTop !== undefined ? { marginTop: dynamicMarginTop } : {}),
177
- ...(dynamicMarginBottom !== undefined ? { marginBottom: dynamicMarginBottom } : {}),
178
- ...(dynamicMarginLeft !== undefined ? { marginLeft: dynamicMarginLeft } : {}),
179
- ...(dynamicMarginRight !== undefined ? { marginRight: dynamicMarginRight } : {}),
180
153
  };
181
- return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-field-path": path, "data-preview-placeholder": isPlaceholderActive ? 'true' : undefined, style: typographyStyle, ...props, children: displayContent }));
154
+ return ((0, jsx_runtime_1.jsx)(Component, { "data-preview-field-path": path, "data-preview-style-target": path, "data-preview-style-type": "text", "data-preview-placeholder": isPlaceholderActive ? 'true' : undefined, className: `deneb-text ${className}`.trim(), style: typographyStyle, ...props, children: displayContent }));
182
155
  }
183
156
  function EditableHeading({ level = 2, as, ...props }) {
184
157
  const variant = `h${level}`;
@@ -270,6 +243,7 @@ function EditableLink({ id, 'data-preview-field-path': previewFieldPath, targetP
270
243
  function EditableButton({ id, 'data-preview-field-path': previewFieldPath, defaultValue, targetPage, btnVariant = 'primary', size = 'md', children, className = '', style, ...props }) {
271
244
  const path = previewFieldPath || id;
272
245
  const content = children !== undefined ? children : defaultValue;
246
+ const { cssVars: styleVars } = (0, useComponentStyle_1.useComponentStyle)(path, 'button');
273
247
  const sizeStyles = {
274
248
  sm: { padding: '0.375rem 0.875rem', fontSize: '0.875rem', borderRadius: '6px' },
275
249
  md: { padding: '0.625rem 1.25rem', fontSize: '1rem', borderRadius: '8px' },
@@ -319,9 +293,10 @@ function EditableButton({ id, 'data-preview-field-path': previewFieldPath, defau
319
293
  transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
320
294
  ...sizeStyles[size],
321
295
  ...variantStyles[btnVariant],
296
+ ...styleVars,
322
297
  ...style,
323
298
  };
324
- const buttonEl = ((0, jsx_runtime_1.jsx)("button", { style: baseStyle, className: `editable-btn ${className}`.trim(), ...props, children: path ? ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": path, children: content })) : (content) }));
299
+ const buttonEl = ((0, jsx_runtime_1.jsx)("button", { "data-preview-style-target": path, "data-preview-style-type": "button", style: baseStyle, className: `deneb-btn editable-btn ${className}`.trim(), ...props, children: path ? ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": path, children: content })) : (content) }));
325
300
  if (targetPage) {
326
301
  return (0, jsx_runtime_1.jsx)("span", { "data-target-page": targetPage, children: buttonEl });
327
302
  }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ /**
3
+ * Injects viewport-aware CSS for all DENEB UI components.
4
+ * Works without Tailwind — every template gets mobile / tablet / desktop behavior
5
+ * when this is mounted once (included automatically by ThemeStyles).
6
+ */
7
+ export declare function ResponsiveBaseStyles(): React.JSX.Element;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponsiveBaseStyles = ResponsiveBaseStyles;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /**
6
+ * Injects viewport-aware CSS for all DENEB UI components.
7
+ * Works without Tailwind — every template gets mobile / tablet / desktop behavior
8
+ * when this is mounted once (included automatically by ThemeStyles).
9
+ */
10
+ function ResponsiveBaseStyles() {
11
+ const css = `
12
+ /* ── Breakpoints: mobile <768 | tablet 768–1023 | desktop ≥1024 ── */
13
+
14
+ /* Navbar: hide desktop nav + compact header on mobile */
15
+ .deneb-desktop-nav { display: none !important; }
16
+ .deneb-mobile-toggle { display: flex !important; }
17
+ .deneb-header-cta { display: none !important; }
18
+
19
+ @media (min-width: 768px) {
20
+ .deneb-desktop-nav { display: flex !important; }
21
+ .deneb-mobile-toggle { display: none !important; }
22
+ .deneb-header-cta { display: inline-flex !important; }
23
+ .deneb-mobile-drawer { display: none !important; }
24
+ }
25
+
26
+ @media (max-width: 767px) {
27
+ .deneb-site-title { font-size: 1rem !important; max-width: 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
28
+ .deneb-logo { height: 32px !important; max-width: 100px !important; }
29
+ }
30
+
31
+ /* Responsive grid columns via data attributes */
32
+ .editable-grid[data-deneb-responsive-cols="true"] {
33
+ grid-template-columns: repeat(var(--deneb-cols, 1), minmax(0, 1fr));
34
+ }
35
+ @media (min-width: 640px) {
36
+ .editable-grid[data-deneb-responsive-cols="true"] {
37
+ grid-template-columns: repeat(var(--deneb-cols-tablet, 2), minmax(0, 1fr));
38
+ }
39
+ }
40
+ @media (min-width: 1024px) {
41
+ .editable-grid[data-deneb-responsive-cols="true"] {
42
+ grid-template-columns: repeat(var(--deneb-cols-desktop, 3), minmax(0, 1fr));
43
+ }
44
+ }
45
+
46
+ /* Horizontal product card stacks on mobile */
47
+ .editable-product-card.is-horizontal { flex-direction: column !important; }
48
+ .editable-product-card.is-horizontal .deneb-product-card-media { width: 100% !important; }
49
+ @media (min-width: 640px) {
50
+ .editable-product-card.is-horizontal { flex-direction: row !important; align-items: center !important; }
51
+ .editable-product-card.is-horizontal .deneb-product-card-media { width: 38% !important; }
52
+ }
53
+
54
+ /* Card padding scales down on small screens */
55
+ .editable-pricing-card,
56
+ .editable-testimonial-card {
57
+ padding: clamp(1.25rem, 4vw, 2.5rem) clamp(1rem, 3vw, 2rem) !important;
58
+ }
59
+ .editable-pricing-card .deneb-pricing-amount {
60
+ font-size: clamp(2rem, 6vw, 2.75rem) !important;
61
+ }
62
+
63
+ /* Dialog: tighter padding on phones */
64
+ .deneb-dialog-portal { padding: clamp(0.5rem, 3vw, 1rem) !important; }
65
+ .deneb-dialog-content { padding: clamp(1.25rem, 4vw, 2rem) !important; border-radius: clamp(12px, 3vw, 20px) !important; }
66
+ .deneb-dialog-content h2 { font-size: clamp(1.1rem, 4vw, 1.35rem) !important; }
67
+
68
+ /* Floating contact: prevent popup overflow */
69
+ .deneb-contact-popup {
70
+ width: min(18rem, calc(100vw - 2rem)) !important;
71
+ max-width: calc(100vw - 2rem) !important;
72
+ }
73
+ @media (max-width: 479px) {
74
+ .deneb-floating-contact { bottom: 1rem !important; right: 1rem !important; left: auto !important; }
75
+ .deneb-floating-contact.deneb-floating-left { left: 1rem !important; right: auto !important; }
76
+ }
77
+
78
+ /* Filter sidebar: collapsible on mobile, always visible on tablet+ */
79
+ .deneb-filter-mobile-toggle { display: flex; width: 100%; align-items: center; justify-content: space-between; }
80
+ @media (min-width: 768px) {
81
+ .deneb-filter-mobile-toggle { display: none !important; }
82
+ .deneb-filter-sidebar-panel { display: block !important; }
83
+ }
84
+ @media (max-width: 767px) {
85
+ .deneb-filter-sidebar-panel { display: none; }
86
+ .deneb-filter-sidebar-panel.is-open { display: block; }
87
+ .deneb-filter-sidebar .deneb-filter-size-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
88
+ }
89
+
90
+ /* Contact actions: stack on mobile when row layout */
91
+ @media (max-width: 639px) {
92
+ .deneb-contact-actions.deneb-layout-row {
93
+ flex-direction: column !important;
94
+ align-items: stretch !important;
95
+ }
96
+ .deneb-contact-actions.deneb-layout-row > * { width: 100%; }
97
+ }
98
+
99
+ /* Contact form title */
100
+ .deneb-contact-form-title { font-size: clamp(1.25rem, 4vw, 1.75rem) !important; }
101
+
102
+ /* Product detail: size grid on xs */
103
+ @media (max-width: 479px) {
104
+ .deneb-product-detail-sizes { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
105
+ .deneb-product-detail-gallery { max-height: 420px !important; }
106
+ }
107
+
108
+ /* Footer / trust badges / product grid fallbacks when Tailwind is absent */
109
+ @media (max-width: 639px) {
110
+ .deneb-footer-grid { grid-template-columns: 1fr !important; }
111
+ .deneb-trust-grid { grid-template-columns: 1fr !important; }
112
+ .deneb-product-grid { grid-template-columns: 1fr !important; }
113
+ }
114
+ @media (min-width: 640px) and (max-width: 1023px) {
115
+ .deneb-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
116
+ .deneb-trust-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
117
+ .deneb-product-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
118
+ }
119
+ @media (min-width: 1024px) {
120
+ .deneb-footer-grid { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
121
+ .deneb-trust-grid { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
122
+ }
123
+
124
+ /* Sticky mobile bar: hide on desktop */
125
+ .deneb-sticky-mobile-bar { display: flex; }
126
+ @media (min-width: 1024px) {
127
+ .deneb-sticky-mobile-bar { display: none !important; }
128
+ }
129
+
130
+ /* Dialog animations */
131
+ @keyframes deneb-fade-in { from { opacity: 0; } to { opacity: 1; } }
132
+ @keyframes deneb-zoom-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }
133
+ @keyframes deneb-pop { from { opacity: 0; transform: translateY(8px) scale(0.96); } to { opacity: 1; transform: translateY(0) scale(1); } }
134
+ `;
135
+ return (0, jsx_runtime_1.jsx)("style", { "data-deneb-responsive": "true", dangerouslySetInnerHTML: { __html: css } });
136
+ }
@@ -9,6 +9,7 @@ export declare const DENEB_PREVIEW_FOCUS_MESSAGE = "DENEB_PREVIEW_FOCUS_PAGE";
9
9
  export declare const PREVIEW_FOCUS_MESSAGE = "FIVORA_PREVIEW_FOCUS_PAGE";
10
10
  export declare const LEGACY_PREVIEW_FOCUS_MESSAGE: string;
11
11
  export declare const PREVIEW_FIELD_ATTRIBUTE = "data-preview-field-path";
12
+ export { STYLE_PATCH_MESSAGE, DENEB_STYLE_PATCH_MESSAGE } from '@deneb-ui/core';
12
13
  export type GenericRecord = Record<string, unknown>;
13
14
  export type SiteData = {
14
15
  project?: {
@@ -25,6 +26,7 @@ export type SiteData = {
25
26
  requiredPages?: string[] | null;
26
27
  } | null;
27
28
  content?: GenericRecord | null;
29
+ styles?: GenericRecord | null;
28
30
  [key: string]: unknown;
29
31
  };
30
32
  export declare const SiteDataContext: React.Context<SiteData>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  'use client';
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.DenebDataContext = exports.useDenebData = exports.DenebDataProvider = exports.SiteDataContext = exports.PREVIEW_FIELD_ATTRIBUTE = exports.LEGACY_PREVIEW_FOCUS_MESSAGE = exports.PREVIEW_FOCUS_MESSAGE = exports.DENEB_PREVIEW_FOCUS_MESSAGE = exports.LEGACY_PREVIEW_READY_MESSAGE = exports.PREVIEW_READY_MESSAGE = exports.DENEB_PREVIEW_READY_MESSAGE = exports.LEGACY_PREVIEW_DATA_MESSAGE = exports.PREVIEW_DATA_MESSAGE = exports.DENEB_PREVIEW_DATA_MESSAGE = void 0;
4
+ exports.DenebDataContext = exports.useDenebData = exports.DenebDataProvider = exports.SiteDataContext = exports.DENEB_STYLE_PATCH_MESSAGE = exports.STYLE_PATCH_MESSAGE = exports.PREVIEW_FIELD_ATTRIBUTE = exports.LEGACY_PREVIEW_FOCUS_MESSAGE = exports.PREVIEW_FOCUS_MESSAGE = exports.DENEB_PREVIEW_FOCUS_MESSAGE = exports.LEGACY_PREVIEW_READY_MESSAGE = exports.PREVIEW_READY_MESSAGE = exports.DENEB_PREVIEW_READY_MESSAGE = exports.LEGACY_PREVIEW_DATA_MESSAGE = exports.PREVIEW_DATA_MESSAGE = exports.DENEB_PREVIEW_DATA_MESSAGE = void 0;
5
5
  exports.isRecord = isRecord;
6
6
  exports.mergeSiteData = mergeSiteData;
7
7
  exports.normalizeOrigin = normalizeOrigin;
@@ -17,6 +17,10 @@ exports.getFieldStyle = getFieldStyle;
17
17
  exports.useFieldStyle = useFieldStyle;
18
18
  const jsx_runtime_1 = require("react/jsx-runtime");
19
19
  const react_1 = require("react");
20
+ const core_1 = require("@deneb-ui/core");
21
+ const DenebComponentStyles_1 = require("./DenebComponentStyles");
22
+ const FontLoader_1 = require("./fonts/FontLoader");
23
+ const ResponsiveBaseStyles_1 = require("./ResponsiveBaseStyles");
20
24
  exports.DENEB_PREVIEW_DATA_MESSAGE = 'DENEB_PREVIEW_SITE_DATA';
21
25
  exports.PREVIEW_DATA_MESSAGE = 'FIVORA_PREVIEW_SITE_DATA';
22
26
  const PREVIOUS_PREVIEW_PREFIX = `${['MARKET', 'PLACE'].join('')}_PREVIEW_`;
@@ -30,6 +34,9 @@ exports.DENEB_PREVIEW_FOCUS_MESSAGE = 'DENEB_PREVIEW_FOCUS_PAGE';
30
34
  exports.PREVIEW_FOCUS_MESSAGE = 'FIVORA_PREVIEW_FOCUS_PAGE';
31
35
  exports.LEGACY_PREVIEW_FOCUS_MESSAGE = previousPreviewMessage('FOCUS_PAGE');
32
36
  exports.PREVIEW_FIELD_ATTRIBUTE = 'data-preview-field-path';
37
+ var core_2 = require("@deneb-ui/core");
38
+ Object.defineProperty(exports, "STYLE_PATCH_MESSAGE", { enumerable: true, get: function () { return core_2.STYLE_PATCH_MESSAGE; } });
39
+ Object.defineProperty(exports, "DENEB_STYLE_PATCH_MESSAGE", { enumerable: true, get: function () { return core_2.DENEB_STYLE_PATCH_MESSAGE; } });
33
40
  const PARENT_ORIGIN_KEY = '__FIVORA_PREVIEW_PARENT_ORIGIN__';
34
41
  const LEGACY_PARENT_ORIGIN_KEY = previousPreviewStorageKey('PARENT_ORIGIN');
35
42
  const SITE_DATA_CACHE_KEY = '__FIVORA_PREVIEW_SITE_DATA_CACHE__';
@@ -50,7 +57,7 @@ function mergeSiteData(current, incoming) {
50
57
  for (const key of Object.keys(incoming)) {
51
58
  // Parent preview always sends complete content/media snapshots. Replacing
52
59
  // them wholesale avoids deep-cloning large collections on every keystroke.
53
- if (key === 'content' || key === 'media') {
60
+ if (key === 'content' || key === 'media' || key === 'styles') {
54
61
  next[key] = incoming[key];
55
62
  continue;
56
63
  }
@@ -200,7 +207,9 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, }) {
200
207
  const isFocus = event.data.type === exports.DENEB_PREVIEW_FOCUS_MESSAGE ||
201
208
  event.data.type === exports.PREVIEW_FOCUS_MESSAGE ||
202
209
  event.data.type === exports.LEGACY_PREVIEW_FOCUS_MESSAGE;
203
- if (!isData && !isFocus) {
210
+ const isStylePatch = event.data.type === core_1.STYLE_PATCH_MESSAGE ||
211
+ event.data.type === core_1.DENEB_STYLE_PATCH_MESSAGE;
212
+ if (!isData && !isFocus && !isStylePatch) {
204
213
  return;
205
214
  }
206
215
  // Pin the first concrete parent origin when referrer was suppressed.
@@ -225,6 +234,15 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, }) {
225
234
  applyIncomingSiteData(event.data.siteData);
226
235
  return;
227
236
  }
237
+ if (isStylePatch) {
238
+ const targetPath = typeof event.data.targetPath === 'string' ? event.data.targetPath : '';
239
+ const styleType = typeof event.data.styleType === 'string' ? event.data.styleType : 'text';
240
+ const properties = isRecord(event.data.properties) ? event.data.properties : {};
241
+ if (targetPath) {
242
+ (0, core_1.patchStyleByPath)(targetPath, styleType, properties);
243
+ }
244
+ return;
245
+ }
228
246
  if (isFocus) {
229
247
  const fieldPath = typeof event.data.fieldPath === 'string' ? event.data.fieldPath : '';
230
248
  if (!fieldPath)
@@ -248,7 +266,7 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, }) {
248
266
  return () => window.removeEventListener('message', onMessage);
249
267
  }, []);
250
268
  const value = (0, react_1.useMemo)(() => siteData, [siteData]);
251
- return ((0, jsx_runtime_1.jsx)(exports.SiteDataContext.Provider, { value: value, children: children }));
269
+ return ((0, jsx_runtime_1.jsxs)(exports.SiteDataContext.Provider, { value: value, children: [(0, jsx_runtime_1.jsx)(FontLoader_1.FontLoader, {}), (0, jsx_runtime_1.jsx)(ResponsiveBaseStyles_1.ResponsiveBaseStyles, {}), (0, jsx_runtime_1.jsx)(DenebComponentStyles_1.DenebComponentStyles, {}), children] }));
252
270
  }
253
271
  function useSiteData() {
254
272
  return (0, react_1.useContext)(exports.SiteDataContext);
@@ -70,7 +70,7 @@ function StickyMobileBar({ fieldPath, actions, showOnDesktop = false, className
70
70
  return ((0, jsx_runtime_1.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 10V3L4 14h7v7l9-11h-7z" }) }));
71
71
  }
72
72
  };
73
- return ((0, jsx_runtime_1.jsx)("aside", { className: `fixed bottom-0 left-0 right-0 z-50 p-2 sm:p-3 transition-transform duration-300 ${showOnDesktop ? 'block' : 'lg:hidden'} ${className}`, "data-preview-field-path": fieldPath, style: {
73
+ return ((0, jsx_runtime_1.jsx)("aside", { className: `deneb-sticky-mobile-bar fixed bottom-0 left-0 right-0 z-50 p-2 sm:p-3 transition-transform duration-300 ${showOnDesktop ? 'block' : 'lg:hidden'} ${className}`, "data-preview-field-path": fieldPath, style: {
74
74
  backgroundColor: 'rgba(255, 255, 255, 0.92)',
75
75
  backdropFilter: 'blur(12px)',
76
76
  WebkitBackdropFilter: 'blur(12px)',
@@ -5,6 +5,7 @@ exports.getCategoryTheme = getCategoryTheme;
5
5
  exports.getThemeCssProperties = getThemeCssProperties;
6
6
  exports.ThemeStyles = ThemeStyles;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const ResponsiveBaseStyles_1 = require("./ResponsiveBaseStyles");
8
9
  /**
9
10
  * Pre-configured, high-converting theme presets tailored for different business categories.
10
11
  * Allows developers and AI agents to instantly generate distinct designs without copy-pasting styles.
@@ -177,5 +178,5 @@ function ThemeStyles({ theme, defaultPrimary = '#2563eb', defaultSecondary = '#0
177
178
  ${cssLines}
178
179
  }
179
180
  `;
180
- return (0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: css } });
181
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ResponsiveBaseStyles_1.ResponsiveBaseStyles, {}), (0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: css } })] }));
181
182
  }
@@ -60,7 +60,7 @@ function TrustBadges({ fieldPath = 'content.trustBadges', title, subtitle, badge
60
60
  };
61
61
  return ((0, jsx_runtime_1.jsxs)("section", { className: `w-full py-8 my-4 ${className}`, "data-preview-field-path": fieldPath, style: style, children: [(title || subtitle) && ((0, jsx_runtime_1.jsxs)("div", { className: "text-center mb-8", children: [title && ((0, jsx_runtime_1.jsx)("h3", { className: "text-xl sm:text-2xl font-bold tracking-tight text-slate-900", children: title })), subtitle && ((0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-sm text-slate-600 max-w-xl mx-auto", children: subtitle }))] })), (0, jsx_runtime_1.jsx)("div", { className: variant === 'inline'
62
62
  ? 'flex flex-wrap items-center justify-around gap-6'
63
- : 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6', children: badges.map((badge) => ((0, jsx_runtime_1.jsxs)("div", { className: `flex items-start gap-4 p-5 rounded-2xl transition-all duration-200 hover:-translate-y-0.5 ${variant === 'cards'
63
+ : 'deneb-trust-grid grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6', children: badges.map((badge) => ((0, jsx_runtime_1.jsxs)("div", { className: `flex items-start gap-4 p-5 rounded-2xl transition-all duration-200 hover:-translate-y-0.5 ${variant === 'cards'
64
64
  ? 'bg-white border border-slate-200/80 shadow-sm hover:shadow-md'
65
65
  : 'bg-transparent'}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-shrink-0 p-2.5 rounded-xl bg-slate-50 border border-slate-100 flex items-center justify-center", children: renderIcon(badge) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-sm font-semibold text-slate-900 leading-tight", children: badge.title }), (0, jsx_runtime_1.jsx)("p", { className: "mt-1 text-xs text-slate-500 leading-relaxed", children: badge.description })] })] }, badge.id))) })] }));
66
66
  }
@@ -56,7 +56,8 @@ function FloatingContactWidget({ fieldPath = 'contact', defaultPhone, defaultWha
56
56
  position: 'absolute',
57
57
  bottom: '4.25rem',
58
58
  [isRight ? 'right' : 'left']: '0',
59
- width: '18rem',
59
+ width: 'min(18rem, calc(100vw - 2rem))',
60
+ maxWidth: 'calc(100vw - 2rem)',
60
61
  backgroundColor: '#ffffff',
61
62
  borderRadius: '1rem',
62
63
  boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.15), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
@@ -64,5 +65,5 @@ function FloatingContactWidget({ fieldPath = 'contact', defaultPhone, defaultWha
64
65
  overflow: 'hidden',
65
66
  animation: 'deneb-pop 0.2s cubic-bezier(0.16, 1, 0.3, 1)',
66
67
  };
67
- return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-floating-contact fixed z-50 bottom-6 ${isRight ? 'right-6' : 'left-6'} ${className}`, style: containerStyle, "data-preview-field-path": fieldPath, children: [isOpen && ((0, jsx_runtime_1.jsxs)("div", { className: "deneb-contact-popup absolute bottom-16 bg-white rounded-2xl shadow-2xl border border-slate-200 w-72 overflow-hidden text-slate-800", style: menuStyle, children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-slate-900 text-white p-4 flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-bold text-sm leading-tight text-white", children: storeName }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-emerald-400 font-medium flex items-center gap-1.5 mt-0.5", children: [(0, jsx_runtime_1.jsx)("span", { className: "w-2 h-2 rounded-full bg-emerald-400 animate-pulse" }), "Online & Ready to Help"] })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setIsOpen(false), className: "text-slate-400 hover:text-white p-1 rounded transition-colors", "aria-label": "Close contact drawer", children: (0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-2 text-sm bg-slate-50", children: [hasWhatsApp && ((0, jsx_runtime_1.jsxs)("a", { href: (0, urls_1.createWhatsAppUrl)(whatsapp, defaultMessage), target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-3 p-2.5 rounded-xl bg-white border border-slate-200/80 hover:border-emerald-400 hover:shadow-sm transition-all text-slate-800", "data-preview-field-path": `${fieldPath}.whatsapp`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-9 h-9 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M12.031 6.172c-3.181 0-5.767 2.586-5.768 5.766-.001 1.298.38 2.27 1.019 3.287l-.582 2.128 2.182-.573c.978.58 1.911.928 3.145.929 3.178 0 5.767-2.587 5.768-5.766.001-3.187-2.575-5.77-5.764-5.771zm3.392 8.244c-.144.405-.837.774-1.17.824-.312.045-.694.062-1.116-.073-.266-.086-.61-.225-1.047-.417-1.854-.814-3.056-2.695-3.15-2.819-.092-.124-.755-.999-.755-1.907 0-.909.479-1.353.649-1.536.17-.183.371-.23.495-.23.124 0 .248.002.355.008.113.006.265-.043.414.316.155.372.531 1.296.577 1.39.046.094.077.204.015.328-.061.124-.092.202-.184.31-.092.108-.195.241-.278.324-.093.093-.19.195-.082.381.109.186.483.797 1.037 1.289.713.633 1.314.829 1.501.922.186.093.295.078.404-.047.11-.124.467-.543.591-.729.124-.186.248-.155.418-.093.17.062 1.082.51 1.268.603.186.093.31.14.356.217.046.077.046.449-.098.854z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold text-slate-900 text-xs", children: "Chat on WhatsApp" }), (0, jsx_runtime_1.jsx)("div", { className: "text-[11px] text-slate-500 truncate", children: whatsapp })] })] })), hasPhone && ((0, jsx_runtime_1.jsxs)("a", { href: (0, urls_1.createPhoneUrl)(phone), className: "flex items-center gap-3 p-2.5 rounded-xl bg-white border border-slate-200/80 hover:border-blue-400 hover:shadow-sm transition-all text-slate-800", "data-preview-field-path": `${fieldPath}.phone`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-9 h-9 rounded-lg bg-blue-50 text-blue-600 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold text-slate-900 text-xs", children: "Direct Call" }), (0, jsx_runtime_1.jsx)("div", { className: "text-[11px] text-slate-500 truncate", children: phone })] })] })), hasEmail && ((0, jsx_runtime_1.jsxs)("a", { href: (0, urls_1.createEmailUrl)(email, `Inquiry: ${storeName}`), className: "flex items-center gap-3 p-2.5 rounded-xl bg-white border border-slate-200/80 hover:border-purple-400 hover:shadow-sm transition-all text-slate-800", "data-preview-field-path": `${fieldPath}.email`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-9 h-9 rounded-lg bg-purple-50 text-purple-600 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" }), (0, jsx_runtime_1.jsx)("polyline", { points: "22,6 12,13 2,6" })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold text-slate-900 text-xs", children: "Send Email" }), (0, jsx_runtime_1.jsx)("div", { className: "text-[11px] text-slate-500 truncate", children: email })] })] }))] })] })), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setIsOpen(!isOpen), style: bubbleStyle, className: "deneb-bubble hover:scale-105 active:scale-95 flex items-center justify-center focus:outline-none", "aria-label": "Toggle contact channels", children: isOpen ? ((0, jsx_runtime_1.jsxs)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] })) : ((0, jsx_runtime_1.jsx)("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M12.031 6.172c-3.181 0-5.767 2.586-5.768 5.766-.001 1.298.38 2.27 1.019 3.287l-.582 2.128 2.182-.573c.978.58 1.911.928 3.145.929 3.178 0 5.767-2.587 5.768-5.766.001-3.187-2.575-5.77-5.764-5.771zm3.392 8.244c-.144.405-.837.774-1.17.824-.312.045-.694.062-1.116-.073-.266-.086-.61-.225-1.047-.417-1.854-.814-3.056-2.695-3.15-2.819-.092-.124-.755-.999-.755-1.907 0-.909.479-1.353.649-1.536.17-.183.371-.23.495-.23.124 0 .248.002.355.008.113.006.265-.043.414.316.155.372.531 1.296.577 1.39.046.094.077.204.015.328-.061.124-.092.202-.184.31-.092.108-.195.241-.278.324-.093.093-.19.195-.082.381.109.186.483.797 1.037 1.289.713.633 1.314.829 1.501.922.186.093.295.078.404-.047.11-.124.467-.543.591-.729.124-.186.248-.155.418-.093.17.062 1.082.51 1.268.603.186.093.31.14.356.217.046.077.046.449-.098.854z" }) })) })] }));
68
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-floating-contact fixed z-50 bottom-6 ${isRight ? 'right-6 deneb-floating-right' : 'left-6 deneb-floating-left'} ${className}`, style: containerStyle, "data-preview-field-path": fieldPath, children: [isOpen && ((0, jsx_runtime_1.jsxs)("div", { className: "deneb-contact-popup absolute bottom-16 bg-white rounded-2xl shadow-2xl border border-slate-200 w-72 overflow-hidden text-slate-800", style: menuStyle, children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-slate-900 text-white p-4 flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-bold text-sm leading-tight text-white", children: storeName }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-emerald-400 font-medium flex items-center gap-1.5 mt-0.5", children: [(0, jsx_runtime_1.jsx)("span", { className: "w-2 h-2 rounded-full bg-emerald-400 animate-pulse" }), "Online & Ready to Help"] })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setIsOpen(false), className: "text-slate-400 hover:text-white p-1 rounded transition-colors", "aria-label": "Close contact drawer", children: (0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-2 text-sm bg-slate-50", children: [hasWhatsApp && ((0, jsx_runtime_1.jsxs)("a", { href: (0, urls_1.createWhatsAppUrl)(whatsapp, defaultMessage), target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-3 p-2.5 rounded-xl bg-white border border-slate-200/80 hover:border-emerald-400 hover:shadow-sm transition-all text-slate-800", "data-preview-field-path": `${fieldPath}.whatsapp`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-9 h-9 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M12.031 6.172c-3.181 0-5.767 2.586-5.768 5.766-.001 1.298.38 2.27 1.019 3.287l-.582 2.128 2.182-.573c.978.58 1.911.928 3.145.929 3.178 0 5.767-2.587 5.768-5.766.001-3.187-2.575-5.77-5.764-5.771zm3.392 8.244c-.144.405-.837.774-1.17.824-.312.045-.694.062-1.116-.073-.266-.086-.61-.225-1.047-.417-1.854-.814-3.056-2.695-3.15-2.819-.092-.124-.755-.999-.755-1.907 0-.909.479-1.353.649-1.536.17-.183.371-.23.495-.23.124 0 .248.002.355.008.113.006.265-.043.414.316.155.372.531 1.296.577 1.39.046.094.077.204.015.328-.061.124-.092.202-.184.31-.092.108-.195.241-.278.324-.093.093-.19.195-.082.381.109.186.483.797 1.037 1.289.713.633 1.314.829 1.501.922.186.093.295.078.404-.047.11-.124.467-.543.591-.729.124-.186.248-.155.418-.093.17.062 1.082.51 1.268.603.186.093.31.14.356.217.046.077.046.449-.098.854z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold text-slate-900 text-xs", children: "Chat on WhatsApp" }), (0, jsx_runtime_1.jsx)("div", { className: "text-[11px] text-slate-500 truncate", children: whatsapp })] })] })), hasPhone && ((0, jsx_runtime_1.jsxs)("a", { href: (0, urls_1.createPhoneUrl)(phone), className: "flex items-center gap-3 p-2.5 rounded-xl bg-white border border-slate-200/80 hover:border-blue-400 hover:shadow-sm transition-all text-slate-800", "data-preview-field-path": `${fieldPath}.phone`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-9 h-9 rounded-lg bg-blue-50 text-blue-600 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold text-slate-900 text-xs", children: "Direct Call" }), (0, jsx_runtime_1.jsx)("div", { className: "text-[11px] text-slate-500 truncate", children: phone })] })] })), hasEmail && ((0, jsx_runtime_1.jsxs)("a", { href: (0, urls_1.createEmailUrl)(email, `Inquiry: ${storeName}`), className: "flex items-center gap-3 p-2.5 rounded-xl bg-white border border-slate-200/80 hover:border-purple-400 hover:shadow-sm transition-all text-slate-800", "data-preview-field-path": `${fieldPath}.email`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-9 h-9 rounded-lg bg-purple-50 text-purple-600 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" }), (0, jsx_runtime_1.jsx)("polyline", { points: "22,6 12,13 2,6" })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-semibold text-slate-900 text-xs", children: "Send Email" }), (0, jsx_runtime_1.jsx)("div", { className: "text-[11px] text-slate-500 truncate", children: email })] })] }))] })] })), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setIsOpen(!isOpen), style: bubbleStyle, className: "deneb-bubble hover:scale-105 active:scale-95 flex items-center justify-center focus:outline-none", "aria-label": "Toggle contact channels", children: isOpen ? ((0, jsx_runtime_1.jsxs)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] })) : ((0, jsx_runtime_1.jsx)("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { d: "M12.031 6.172c-3.181 0-5.767 2.586-5.768 5.766-.001 1.298.38 2.27 1.019 3.287l-.582 2.128 2.182-.573c.978.58 1.911.928 3.145.929 3.178 0 5.767-2.587 5.768-5.766.001-3.187-2.575-5.77-5.764-5.771zm3.392 8.244c-.144.405-.837.774-1.17.824-.312.045-.694.062-1.116-.073-.266-.086-.61-.225-1.047-.417-1.854-.814-3.056-2.695-3.15-2.819-.092-.124-.755-.999-.755-1.907 0-.909.479-1.353.649-1.536.17-.183.371-.23.495-.23.124 0 .248.002.355.008.113.006.265-.043.414.316.155.372.531 1.296.577 1.39.046.094.077.204.015.328-.061.124-.092.202-.184.31-.092.108-.195.241-.278.324-.093.093-.19.195-.082.381.109.186.483.797 1.037 1.289.713.633 1.314.829 1.501.922.186.093.295.078.404-.047.11-.124.467-.543.591-.729.124-.186.248-.155.418-.093.17.062 1.082.51 1.268.603.186.093.31.14.356.217.046.077.046.449-.098.854z" }) })) })] }));
68
69
  }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ export declare const DENEB_FONTS_LINK_ID = "deneb-google-fonts";
3
+ export interface FontLoaderProps {
4
+ /** Additional font ids to preload beyond site-data discovery */
5
+ fontIds?: string[];
6
+ /** Use Google Fonts CDN (default in preview). Set false when `deneb fonts install` CSS is present */
7
+ useGoogleCdn?: boolean;
8
+ }
9
+ /**
10
+ * Dynamically loads Google Fonts used by the active site-data theme + style tree.
11
+ * In production, pair with `deneb fonts install` which writes self-hosted @fontsource CSS.
12
+ */
13
+ export declare function FontLoader({ fontIds, useGoogleCdn }: FontLoaderProps): React.JSX.Element | null;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.DENEB_FONTS_LINK_ID = void 0;
5
+ exports.FontLoader = FontLoader;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const useDenebFonts_1 = require("./useDenebFonts");
9
+ exports.DENEB_FONTS_LINK_ID = 'deneb-google-fonts';
10
+ /**
11
+ * Dynamically loads Google Fonts used by the active site-data theme + style tree.
12
+ * In production, pair with `deneb fonts install` which writes self-hosted @fontsource CSS.
13
+ */
14
+ function FontLoader({ fontIds = [], useGoogleCdn = true }) {
15
+ const { googleStylesheetUrl, cssVariables, fontIds: activeFontIds } = (0, useDenebFonts_1.useDenebFonts)(fontIds);
16
+ const loadedUrl = (0, react_1.useRef)(null);
17
+ const enableCdn = useGoogleCdn;
18
+ (0, react_1.useEffect)(() => {
19
+ if (!enableCdn || !googleStylesheetUrl || typeof document === 'undefined')
20
+ return;
21
+ const selfHosted = getComputedStyle(document.documentElement)
22
+ .getPropertyValue('--deneb-fonts-selfhosted')
23
+ .trim();
24
+ if (selfHosted === '1')
25
+ return;
26
+ if (loadedUrl.current === googleStylesheetUrl)
27
+ return;
28
+ let link = document.getElementById(exports.DENEB_FONTS_LINK_ID);
29
+ if (!link) {
30
+ link = document.createElement('link');
31
+ link.id = exports.DENEB_FONTS_LINK_ID;
32
+ link.rel = 'stylesheet';
33
+ document.head.appendChild(link);
34
+ }
35
+ link.href = googleStylesheetUrl;
36
+ loadedUrl.current = googleStylesheetUrl;
37
+ }, [enableCdn, googleStylesheetUrl]);
38
+ if (Object.keys(cssVariables).length === 0)
39
+ return null;
40
+ return ((0, jsx_runtime_1.jsx)("style", { "data-deneb-font-vars": true, "data-deneb-font-count": activeFontIds.length, children: `:root { ${Object.entries(cssVariables)
41
+ .map(([key, value]) => `${key}: ${value};`)
42
+ .join(' ')} }` }));
43
+ }
@@ -0,0 +1,6 @@
1
+ export declare function useDenebFonts(extraFontIds?: string[]): {
2
+ fontIds: string[];
3
+ googleStylesheetUrl: string | null;
4
+ cssVariables: Record<string, string>;
5
+ catalog: (import("@deneb-ui/core").DenebFontDefinition | null)[];
6
+ };