@adtogether/web-sdk 0.1.13 → 0.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
- ## 0.1.13
1
+ ## 0.1.14
2
2
 
3
+ * **Feature**: Added `onAdClosed` callback support to banner components.
4
+ * **Feature**: Improved automatic `bundleId` detection across all platforms.
5
+ * **Security**: Hardened ad-serving logic to prevent payout fraud.
3
6
  * **Sync**: Version parity across all AdTogether SDKs.
4
7
 
5
8
  ## 0.1.12
package/README.md CHANGED
@@ -45,7 +45,10 @@ Call `AdTogether.initialize()` before rendering any ad components. You can obtai
45
45
  ```typescript
46
46
  import { AdTogether } from '@adtogether/web-sdk';
47
47
 
48
- AdTogether.initialize({ appId: 'YOUR_APP_ID' });
48
+ AdTogether.initialize({
49
+ appId: 'YOUR_APP_ID',
50
+ // bundleId: 'com.example.app' // optional: automatically detected from window.location.hostname
51
+ });
49
52
  ```
50
53
 
51
54
  ## Usage
@@ -64,8 +67,10 @@ function MyApp() {
64
67
 
65
68
  <AdTogetherBanner
66
69
  adUnitId="home_bottom_banner"
70
+ showCloseButton={true}
67
71
  onAdLoaded={() => console.log('Banner loaded!')}
68
72
  onAdFailedToLoad={(error) => console.error('Banner error:', error)}
73
+ onAdClosed={() => console.log('Banner closed!')}
69
74
  />
70
75
  </div>
71
76
  );
