@datlv-trustshop/shopify-inapp-components 0.2.13 → 0.2.14
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopBanner.d.ts","sourceRoot":"","sources":["../../src/components/TopBanner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AASnD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAU,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGhE,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,yCAAyC;IACzC,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACzC;
|
|
1
|
+
{"version":3,"file":"TopBanner.d.ts","sourceRoot":"","sources":["../../src/components/TopBanner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AASnD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAU,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGhE,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,yCAAyC;IACzC,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CACzC;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA6H9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -5,81 +5,32 @@ import { ExternalIcon } from "@shopify/polaris-icons";
|
|
|
5
5
|
import { useTopBanner } from "../hooks/useBanner";
|
|
6
6
|
import { useSDK } from "../core/SDKManager";
|
|
7
7
|
import { COMPONENT_DEFAULTS } from "../config/component-defaults";
|
|
8
|
-
const BANNER_MIN_HEIGHT = 100;
|
|
9
|
-
const TopBannerSkeleton = ({ className, visible }) => {
|
|
10
|
-
// When not visible, return zero-space container
|
|
11
|
-
if (!visible) {
|
|
12
|
-
return (_jsx("div", { className: className, style: {
|
|
13
|
-
width: "100%",
|
|
14
|
-
height: 0,
|
|
15
|
-
overflow: "hidden",
|
|
16
|
-
position: "absolute",
|
|
17
|
-
pointerEvents: "none",
|
|
18
|
-
}, "aria-hidden": "true" }));
|
|
19
|
-
}
|
|
20
|
-
return (_jsxs("div", { className: className, style: {
|
|
21
|
-
width: "100%",
|
|
22
|
-
}, children: [_jsxs("div", { style: {
|
|
23
|
-
minHeight: `${BANNER_MIN_HEIGHT}px`,
|
|
24
|
-
padding: "16px",
|
|
25
|
-
borderRadius: "8px",
|
|
26
|
-
border: "1px solid var(--p-color-border-subdued)",
|
|
27
|
-
backgroundColor: "var(--p-color-bg-surface)",
|
|
28
|
-
display: "flex",
|
|
29
|
-
alignItems: "center",
|
|
30
|
-
gap: "16px",
|
|
31
|
-
}, children: [_jsx("div", { style: {
|
|
32
|
-
width: 72,
|
|
33
|
-
height: 72,
|
|
34
|
-
borderRadius: "8px",
|
|
35
|
-
backgroundColor: "var(--p-color-bg-surface-secondary)",
|
|
36
|
-
flexShrink: 0,
|
|
37
|
-
animation: "pulse 1.5s ease-in-out infinite",
|
|
38
|
-
} }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: {
|
|
39
|
-
height: 20,
|
|
40
|
-
width: "30%",
|
|
41
|
-
backgroundColor: "var(--p-color-bg-surface-secondary)",
|
|
42
|
-
borderRadius: "4px",
|
|
43
|
-
marginBottom: "8px",
|
|
44
|
-
animation: "pulse 1.5s ease-in-out infinite",
|
|
45
|
-
} }), _jsx("div", { style: {
|
|
46
|
-
height: 16,
|
|
47
|
-
width: "70%",
|
|
48
|
-
backgroundColor: "var(--p-color-bg-surface-secondary)",
|
|
49
|
-
borderRadius: "4px",
|
|
50
|
-
animation: "pulse 1.5s ease-in-out infinite",
|
|
51
|
-
} })] })] }), _jsx("style", { children: `
|
|
52
|
-
@keyframes pulse {
|
|
53
|
-
0% {
|
|
54
|
-
opacity: 1;
|
|
55
|
-
}
|
|
56
|
-
50% {
|
|
57
|
-
opacity: 0.6;
|
|
58
|
-
}
|
|
59
|
-
100% {
|
|
60
|
-
opacity: 1;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
` })] }));
|
|
64
|
-
};
|
|
65
8
|
export const TopBanner = ({ className = "", open = true, onClose, onAction,
|
|
66
|
-
// SDK options (optional
|
|
9
|
+
// SDK options (optional)
|
|
67
10
|
shopInfo, locale, translations, config, }) => {
|
|
68
|
-
//
|
|
69
|
-
|
|
11
|
+
// Early return if not open - no rendering at all to prevent CLS
|
|
12
|
+
if (!open) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
// Initialize SDK (auto-initializes if needed)
|
|
16
|
+
useSDK({ shopInfo, locale, translations, config });
|
|
70
17
|
const banner = useTopBanner();
|
|
71
|
-
const [isDismissed, setIsDismissed] = useState(false);
|
|
72
|
-
const [dismissChecked, setDismissChecked] = useState(false);
|
|
73
18
|
// Use internal defaults
|
|
74
19
|
const { closable } = COMPONENT_DEFAULTS.topBanner;
|
|
75
|
-
|
|
76
|
-
const
|
|
20
|
+
// Dismiss state management
|
|
21
|
+
const [isDismissed, setIsDismissed] = useState(false);
|
|
22
|
+
const DISMISS_KEY = `trustshop_banner_dismissed_${banner?.id || "default"}`;
|
|
23
|
+
const DISMISS_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
24
|
+
// Check dismiss state on mount
|
|
77
25
|
useEffect(() => {
|
|
78
|
-
|
|
79
|
-
|
|
26
|
+
if (!banner)
|
|
27
|
+
return;
|
|
28
|
+
const dismissDataStr = localStorage.getItem(DISMISS_KEY);
|
|
29
|
+
if (dismissDataStr) {
|
|
80
30
|
try {
|
|
81
|
-
const
|
|
31
|
+
const dismissData = JSON.parse(dismissDataStr);
|
|
82
32
|
const now = Date.now();
|
|
33
|
+
const timestamp = dismissData.timestamp || 0;
|
|
83
34
|
if (now - timestamp < DISMISS_DURATION) {
|
|
84
35
|
setIsDismissed(true);
|
|
85
36
|
}
|
|
@@ -91,8 +42,7 @@ shopInfo, locale, translations, config, }) => {
|
|
|
91
42
|
localStorage.removeItem(DISMISS_KEY);
|
|
92
43
|
}
|
|
93
44
|
}
|
|
94
|
-
|
|
95
|
-
}, []);
|
|
45
|
+
}, [banner, DISMISS_KEY, DISMISS_DURATION]);
|
|
96
46
|
const handleClose = () => {
|
|
97
47
|
const dismissData = {
|
|
98
48
|
timestamp: Date.now(),
|
|
@@ -110,38 +60,14 @@ shopInfo, locale, translations, config, }) => {
|
|
|
110
60
|
onAction?.(banner);
|
|
111
61
|
}
|
|
112
62
|
};
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Always render skeleton during loading, but control visibility
|
|
117
|
-
if (!dismissChecked || !sdk.initialized || sdk.loading || sdk.isInitializing) {
|
|
118
|
-
return _jsx(TopBannerSkeleton, { className: className, visible: showSkeleton });
|
|
119
|
-
}
|
|
120
|
-
// No banner data available - render invisible container to maintain mount
|
|
121
|
-
if (!banner) {
|
|
122
|
-
return (_jsx("div", { className: className, style: {
|
|
123
|
-
width: "100%",
|
|
124
|
-
height: 0,
|
|
125
|
-
overflow: "hidden",
|
|
126
|
-
position: "absolute",
|
|
127
|
-
pointerEvents: "none",
|
|
128
|
-
}, "aria-hidden": "true" }));
|
|
129
|
-
}
|
|
130
|
-
// Removed custom render function - using SDK default rendering
|
|
131
|
-
// Default banner render with visibility control
|
|
132
|
-
// When not showing, render zero-space container
|
|
133
|
-
if (!showBanner) {
|
|
134
|
-
return (_jsx("div", { className: className, style: {
|
|
135
|
-
width: "100%",
|
|
136
|
-
height: 0,
|
|
137
|
-
overflow: "hidden",
|
|
138
|
-
position: "absolute",
|
|
139
|
-
pointerEvents: "none",
|
|
140
|
-
}, "aria-hidden": "true" }));
|
|
63
|
+
// Don't render if dismissed or no banner data
|
|
64
|
+
if (isDismissed || !banner) {
|
|
65
|
+
return null;
|
|
141
66
|
}
|
|
67
|
+
// Render the actual banner
|
|
142
68
|
return (_jsx("div", { className: className, style: {
|
|
143
69
|
width: "100%",
|
|
144
|
-
minHeight: `${BANNER_MIN_HEIGHT}px`,
|
|
145
70
|
}, children: _jsx(Banner, { hideIcon: true, onDismiss: closable ? handleClose : undefined, children: _jsxs(InlineStack, { gap: "400", blockAlign: "center", wrap: false, children: [banner.icon && (_jsx("div", { style: { flexShrink: 0 }, children: _jsx("img", { src: banner.icon, alt: "", width: 72, height: 72, style: { borderRadius: "8px" }, loading: "eager" }) })), _jsx("div", { style: { flex: 1, minWidth: 0 }, children: _jsxs(BlockStack, { gap: "100", align: "space-between", children: [_jsxs(BlockStack, { gap: "100", children: [_jsx(Text, { variant: "headingSm", as: "h3", children: banner.title }), banner.description && (_jsx(Text, { variant: "bodyMd", tone: "subdued", as: "p", children: banner.description }))] }), banner.link && (_jsx("div", { style: { flexShrink: 0 }, children: _jsx(Button, { icon: ExternalIcon, onClick: handleAction, children: banner.linkText || "Learn More" }) }))] }) })] }) }) }));
|
|
146
71
|
};
|
|
72
|
+
export default TopBanner;
|
|
147
73
|
//# sourceMappingURL=TopBanner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopBanner.js","sourceRoot":"","sources":["../../src/components/TopBanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useEffect } from \"react\";\nimport {\n Banner,\n Button,\n Text,\n BlockStack,\n InlineStack,\n} from \"@shopify/polaris\";\nimport { ExternalIcon } from \"@shopify/polaris-icons\";\nimport { BannerItem } from \"../types\";\nimport { useTopBanner } from \"../hooks/useBanner\";\nimport { useSDK, type UseSDKOptions } from \"../core/SDKManager\";\nimport { COMPONENT_DEFAULTS } from \"../config/component-defaults\";\n\nexport interface TopBannerProps extends UseSDKOptions {\n /** Optional CSS class for styling */\n className?: string;\n \n /** Control visibility (default: true) */\n open?: boolean;\n \n /** Handle close event */\n onClose?: () => void;\n \n /** Handle primary action click */\n onAction?: (banner: BannerItem) => void;\n}\n\nconst BANNER_MIN_HEIGHT = 100;\n\nconst TopBannerSkeleton: React.FC<{ \n className?: string;\n visible: boolean;\n}> = ({ className, visible }) => {\n // When not visible, return zero-space container\n if (!visible) {\n return (\n <div \n className={className}\n style={{\n width: \"100%\",\n height: 0,\n overflow: \"hidden\",\n position: \"absolute\",\n pointerEvents: \"none\",\n }}\n aria-hidden=\"true\"\n />\n );\n }\n\n return (\n <div \n className={className} \n style={{ \n width: \"100%\",\n }}\n >\n <div\n style={{\n minHeight: `${BANNER_MIN_HEIGHT}px`,\n padding: \"16px\",\n borderRadius: \"8px\",\n border: \"1px solid var(--p-color-border-subdued)\",\n backgroundColor: \"var(--p-color-bg-surface)\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"16px\",\n }}\n >\n <div\n style={{\n width: 72,\n height: 72,\n borderRadius: \"8px\",\n backgroundColor: \"var(--p-color-bg-surface-secondary)\",\n flexShrink: 0,\n animation: \"pulse 1.5s ease-in-out infinite\",\n }}\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <div\n style={{\n height: 20,\n width: \"30%\",\n backgroundColor: \"var(--p-color-bg-surface-secondary)\",\n borderRadius: \"4px\",\n marginBottom: \"8px\",\n animation: \"pulse 1.5s ease-in-out infinite\",\n }}\n />\n <div\n style={{\n height: 16,\n width: \"70%\",\n backgroundColor: \"var(--p-color-bg-surface-secondary)\",\n borderRadius: \"4px\",\n animation: \"pulse 1.5s ease-in-out infinite\",\n }}\n />\n </div>\n </div>\n <style>{`\n @keyframes pulse {\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0.6;\n }\n 100% {\n opacity: 1;\n }\n }\n `}</style>\n </div>\n );\n};\n\nexport const TopBanner: React.FC<TopBannerProps> = ({\n className = \"\",\n open = true,\n onClose,\n onAction,\n // SDK options (optional - for customization)\n shopInfo,\n locale,\n translations,\n config,\n}) => {\n // Connect to SDK Manager (auto-initializes)\n const sdk = useSDK({ shopInfo, locale, translations, config });\n \n const banner = useTopBanner();\n const [isDismissed, setIsDismissed] = useState(false);\n const [dismissChecked, setDismissChecked] = useState(false);\n\n // Use internal defaults\n const { closable } = COMPONENT_DEFAULTS.topBanner;\n const DISMISS_KEY = \"ts-top-banner-dismissed\";\n const DISMISS_DURATION = 7 * 24 * 60 * 60 * 1000;\n\n useEffect(() => {\n const dismissedData = localStorage.getItem(DISMISS_KEY);\n if (dismissedData) {\n try {\n const { timestamp } = JSON.parse(dismissedData);\n const now = Date.now();\n\n if (now - timestamp < DISMISS_DURATION) {\n setIsDismissed(true);\n } else {\n localStorage.removeItem(DISMISS_KEY);\n }\n } catch (error) {\n localStorage.removeItem(DISMISS_KEY);\n }\n }\n setDismissChecked(true);\n }, []);\n\n const handleClose = () => {\n const dismissData = {\n timestamp: Date.now(),\n dismissed: true,\n };\n localStorage.setItem(DISMISS_KEY, JSON.stringify(dismissData));\n\n setIsDismissed(true);\n onClose?.();\n };\n\n const handleAction = () => {\n if (banner) {\n if (banner.link) {\n window.open(\n banner.link,\n banner.openType === \"new_tab\" ? \"_blank\" : \"_self\",\n );\n }\n onAction?.(banner);\n }\n };\n\n const shouldShow = open && !isDismissed;\n const showSkeleton = shouldShow && (!dismissChecked || !sdk.initialized || sdk.loading || sdk.isInitializing);\n const showBanner = shouldShow && dismissChecked && sdk.initialized && !sdk.loading && !sdk.isInitializing && banner;\n\n // Always render skeleton during loading, but control visibility\n if (!dismissChecked || !sdk.initialized || sdk.loading || sdk.isInitializing) {\n return <TopBannerSkeleton className={className} visible={showSkeleton} />;\n }\n\n // No banner data available - render invisible container to maintain mount\n if (!banner) {\n return (\n <div \n className={className}\n style={{\n width: \"100%\",\n height: 0,\n overflow: \"hidden\",\n position: \"absolute\",\n pointerEvents: \"none\",\n }}\n aria-hidden=\"true\"\n />\n );\n }\n\n // Removed custom render function - using SDK default rendering\n\n // Default banner render with visibility control\n // When not showing, render zero-space container\n if (!showBanner) {\n return (\n <div \n className={className}\n style={{\n width: \"100%\",\n height: 0,\n overflow: \"hidden\",\n position: \"absolute\",\n pointerEvents: \"none\",\n }}\n aria-hidden=\"true\"\n />\n );\n }\n\n return (\n <div\n className={className}\n style={{\n width: \"100%\",\n minHeight: `${BANNER_MIN_HEIGHT}px`,\n }}\n >\n <Banner hideIcon onDismiss={closable ? handleClose : undefined}>\n <InlineStack gap=\"400\" blockAlign=\"center\" wrap={false}>\n {banner.icon && (\n <div style={{ flexShrink: 0 }}>\n <img\n src={banner.icon}\n alt=\"\"\n width={72}\n height={72}\n style={{ borderRadius: \"8px\" }}\n loading=\"eager\"\n />\n </div>\n )}\n <div style={{ flex: 1, minWidth: 0 }}>\n <BlockStack gap=\"100\" align=\"space-between\">\n <BlockStack gap=\"100\">\n <Text variant=\"headingSm\" as=\"h3\">\n {banner.title}\n </Text>\n {banner.description && (\n <Text variant=\"bodyMd\" tone=\"subdued\" as=\"p\">\n {banner.description}\n </Text>\n )}\n </BlockStack>\n {banner.link && (\n <div style={{ flexShrink: 0 }}>\n <Button icon={ExternalIcon} onClick={handleAction}>\n {banner.linkText || \"Learn More\"}\n </Button>\n </div>\n )}\n </BlockStack>\n </div>\n </InlineStack>\n </Banner>\n </div>\n );\n};"]}
|
|
1
|
+
{"version":3,"file":"TopBanner.js","sourceRoot":"","sources":["../../src/components/TopBanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useEffect } from \"react\";\nimport {\n Banner,\n Button,\n Text,\n BlockStack,\n InlineStack,\n} from \"@shopify/polaris\";\nimport { ExternalIcon } from \"@shopify/polaris-icons\";\nimport { BannerItem } from \"../types\";\nimport { useTopBanner } from \"../hooks/useBanner\";\nimport { useSDK, type UseSDKOptions } from \"../core/SDKManager\";\nimport { COMPONENT_DEFAULTS } from \"../config/component-defaults\";\n\nexport interface TopBannerProps extends UseSDKOptions {\n /** Optional CSS class for styling */\n className?: string;\n\n /** Control visibility (default: true) */\n open?: boolean;\n\n /** Handle close event */\n onClose?: () => void;\n\n /** Handle primary action click */\n onAction?: (banner: BannerItem) => void;\n}\n\nexport const TopBanner: React.FC<TopBannerProps> = ({\n className = \"\",\n open = true,\n onClose,\n onAction,\n // SDK options (optional)\n shopInfo,\n locale,\n translations,\n config,\n}) => {\n // Early return if not open - no rendering at all to prevent CLS\n if (!open) {\n return null;\n }\n\n // Initialize SDK (auto-initializes if needed)\n useSDK({ shopInfo, locale, translations, config });\n const banner = useTopBanner();\n\n // Use internal defaults\n const { closable } = COMPONENT_DEFAULTS.topBanner;\n\n // Dismiss state management\n const [isDismissed, setIsDismissed] = useState(false);\n const DISMISS_KEY = `trustshop_banner_dismissed_${banner?.id || \"default\"}`;\n const DISMISS_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days\n\n // Check dismiss state on mount\n useEffect(() => {\n if (!banner) return;\n\n const dismissDataStr = localStorage.getItem(DISMISS_KEY);\n if (dismissDataStr) {\n try {\n const dismissData = JSON.parse(dismissDataStr);\n const now = Date.now();\n const timestamp = dismissData.timestamp || 0;\n\n if (now - timestamp < DISMISS_DURATION) {\n setIsDismissed(true);\n } else {\n localStorage.removeItem(DISMISS_KEY);\n }\n } catch (error) {\n localStorage.removeItem(DISMISS_KEY);\n }\n }\n }, [banner, DISMISS_KEY, DISMISS_DURATION]);\n\n const handleClose = () => {\n const dismissData = {\n timestamp: Date.now(),\n dismissed: true,\n };\n localStorage.setItem(DISMISS_KEY, JSON.stringify(dismissData));\n\n setIsDismissed(true);\n onClose?.();\n };\n\n const handleAction = () => {\n if (banner) {\n if (banner.link) {\n window.open(\n banner.link,\n banner.openType === \"new_tab\" ? \"_blank\" : \"_self\",\n );\n }\n onAction?.(banner);\n }\n };\n\n // Don't render if dismissed or no banner data\n if (isDismissed || !banner) {\n return null;\n }\n\n // Render the actual banner\n return (\n <div\n className={className}\n style={{\n width: \"100%\",\n }}\n >\n <Banner hideIcon onDismiss={closable ? handleClose : undefined}>\n <InlineStack gap=\"400\" blockAlign=\"center\" wrap={false}>\n {banner.icon && (\n <div style={{ flexShrink: 0 }}>\n <img\n src={banner.icon}\n alt=\"\"\n width={72}\n height={72}\n style={{ borderRadius: \"8px\" }}\n loading=\"eager\"\n />\n </div>\n )}\n <div style={{ flex: 1, minWidth: 0 }}>\n <BlockStack gap=\"100\" align=\"space-between\">\n <BlockStack gap=\"100\">\n <Text variant=\"headingSm\" as=\"h3\">\n {banner.title}\n </Text>\n {banner.description && (\n <Text variant=\"bodyMd\" tone=\"subdued\" as=\"p\">\n {banner.description}\n </Text>\n )}\n </BlockStack>\n {banner.link && (\n <div style={{ flexShrink: 0 }}>\n <Button icon={ExternalIcon} onClick={handleAction}>\n {banner.linkText || \"Learn More\"}\n </Button>\n </div>\n )}\n </BlockStack>\n </div>\n </InlineStack>\n </Banner>\n </div>\n );\n};\n\nexport default TopBanner;"]}
|