@deneb-ui/ui 2.0.40 → 2.0.42

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.
@@ -12,6 +12,7 @@ const EditableText_2 = require("./EditableText");
12
12
  */
13
13
  function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass', imageFallback, as: Component = 'article', showPrice = true, showDescription = true, showCategory = true, actionSlot, actionLabel, actionLabelPath, className = '', style, ...props }) {
14
14
  const name = String(product?.name || product?.title || '');
15
+ const hasPrice = showPrice && product?.price !== undefined && product?.price !== null && String(product.price).trim() !== '';
15
16
  const price = product?.price !== undefined ? String(product.price) : '';
16
17
  const originalPrice = product?.originalPrice !== undefined ? String(product.originalPrice) : '';
17
18
  const description = String(product?.description || '');
@@ -61,13 +62,13 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
61
62
  overflow: 'hidden',
62
63
  width: isHorizontal ? '100%' : '100%',
63
64
  flexShrink: 0,
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
+ }, children: [(0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.imageUrl`, "data-preview-field-path": `${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`, "data-preview-field-path": `${itemPath}.badge`, defaultValue: badge, badgeVariant: "primary" }) }))] }), (0, jsx_runtime_1.jsxs)("div", { style: {
65
66
  padding: '1.25rem',
66
67
  display: 'flex',
67
68
  flexDirection: 'column',
68
69
  flex: 1,
69
70
  justifyContent: 'space-between',
70
- }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [showCategory && ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.category`, defaultValue: category, style: {
71
+ }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [showCategory && ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.category`, "data-preview-field-path": `${itemPath}.category`, defaultValue: category, style: {
71
72
  fontSize: '0.75rem',
72
73
  textTransform: 'uppercase',
73
74
  letterSpacing: '0.05em',
@@ -75,13 +76,13 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
75
76
  fontWeight: 600,
76
77
  display: 'inline-block',
77
78
  marginBottom: '0.375rem',
78
- } })), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.name`, defaultValue: name, style: {
79
+ } })), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h3", id: `${itemPath}.name`, "data-preview-field-path": `${itemPath}.name`, defaultValue: name, style: {
79
80
  fontSize: '1.125rem',
80
81
  fontWeight: 700,
81
82
  lineHeight: 1.3,
82
83
  color: 'var(--heading-color, #0f172a)',
83
84
  marginBottom: '0.375rem',
84
- } }), showDescription && ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, defaultValue: description, style: {
85
+ } }), showDescription && ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, "data-preview-field-path": `${itemPath}.description`, defaultValue: description, style: {
85
86
  fontSize: '0.875rem',
86
87
  color: 'var(--muted-text, #64748b)',
87
88
  lineHeight: 1.5,
@@ -94,20 +95,20 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
94
95
  alignItems: 'center',
95
96
  justifyContent: 'space-between',
96
97
  gap: '0.5rem',
97
- }, children: [showPrice && ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.375rem' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, defaultValue: price, style: {
98
+ }, children: [hasPrice ? ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'baseline', gap: '0.375rem' }, children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, "data-preview-field-path": `${itemPath}.price`, defaultValue: price, style: {
98
99
  fontSize: '1.25rem',
99
100
  fontWeight: 700,
100
101
  color: 'var(--brand-color, #2563eb)',
101
- } }), originalPrice ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.originalPrice`, defaultValue: originalPrice, style: {
102
+ } }), originalPrice ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.originalPrice`, "data-preview-field-path": `${itemPath}.originalPrice`, defaultValue: originalPrice, style: {
102
103
  fontSize: '0.875rem',
103
104
  textDecoration: 'line-through',
104
105
  color: 'var(--muted-text, #94a3b8)',
105
- } })) : null, product?.measurement ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.measurement`, defaultValue: `/ ${String(product.measurement)}`, style: {
106
+ } })) : null, product?.measurement ? ((0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.measurement`, "data-preview-field-path": `${itemPath}.measurement`, defaultValue: `/ ${String(product.measurement)}`, style: {
106
107
  fontSize: '0.8rem',
107
108
  fontWeight: 500,
108
109
  color: 'var(--muted-text, #64748b)',
109
110
  marginLeft: '0.25rem',
110
- } })) : null] })), actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsx)("button", { type: "button", style: {
111
+ } })) : null] })) : null, actionSlot ? ((0, jsx_runtime_1.jsx)("div", { children: actionSlot })) : ((0, jsx_runtime_1.jsx)("button", { type: "button", style: {
111
112
  backgroundColor: 'var(--brand-color, #2563eb)',
112
113
  color: '#ffffff',
113
114
  border: 'none',
@@ -117,5 +118,5 @@ function EditableProductCard({ itemPath, product, cardVariant = 'modern-glass',
117
118
  fontWeight: 600,
118
119
  cursor: 'pointer',
119
120
  transition: 'opacity 0.2s ease',
120
- }, children: (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: actionLabelPath || `${itemPath}.buttonText`, defaultValue: actionLabel || product?.buttonText || 'Buy Now', style: { color: '#ffffff', fontWeight: 600 } }) }))] })] })] }));
121
+ }, children: (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: actionLabelPath || `${itemPath}.buttonText`, "data-preview-field-path": actionLabelPath || `${itemPath}.buttonText`, defaultValue: actionLabel || product?.buttonText || 'Buy Now', style: { color: '#ffffff', fontWeight: 600 } }) }))] })] })] }));
121
122
  }
