@adland/react 0.13.1 → 0.14.0

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,11 @@
1
1
  # @adland/react
2
2
 
3
+ ## 0.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bd79045: update empty state & props
8
+
3
9
  ## 0.13.1
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adland/react",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -34,8 +34,8 @@
34
34
  "lucide-react": "0.561.0",
35
35
  "tsup": "^8.0.1",
36
36
  "viem": "^2.0.0",
37
- "@adland/data": "0.14.1",
38
- "@0xslots/sdk": "0.10.1"
37
+ "@0xslots/sdk": "0.10.1",
38
+ "@adland/data": "0.14.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@typescript-eslint/eslint-plugin": "^7.13.1",
@@ -6,7 +6,7 @@ import { createReadClient, fetchAdFromURI, fetchMetadataURI } from "../fetch";
6
6
  import { AdContext, useAd } from "../hooks/useAdContext";
7
7
  import { useFetch } from "../hooks/useFetch";
8
8
  import { AdDataQueryError, type AdProps } from "../types";
9
- import { performAdAction } from "../utils/ad-actions";
9
+ import { performAdAction, performEmptyAdAction } from "../utils/ad-actions";
10
10
  import { getAdDescription, getAdImage, getAdTitle, getAdType } from "../utils/ad-fields";
11
11
  import { adCardIcon, adCardLabel } from "../utils/constants";
12
12
 
@@ -30,6 +30,7 @@ export function Ad({
30
30
  data: staticData,
31
31
  chainId = SlotsChain.BASE,
32
32
  rpcUrl,
33
+ baseLinkUrl = "https://app.0xslots.org",
33
34
  children,
34
35
  ...props
35
36
  }: AdProps) {
@@ -72,11 +73,15 @@ export function Ad({
72
73
  target.tagName === "BUTTON" ||
73
74
  target.closest("a") !== null ||
74
75
  target.closest("button") !== null;
75
- if (!isInteractive && adData) {
76
+ if (isInteractive) return;
77
+
78
+ if (adData) {
76
79
  performAdAction(adData);
80
+ } else if (isEmpty && slot) {
81
+ performEmptyAdAction(slot, chainId, baseLinkUrl);
77
82
  }
78
83
  },
79
- [adData],
84
+ [adData, isEmpty, slot, chainId, baseLinkUrl],
80
85
  );
81
86
 
82
87
  return (
@@ -87,6 +92,8 @@ export function Ad({
87
92
  error,
88
93
  isEmpty,
89
94
  slot,
95
+ baseLinkUrl,
96
+ chainId,
90
97
  }}
91
98
  >
92
99
  <div ref={ref} onClick={onClick} {...props}>
@@ -172,7 +179,7 @@ export function AdLoading({ children, ...props }: AdStatusProps) {
172
179
  export function AdEmpty({ children, ...props }: AdStatusProps) {
173
180
  const { isEmpty } = useAd();
174
181
  if (!isEmpty) return null;
175
- return <div {...props}>{children ?? "No ad"}</div>;
182
+ return <div {...props}>{children ?? "Your ad here"}</div>;
176
183
  }
177
184
 
178
185
  export function AdError({ children, ...props }: AdStatusProps) {
@@ -1,3 +1,4 @@
1
+ import type { SlotsChain } from "@0xslots/sdk";
1
2
  import type { AdData } from "@adland/data";
2
3
  import { createContext, useContext } from "react";
3
4
 
@@ -7,6 +8,8 @@ export interface AdContextValue {
7
8
  error: unknown;
8
9
  isEmpty: boolean;
9
10
  slot?: string;
11
+ baseLinkUrl: string;
12
+ chainId: SlotsChain;
10
13
  }
11
14
 
12
15
  export const AdContext = createContext<AdContextValue | null>(null);
package/src/types.ts CHANGED
@@ -19,6 +19,12 @@ export interface AdProps extends React.HTMLAttributes<HTMLDivElement> {
19
19
  * Optional RPC URL override. If not provided, uses public RPC for the chain.
20
20
  */
21
21
  rpcUrl?: string;
22
+ /**
23
+ * Base URL for the "Your ad here" CTA link.
24
+ * Empty-state click navigates to `${baseLinkUrl}/slots/${slot}?chain=${chainId}`.
25
+ * Defaults to "https://app.0xslots.org".
26
+ */
27
+ baseLinkUrl?: string;
22
28
  /**
23
29
  * Compound children (AdImage, AdTitle, etc.)
24
30
  */
@@ -1,6 +1,19 @@
1
+ import type { SlotsChain } from "@0xslots/sdk";
1
2
  import type { AdData } from "@adland/data";
2
3
  import sdk from "@farcaster/miniapp-sdk";
3
4
 
5
+ async function isMiniApp(): Promise<boolean> {
6
+ try {
7
+ const context = await Promise.race([
8
+ sdk.context,
9
+ new Promise((r) => setTimeout(r, 500)),
10
+ ]);
11
+ return !!context;
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
16
+
4
17
  export function performAdAction(adData: AdData) {
5
18
  try {
6
19
  switch (adData.type) {
@@ -17,10 +30,30 @@ export function performAdAction(adData: AdData) {
17
30
  sdk.actions.viewToken({ token: adData.data.address });
18
31
  break;
19
32
  case "farcasterProfile":
20
- sdk.actions.viewProfile({ fid: Number.parseInt(adData.data.fid, 10) });
33
+ sdk.actions.viewProfile({
34
+ fid: Number.parseInt(adData.data.fid, 10),
35
+ });
21
36
  break;
22
37
  }
23
38
  } catch (err) {
24
- console.error("[@adland/react] Failed to perform ad action:", err);
39
+ // Fallback for web (non-miniapp) context
40
+ if (adData.type === "link" || adData.type === "miniapp") {
41
+ window.open(adData.data.url, "_blank");
42
+ } else {
43
+ console.error("[@adland/react] Failed to perform ad action:", err);
44
+ }
45
+ }
46
+ }
47
+
48
+ export async function performEmptyAdAction(
49
+ slot: string,
50
+ chainId: SlotsChain,
51
+ baseLinkUrl: string,
52
+ ) {
53
+ const url = `${baseLinkUrl}/slots/${slot}?chain=${chainId}`;
54
+ if (await isMiniApp()) {
55
+ sdk.actions.openMiniApp({ url });
56
+ } else {
57
+ window.open(url, "_blank");
25
58
  }
26
59
  }