@deneb-ui/ui 2.0.95 → 2.0.96

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 (37) hide show
  1. package/README.md +119 -0
  2. package/dist/DenebComponentStyles.js +7 -0
  3. package/dist/EditableCustomerReviews.d.ts +2 -1
  4. package/dist/EditableCustomerReviews.js +2 -2
  5. package/dist/EditableFAQAccordion.d.ts +3 -2
  6. package/dist/EditableFAQAccordion.js +2 -1
  7. package/dist/EditableGoogleFeedback.js +1 -1
  8. package/dist/EditableHero.js +2 -2
  9. package/dist/EditableProductCard.d.ts +15 -71
  10. package/dist/EditableProductCard.js +176 -27
  11. package/dist/EditableProductDetail.d.ts +11 -6
  12. package/dist/EditableProductDetail.js +24 -9
  13. package/dist/EditableProductGrid.d.ts +4 -1
  14. package/dist/EditableProductGrid.js +3 -3
  15. package/dist/EditableProductShowcase.js +1 -1
  16. package/dist/EditableSection.d.ts +32 -7
  17. package/dist/EditableSection.js +20 -7
  18. package/dist/EditableTestimonialSection.js +1 -1
  19. package/dist/EditableText.d.ts +5 -1
  20. package/dist/EditableText.js +2 -2
  21. package/dist/SiteDataProvider.js +16 -5
  22. package/dist/TrustBadges.js +1 -1
  23. package/dist/cart/useCart.d.ts +3 -0
  24. package/dist/cart/useCart.js +20 -9
  25. package/dist/examples/CompleteStorefrontExample.d.ts +11 -0
  26. package/dist/examples/CompleteStorefrontExample.js +97 -0
  27. package/dist/examples/ProductPricingExample.d.ts +9 -0
  28. package/dist/examples/ProductPricingExample.js +99 -0
  29. package/dist/examples/SectionLayoutExample.d.ts +7 -0
  30. package/dist/examples/SectionLayoutExample.js +17 -0
  31. package/dist/examples/index.d.ts +3 -0
  32. package/dist/examples/index.js +19 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +2 -0
  35. package/dist/utils/productOptions.d.ts +57 -40
  36. package/dist/utils/productOptions.js +249 -62
  37. package/package.json +2 -2
package/README.md CHANGED
@@ -600,6 +600,125 @@ The engine automatically:
600
600
 
601
601
  ---
602
602
 