@@ -5,6 +5,11 @@ export interface EditableProductGridProps extends React.HTMLAttributes<HTMLEleme
5
5
  * Field path prefix for live Fivora Visual Editing synchronization (e.g. "home").
6
6
  */
7
7
  sectionPath?: string;
8
+ /**
9
+ * Collection path for products (default: "products").
10
+ * When set, products are iterated with standard array indexing (e.g. "products[0]").
11
+ */
12
+ listPath?: string;
8
13
  /**
9
14
  * Title of the product grid section.
10
15
  */
@@ -51,5 +56,5 @@ export interface EditableProductGridProps extends React.HTMLAttributes<HTMLEleme
51
56
  *
52
57
  * Created by Chamika Gayashan & Induranga Kawishwara
53
58
  */
54
- export declare function EditableProductGrid({ sectionPath, title, subtitle, products, categories, cardVariant, columns, onQuickView, cardPrefix, className, style, ...props }: EditableProductGridProps): React.JSX.Element;
59
+ export declare function EditableProductGrid({ sectionPath, listPath, title, subtitle, products, categories, cardVariant, columns, onQuickView, cardPrefix, className, style, ...props }: EditableProductGridProps): React.JSX.Element;
55
60
  export declare const ProductGrid: typeof EditableProductGrid;
@@ -12,7 +12,7 @@ const EditableProductCard_1 = require("./EditableProductCard");
12
12
  *
13
13
  * Created by Chamika Gayashan & Induranga Kawishwara
14
14
  */
15
- function EditableProductGrid({ sectionPath = 'home', title = 'Featured Collection', subtitle = 'Just Dropped', products = [], categories = ['All'], cardVariant = 'modern-glass', columns = { mobile: 1, tablet: 2, desktop: 4 }, onQuickView, cardPrefix = 'product', className = '', style, ...props }) {
15
+ function EditableProductGrid({ sectionPath = 'home', listPath = 'products', title = 'Featured Collection', subtitle = 'Just Dropped', products = [], categories = ['All'], cardVariant = 'modern-glass', columns = { mobile: 1, tablet: 2, desktop: 4 }, onQuickView, cardPrefix = 'product', className = '', style, ...props }) {
16
16
  const [activeCategory, setActiveCategory] = (0, react_1.useState)(categories[0] || 'All');
17
17
  const filteredProducts = (0, react_1.useMemo)(() => {
18
18
  if (!activeCategory || activeCategory.toLowerCase() === 'all') {
@@ -38,9 +38,11 @@ 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: `deneb-product-grid grid ${gridColClasses} gap-6 sm:gap-8`, children: filteredProducts.map((product, idx) => {
42
- const itemPath = `${sectionPath}.${cardPrefix}${idx + 1}`;
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));
41
+ }) }))] }), filteredProducts.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { ...(listPath ? { 'data-preview-list-path': listPath } : {}), className: `deneb-product-grid grid ${gridColClasses} gap-6 sm:gap-8`, children: filteredProducts.map((product, idx) => {
42
+ const itemPath = listPath
43
+ ? `${listPath}[${idx}]`
44
+ : `${sectionPath}.${cardPrefix}${idx + 1}`;
45
+ return ((0, jsx_runtime_1.jsxs)("div", { "data-preview-item-path": itemPath, 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
46
  }) })) : (
45
47
  /* Empty State */
46
48
  (0, jsx_runtime_1.jsxs)("div", { className: "text-center py-20 px-4 rounded-3xl border border-dashed border-slate-800 bg-slate-900/30", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-sm font-medium text-slate-400", children: ["No products found matching category \"", activeCategory, "\"."] }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => setActiveCategory('All'), className: "mt-4 px-4 py-2 rounded-xl text-xs font-bold bg-lime-400 text-slate-950 hover:bg-lime-300 transition-colors", children: "View All Products" })] }))] }));
@@ -3,6 +3,7 @@ export interface ServiceItem {
3
3
  id?: string | number;
4
4
  name?: string;
5
5
  title?: string;
6
+ price?: string | number;
6
7
  description?: string;
7
8
  imageUrl?: string;
8
9
  image?: string;
@@ -30,9 +31,10 @@ export interface EditableServiceCardProps extends React.HTMLAttributes<HTMLEleme
30
31
  * Text/content alignment for the card ('left' | 'center' | 'right').
31
32
  */
32
33
  align?: 'left' | 'center' | 'right';
34
+ showPrice?: boolean;
33
35
  }
