@deneb-ui/ui 2.0.108 → 2.0.110

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.
@@ -17,5 +17,5 @@ export interface EditableCategoryPillsProps {
17
17
  *
18
18
  * Created by Chamika Gayashan & Induranga Kawishwara
19
19
  */
20
- export declare function EditableCategoryPills({ categories, fieldPath, selectedCategory: controlledSelected, onSelectCategory, allLabel, className, style, }: EditableCategoryPillsProps): React.JSX.Element;
20
+ export declare function EditableCategoryPills({ categories, fieldPath, selectedCategory: controlledSelected, onSelectCategory, allLabel, className, style, }: EditableCategoryPillsProps): React.JSX.Element | null;
21
21
  export declare const CategoryPills: typeof EditableCategoryPills;
@@ -54,23 +54,43 @@ function EditableCategoryPills({ categories, fieldPath = 'categories', selectedC
54
54
  const activeCategory = controlledSelected !== undefined ? controlledSelected : internalSelected;
55
55
  // Resolve list of categories
56
56
  const resolvedCategories = react_1.default.useMemo(() => {
57
+ const rawCandidates = [];
57
58
  if (categories && categories.length > 0) {
58
- return categories.includes(allLabel) ? categories : [allLabel, ...categories];
59
+ rawCandidates.push(...categories);
59
60
  }
60
- const rawCategories = siteData?.categories;
61
- if (Array.isArray(rawCategories) && rawCategories.length > 0) {
62
- const cats = rawCategories.map((c) => (typeof c === 'string' ? c : c.name || String(c)));
63
- return cats.includes(allLabel) ? cats : [allLabel, ...cats];
61
+ else {
62
+ const rawCategories = siteData?.categories;
63
+ if (Array.isArray(rawCategories) && rawCategories.length > 0) {
64
+ for (const c of rawCategories) {
65
+ const name = typeof c === "string" ? c : c?.name || String(c);
66
+ if (name)
67
+ rawCandidates.push(name);
68
+ }
69
+ }
70
+ else {
71
+ const rawProducts = siteData?.products;
72
+ if (Array.isArray(rawProducts) && rawProducts.length > 0) {
73
+ for (const p of rawProducts) {
74
+ if (p?.category)
75
+ rawCandidates.push(p.category);
76
+ }
77
+ }
78
+ }
64
79
  }
65
- // Infer categories from products array if present
66
- const rawProducts = siteData?.products;
67
- if (Array.isArray(rawProducts) && rawProducts.length > 0) {
68
- const inferred = Array.from(new Set(rawProducts.map((p) => p.category).filter(Boolean)));
69
- if (inferred.length > 0) {
70
- return [allLabel, ...inferred];
80
+ const map = new Map();
81
+ for (const item of rawCandidates) {
82
+ if (typeof item !== "string")
83
+ continue;
84
+ const trimmed = item.trim();
85
+ if (!trimmed || trimmed.toLowerCase() === allLabel.toLowerCase())
86
+ continue;
87
+ const lower = trimmed.toLowerCase();
88
+ if (!map.has(lower)) {
89
+ map.set(lower, trimmed);
71
90
  }
72
91
  }
73
- return DEFAULT_CATEGORIES;
92
+ const distinct = Array.from(map.values());
93
+ return distinct.length > 1 ? [allLabel, ...distinct] : [];
74
94
  }, [categories, siteData, allLabel]);
75
95
  const handleSelect = (category) => {
76
96
  if (controlledSelected === undefined) {
@@ -80,6 +100,9 @@ function EditableCategoryPills({ categories, fieldPath = 'categories', selectedC
80
100
  onSelectCategory(category);
81
101
  }
82
102
  };
103
+ if (resolvedCategories.length <= 1) {
104
+ return null;
105
+ }
83
106
  return ((0, jsx_runtime_1.jsx)("nav", { className: `deneb-category-pills flex items-center gap-2 overflow-x-auto py-2 no-scrollbar ${className}`, style: {
84
107
  display: 'flex',
85
108
  alignItems: 'center',
@@ -91,7 +114,7 @@ function EditableCategoryPills({ categories, fieldPath = 'categories', selectedC
91
114
  msOverflowStyle: 'none',
92
115
  ...style,
93
116
  }, "data-preview-field-path": fieldPath, "aria-label": "Product categories", children: resolvedCategories.map((cat, idx) => {
94
- const isSelected = activeCategory.toLowerCase() === cat.toLowerCase();
117
+ const isSelected = activeCategory.trim().toLowerCase() === cat.trim().toLowerCase();
95
118
  return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => handleSelect(cat), className: `deneb-pill px-4 py-2 rounded-full text-xs md:text-sm font-semibold whitespace-nowrap transition-all duration-200 border ${isSelected
96
119
  ? 'bg-slate-900 text-white border-slate-900 shadow-sm scale-105'
97
120
  : 'bg-white text-slate-600 border-slate-200 hover:border-slate-300 hover:text-slate-900 hover:bg-slate-50'}`, style: {
@@ -1,13 +1,101 @@
1
1
  "use strict";
2
2
  'use client';
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
37
  exports.FilterSidebar = void 0;
5
38
  exports.EditableFilterSidebar = EditableFilterSidebar;
6
39
  const jsx_runtime_1 = require("react/jsx-runtime");
7
- const react_1 = require("react");
40
+ const react_1 = __importStar(require("react"));
8
41
  const SiteDataProvider_1 = require("./SiteDataProvider");
9
- function EditableFilterSidebar({ basePath = 'filters', categories = ['All', 'Running', 'Lifestyle', 'Basketball', 'Training', 'Outdoor'], sizes = ['US 7', 'US 8', 'US 9', 'US 10', 'US 11', 'US 12'], minPrice = 0, maxPrice = 300, currency = '$', initialFilters, onFilterChange, className = '', }) {
42
+ function EditableFilterSidebar({ basePath = 'filters', categories = [], sizes = [], minPrice = 0, maxPrice = 300, currency = '$', initialFilters, onFilterChange, className = '', }) {
10
43
  const { siteData } = (0, SiteDataProvider_1.useSiteData)();
44
+ const sanitizedCategories = react_1.default.useMemo(() => {
45
+ if (!categories || !Array.isArray(categories))
46
+ return [];
47
+ const map = new Map();
48
+ for (const c of categories) {
49
+ if (typeof c !== "string")
50
+ continue;
51
+ const trimmed = c.trim();
52
+ if (!trimmed || trimmed.toLowerCase() === "all")
53
+ continue;
54
+ const lower = trimmed.toLowerCase();
55
+ if (!map.has(lower)) {
56
+ map.set(lower, trimmed);
57
+ }
58
+ }
59
+ return Array.from(map.values());
60
+ }, [categories]);
61
+ const sanitizedSizes = react_1.default.useMemo(() => {
62
+ const rawList = [];
63
+ if (sizes && Array.isArray(sizes) && sizes.length > 0) {
64
+ rawList.push(...sizes);
65
+ }
66
+ else {
67
+ const rawProducts = siteData?.content?.products || siteData?.products;
68
+ if (Array.isArray(rawProducts)) {
69
+ for (const p of rawProducts) {
70
+ if (Array.isArray(p?.sizes)) {
71
+ for (const s of p.sizes) {
72
+ if (s != null)
73
+ rawList.push(String(s));
74
+ }
75
+ }
76
+ else if (Array.isArray(p?.options)) {
77
+ for (const o of p.options) {
78
+ if (o != null)
79
+ rawList.push(String(o));
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ const map = new Map();
86
+ for (const s of rawList) {
87
+ if (typeof s !== "string")
88
+ continue;
89
+ const trimmed = s.trim();
90
+ if (!trimmed)
91
+ continue;
92
+ const lower = trimmed.toLowerCase();
93
+ if (!map.has(lower)) {
94
+ map.set(lower, trimmed);
95
+ }
96
+ }
97
+ return Array.from(map.values());
98
+ }, [sizes, siteData]);
11
99
  const [selectedCategories, setSelectedCategories] = (0, react_1.useState)(initialFilters?.selectedCategories || []);
12
100
  const [currentPrice, setCurrentPrice] = (0, react_1.useState)(initialFilters?.priceRange ? initialFilters.priceRange[1] : maxPrice);
13
101
  const [selectedSizes, setSelectedSizes] = (0, react_1.useState)(initialFilters?.selectedSizes || []);
@@ -29,16 +117,20 @@ function EditableFilterSidebar({ basePath = 'filters', categories = ['All', 'Run
29
117
  }
30
118
  };
31
119
  const toggleCategory = (cat) => {
32
- const next = selectedCategories.includes(cat)
33
- ? selectedCategories.filter((c) => c !== cat)
34
- : [...selectedCategories, cat];
120
+ const trimmedCat = cat.trim();
121
+ const exists = selectedCategories.some((c) => c.trim().toLowerCase() === trimmedCat.toLowerCase());
122
+ const next = exists
123
+ ? selectedCategories.filter((c) => c.trim().toLowerCase() !== trimmedCat.toLowerCase())
124
+ : [...selectedCategories, trimmedCat];
35
125
  setSelectedCategories(next);
36
126
  triggerChange(next, currentPrice, selectedSizes, inStockOnly);
37
127
  };
38
128
  const toggleSize = (size) => {
39
- const next = selectedSizes.includes(size)
40
- ? selectedSizes.filter((s) => s !== size)
41
- : [...selectedSizes, size];
129
+ const trimmedSize = size.trim();
130
+ const exists = selectedSizes.some((s) => s.trim().toLowerCase() === trimmedSize.toLowerCase());
131
+ const next = exists
132
+ ? selectedSizes.filter((s) => s.trim().toLowerCase() !== trimmedSize.toLowerCase())
133
+ : [...selectedSizes, trimmedSize];
42
134
  setSelectedSizes(next);
43
135
  triggerChange(selectedCategories, currentPrice, next, inStockOnly);
44
136
  };
@@ -59,8 +151,8 @@ function EditableFilterSidebar({ basePath = 'filters', categories = ['All', 'Run
59
151
  setInStockOnly(false);
60
152
  triggerChange([], maxPrice, [], false);
61
153
  };
62
- const activeFiltersCount = selectedCategories.length +
63
- selectedSizes.length +
154
+ const activeFiltersCount = (sanitizedCategories.length > 1 ? selectedCategories.length : 0) +
155
+ (sanitizedSizes.length > 1 ? selectedSizes.length : 0) +
64
156
  (currentPrice < maxPrice ? 1 : 0) +
65
157
  (inStockOnly ? 1 : 0);
66
158
  const title = getContent('title', 'Filters');
@@ -70,16 +162,16 @@ function EditableFilterSidebar({ basePath = 'filters', categories = ['All', 'Run
70
162
  const availabilityTitle = getContent('availabilityTitle', 'Availability');
71
163
  const inStockLabel = getContent('inStockLabel', 'In Stock Only');
72
164
  const clearAllText = getContent('clearAllText', 'Clear All');
73
- return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-filter-sidebar-wrap w-full ${className}`, children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "deneb-filter-mobile-toggle mb-3 rounded-xl border border-neutral-800 bg-neutral-900/90 px-4 py-3 text-sm font-semibold text-white", onClick: () => setMobileOpen((open) => !open), "aria-expanded": mobileOpen, "aria-controls": "deneb-filter-panel", "data-preview-static": "filter-mobile-toggle", children: [(0, jsx_runtime_1.jsx)("span", { children: title }), (0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2 text-neutral-400", children: [activeFiltersCount > 0 ? ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", children: activeFiltersCount })) : null, mobileOpen ? '−' : '+'] })] }), (0, jsx_runtime_1.jsxs)("aside", { id: "deneb-filter-panel", className: `deneb-filter-sidebar deneb-filter-sidebar-panel w-full rounded-2xl border border-neutral-800 bg-neutral-900/80 backdrop-blur-md p-6 text-white shadow-xl ${mobileOpen ? 'is-open' : ''}`, "aria-label": "Product Filters", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between border-b border-neutral-800 pb-4 mb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold tracking-tight text-white", "data-preview-field-path": fieldPath('title'), children: title }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", "data-preview-static": "filter-active-count", children: activeFiltersCount }))] }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClearAll, className: "text-xs font-medium text-neutral-400 hover:text-white transition-colors", "data-preview-static": "filter-clear-all", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": fieldPath('clearAllText'), children: clearAllText }) }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath('categoryTitle'), children: categoryTitle }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap gap-2", children: categories.map((cat) => {
74
- const isSelected = selectedCategories.includes(cat);
165
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `deneb-filter-sidebar-wrap w-full ${className}`, children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "deneb-filter-mobile-toggle mb-3 rounded-xl border border-neutral-800 bg-neutral-900/90 px-4 py-3 text-sm font-semibold text-white", onClick: () => setMobileOpen((open) => !open), "aria-expanded": mobileOpen, "aria-controls": "deneb-filter-panel", "data-preview-static": "filter-mobile-toggle", children: [(0, jsx_runtime_1.jsx)("span", { children: title }), (0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2 text-neutral-400", children: [activeFiltersCount > 0 ? ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", children: activeFiltersCount })) : null, mobileOpen ? '−' : '+'] })] }), (0, jsx_runtime_1.jsxs)("aside", { id: "deneb-filter-panel", className: `deneb-filter-sidebar deneb-filter-sidebar-panel w-full rounded-2xl border border-neutral-800 bg-neutral-900/80 backdrop-blur-md p-6 text-white shadow-xl ${mobileOpen ? 'is-open' : ''}`, "aria-label": "Product Filters", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between border-b border-neutral-800 pb-4 mb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold tracking-tight text-white", "data-preview-field-path": fieldPath('title'), children: title }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-500 text-xs font-bold text-black", "data-preview-static": "filter-active-count", children: activeFiltersCount }))] }), activeFiltersCount > 0 && ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClearAll, className: "text-xs font-medium text-neutral-400 hover:text-white transition-colors", "data-preview-static": "filter-clear-all", children: (0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": fieldPath('clearAllText'), children: clearAllText }) }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [sanitizedCategories.length > 1 && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath("categoryTitle"), children: categoryTitle }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap gap-2", children: sanitizedCategories.map((cat) => {
166
+ const isSelected = selectedCategories.some((c) => c.trim().toLowerCase() === cat.trim().toLowerCase());
75
167
  return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => toggleCategory(cat), "data-preview-static": "filter-cat-btn", className: `rounded-lg px-3 py-1.5 text-xs font-medium transition-all ${isSelected
76
- ? 'bg-white text-black shadow-md'
77
- : 'bg-neutral-800 text-neutral-300 hover:bg-neutral-700 hover:text-white'}`, children: cat }, cat));
78
- }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400", "data-preview-field-path": fieldPath('priceTitle'), children: priceTitle }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-semibold text-emerald-400", "data-preview-static": "filter-price-display", children: ["Up to ", currency, currentPrice] })] }), (0, jsx_runtime_1.jsx)("input", { type: "range", min: minPrice, max: maxPrice, step: 5, value: currentPrice, onChange: handlePriceChange, "data-preview-static": "filter-price-slider", className: "w-full accent-emerald-500 bg-neutral-800 h-1.5 rounded-lg cursor-pointer" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-xs text-neutral-500 mt-1", children: [(0, jsx_runtime_1.jsxs)("span", { children: [currency, minPrice] }), (0, jsx_runtime_1.jsxs)("span", { children: [currency, maxPrice] })] })] }), sizes.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath('sizeTitle'), children: sizeTitle }), (0, jsx_runtime_1.jsx)("div", { className: "deneb-filter-size-grid grid grid-cols-3 gap-2", children: sizes.map((size) => {
79
- const isSelected = selectedSizes.includes(size);
168
+ ? "bg-white text-black shadow-md"
169
+ : "bg-neutral-800 text-neutral-300 hover:bg-neutral-700 hover:text-white"}`, children: cat }, cat));
170
+ }) })] })), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400", "data-preview-field-path": fieldPath('priceTitle'), children: priceTitle }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-semibold text-emerald-400", "data-preview-static": "filter-price-display", children: ["Up to ", currency, currentPrice] })] }), (0, jsx_runtime_1.jsx)("input", { type: "range", min: minPrice, max: maxPrice, step: 5, value: currentPrice, onChange: handlePriceChange, "data-preview-static": "filter-price-slider", className: "w-full accent-emerald-500 bg-neutral-800 h-1.5 rounded-lg cursor-pointer" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-xs text-neutral-500 mt-1", children: [(0, jsx_runtime_1.jsxs)("span", { children: [currency, minPrice] }), (0, jsx_runtime_1.jsxs)("span", { children: [currency, maxPrice] })] })] }), sanitizedSizes.length > 1 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-3", "data-preview-field-path": fieldPath("sizeTitle"), children: sizeTitle }), (0, jsx_runtime_1.jsx)("div", { className: "deneb-filter-size-grid grid grid-cols-3 gap-2", children: sanitizedSizes.map((size) => {
171
+ const isSelected = selectedSizes.some((s) => s.trim().toLowerCase() === size.trim().toLowerCase());
80
172
  return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => toggleSize(size), "data-preview-static": "filter-size-btn", className: `rounded-lg py-2 text-xs font-semibold transition-all border ${isSelected
81
- ? 'border-white bg-white text-black'
82
- : 'border-neutral-800 bg-neutral-800/50 text-neutral-300 hover:border-neutral-700'}`, children: size }, size));
173
+ ? "border-white bg-white text-black"
174
+ : "border-neutral-800 bg-neutral-800/50 text-neutral-300 hover:border-neutral-700"}`, children: size }, size));
83
175
  }) })] })), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-800/80 pt-6", children: [(0, jsx_runtime_1.jsx)("h4", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-neutral-400", "data-preview-field-path": fieldPath('availabilityTitle'), children: availabilityTitle }), (0, jsx_runtime_1.jsxs)("label", { className: "flex items-center justify-between cursor-pointer group", "data-preview-static": "filter-instock-toggle", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-neutral-300 group-hover:text-white transition-colors", "data-preview-field-path": fieldPath('inStockLabel'), children: inStockLabel }), (0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: inStockOnly, onChange: toggleInStock, className: "h-4 w-4 rounded border-neutral-700 bg-neutral-800 text-emerald-500 accent-emerald-500 cursor-pointer" })] })] })] })] })] }));
84
176
  }
85
177
  exports.FilterSidebar = EditableFilterSidebar;
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
2
  import { MeasurementUnit, ProductVariant } from './utils/productOptions';
3
3
  export interface ProductItem {
4
+ href?: string;
5
+ detailHref?: string;
4
6
  id?: string | number;
5
7
  name?: string;
6
8
  title?: string;
@@ -87,7 +89,13 @@ export interface EditableProductCardProps extends React.HTMLAttributes<HTMLEleme
87
89
  actionSlot?: React.ReactNode;
88
90
  actionLabel?: string;
89
91
  actionLabelPath?: string;
92
+ href?: string;
93
+ detailHref?: string;
94
+ showDetailLink?: boolean;
95
+ showDetailButton?: boolean;
96
+ detailButtonText?: string;
97
+ onDetailClick?: (product: ProductItem, url: string) => void;
90
98
  onAddToCart?: (product: ProductItem) => void;
91
99
  onWhatsAppClick?: (product: ProductItem, url: string) => void;
92
100
  }
93
- export declare function EditableProductCard({ itemPath, product: productProp, item: itemProp, cardVariant, imageFallback, as: Component, currency, showBrand, showPrice, showDescription, showCategory, whatsappNumber: whatsappNumberProp, whatsappPhone: whatsappPhoneProp, storeName, showWhatsAppButton, showAddToCartButton, whatsappActionLabel, addToCartLabel, actionSlot, onAddToCart, onWhatsAppClick, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
101
+ export declare function EditableProductCard({ itemPath, product: productProp, item: itemProp, cardVariant, imageFallback, as: Component, currency, showBrand, showPrice, showDescription, showCategory, whatsappNumber: whatsappNumberProp, whatsappPhone: whatsappPhoneProp, storeName, showWhatsAppButton, showAddToCartButton, whatsappActionLabel, addToCartLabel, actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, href, detailHref, showDetailLink, showDetailButton, detailButtonText, onDetailClick, className, style, ...props }: EditableProductCardProps): React.JSX.Element;
@@ -8,6 +8,7 @@ const EditableText_1 = require("./EditableText");
8
8
  const EditableImage_1 = require("./EditableImage");
9
9
  const useCart_1 = require("./cart/useCart");
10
10
  const productOptions_1 = require("./utils/productOptions");
11
+ const PlatformProductDetail_1 = require("./PlatformProductDetail");
11
12
  const COLOR_HEX_MAP = {
12
13
  black: '#111827',
13
14
  white: '#ffffff',
@@ -45,8 +46,45 @@ function WhatsAppIcon({ className = '', style = {} }) {
45
46
  function CartIcon({ className = '', style = {} }) {
46
47
  return ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, style: { display: 'inline-block', verticalAlign: 'middle', flexShrink: 0, ...style }, "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "9", cy: "21", r: "1" }), (0, jsx_runtime_1.jsx)("circle", { cx: "20", cy: "21", r: "1" }), (0, jsx_runtime_1.jsx)("path", { d: "M1 1h4l2.68 13.39a2 2 0 002 1.61h9.72a2 2 0 002-1.61L23 6H6" })] }));
47
48
  }
48
- function EditableProductCard({ itemPath, product: productProp, item: itemProp, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', currency = 'LKR', showBrand = true, showPrice = true, showDescription = true, showCategory = true, whatsappNumber: whatsappNumberProp, whatsappPhone: whatsappPhoneProp, storeName, showWhatsAppButton = true, showAddToCartButton = true, whatsappActionLabel = 'Inquire on WhatsApp', addToCartLabel = 'Add to Cart', actionSlot, onAddToCart, onWhatsAppClick, className = '', style, ...props }) {
49
- const product = (0, react_1.useMemo)(() => (productProp || itemProp || {}), [productProp, itemProp]);
49
+ function EditableProductCard({ itemPath, product: productProp, item: itemProp, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', currency = 'LKR', showBrand = true, showPrice = true, showDescription = true, showCategory = true, whatsappNumber: whatsappNumberProp, whatsappPhone: whatsappPhoneProp, storeName, showWhatsAppButton = true, showAddToCartButton = true, whatsappActionLabel = 'Inquire on WhatsApp', addToCartLabel = 'Add to Cart', actionSlot, actionLabel, actionLabelPath, onAddToCart, onWhatsAppClick, href, detailHref, showDetailLink = true, showDetailButton, detailButtonText, onDetailClick, className = '', style, ...props }) {
50
+ const anyProps = props;
51
+ const product = (0, react_1.useMemo)(() => {
52
+ const base = (productProp || itemProp || {});
53
+ return {
54
+ ...base,
55
+ id: base.id ?? anyProps.id,
56
+ name: base.name || anyProps.name,
57
+ title: base.title || anyProps.title,
58
+ productName: base.productName || anyProps.productName,
59
+ brand: base.brand || anyProps.brand,
60
+ price: base.price ?? anyProps.price,
61
+ originalPrice: base.originalPrice ?? anyProps.originalPrice ?? anyProps.compareAtPrice,
62
+ compareAtPrice: base.compareAtPrice ?? anyProps.compareAtPrice,
63
+ description: base.description || anyProps.description || anyProps.desc,
64
+ category: base.category || anyProps.category,
65
+ badge: base.badge || anyProps.badge || anyProps.tag,
66
+ imageUrl: base.imageUrl || anyProps.imageUrl || anyProps.image || anyProps.photo,
67
+ currency: base.currency || anyProps.currency,
68
+ measurement: base.measurement || anyProps.measurement,
69
+ unit: base.unit || anyProps.unit,
70
+ href: base.href || anyProps.href,
71
+ };
72
+ }, [productProp, itemProp, anyProps]);
73
+ const rawId = product?.id ?? product?.productId;
74
+ const resolvedDetailHref = (0, react_1.useMemo)(() => {
75
+ if (href && typeof href === 'string' && href.trim() !== '')
76
+ return href.trim();
77
+ if (detailHref && typeof detailHref === 'string' && detailHref.trim() !== '')
78
+ return detailHref.trim();
79
+ if (product?.href && typeof product.href === 'string' && product.href.trim() !== '') {
80
+ return product.href.trim();
81
+ }
82
+ if (rawId !== undefined && rawId !== null && String(rawId).trim() !== '') {
83
+ return (0, PlatformProductDetail_1.platformProductDetailHref)(rawId);
84
+ }
85
+ return undefined;
86
+ }, [href, detailHref, product?.href, rawId]);
87
+ const resolvedActionLabel = String(actionLabel || detailButtonText || 'View details');
50
88
  const whatsappNumber = whatsappPhoneProp || whatsappNumberProp || '94770000000';
51
89
  const cart = (0, useCart_1.useOptionalCart)();
52
90
  // Dynamic Options, Measurements & Colors resolution
@@ -279,7 +317,11 @@ function EditableProductCard({ itemPath, product: productProp, item: itemProp, c
279
317
  overflow: 'hidden',
280
318
  width: isHorizontal ? '40%' : '100%',
281
319
  flexShrink: 0,
282
- }, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.${imageKey}`, "data-preview-field-path": `${itemPath}.${imageKey}`, src: currentImage, 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_1.EditableBadge, { id: `${itemPath}.${badgeKey}`, "data-preview-field-path": `${itemPath}.${badgeKey}`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
320
+ }, children: [resolvedDetailHref && showDetailLink ? ((0, jsx_runtime_1.jsx)("a", { href: resolvedDetailHref, onClick: () => {
321
+ if (onDetailClick) {
322
+ onDetailClick(product, resolvedDetailHref);
323
+ }
324
+ }, "data-preview-static": "Open the stable live product detail page", style: { display: 'block', width: '100%', height: '100%', textDecoration: 'none' }, title: `View details for ${name}`, children: (0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.${imageKey}`, "data-preview-field-path": `${itemPath}.${imageKey}`, src: currentImage, fallbackSrc: imageFallback, alt: name, aspectRatio: isHorizontal ? 'square' : '4/3', fit: "cover", hoverZoom: true, style: { width: '100%', height: '100%', display: 'block' } }) })) : ((0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.${imageKey}`, "data-preview-field-path": `${itemPath}.${imageKey}`, src: currentImage, 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_1.EditableBadge, { id: `${itemPath}.${badgeKey}`, "data-preview-field-path": `${itemPath}.${badgeKey}`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
283
325
  padding: '1.25rem',
284
326
  display: 'flex',
285
327
  flexDirection: 'column',
@@ -301,13 +343,27 @@ function EditableProductCard({ itemPath, product: productProp, item: itemProp, c
301
343
  backgroundColor: 'var(--tag-bg, var(--color-secondary, rgba(241, 245, 249, 0.9)))',
302
344
  padding: '2px 8px',
303
345
  borderRadius: '6px',
304
- } })) : null] }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.${titleKey}`, "data-preview-field-path": `${itemPath}.${titleKey}`, defaultValue: name, style: {
346
+ } })) : null] }), resolvedDetailHref && showDetailLink ? ((0, jsx_runtime_1.jsx)("a", { href: resolvedDetailHref, onClick: () => {
347
+ if (onDetailClick) {
348
+ onDetailClick(product, resolvedDetailHref);
349
+ }
350
+ }, "data-preview-static": "Open the stable live product detail page", style: {
351
+ color: 'inherit',
352
+ textDecoration: 'none',
353
+ display: 'inline-block',
354
+ }, className: "hover:underline", children: (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.${titleKey}`, "data-preview-field-path": `${itemPath}.${titleKey}`, defaultValue: name, style: {
355
+ fontSize: '1.125rem',
356
+ fontWeight: 700,
357
+ lineHeight: 1.35,
358
+ color: 'var(--heading-color, #ffffff)',
359
+ marginBottom: '0.375rem',
360
+ } }) })) : ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.${titleKey}`, "data-preview-field-path": `${itemPath}.${titleKey}`, defaultValue: name, style: {
305
361
  fontSize: '1.125rem',
306
362
  fontWeight: 700,
307
363
  lineHeight: 1.35,
308
364
  color: 'var(--heading-color, #ffffff)',
309
365
  marginBottom: '0.375rem',
310
- } }), showDescription && description ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.${descriptionKey}`, "data-preview-field-path": `${itemPath}.${descriptionKey}`, defaultValue: description, style: {
366
+ } })), showDescription && description ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.${descriptionKey}`, "data-preview-field-path": `${itemPath}.${descriptionKey}`, defaultValue: description, style: {
311
367
  fontSize: '0.875rem',
312
368
  color: 'var(--muted-text, #94a3b8)',
313
369
  lineHeight: 1.5,
@@ -388,40 +444,59 @@ function EditableProductCard({ itemPath, product: productProp, item: itemProp, c
388
444
  color: 'var(--muted-text, #94a3b8)',
389
445
  border: '1px solid rgba(255, 255, 255, 0.12)',
390
446
  letterSpacing: '0.01em',
391
- }, children: "Price on Request" }) })) : null, actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsxs)("div", { style: {
392
- display: 'grid',
393
- gridTemplateColumns: showWhatsAppButton && showAddToCartButton ? '1fr 1fr' : '1fr',
394
- gap: '0.5rem',
395
- width: '100%',
396
- }, children: [showWhatsAppButton && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: handleWhatsAppClick, title: "Chat directly on WhatsApp about this product", style: {
397
- backgroundColor: '#25D366',
398
- color: '#ffffff',
399
- border: 'none',
400
- padding: '0.55rem 0.75rem',
401
- borderRadius: '10px',
402
- fontSize: '0.8125rem',
403
- fontWeight: 600,
404
- cursor: 'pointer',
447
+ }, children: "Price on Request" }) })) : null, actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column', gap: '0.5rem', width: '100%' }, children: [(showWhatsAppButton || showAddToCartButton) && ((0, jsx_runtime_1.jsxs)("div", { style: {
448
+ display: 'grid',
449
+ gridTemplateColumns: showWhatsAppButton && showAddToCartButton ? '1fr 1fr' : '1fr',
450
+ gap: '0.5rem',
451
+ width: '100%',
452
+ }, children: [showWhatsAppButton && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: handleWhatsAppClick, title: "Chat directly on WhatsApp about this product", style: {
453
+ backgroundColor: '#25D366',
454
+ color: '#ffffff',
455
+ border: 'none',
456
+ padding: '0.55rem 0.75rem',
457
+ borderRadius: '10px',
458
+ fontSize: '0.8125rem',
459
+ fontWeight: 600,
460
+ cursor: 'pointer',
461
+ display: 'flex',
462
+ alignItems: 'center',
463
+ justifyContent: 'center',
464
+ gap: '0.375rem',
465
+ transition: 'all 0.2s ease',
466
+ boxShadow: '0 2px 8px rgba(37, 211, 102, 0.25)',
467
+ }, className: "hover:brightness-105 active:scale-95", children: [(0, jsx_runtime_1.jsx)(WhatsAppIcon, {}), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.whatsappButtonText`, "data-preview-field-path": `${itemPath}.whatsappButtonText`, defaultValue: resolvedWhatsAppText, style: { color: '#ffffff', fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } })] })), showAddToCartButton && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: handleAddToCartClick, title: "Add this product to shopping cart", style: {
468
+ backgroundColor: 'var(--button-bg, var(--brand-color, #2563eb))',
469
+ color: 'var(--button-text, #ffffff)',
470
+ border: 'none',
471
+ padding: '0.55rem 0.75rem',
472
+ borderRadius: '10px',
473
+ fontSize: '0.8125rem',
474
+ fontWeight: 600,
475
+ cursor: 'pointer',
476
+ display: 'flex',
477
+ alignItems: 'center',
478
+ justifyContent: 'center',
479
+ gap: '0.375rem',
480
+ transition: 'all 0.2s ease',
481
+ boxShadow: '0 2px 8px rgba(37, 99, 235, 0.25)',
482
+ }, className: "hover:brightness-105 active:scale-95", children: [(0, jsx_runtime_1.jsx)(CartIcon, {}), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.addToCartButtonText`, "data-preview-field-path": `${itemPath}.addToCartButtonText`, defaultValue: resolvedAddToCartText, style: { color: 'var(--button-text, #ffffff)', fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } })] }))] })), resolvedDetailHref && (showDetailButton || Boolean(actionLabel || actionLabelPath)) && ((0, jsx_runtime_1.jsx)("a", { href: resolvedDetailHref, onClick: () => {
483
+ if (onDetailClick) {
484
+ onDetailClick(product, resolvedDetailHref);
485
+ }
486
+ }, "data-preview-static": "Open the stable live product detail page", style: {
405
487
  display: 'flex',
406
488
  alignItems: 'center',
407
489
  justifyContent: 'center',
408
- gap: '0.375rem',
409
- transition: 'all 0.2s ease',
410
- boxShadow: '0 2px 8px rgba(37, 211, 102, 0.25)',
411
- }, className: "hover:brightness-105 active:scale-95", children: [(0, jsx_runtime_1.jsx)(WhatsAppIcon, {}), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.whatsappButtonText`, "data-preview-field-path": `${itemPath}.whatsappButtonText`, defaultValue: resolvedWhatsAppText, style: { color: '#ffffff', fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } })] })), showAddToCartButton && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: handleAddToCartClick, title: "Add this product to shopping cart", style: {
412
- backgroundColor: 'var(--button-bg, var(--brand-color, #2563eb))',
413
- color: 'var(--button-text, #ffffff)',
414
- border: 'none',
490
+ width: '100%',
491
+ textAlign: 'center',
415
492
  padding: '0.55rem 0.75rem',
416
493
  borderRadius: '10px',
417
494
  fontSize: '0.8125rem',
418
495
  fontWeight: 600,
419
- cursor: 'pointer',
420
- display: 'flex',
421
- alignItems: 'center',
422
- justifyContent: 'center',
423
- gap: '0.375rem',
496
+ backgroundColor: 'var(--button-secondary-bg, rgba(255, 255, 255, 0.08))',
497
+ color: 'var(--button-secondary-text, var(--muted-text, #e2e8f0))',
498
+ border: '1px solid var(--card-border, rgba(226, 232, 240, 0.25))',
499
+ textDecoration: 'none',
424
500
  transition: 'all 0.2s ease',
425
- boxShadow: '0 2px 8px rgba(37, 99, 235, 0.25)',
426
- }, className: "hover:brightness-105 active:scale-95", children: [(0, jsx_runtime_1.jsx)(CartIcon, {}), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.addToCartButtonText`, "data-preview-field-path": `${itemPath}.addToCartButtonText`, defaultValue: resolvedAddToCartText, style: { color: 'var(--button-text, #ffffff)', fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } })] }))] }))] })] })] }));
501
+ }, className: "hover:brightness-110 active:scale-95", children: actionLabelPath ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: actionLabelPath, "data-preview-field-path": actionLabelPath, defaultValue: resolvedActionLabel })) : ((0, jsx_runtime_1.jsx)("span", { children: resolvedActionLabel })) }))] }))] })] })] }));
427
502
  }
@@ -1,5 +1,13 @@
1
1
  import React from 'react';
2
2
  import { ProductItem, ProductCardVariant } from './EditableProductCard';
3
+ import { EditableFilterSidebarProps, FilterState } from './EditableFilterSidebar';
4
+ export interface ProductFilters {
5
+ categories?: string[];
6
+ priceRange?: [number, number];
7
+ maxPrice?: number;
8
+ sizes?: string[];
9
+ inStockOnly?: boolean;
10
+ }
3
11
  export interface EditableProductGridProps extends React.HTMLAttributes<HTMLElement> {
4
12
  /**
5
13
  * Field path prefix for live Fivora Visual Editing synchronization (e.g. "home").
@@ -111,19 +119,34 @@ export interface EditableProductGridProps extends React.HTMLAttributes<HTMLEleme
111
119
  * Total products count override when backend performs server-side pagination slicing.
112
120
  */
113
121
  totalProducts?: number;
122
+ /**
123
+ * Controlled or external filters (typically from EditableFilterSidebar).
124
+ */
125
+ filters?: ProductFilters;
126
+ /**
127
+ * Initial filters when using internal filter state.
128
+ */
129
+ initialFilters?: ProductFilters;
130
+ /**
131
+ * Callback fired whenever filter state changes.
132
+ */
133
+ onFilterChange?: (filters: FilterState) => void;
134
+ /**
135
+ * Whether to display the integrated EditableFilterSidebar alongside the product grid (default: false).
136
+ */
137
+ showFilterSidebar?: boolean;
138
+ /**
139
+ * Customization props passed directly to the embedded EditableFilterSidebar.
140
+ */
141
+ filterSidebarProps?: Partial<EditableFilterSidebarProps>;
114
142
  currency?: string;
115
143
  whatsappNumber?: string;
116
144
  whatsappPhone?: string;
145
+ showDetailLink?: boolean;
146
+ showDetailButton?: boolean;
147
+ detailActionLabel?: string;
117
148
  className?: string;
118
149
  }
119
- /**
120
- * EditableProductGrid is an elite, fully responsive e-commerce showcase grid
121
- * with interactive category filtering, live Fivora visual editing synchronization,
122
- * smart multi-variant pagination, automatic useProducts() fallback rehydration,
123
- * and built-in Quick View modal triggers.
124
- *
125
- * Created by Chamika Gayashan & Induranga Kawishwara
126
- */
127
- export declare function EditableProductGrid({ currency, whatsappNumber, whatsappPhone, sectionPath, listPath, title, subtitle, products: userProducts, categories, cardVariant, columns, onQuickView, cardPrefix, showSearch, searchPlaceholder, enableBackendSearch, onSearchChange, enablePagination, pageSize, pageSizeOptions, showPageSizeSelector, paginationVariant, hidePaginationOnSinglePage, currentPage: controlledPage, initialPage, onPageChange, scrollToTopOnPageChange, totalProducts, className, style, ...props }: EditableProductGridProps): React.JSX.Element;
150
+ export declare function EditableProductGrid({ currency, whatsappNumber, whatsappPhone, sectionPath, listPath, title, subtitle, products: userProducts, categories, cardVariant, columns, onQuickView, cardPrefix, showSearch, searchPlaceholder, enableBackendSearch, onSearchChange, enablePagination, pageSize, pageSizeOptions, showPageSizeSelector, paginationVariant, hidePaginationOnSinglePage, currentPage: controlledPage, initialPage, onPageChange, scrollToTopOnPageChange, totalProducts, filters: controlledFilters, initialFilters, onFilterChange: onFilterChangeProp, showFilterSidebar, filterSidebarProps, showDetailLink, showDetailButton, detailActionLabel, className, style, ...props }: EditableProductGridProps): React.JSX.Element;
128
151
  export declare const ProductGrid: typeof EditableProductGrid;
129
152
  export type ProductGridItem = ProductItem;