603
+ ### Modular Section Architecture (`<section>` & `<Section>`)
604
+
605
+ DENEB UI introduces a modular `<section>` architecture designed specifically for visual website builders, enabling 1-click section deletion, full layout centering, and background styling.
606
+
607
+ #### Key Features
608
+ * **100% Contract Compliant**: Automatically sets `data-design-section`, `data-section-id`, and `id`.
609
+ * **1-Click Delete / Hide**: Supports `hidden={true}` or visual editor hide toggle (`display: none`).
610
+ * **Instant Centering**: One-prop horizontal and text centering with `center={true}` or `align="center"`.
611
+ * **Responsive Container**: `container={true}` wraps children in a responsive, max-width contained inner wrapper (`1280px`).
612
+
613
+ ```tsx
614
+ import { Section, EditableSection, Heading, Paragraph, Button } from "@deneb-ui/ui";
615
+
616
+ export function PromoSection() {
617
+ return (
618
+ // Clean shorthand alias
619
+ <Section
620
+ name="special-promo"
621
+ center={true}
622
+ container={true}
623
+ bg="#f8fafc"
624
+ padding="xl"
625
+ >
626
+ <Heading level={2} id="promo.title" defaultValue="Limited Time Offer" />
627
+ <Paragraph id="promo.subtitle" defaultValue="Get 20% off all handcrafted items." />
628
+ <Button id="promo.cta" defaultValue="Shop the Sale" />
629
+ </Section>
630
+ );
631
+ }
632
+ ```
633
+
634
+ ---
635
+
636
+ ### Dual Product Pricing & Apparel Variants
637
+
638
+ DENEB UI commerce components natively support both **Single Fixed Prices** and **Dynamic Price Ranges**, as well as apparel clothing options (color swatches with image swapping and size chips).
639
+
640
+ #### 1. Single Fixed Price
641
+ ```tsx
642
+ import { ProductCard } from "@deneb-ui/ui";
643
+
644
+ <ProductCard
645
+ item={{
646
+ id: "prod-1",
647
+ name: "Classic Silk Shirt",
648
+ price: 3500,
649
+ compareAtPrice: 4500,
650
+ currency: "LKR",
651
+ imageUrl: "/images/shirt.jpg"
652
+ }}
653
+ itemPath="products[0]"
654
+ />
655
+ ```
656
+
657
+ #### 2. Dynamic Price Range & Apparel Color Swatches
658
+ ```tsx
659
+ import { ProductCard } from "@deneb-ui/ui";
660
+
661
+ <ProductCard
662
+ item={{
663
+ id: "prod-2",
664
+ name: "Linen Summer Tunic",
665
+ minPrice: 2500,
666
+ maxPrice: 4500,
667
+ priceRange: "LKR 2,500 – LKR 4,500",
668
+ isPriceRange: true,
669
+ currency: "LKR",
670
+ imageUrl: "/images/tunic-navy.jpg",
671
+ colors: [
672
+ { name: "Navy Blue", hex: "#1e3a8a", imageUrl: "/images/tunic-navy.jpg" },
673
+ { name: "Olive Green", hex: "#3f6212", imageUrl: "/images/tunic-olive.jpg" },
674
+ { name: "Cream White", hex: "#f8fafc", imageUrl: "/images/tunic-white.jpg" }
675
+ ],
676
+ sizes: ["S", "M", "L", "XL"],
677
+ variants: [
678
+ { color: "Navy Blue", size: "S", price: 2500 },
679
+ { color: "Navy Blue", size: "XL", price: 3200 },
680
+ { color: "Olive Green", size: "L", price: 4500 }
681
+ ]
682
+ }}
683
+ itemPath="products[1]"
684
+ whatsappPhone="+94771234567"
685
+ />
686
+ ```
687
+ * **Interactive Color Swatches**: Clicking a color automatically swaps the card's active product photo to that color's image.
688
+ * **Variant Price Resolution**: Displays the range (`LKR 2,500 – LKR 4,500`) initially, then resolves to the exact variant price when a size/color is selected.
689
+ * **Smart WhatsApp & Cart**: Automatically compiles `[Color: Navy Blue, Size: XL]` into the customer's WhatsApp order message and cart drawer line items.
690
+
691
+ ---
692
+
693
+ ## Reference Examples
694
+
695
+ DENEB UI includes full, ready-to-run reference examples demonstrating modular layouts, dual pricing, and complete storefront architecture:
696
+
697
+ ```tsx
698
+ import {
699
+ SectionLayoutExample,
700
+ ProductPricingExample,
701
+ CompleteStorefrontExample
702
+ } from "@deneb-ui/ui";
703
+
704
+ // 1. Modular section centering & hiding controls
705
+ export function SectionDemo() {
706
+ return <SectionLayoutExample />;
707
+ }
708
+
709
+ // 2. Single price, price ranges, and apparel swatches with photo switching
710
+ export function CommerceDemo() {
711
+ return <ProductPricingExample />;
712
+ }
713
+
714
+ // 3. Full production-ready Next.js storefront page
715
+ export function FullStorefrontDemo() {
716
+ return <CompleteStorefrontExample />;
717
+ }
718
+ ```
719
+
720
+ ---
721
+
603
722
  ## Related Packages
604
723
 
605
724
  | Package | Purpose |