34
36
  /**
35
37
  * EditableServiceCard standardizes service presentation across Home and Services pages.
36
38
  * Supports service name, description, image, and repeatable features checklist.
37
39
  */
38
- export declare function EditableServiceCard({ itemPath, service, imageFallback, as: Component, align, className, style, children, ...props }: EditableServiceCardProps): React.JSX.Element;
40
+ export declare function EditableServiceCard({ itemPath, service, imageFallback, as: Component, align, showPrice, className, style, children, ...props }: EditableServiceCardProps): React.JSX.Element;
@@ -8,16 +8,21 @@ const EditableImage_1 = require("./EditableImage");
8
8
  * EditableServiceCard standardizes service presentation across Home and Services pages.
9
9
  * Supports service name, description, image, and repeatable features checklist.
10
10
  */
11
- function EditableServiceCard({ itemPath, service, imageFallback = '/placeholder.svg', as: Component = 'article', align = 'left', className = '', style, children, ...props }) {
11
+ function EditableServiceCard({ itemPath, service, imageFallback = '/placeholder.svg', as: Component = 'article', align = 'left', showPrice = true, className = '', style, children, ...props }) {
12
12
  const name = String(service?.name || service?.title || '');
13
13
  const description = String(service?.description || '');
14
+ const hasPrice = showPrice && service?.price !== undefined && service?.price !== null && String(service.price).trim() !== '';
14
15
  const imageUrl = String(service?.imageUrl || service?.image || '');
15
16
  const features = Array.isArray(service?.features) ? service.features : [];
16
17
  const mergedStyle = {
17
18
  textAlign: align,
18
19
  ...style,
19
20
  };
20
- return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, className: `editable-service-card ${className}`.trim(), style: mergedStyle, ...props, children: [(imageUrl || service?.imageUrl !== undefined || service?.image !== undefined) && ((0, jsx_runtime_1.jsx)("div", { className: "service-card-image-wrap", children: (0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.imageUrl`, "data-preview-field-path": `${itemPath}.imageUrl`, src: imageUrl, fallbackSrc: imageFallback, alt: name, className: "service-card-image" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "service-card-body", children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h2", id: `${itemPath}.name`, "data-preview-field-path": `${itemPath}.name`, defaultValue: name, className: "service-card-title" }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, "data-preview-field-path": `${itemPath}.description`, defaultValue: description, className: "service-card-description" }), (features.length > 0 || Array.isArray(service?.features)) && ((0, jsx_runtime_1.jsx)("ul", { "data-preview-list-path": `${itemPath}.features`, className: "service-card-features", children: features.map((feature, featureIndex) => {
21
+ return ((0, jsx_runtime_1.jsxs)(Component, { "data-preview-item-path": itemPath, className: `editable-service-card ${className}`.trim(), style: mergedStyle, ...props, children: [(imageUrl || service?.imageUrl !== undefined || service?.image !== undefined) && ((0, jsx_runtime_1.jsx)("div", { className: "service-card-image-wrap", children: (0, jsx_runtime_1.jsx)(EditableImage_1.EditableImage, { id: `${itemPath}.imageUrl`, "data-preview-field-path": `${itemPath}.imageUrl`, src: imageUrl, fallbackSrc: imageFallback, alt: name, className: "service-card-image" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "service-card-body", children: [(0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "h2", id: `${itemPath}.name`, "data-preview-field-path": `${itemPath}.name`, defaultValue: name, className: "service-card-title" }), (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "p", id: `${itemPath}.description`, "data-preview-field-path": `${itemPath}.description`, defaultValue: description, className: "service-card-description" }), hasPrice && ((0, jsx_runtime_1.jsx)("div", { className: "service-card-price-wrap", style: { margin: '0.5rem 0' }, children: (0, jsx_runtime_1.jsx)(EditableText_1.EditableText, { as: "span", id: `${itemPath}.price`, "data-preview-field-path": `${itemPath}.price`, defaultValue: String(service.price), className: "service-card-price", style: {
22
+ fontSize: '1.125rem',
23
+ fontWeight: 700,
24
+ color: 'var(--brand-color, #2563eb)',
25
+ } }) })), (features.length > 0 || Array.isArray(service?.features)) && ((0, jsx_runtime_1.jsx)("ul", { "data-preview-list-path": `${itemPath}.features`, className: "service-card-features", children: features.map((feature, featureIndex) => {
21
26
  const featureText = typeof feature === 'string'
22
27
  ? feature
23
28
  : typeof feature?.title === 'string'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deneb-ui/ui",
3
- "version": "2.0.40",
3
+ "version": "2.0.42",
4
4
  "description": "Visual-first React component library for editable commerce storefronts. Built for Next.js and Fivora.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -49,7 +49,7 @@
49
49
  ],
50
50
  "license": "MIT",
51
51
  "dependencies": {
52
- "@deneb-ui/core": "^2.0.40"
52
+ "@deneb-ui/core": "^2.0.42"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "react": "^18.0.0 || ^19.0.0",