@datlv-trustshop/shopify-inapp-components 0.2.5 → 0.2.7

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.
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import { BannerItem } from "../types";
3
3
  export interface TopBannerProps {
4
4
  className?: string;
5
+ open?: boolean;
5
6
  onClose?: () => void;
6
7
  onAction?: (banner: BannerItem) => void;
7
8
  closable?: boolean;
@@ -1,11 +1,67 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useContext } from "react";
3
3
  import { Banner, Button, Text, BlockStack, InlineStack, } from "@shopify/polaris";
4
4
  import { ExternalIcon } from "@shopify/polaris-icons";
5
5
  import { useTopBanner } from "../hooks/useBanner";
6
- export const TopBanner = ({ className = "", onClose, onAction, closable = true, renderBanner, }) => {
6
+ import { DashboardContext } from "../provider/DashboardProvider";
7
+ const BANNER_MIN_HEIGHT = 100;
8
+ const TopBannerSkeleton = ({ className, visible }) => {
9
+ return (_jsxs("div", { className: className, style: {
10
+ width: "100%",
11
+ opacity: visible ? 1 : 0,
12
+ visibility: visible ? "visible" : "hidden",
13
+ transition: "opacity 0.2s ease, visibility 0.2s ease",
14
+ pointerEvents: visible ? "auto" : "none",
15
+ }, children: [_jsxs("div", { style: {
16
+ minHeight: `${BANNER_MIN_HEIGHT}px`,
17
+ padding: "16px",
18
+ borderRadius: "8px",
19
+ border: "1px solid var(--p-color-border-subdued)",
20
+ backgroundColor: "var(--p-color-bg-surface)",
21
+ display: "flex",
22
+ alignItems: "center",
23
+ gap: "16px",
24
+ }, children: [_jsx("div", { style: {
25
+ width: 72,
26
+ height: 72,
27
+ borderRadius: "8px",
28
+ backgroundColor: "var(--p-color-bg-surface-secondary)",
29
+ flexShrink: 0,
30
+ animation: "pulse 1.5s ease-in-out infinite",
31
+ } }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: {
32
+ height: 20,
33
+ width: "30%",
34
+ backgroundColor: "var(--p-color-bg-surface-secondary)",
35
+ borderRadius: "4px",
36
+ marginBottom: "8px",
37
+ animation: "pulse 1.5s ease-in-out infinite",
38
+ } }), _jsx("div", { style: {
39
+ height: 16,
40
+ width: "70%",
41
+ backgroundColor: "var(--p-color-bg-surface-secondary)",
42
+ borderRadius: "4px",
43
+ animation: "pulse 1.5s ease-in-out infinite",
44
+ } })] })] }), _jsx("style", { children: `
45
+ @keyframes pulse {
46
+ 0% {
47
+ opacity: 1;
48
+ }
49
+ 50% {
50
+ opacity: 0.6;
51
+ }
52
+ 100% {
53
+ opacity: 1;
54
+ }
55
+ }
56
+ ` })] }));
57
+ };
58
+ export const TopBanner = ({ className = "", open = true, onClose, onAction, closable = true, renderBanner, }) => {
59
+ const context = useContext(DashboardContext);
60
+ const isInitialized = context?.isInitialized ?? false;
61
+ const isLoading = context?.state?.loading ?? true;
7
62
  const banner = useTopBanner();
8
63
  const [isDismissed, setIsDismissed] = useState(false);
64
+ const [dismissChecked, setDismissChecked] = useState(false);
9
65
  const DISMISS_KEY = "ts-top-banner-dismissed";
10
66
  const DISMISS_DURATION = 7 * 24 * 60 * 60 * 1000;
11
67
  useEffect(() => {
@@ -25,6 +81,7 @@ export const TopBanner = ({ className = "", onClose, onAction, closable = true,
25
81
  localStorage.removeItem(DISMISS_KEY);
26
82
  }
27
83
  }
84
+ setDismissChecked(true);
28
85
  }, []);
29
86
  const handleClose = () => {
30
87
  const dismissData = {
@@ -43,14 +100,39 @@ export const TopBanner = ({ className = "", onClose, onAction, closable = true,
43
100
  onAction?.(banner);
44
101
  }
45
102
  };
46
- if (!banner || isDismissed) {
47
- return null;
103
+ const shouldShow = open && !isDismissed;
104
+ const showSkeleton = shouldShow && (!dismissChecked || !isInitialized || isLoading);
105
+ const showBanner = shouldShow && dismissChecked && isInitialized && !isLoading && banner;
106
+ if (!dismissChecked || !isInitialized || isLoading) {
107
+ return _jsx(TopBannerSkeleton, { className: className, visible: showSkeleton });
108
+ }
109
+ if (!banner) {
110
+ return (_jsx("div", { className: className, style: {
111
+ width: "100%",
112
+ height: 0,
113
+ overflow: "hidden",
114
+ opacity: 0,
115
+ visibility: "hidden",
116
+ }, "aria-hidden": "true" }));
48
117
  }
49
118
  if (renderBanner) {
50
- return (_jsx(_Fragment, { children: renderBanner(banner, {
119
+ return (_jsx("div", { style: {
120
+ opacity: showBanner ? 1 : 0,
121
+ visibility: showBanner ? "visible" : "hidden",
122
+ transition: "opacity 0.3s ease, visibility 0.3s ease",
123
+ pointerEvents: showBanner ? "auto" : "none",
124
+ }, children: renderBanner(banner, {
51
125
  onClose: handleClose,
52
126
  onAction: handleAction,
53
127
  }) }));
54
128
  }
55
- return (_jsx("div", { className: className, style: { width: "100%" }, 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" } }) })), _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" }) }))] }) })] }) }) }));
129
+ return (_jsx("div", { className: className, style: {
130
+ width: "100%",
131
+ minHeight: showBanner ? `${BANNER_MIN_HEIGHT}px` : 0,
132
+ opacity: showBanner ? 1 : 0,
133
+ visibility: showBanner ? "visible" : "hidden",
134
+ transition: "opacity 0.3s ease, visibility 0.3s ease, min-height 0.3s ease",
135
+ pointerEvents: showBanner ? "auto" : "none",
136
+ overflow: "hidden",
137
+ }, 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" }) }))] }) })] }) }) }));
56
138
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datlv-trustshop/shopify-inapp-components",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "private": false,
5
5
  "description": "React TypeScript components for Shopify in-app dashboard content",
6
6
  "main": "dist/index.js",