@@ -78,6 +78,13 @@ function DenebComponentStyles() {
78
78
  max-width: var(--deneb-section-max-w, inherit);
79
79
  background-color: var(--deneb-section-bg, inherit);
80
80
  background-image: var(--deneb-section-bg-image, none);
81
+ text-align: var(--deneb-section-align, inherit);
82
+ display: var(--deneb-section-display, block);
83
+ order: var(--deneb-section-order, 0);
84
+ }
85
+ body > main, main, [data-preview-page-key] {
86
+ display: flex;
87
+ flex-direction: column;
81
88
  }
82
89
  `;
83
90
  return (0, jsx_runtime_1.jsx)("style", { "data-deneb-component-styles": true, children: css });
@@ -15,6 +15,7 @@ export interface EditableCustomerReviewsProps extends React.HTMLAttributes<HTMLE
15
15
  * Field path prefix for live Fivora Visual Editing synchronization (e.g. "home").
16
16
  */
17
17
  sectionPath?: string;
18
+ listPath?: string;
18
19
  /**
19
20
  * Title of the reviews section.
20
21
  */
@@ -44,5 +45,5 @@ export interface EditableCustomerReviewsProps extends React.HTMLAttributes<HTMLE
44
45
  *
45
46
  * Created by Chamika Gayashan & Induranga Kawishwara
46
47
  */
47
- export declare function EditableCustomerReviews({ sectionPath, title, subtitle, averageRating, totalReviews, reviews, className, style, ...props }: EditableCustomerReviewsProps): React.JSX.Element;
48
+ export declare function EditableCustomerReviews({ sectionPath, listPath, title, subtitle, averageRating, totalReviews, reviews, className, style, ...props }: EditableCustomerReviewsProps): React.JSX.Element;
48
49
  export declare const CustomerReviews: typeof EditableCustomerReviews;
@@ -44,7 +44,7 @@ const DEFAULT_REVIEWS = [
44
44
  *
45
45
  * Created by Chamika Gayashan & Induranga Kawishwara
46
46
  */
47
- function EditableCustomerReviews({ sectionPath = 'home', title, subtitle, averageRating, totalReviews, reviews, className = '', style, ...props }) {
47
+ function EditableCustomerReviews({ sectionPath = 'home', listPath = 'reviews', title, subtitle, averageRating, totalReviews, reviews, className = '', style, ...props }) {
48
48
  const [selectedStarFilter, setSelectedStarFilter] = (0, react_1.useState)(null);
49
49
  const liveReviews = (0, SiteDataProvider_1.useReviews)();
50
50
  const siteData = (0, SiteDataProvider_1.useSiteData)();
@@ -85,7 +85,7 @@ function EditableCustomerReviews({ sectionPath = 'home', title, subtitle, averag
85
85
  return normalizedReviews;
86
86
  return normalizedReviews.filter((r) => r.rating === selectedStarFilter);
87
87
  }, [normalizedReviews, selectedStarFilter]);
88
- return ((0, jsx_runtime_1.jsxs)("section", { "data-preview-page-key": sectionPath, className: `editable-customer-reviews max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 ${className}`.trim(), style: style, ...props, children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-center max-w-2xl mx-auto mb-12", children: [subtitle && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsSubtitle`, className: "text-xs font-black tracking-widest uppercase text-emerald-600 dark:text-lime-400 block mb-2", children: resolvedSubtitle })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `${sectionPath}.reviewsTitle`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-slate-900 dark:text-white leading-tight", children: resolvedTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex text-amber-500 dark:text-amber-400 text-lg", children: '★★★★★' }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-900 dark:text-white font-extrabold text-lg", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsAverage`, children: resolvedAverageRating }), " / 5.0"] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-500 dark:text-slate-400 text-sm", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsCount`, children: resolvedTotalReviews }), " reviews)"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center gap-2 mb-8", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedStarFilter(null), className: `px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all ${selectedStarFilter === null
88
+ return ((0, jsx_runtime_1.jsxs)("section", { id: props.id || "customer-reviews", "data-design-section": "customer-reviews", "data-section-id": "customer-reviews", "data-preview-page-key": sectionPath, className: `editable-customer-reviews max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 ${className}`.trim(), style: style, ...props, children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-center max-w-2xl mx-auto mb-12", children: [subtitle && ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsSubtitle`, className: "text-xs font-black tracking-widest uppercase text-emerald-600 dark:text-lime-400 block mb-2", children: resolvedSubtitle })), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `${sectionPath}.reviewsTitle`, className: "text-3xl sm:text-4xl font-extrabold tracking-tight text-slate-900 dark:text-white leading-tight", children: resolvedTitle }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex text-amber-500 dark:text-amber-400 text-lg", children: '★★★★★' }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-900 dark:text-white font-extrabold text-lg", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsAverage`, children: resolvedAverageRating }), " / 5.0"] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-slate-500 dark:text-slate-400 text-sm", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `${sectionPath}.reviewsCount`, children: resolvedTotalReviews }), " reviews)"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center gap-2 mb-8", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setSelectedStarFilter(null), className: `px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all ${selectedStarFilter === null
89
89
  ? 'bg-slate-900 text-white dark:bg-lime-400 dark:text-slate-950 font-extrabold shadow-sm'
90
90
  : 'bg-slate-100 text-slate-600 hover:text-slate-900 border border-slate-200 dark:bg-slate-900/60 dark:text-slate-400 dark:hover:text-white dark:border-slate-800'}`, children: "All Reviews" }), [5, 4, 3].map((stars) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: () => setSelectedStarFilter(stars), className: `px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-1 ${selectedStarFilter === stars
91
91
  ? 'bg-slate-900 text-white dark:bg-lime-400 dark:text-slate-950 font-extrabold shadow-sm'
@@ -13,7 +13,8 @@ export interface EditableFAQItemProps extends React.HTMLAttributes<HTMLElement>
13
13
  export declare function EditableFAQItem({ itemPath, item, defaultOpen, className, style, ...props }: EditableFAQItemProps): React.JSX.Element;
14
14
  export interface EditableFAQAccordionProps extends React.HTMLAttributes<HTMLDivElement> {
15
15
  listPath?: string;
16
- items: FAQItem[];
16
+ items?: FAQItem[];
17
+ faqs?: FAQItem[];
17
18
  defaultOpenIndex?: number;
18
19
  }
19
- export declare function EditableFAQAccordion({ listPath, items, defaultOpenIndex, className, style, ...props }: EditableFAQAccordionProps): React.JSX.Element;
20
+ export declare function EditableFAQAccordion({ listPath, items: itemsProp, faqs, defaultOpenIndex, className, style, ...props }: EditableFAQAccordionProps): React.JSX.Element;
@@ -53,7 +53,8 @@ function EditableFAQItem({ itemPath, item, defaultOpen = true, className = '', s
53
53
  lineHeight: 1.6,
54
54
  } }) })] }));