@@ -77,6 +82,8 @@ function MyApp() {
77
82
  | Prop | Type | Default | Description |
78
83
  |--------------------|-------------------------|-----------|-------------|
79
84
  | `adUnitId` | `string` | **required** | Unique identifier for this ad placement. |
85
+ | `showCloseButton` | `boolean` | `false` | Show a dismissable close button overlay. |
86
+ | `onAdClosed` | `() => void` | — | Called when the user closes the ad. |
80
87
  | `width` | `number \| string` | `'100%'` | Width of the ad element. |
81
88
  | `height` | `number \| string` | `'auto'` | Height of the ad element. |
82
89
  | `theme` | `'dark' \| 'light' \| 'auto'` | `'auto'` | Color scheme. `'auto'` follows system preference. |
@@ -13,6 +13,11 @@ var AdTogether = class _AdTogether {
13
13
  static initialize(options) {
14
14
  const sdk = _AdTogether.shared;
15
15
  sdk.appId = options.apiKey || options.appId;
16
+ if (options.bundleId) {
17
+ sdk.bundleId = options.bundleId;
18
+ } else if (typeof window !== "undefined") {
19
+ sdk.bundleId = window.location.hostname;
20
+ }
16
21
  if (options.allowSelfAds !== void 0) {
17
22
  sdk.allowSelfAds = options.allowSelfAds;
18
23
  }
@@ -43,6 +48,9 @@ var AdTogether = class _AdTogether {
43
48
  if (sdk.lastAdId) {
44
49
  url += `&exclude=${sdk.lastAdId}`;
45
50
  }
51
+ if (sdk.bundleId) {
52
+ url += `&bundleId=${sdk.bundleId}`;
53
+ }
46
54
  url += `&allowSelfAds=${sdk.allowSelfAds}`;
47
55
  if (typeof window !== "undefined") {
48
56
  url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
@@ -74,7 +82,11 @@ var AdTogether = class _AdTogether {
74
82
  body: JSON.stringify({
75
83
  adId,
76
84
  token,
77
- apiKey: _AdTogether.shared.appId
85
+ apiKey: _AdTogether.shared.appId,
86
+ ..._AdTogether.shared.bundleId ? { bundleId: _AdTogether.shared.bundleId } : {},
87
+ // Send platform and environment to match Flutter SDK
88
+ platform: "web",
89
+ environment: typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? "development" : "production"
78
90
  })
79
91
  }).catch(console.error);
80
92
  }
package/dist/index.d.mts CHANGED
@@ -12,6 +12,7 @@ interface AdTogetherOptions {
12
12
  appId?: string;
13
13
  apiKey?: string;
14
14
  baseUrl?: string;
15
+ bundleId?: string;
15
16
  /** Whether to show your own ads as fallback if no external ads are available. Defaults to true. */
16
17
  allowSelfAds?: boolean;
17
18
  }
@@ -19,6 +20,7 @@ interface AdTogetherOptions {
19
20
  declare class AdTogether {
20
21
  private static instance;
21
22
  private appId?;
23
+ private bundleId?;
22
24
  private allowSelfAds;
23
25
  baseUrl: string;
24
26
  private constructor();
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ interface AdTogetherOptions {
12
12
  appId?: string;
13
13
  apiKey?: string;
14
14
  baseUrl?: string;
15
+ bundleId?: string;
15
16
  /** Whether to show your own ads as fallback if no external ads are available. Defaults to true. */
16
17
  allowSelfAds?: boolean;
17
18
  }
@@ -19,6 +20,7 @@ interface AdTogetherOptions {
19
20
  declare class AdTogether {
20
21
  private static instance;
21
22
  private appId?;
23
+ private bundleId?;
22
24
  private allowSelfAds;
23
25
  baseUrl: string;
24
26
  private constructor();
package/dist/index.js CHANGED
@@ -39,6 +39,11 @@ var AdTogether = class _AdTogether {
39
39
  static initialize(options) {
40
40
  const sdk = _AdTogether.shared;
41
41
  sdk.appId = options.apiKey || options.appId;
42
+ if (options.bundleId) {
43
+ sdk.bundleId = options.bundleId;
44
+ } else if (typeof window !== "undefined") {
45
+ sdk.bundleId = window.location.hostname;
46
+ }
42
47
  if (options.allowSelfAds !== void 0) {
43
48
  sdk.allowSelfAds = options.allowSelfAds;
44
49
  }
@@ -69,6 +74,9 @@ var AdTogether = class _AdTogether {
69
74
  if (sdk.lastAdId) {
70
75
  url += `&exclude=${sdk.lastAdId}`;
71
76
  }
77
+ if (sdk.bundleId) {
78
+ url += `&bundleId=${sdk.bundleId}`;
79
+ }
72
80
  url += `&allowSelfAds=${sdk.allowSelfAds}`;
73
81
  if (typeof window !== "undefined") {
74
82
  url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
@@ -100,7 +108,11 @@ var AdTogether = class _AdTogether {
100
108
  body: JSON.stringify({
101
109
  adId,
102
110
  token,
103
- apiKey: _AdTogether.shared.appId
111
+ apiKey: _AdTogether.shared.appId,
112
+ ..._AdTogether.shared.bundleId ? { bundleId: _AdTogether.shared.bundleId } : {},
113
+ // Send platform and environment to match Flutter SDK
114
+ platform: "web",
115
+ environment: typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? "development" : "production"
104
116
  })
105
117
  }).catch(console.error);
106
118
  }
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AdTogether
3
- } from "./chunk-7IJIBJD4.mjs";
3
+ } from "./chunk-RW43ES42.mjs";
4
4
  export {
5
5
  AdTogether
6
6
  };
@@ -6,6 +6,10 @@ interface AdTogetherBannerProps {
6
6
  style?: React.CSSProperties;
7
7
  onAdLoaded?: () => void;
8
8
  onAdFailedToLoad?: (error: Error) => void;
9
+ /** Whether to show a close button on the banner */
10
+ showCloseButton?: boolean;
11
+ /** Callback when the user closes the ad */
12
+ onAdClosed?: () => void;
9
13
  /** Width of the ad element. Defaults to '100%' */
10
14
  width?: number | string;
11
15
  /** Height of the ad element. Defaults to 'auto' */
@@ -6,6 +6,10 @@ interface AdTogetherBannerProps {
6
6
  style?: React.CSSProperties;
7
7
  onAdLoaded?: () => void;
8
8
  onAdFailedToLoad?: (error: Error) => void;
9
+ /** Whether to show a close button on the banner */
10
+ showCloseButton?: boolean;
11
+ /** Callback when the user closes the ad */
12
+ onAdClosed?: () => void;
9
13
  /** Width of the ad element. Defaults to '100%' */
10
14
  width?: number | string;
11
15
  /** Height of the ad element. Defaults to 'auto' */
@@ -43,6 +43,11 @@ var AdTogether = class _AdTogether {
43
43
  static initialize(options) {
44
44
  const sdk = _AdTogether.shared;
45
45
  sdk.appId = options.apiKey || options.appId;
46
+ if (options.bundleId) {
47
+ sdk.bundleId = options.bundleId;
48
+ } else if (typeof window !== "undefined") {
49
+ sdk.bundleId = window.location.hostname;
50
+ }
46
51
  if (options.allowSelfAds !== void 0) {
47
52
  sdk.allowSelfAds = options.allowSelfAds;
48
53
  }
@@ -73,6 +78,9 @@ var AdTogether = class _AdTogether {
73
78
  if (sdk.lastAdId) {
74
79
  url += `&exclude=${sdk.lastAdId}`;
75
80
  }
81
+ if (sdk.bundleId) {
82
+ url += `&bundleId=${sdk.bundleId}`;
83
+ }
76
84
  url += `&allowSelfAds=${sdk.allowSelfAds}`;
77
85
  if (typeof window !== "undefined") {
78
86
  url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
@@ -104,7 +112,11 @@ var AdTogether = class _AdTogether {
104
112
  body: JSON.stringify({
105
113
  adId,
106
114
  token,
107
- apiKey: _AdTogether.shared.appId
115
+ apiKey: _AdTogether.shared.appId,
116
+ ..._AdTogether.shared.bundleId ? { bundleId: _AdTogether.shared.bundleId } : {},
117
+ // Send platform and environment to match Flutter SDK
118
+ platform: "web",
119
+ environment: typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? "development" : "production"
108
120
  })
109
121
  }).catch(console.error);
110
122
  }
@@ -118,6 +130,8 @@ var AdTogetherBanner = ({
118
130
  style = {},
119
131
  onAdLoaded,
120
132
  onAdFailedToLoad,
133
+ showCloseButton = false,
134
+ onAdClosed,
121
135
  width = "100%",
122
136
  height = "auto",
123
137
  theme = "auto"
@@ -125,6 +139,7 @@ var AdTogetherBanner = ({
125
139
  const [adData, setAdData] = (0, import_react.useState)(null);
126
140
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
127
141
  const [hasError, setHasError] = (0, import_react.useState)(false);
142
+ const [isVisible, setIsVisible] = (0, import_react.useState)(true);
128
143
  const [isDarkMode, setIsDarkMode] = (0, import_react.useState)(theme === "dark");
129
144
  const containerRef = (0, import_react.useRef)(null);
130
145
  const impressionTrackedRef = (0, import_react.useRef)(false);
@@ -141,7 +156,7 @@ var AdTogetherBanner = ({
141
156
  }, [theme]);
142
157
  (0, import_react.useEffect)(() => {
143
158
  let isMounted = true;
144
- AdTogether.fetchAd(adUnitId).then((ad) => {
159
+ AdTogether.fetchAd(adUnitId, "banner").then((ad) => {
145
160
  if (isMounted) {
146
161
  setAdData(ad);
147
162
  setIsLoading(false);
@@ -183,6 +198,14 @@ var AdTogetherBanner = ({
183
198
  window.open(adData.clickUrl, "_blank", "noopener,noreferrer");
184
199
  }
185
200
  };
201
+ const handleClose = (e) => {
202
+ e.stopPropagation();
203
+ setIsVisible(false);
204
+ onAdClosed?.();
205
+ };
206
+ if (!isVisible) {
207
+ return null;
208
+ }
186
209
  if (isLoading) {
187
210
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
188
211
  "div",
@@ -217,6 +240,7 @@ var AdTogetherBanner = ({
217
240
  overflow: "hidden",
218
241
  cursor: "pointer",
219
242
  boxSizing: "border-box",
243
+ position: "relative",
220
244
  ...style
221
245
  },
222
246
  onMouseOver: (e) => {
@@ -249,7 +273,35 @@ var AdTogetherBanner = ({
249
273
  }, children: "AD" })
250
274
  ] }),
251
275
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "12px", color: descColor, overflow: "hidden", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical" }, children: adData.description })
252
- ] })
276
+ ] }),
277
+ showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
278
+ "button",
279
+ {
280
+ onClick: handleClose,
281
+ "aria-label": "Close ad",
282
+ style: {
283
+ position: "absolute",
284
+ top: "8px",
285
+ right: "8px",
286
+ width: "24px",
287
+ height: "24px",
288
+ borderRadius: "50%",
289
+ backgroundColor: "rgba(0, 0, 0, 0.4)",
290
+ border: "none",
291
+ color: "#fff",
292
+ fontSize: "14px",
293
+ fontWeight: "bold",
294
+ cursor: "pointer",
295
+ display: "flex",
296
+ alignItems: "center",
297
+ justifyContent: "center",
298
+ padding: 0,
299
+ lineHeight: 1,
300
+ zIndex: 1
301
+ },
302
+ children: "\xD7"
303
+ }
304
+ )
253
305
  ]
254
306
  }
255
307
  );
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AdTogether
3
- } from "../chunk-7IJIBJD4.mjs";
3
+ } from "../chunk-RW43ES42.mjs";
4
4
 
5
5
  // src/react/AdTogetherBanner.tsx
6
6
  import { useEffect, useRef, useState } from "react";
@@ -11,6 +11,8 @@ var AdTogetherBanner = ({
11
11
  style = {},
12
12
  onAdLoaded,
13
13
  onAdFailedToLoad,
14
+ showCloseButton = false,
15
+ onAdClosed,
14
16
  width = "100%",
15
17
  height = "auto",
16
18
  theme = "auto"
@@ -18,6 +20,7 @@ var AdTogetherBanner = ({
18
20
  const [adData, setAdData] = useState(null);
19
21
  const [isLoading, setIsLoading] = useState(true);
20
22
  const [hasError, setHasError] = useState(false);
23
+ const [isVisible, setIsVisible] = useState(true);
21
24
  const [isDarkMode, setIsDarkMode] = useState(theme === "dark");
22
25
  const containerRef = useRef(null);
23
26
  const impressionTrackedRef = useRef(false);
@@ -34,7 +37,7 @@ var AdTogetherBanner = ({
34
37
  }, [theme]);
35
38
  useEffect(() => {
36
39
  let isMounted = true;
37
- AdTogether.fetchAd(adUnitId).then((ad) => {
40
+ AdTogether.fetchAd(adUnitId, "banner").then((ad) => {
38
41
  if (isMounted) {
39
42
  setAdData(ad);
40
43
  setIsLoading(false);
@@ -76,6 +79,14 @@ var AdTogetherBanner = ({
76
79
  window.open(adData.clickUrl, "_blank", "noopener,noreferrer");
77
80
  }
78
81
  };
82
+ const handleClose = (e) => {
83
+ e.stopPropagation();
84
+ setIsVisible(false);
85
+ onAdClosed?.();
86
+ };
87
+ if (!isVisible) {
88
+ return null;
89
+ }
79
90
  if (isLoading) {
80
91
  return /* @__PURE__ */ jsx(
81
92
  "div",
@@ -110,6 +121,7 @@ var AdTogetherBanner = ({
110
121
  overflow: "hidden",
111
122
  cursor: "pointer",
112
123
  boxSizing: "border-box",
124
+ position: "relative",
113
125
  ...style
114
126
  },
115
127
  onMouseOver: (e) => {
@@ -142,7 +154,35 @@ var AdTogetherBanner = ({
142
154
  }, children: "AD" })
143
155
  ] }),
144
156
  /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: descColor, overflow: "hidden", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical" }, children: adData.description })
145
- ] })
157
+ ] }),
158
+ showCloseButton && /* @__PURE__ */ jsx(
159
+ "button",
160
+ {
161
+ onClick: handleClose,
162
+ "aria-label": "Close ad",
163
+ style: {
164
+ position: "absolute",
165
+ top: "8px",
166
+ right: "8px",
167
+ width: "24px",
168
+ height: "24px",
169
+ borderRadius: "50%",
170
+ backgroundColor: "rgba(0, 0, 0, 0.4)",
171
+ border: "none",
172
+ color: "#fff",
173
+ fontSize: "14px",
174
+ fontWeight: "bold",
175
+ cursor: "pointer",
176
+ display: "flex",
177
+ alignItems: "center",
178
+ justifyContent: "center",
179
+ padding: 0,
180
+ lineHeight: 1,
181
+ zIndex: 1
182
+ },
183
+ children: "\xD7"
184
+ }
185
+ )
146
186
  ]
147
187
  }
148
188
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adtogether/web-sdk",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "The official AdTogether Web SDK — reciprocal ad exchange to increase conversions and grow your audience.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -50,6 +50,7 @@
50
50
  "react-dom": "^19.2.4"
51
51
  },
52
52
  "devDependencies": {
53
+ "@types/node": "^22.0.0",
53
54
  "@types/react": "^19.2.14",
54
55
  "@types/react-dom": "^19.2.3",
55
56
  "tsup": "^8.5.1",
@@ -3,6 +3,7 @@ import { AdModel, AdType, AdTogetherOptions } from './types';
3
3
  export class AdTogether {
4
4
  private static instance: AdTogether;
5
5
  private appId?: string;
6
+ private bundleId?: string;
6
7
  private allowSelfAds: boolean = true;
7
8
  public baseUrl: string = 'https://adtogether.relaxsoftwareapps.com';
8
9
 
@@ -19,6 +20,12 @@ export class AdTogether {
19
20
  const sdk = AdTogether.shared;
20
21
  sdk.appId = options.apiKey || options.appId;
21
22
 
23
+ if (options.bundleId) {
24
+ sdk.bundleId = options.bundleId;
25
+ } else if (typeof window !== 'undefined') {
26
+ sdk.bundleId = window.location.hostname;
27
+ }
28
+
22
29
  if (options.allowSelfAds !== undefined) {
23
30
  sdk.allowSelfAds = options.allowSelfAds;
24
31
  }
@@ -57,6 +64,9 @@ export class AdTogether {
57
64
  if (sdk.lastAdId) {
58
65
  url += `&exclude=${sdk.lastAdId}`;
59
66
  }
67
+ if (sdk.bundleId) {
68
+ url += `&bundleId=${sdk.bundleId}`;
69
+ }
60
70
 
61
71
  // Pass allowSelfAds and source URL for smart serving
62
72
  url += `&allowSelfAds=${sdk.allowSelfAds}`;
@@ -96,7 +106,11 @@ export class AdTogether {
96
106
  body: JSON.stringify({
97
107
  adId,
98
108
  token,
99
- apiKey: AdTogether.shared.appId
109
+ apiKey: AdTogether.shared.appId,
110
+ ...(AdTogether.shared.bundleId ? { bundleId: AdTogether.shared.bundleId } : {}),
111
+ // Send platform and environment to match Flutter SDK
112
+ platform: 'web',
113
+ environment: typeof process !== 'undefined' && process.env?.NODE_ENV === 'development' ? 'development' : 'production',
100
114
  }),
101
115
  }).catch(console.error);
102
116
  }
package/src/core/types.ts CHANGED
@@ -14,6 +14,7 @@ export interface AdTogetherOptions {
14
14
  appId?: string;
15
15
  apiKey?: string;
16
16
  baseUrl?: string;
17
+ bundleId?: string;
17
18
  /** Whether to show your own ads as fallback if no external ads are available. Defaults to true. */
18
19
  allowSelfAds?: boolean;
19
20
  }
@@ -8,6 +8,10 @@ export interface AdTogetherBannerProps {
8
8
  style?: React.CSSProperties;
9
9
  onAdLoaded?: () => void;
10
10
  onAdFailedToLoad?: (error: Error) => void;
11
+ /** Whether to show a close button on the banner */
12
+ showCloseButton?: boolean;
13
+ /** Callback when the user closes the ad */
14
+ onAdClosed?: () => void;
11
15
  /** Width of the ad element. Defaults to '100%' */
12
16
  width?: number | string;
13
17
  /** Height of the ad element. Defaults to 'auto' */
@@ -22,6 +26,8 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
22
26
  style = {},
23
27
  onAdLoaded,
24
28
  onAdFailedToLoad,
29
+ showCloseButton = false,
30
+ onAdClosed,
25
31
  width = '100%',
26
32
  height = 'auto',
27
33
  theme = 'auto',
@@ -29,6 +35,7 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
29
35
  const [adData, setAdData] = useState<AdModel | null>(null);
30
36
  const [isLoading, setIsLoading] = useState(true);
31
37
  const [hasError, setHasError] = useState(false);
38
+ const [isVisible, setIsVisible] = useState(true);
32
39
  const [isDarkMode, setIsDarkMode] = useState(theme === 'dark');
33
40
 
34
41
  const containerRef = useRef<HTMLDivElement>(null);
@@ -52,7 +59,7 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
52
59
  useEffect(() => {
53
60
  let isMounted = true;
54
61
 
55
- AdTogether.fetchAd(adUnitId)
62
+ AdTogether.fetchAd(adUnitId, 'banner')
56
63
  .then((ad) => {
57
64
  if (isMounted) {
58
65
  setAdData(ad);
@@ -104,6 +111,16 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
104
111
  }
105
112
  };
106
113
 
114
+ const handleClose = (e: React.MouseEvent) => {
115
+ e.stopPropagation(); // Prevent triggering the ad click
116
+ setIsVisible(false);
117
+ onAdClosed?.();
118
+ };
119
+
120
+ if (!isVisible) {
121
+ return null;
122
+ }
123
+
107
124
  if (isLoading) {
108
125
  return (
109
126
  <div
@@ -139,6 +156,7 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
139
156
  overflow: 'hidden',
140
157
  cursor: 'pointer',
141
158
  boxSizing: 'border-box',
159
+ position: 'relative',
142
160
  ...style,
143
161
  }}
144
162
  onMouseOver={(e) => {
@@ -179,6 +197,34 @@ export const AdTogetherBanner: React.FC<AdTogetherBannerProps> = ({
179
197
  {adData.description}
180
198
  </span>
181
199
  </div>
200
+ {showCloseButton && (
201
+ <button
202
+ onClick={handleClose}
203
+ aria-label="Close ad"
204
+ style={{
205
+ position: 'absolute',
206
+ top: '8px',
207
+ right: '8px',
208
+ width: '24px',
209
+ height: '24px',
210
+ borderRadius: '50%',
211
+ backgroundColor: 'rgba(0, 0, 0, 0.4)',
212
+ border: 'none',
213
+ color: '#fff',
214
+ fontSize: '14px',
215
+ fontWeight: 'bold',
216
+ cursor: 'pointer',
217
+ display: 'flex',
218
+ alignItems: 'center',
219
+ justifyContent: 'center',
220
+ padding: 0,
221
+ lineHeight: 1,
222
+ zIndex: 1,
223
+ }}
224
+ >
225
+ ×
226
+ </button>
227
+ )}
182
228
  </div>
183
229
  );
184
230
  };