@deneb-ui/ui 2.0.123 → 2.0.125

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.
@@ -594,17 +594,35 @@ function SiteDataProvider({ children, initialSiteData, fallbackSiteData, liveCat
594
594
  return;
595
595
  const sd = siteData;
596
596
  const common = isRecord(sd?.content?.common) ? sd.content.common : null;
597
- const shop = isRecord(sd?.shop) ? sd.shop : null;
597
+ const hasKeys = (o) => isRecord(o) && Object.keys(o).length > 0;
598
+ const shop = hasKeys(sd?.shop) ? sd.shop : (hasKeys(sd?.merchant) ? sd.merchant : (isRecord(sd?.shop) ? sd.shop : null));
598
599
  const site = isRecord(sd?.site) ? sd.site : null;
599
- const candidateTitle = (typeof common?.websiteTitle === "string" && common.websiteTitle.trim()) ||
600
- (typeof shop?.businessName === "string" && shop.businessName.trim()) ||
601
- (typeof site?.name === "string" && site.name.trim());
600
+ const merchant = isRecord(sd?.merchant) ? sd.merchant : null;
601
+ const seo = isRecord(sd?.seo) ? sd.seo : null;
602
+ const seoSite = isRecord(seo?.site) ? seo.site : null;
603
+ const isPlaceholderTitle = (val) => typeof val !== "string" ||
604
+ !val.trim() ||
605
+ /^(demo|template|storefront|website|my shop|coffee)$/i.test(val.trim());
606
+ const realShopName = (typeof shop?.businessName === "string" && shop.businessName.trim()) ||
607
+ (typeof merchant?.businessName === "string" && merchant.businessName.trim()) ||
608
+ "";
609
+ const candidateTitle = realShopName ||
610
+ (!isPlaceholderTitle(common?.websiteTitle) ? (common?.websiteTitle).trim() : "") ||
611
+ (typeof site?.name === "string" && site.name.trim()) ||
612
+ (typeof common?.websiteTitle === "string" ? common.websiteTitle.trim() : "");
602
613
  if (candidateTitle) {
603
614
  document.title = candidateTitle;
604
615
  }
605
- const candidateIcon = (typeof common?.logoUrl === "string" && common.logoUrl.trim()) ||
606
- (typeof shop?.logoUrl === "string" && shop.logoUrl.trim()) ||
607
- (typeof site?.logoUrl === "string" && site.logoUrl.trim());
616
+ const isPlaceholderLogo = (url) => typeof url !== "string" ||
617
+ !url.trim() ||
618
+ url === "/fivora-logo.png" ||
619
+ url.includes("fivora-logo") ||
620
+ url === "/favicon.ico";
621
+ const candidateIcon = (!isPlaceholderLogo(seoSite?.favicon) ? (seoSite?.favicon).trim() : "") ||
622
+ (!isPlaceholderLogo(shop?.logoUrl) ? (shop?.logoUrl).trim() : "") ||
623
+ (!isPlaceholderLogo(merchant?.logoUrl) ? (merchant?.logoUrl).trim() : "") ||
624
+ (!isPlaceholderLogo(site?.logoUrl) ? (site?.logoUrl).trim() : "") ||
625
+ (!isPlaceholderLogo(common?.logoUrl) ? (common?.logoUrl).trim() : "");
608
626
  if (candidateIcon) {
609
627
  let link = document.querySelector("link[rel*='icon']");
610
628
  if (!link) {
@@ -1015,6 +1033,10 @@ function useSiteCatalog() {
1015
1033
  */
1016
1034
  function useShop(fallback = {}) {
1017
1035
  const siteData = useSiteData();
1036
+ if (isRecord(siteData?.shop) && Object.keys(siteData.shop).length > 0)
1037
+ return siteData.shop;
1038
+ if (isRecord(siteData?.merchant) && Object.keys(siteData.merchant).length > 0)
1039
+ return siteData.merchant;
1018
1040
  if (isRecord(siteData?.shop))
1019
1041
  return siteData.shop;
1020
1042
  if (isRecord(siteData?.merchant))
@@ -5,6 +5,7 @@ export interface ContactButtonProps extends React.AnchorHTMLAttributes<HTMLAncho
5
5
  value?: string | null;
6
6
  label?: React.ReactNode;
7
7
  fieldPath?: string;
8
+ labelFieldPath?: string;
8
9
  targetPage?: string;
9
10
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'whatsapp';
10
11
  size?: 'sm' | 'md' | 'lg';
@@ -12,4 +13,4 @@ export interface ContactButtonProps extends React.AnchorHTMLAttributes<HTMLAncho
12
13
  message?: string;
13
14
  subject?: string;
14
15
  }
15
- export declare function ContactButton({ type, value, href, label, children, fieldPath, targetPage, variant, size, icon, message, subject, className, style, ...rest }: ContactButtonProps): React.JSX.Element | null;
16
+ export declare function ContactButton({ type, value, href, label, children, fieldPath, labelFieldPath, targetPage, variant, size, icon, message, subject, className, style, ...rest }: ContactButtonProps): React.JSX.Element | null;
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.ContactButton = ContactButton;
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  const urls_1 = require("../utils/urls");
7
- function ContactButton({ type = 'whatsapp', value, href, label, children, fieldPath, targetPage, variant, size = 'md', icon, message, subject, className = '', style, ...rest }) {
7
+ function ContactButton({ type = 'whatsapp', value, href, label, children, fieldPath, labelFieldPath, targetPage, variant, size = 'md', icon, message, subject, className = '', style, ...rest }) {
8
8
  // If no fieldPath and no value/href/label/children, do not render broken button
9
9
  if (!fieldPath && !value && !href && !children && !label) {
10
10
  return null;
@@ -87,7 +87,16 @@ function ContactButton({ type = 'whatsapp', value, href, label, children, fieldP
87
87
  ...sizeStyles[size],
88
88
  ...variantStyles[resolvedVariant],
89
89
  };
90
- const buttonElement = ((0, jsx_runtime_1.jsxs)("a", { href: resolvedHref, "data-preview-field-path": fieldPath, target: shouldOpenNewTab ? '_blank' : undefined, rel: shouldOpenNewTab ? 'noopener noreferrer' : undefined, className: `deneb-contact-btn deneb-contact-${type} ${className}`.trim(), style: mergedStyles, ...rest, children: [icon !== undefined ? icon : defaultIcon, children || label] }));
90
+ const textContent = typeof children === 'string' ? children : (typeof label === 'string' ? label : '');
91
+ const digitsOnly = (str) => str.replace(/\D/g, '');
92
+ const matchesValue = Boolean(value &&
93
+ textContent &&
94
+ (digitsOnly(textContent) === digitsOnly(String(value)) || textContent.trim().toLowerCase() === String(value).trim().toLowerCase()));
95
+ const staticMarker = rest['data-preview-static'] || `${type}-action`;
96
+ const staticLabelMarker = rest['data-preview-static'] || `${type}-label`;
97
+ const buttonElement = ((0, jsx_runtime_1.jsxs)("a", { href: resolvedHref, ...(fieldPath && (matchesValue || labelFieldPath)
98
+ ? { 'data-preview-field-path': fieldPath }
99
+ : { 'data-preview-static': staticMarker }), target: shouldOpenNewTab ? '_blank' : undefined, rel: shouldOpenNewTab ? 'noopener noreferrer' : undefined, className: `deneb-contact-btn deneb-contact-${type} ${className}`.trim(), style: mergedStyles, ...rest, children: [icon !== undefined ? icon : defaultIcon, labelFieldPath ? ((0, jsx_runtime_1.jsx)("span", { "data-preview-field-path": labelFieldPath, children: children || label })) : fieldPath && matchesValue ? (children || label) : ((0, jsx_runtime_1.jsx)("span", { "data-preview-static": staticLabelMarker, children: children || label }))] }));
91
100
  if (targetPage) {
92
101
  return ((0, jsx_runtime_1.jsx)("span", { "data-target-page": targetPage, style: { display: 'inline-block' }, children: buttonElement }));
93
102
  }
@@ -16,26 +16,41 @@ function WhatsAppButton({ phoneNumber, value, label = 'Chat on WhatsApp', fieldP
16
16
  const isPreview = (0, SiteDataProvider_1.isPreviewValidation)(siteData);
17
17
  const content = (siteData?.content && typeof siteData.content === 'object' ? siteData.content : {});
18
18
  const common = (content.common && typeof content.common === 'object' ? content.common : {});
19
+ const business = (common.business && typeof common.business === 'object' ? common.business : {});
19
20
  const contact = (content.contact && typeof content.contact === 'object' ? content.contact : (common.contact && typeof common.contact === 'object' ? common.contact : {}));
20
21
  const home = (content.home && typeof content.home === 'object' ? content.home : {});
21
22
  const merchant = (siteData && 'merchant' in siteData && typeof siteData.merchant === 'object' ? siteData.merchant : {});
23
+ const shop = (siteData && 'shop' in siteData && typeof siteData.shop === 'object' ? siteData.shop : {});
24
+ const isDemoNumber = (val) => {
25
+ if (typeof val !== "string" || !val.trim())
26
+ return true;
27
+ const digits = val.replace(/\D/g, "");
28
+ return digits.length < 7 || digits.startsWith("123456") || /^0+$/.test(digits);
29
+ };
22
30
  const liveNumber = liveShop?.contact?.whatsapp ||
23
- (typeof liveShop?.businessWhatsapp === 'string' ? liveShop.businessWhatsapp : null) ||
31
+ (typeof liveShop?.businessWhatsapp === "string" ? liveShop.businessWhatsapp : null) ||
32
+ (typeof shop?.businessWhatsapp === "string" ? shop.businessWhatsapp : null) ||
33
+ shop?.whatsapp ||
34
+ merchant?.businessWhatsapp ||
35
+ merchant?.whatsapp ||
36
+ (!isDemoNumber(contact.whatsapp) ? contact.whatsapp : null) ||
37
+ (!isDemoNumber(contact.whatsappNumber) ? contact.whatsappNumber : null) ||
38
+ (!isDemoNumber(common.whatsapp) ? common.whatsapp : null) ||
39
+ (!isDemoNumber(common.whatsappNumber) ? common.whatsappNumber : null) ||
24
40
  liveShop?.contact?.phone ||
25
- (typeof liveShop?.businessPhone === 'string' ? liveShop.businessPhone : null);
26
- const effectiveNumber = phoneNumber ||
27
- (!isPreview ? liveNumber : null) ||
28
- value ||
29
- contact.whatsapp ||
30
- contact.whatsappNumber ||
41
+ (typeof liveShop?.businessPhone === "string" ? liveShop.businessPhone : null) ||
42
+ shop?.phone ||
43
+ merchant?.phone ||
44
+ (!isDemoNumber(business.whatsapp) ? business.whatsapp : null) ||
45
+ business.phone ||
31
46
  contact.phone ||
32
47
  home.whatsappNumber ||
33
- home.whatsappCtaUrl ||
34
- common.whatsapp ||
35
- common.whatsappNumber ||
36
- merchant.whatsapp ||
37
- merchant.phone ||
38
- (isPreview ? SiteDataProvider_1.DUMMY_PREVIEW_WHATSAPP : '');
48
+ home.whatsappCtaUrl;
49
+ const effectiveNumber = (!isPreview ? (liveNumber || null) : null) ||
50
+ (!isDemoNumber(phoneNumber) ? phoneNumber : null) ||
51
+ value ||
52
+ liveNumber ||
53
+ (isPreview ? SiteDataProvider_1.DUMMY_PREVIEW_WHATSAPP : "");
39
54
  if (!effectiveNumber && !fieldPath)
40
55
  return null;
41
56
  return ((0, jsx_runtime_1.jsx)(ContactButton_1.ContactButton, { type: "whatsapp", value: effectiveNumber, label: label, fieldPath: fieldPath, variant: variant, message: message, ...rest }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deneb-ui/ui",
3
- "version": "2.0.123",
3
+ "version": "2.0.125",
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",
@@ -50,7 +50,7 @@
50
50
  ],
51
51
  "license": "MIT",
52
52
  "dependencies": {
53
- "@deneb-ui/core": "^2.0.123"
53
+ "@deneb-ui/core": "^2.0.125"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "react": "^18.0.0 || ^19.0.0",