55
55
  }
56
- function EditableFAQAccordion({ listPath = 'home.faq', items = [], defaultOpenIndex = 0, className = '', style, ...props }) {
56
+ function EditableFAQAccordion({ listPath = 'home.faq', items: itemsProp, faqs, defaultOpenIndex = 0, className = '', style, ...props }) {
57
+ const items = faqs || itemsProp || [];
57
58
  return ((0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": listPath, style: {
58
59
  maxWidth: '800px',
59
60
  margin: '0 auto',
@@ -153,7 +153,7 @@ function EditableGoogleFeedback({ heading, subheading, badgeTitle = 'Google Revi
153
153
  const effectiveSubheading = subheading ?? siteData?.content?.[basePath]?.subheading ?? 'Real stories and verified 5-star reviews from our official Google Business profile.';
154
154
  const hasCustomPy = /(^|\s)(p|py|pt)-/.test(className);
155
155
  const defaultPadding = hasCustomPy ? '' : 'py-6 sm:py-8';
156
- return ((0, jsx_runtime_1.jsx)("section", { "data-preview-page-key": basePath, className: `editable-google-feedback w-full ${defaultPadding} ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-10", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row md:items-end justify-between gap-6 mb-6 sm:mb-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "max-w-2xl space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-2.5 px-3.5 py-1.5 rounded-full bg-slate-100 border border-slate-200 dark:bg-slate-900/80 dark:border-slate-800 shadow-sm", children: [(0, jsx_runtime_1.jsx)("img", { src: badgeIcon || DEFAULT_GOOGLE_ICON, alt: "Google", "data-preview-field-path": `feedback.badgeIcon`, className: "w-4 h-4 object-contain" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeTitle`, className: "text-xs uppercase tracking-widest font-black text-slate-800 dark:text-slate-200", children: badgeTitle }), (0, jsx_runtime_1.jsx)("span", { className: "w-1 h-1 rounded-full bg-slate-400 dark:bg-slate-600" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1.5", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "text-xs font-black text-amber-600 dark:text-amber-400", children: effectiveBadgeRating }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 14 }, sIdx))) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-[11px] text-slate-500 dark:text-slate-400 font-medium hidden sm:inline", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, children: effectiveBadgeCount }), ")"] })] }), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `feedback.heading`, className: "font-heading text-2xl xs:text-3xl sm:text-4xl lg:text-5xl font-black text-slate-900 dark:text-white tracking-tight", children: effectiveHeading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `feedback.subheading`, className: "text-xs sm:text-base text-slate-600 dark:text-slate-400 leading-relaxed", children: effectiveSubheading })] }), (0, jsx_runtime_1.jsx)("div", { className: "hidden md:flex flex-col items-end text-right", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "font-heading text-4xl font-black text-amber-500 dark:text-amber-400", children: badgeRating }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 16 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, className: "text-xs text-slate-500 dark:text-slate-400 font-bold", children: badgeReviewsCount })] })] }) })] }), (0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": `feedback.feedbacks`, className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6", children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(FeedbackCard, { item: item, index: index, maxStars: maxStars, badgeIcon: badgeIcon, badgeTitle: badgeTitle, cardClassName: cardClassName }, item.id || String(index)))) })] }) }));
156
+ return ((0, jsx_runtime_1.jsx)("section", { id: props.id || "google-feedback", "data-design-section": "google-feedback", "data-section-id": "google-feedback", "data-preview-page-key": basePath, className: `editable-google-feedback w-full ${defaultPadding} ${className}`.trim(), style: style, ...props, children: (0, jsx_runtime_1.jsxs)("div", { className: "max-w-[1600px] mx-auto px-4 sm:px-6 lg:px-10", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row md:items-end justify-between gap-6 mb-6 sm:mb-8", children: [(0, jsx_runtime_1.jsxs)("div", { className: "max-w-2xl space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "inline-flex items-center gap-2.5 px-3.5 py-1.5 rounded-full bg-slate-100 border border-slate-200 dark:bg-slate-900/80 dark:border-slate-800 shadow-sm", children: [(0, jsx_runtime_1.jsx)("img", { src: badgeIcon || DEFAULT_GOOGLE_ICON, alt: "Google", "data-preview-field-path": `feedback.badgeIcon`, className: "w-4 h-4 object-contain" }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeTitle`, className: "text-xs uppercase tracking-widest font-black text-slate-800 dark:text-slate-200", children: badgeTitle }), (0, jsx_runtime_1.jsx)("span", { className: "w-1 h-1 rounded-full bg-slate-400 dark:bg-slate-600" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1.5", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "text-xs font-black text-amber-600 dark:text-amber-400", children: effectiveBadgeRating }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 14 }, sIdx))) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-[11px] text-slate-500 dark:text-slate-400 font-medium hidden sm:inline", children: ["(", (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, children: effectiveBadgeCount }), ")"] })] }), (0, jsx_runtime_1.jsx)("h2", { "data-preview-field-path": `feedback.heading`, className: "font-heading text-2xl xs:text-3xl sm:text-4xl lg:text-5xl font-black text-slate-900 dark:text-white tracking-tight", children: effectiveHeading }), (0, jsx_runtime_1.jsx)("p", { "data-preview-field-path": `feedback.subheading`, className: "text-xs sm:text-base text-slate-600 dark:text-slate-400 leading-relaxed", children: effectiveSubheading })] }), (0, jsx_runtime_1.jsx)("div", { className: "hidden md:flex flex-col items-end text-right", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeRating`, className: "font-heading text-4xl font-black text-amber-500 dark:text-amber-400", children: badgeRating }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-[2px]", children: Array.from({ length: 5 }).map((_, sIdx) => ((0, jsx_runtime_1.jsx)(GoogleStarSvg, { filled: true, size: 16 }, sIdx))) }), (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": `feedback.badgeReviewsCount`, className: "text-xs text-slate-500 dark:text-slate-400 font-bold", children: badgeReviewsCount })] })] }) })] }), (0, jsx_runtime_1.jsx)("div", { "data-preview-list-path": `feedback.feedbacks`, className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6", children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(FeedbackCard, { item: item, index: index, maxStars: maxStars, badgeIcon: badgeIcon, badgeTitle: badgeTitle, cardClassName: cardClassName }, item.id || String(index)))) })] }) }));
157
157
  }
158
158
  // Canonical alias
159
159
  exports.GoogleFeedback = EditableGoogleFeedback;
@@ -33,7 +33,7 @@ function EditableHeroCentered({ pageKey = 'home', badgePath = 'home.heroEyebrow'
33
33
  window.location.href = `${cleanBase}${cleanPath}` || '/';
34
34
  }
35
35
  };
36
- return ((0, jsx_runtime_1.jsx)("section", { "data-design-section": "hero", style: {
36
+ return ((0, jsx_runtime_1.jsx)("section", { id: props.id || "hero", "data-design-section": "hero", "data-section-id": "hero", style: {
37
37
  padding: '5rem 1.5rem',
38
38
  textAlign: 'center',
39
39
  position: 'relative',
@@ -112,7 +112,7 @@ function EditableHeroSplit({ pageKey = 'home', badgePath = 'home.heroEyebrow', t
112
112
  window.location.href = `${cleanBase}${cleanPath}` || '/';
113
113
  }
114
114
  };
115
- return ((0, jsx_runtime_1.jsxs)("section", { "data-design-section": "hero", style: {
115
+ return ((0, jsx_runtime_1.jsxs)("section", { id: props.id || "hero", "data-design-section": "hero", "data-section-id": "hero", style: {
116
116
  padding: '5rem 1.5rem',
117
117
  display: 'grid',
118
118
  gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { MeasurementUnit } from './utils/productOptions';
2
+ import { MeasurementUnit, ProductVariant } from './utils/productOptions';
3
3
  export interface ProductItem {
4
4
  id?: string | number;
5
5
  name?: string;
@@ -46,101 +46,45 @@ export interface ProductItem {
46
46
  colors?: Array<string | {
47
47
  name: string;
48
48
  hex?: string;
49
+ image?: string;
49
50
  }> | string;
50
51
  colorsText?: string;
51
52
  colorsLabel?: string;
53
+ variants?: ProductVariant[];
54
+ variantPrices?: Record<string, number | string>;
55
+ minPrice?: string | number;
56
+ maxPrice?: string | number;
57
+ priceMin?: string | number;
58
+ priceMax?: string | number;
59
+ priceRange?: [number | string, number | string] | string;
52
60
  [key: string]: unknown;
53
61
  }
54
62
  export type ProductCardVariant = 'modern-glass' | 'classic' | 'minimal' | 'horizontal';
55
63
  export interface EditableProductCardProps extends React.HTMLAttributes<HTMLElement> {
56
- /**
57
- * The item path for the product, e.g. "products[0]" or "featuredProducts[1]".
58
- */
59
64
  itemPath: string;
60
- /**
61
- * The product data object.
62
- */
63
- product: ProductItem;
64
- /**
65
- * Design variant: 'modern-glass' | 'classic' | 'minimal' | 'horizontal'
66
- */
65
+ product?: ProductItem;
66
+ item?: ProductItem;
67
67
  cardVariant?: ProductCardVariant;
68
- /**
69
- * Fallback image URL if product image is empty.
70
- */
71
68
  imageFallback?: string;
72
- /**
73
- * HTML wrapper tag (default: 'article').
74
- */
75
69
  as?: React.ElementType;
76
- /**
77
- * Currency code or symbol (default: 'LKR').
78
- */
79
70
  currency?: string;
80
- /**
81
- * Whether to display the brand tag (default: true).
82
- */
83
71
  showBrand?: boolean;
84
- /**
85
- * Whether to display the price field (default: true).
86
- */
87
72
  showPrice?: boolean;
88
- /**
89
- * Whether to display the description field (default: true).
90
- */
91
73
  showDescription?: boolean;
92
- /**
93
- * Whether to display category pill (default: true if present).
94
- */
95
74
  showCategory?: boolean;
96
- /**
97
- * Default WhatsApp account number for inquiries (e.g. '94771234567').
98
- */
99
75
  whatsappNumber?: string;
100
- /**
101
- * Store name for WhatsApp message templates.
102
- */
76
+ whatsappPhone?: string;
103
77
  storeName?: string;
104
- /**
105
- * Whether to display the WhatsApp contact button (default: true).
106
- */
78
+ showOptions?: boolean;
79
+ allowInteractiveSwatches?: boolean;
107
80
  showWhatsAppButton?: boolean;
108
- /**
109
- * Whether to display the Add to Cart button (default: true).
110
- */
111
81
  showAddToCartButton?: boolean;
112
- /**
113
- * Default label for the WhatsApp button (default: 'Inquire on WhatsApp').
114
- */
115
82
  whatsappActionLabel?: string;
116
- /**
117
- * Default label for the Add to Cart button (default: 'Add to Cart').
118
- */
119
83
  addToCartLabel?: string;
120
- /**
121
- * Optional custom action slot (overrides dual action buttons).
122
- */
123
84
  actionSlot?: React.ReactNode;
124
- /**
125
- * Legacy action label fallback.
126
- */
127
85
  actionLabel?: string;
128
- /**
129
- * Legacy action label path fallback.
130
- */
131
86
  actionLabelPath?: string;
132
- /**
133
- * Optional callback when Add to Cart is clicked.
134
- */
135
87
  onAddToCart?: (product: ProductItem) => void;
136
- /**
137
- * Optional callback when WhatsApp button is clicked.
138
- */
139
88
  onWhatsAppClick?: (product: ProductItem, url: string) => void;
140
89
  }
141
- /**
142
- * EditableProductCard is an elite, auto-balancing commerce card featuring
143
- * Sri Lankan Rupee (LKR) pricing, dual WhatsApp + Add to Cart actions,
144
- * brand attribution, and strict Fivora visual editing synchronization.
145
- */
146
- export declare function EditableProductCard({ itemPath, product, cardVariant, imageFallback, as: Component, currency, showBrand, showPrice, showDescription, showCategory, whatsappNumber, storeName, showWhatsAppButton, showAddToCartButton, whatsappActionLabel, addToCartLabel, actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
90
+ export declare function EditableProductCard({ itemPath, product: productProp, item: itemProp, cardVariant, imageFallback, as: Component, currency, showBrand, showPrice, showDescription, showCategory, whatsappNumber: whatsappNumberProp, whatsappPhone: whatsappPhoneProp, showOptions, allowInteractiveSwatches, storeName, showWhatsAppButton, showAddToCartButton, whatsappActionLabel, addToCartLabel, actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, className, style, ...props }: EditableProductCardProps): React.JSX.Element;