@0xsequence/marketplace-sdk 0.8.8 → 0.8.10

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.
Files changed (115) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/{chunk-FMEEJFAF.js → chunk-5C6ZZ6WX.js} +1 -1
  3. package/dist/{chunk-YEGD7PWE.js → chunk-5O44EPXZ.js} +2 -2
  4. package/dist/chunk-6CTFVBKU.js +1 -0
  5. package/dist/{chunk-KGM2WLSP.js → chunk-7F27CJZW.js} +14 -2
  6. package/dist/{chunk-KGM2WLSP.js.map → chunk-7F27CJZW.js.map} +1 -1
  7. package/dist/{chunk-MAD64DLJ.js → chunk-A7BVFBWB.js} +2 -2
  8. package/dist/{chunk-YBOFRP65.js → chunk-FGM57QUU.js} +2 -2
  9. package/dist/{chunk-HHYNOPPI.js → chunk-KTST7ORH.js} +2 -2
  10. package/dist/{chunk-35WWD5V6.js → chunk-M6NJ73Y5.js} +3 -3
  11. package/dist/chunk-Q3ECVC4F.js +811 -0
  12. package/dist/chunk-Q3ECVC4F.js.map +1 -0
  13. package/dist/{chunk-EODKQL6Y.js → chunk-RVIUUJTP.js} +2 -2
  14. package/dist/{chunk-G3447GIP.js → chunk-SXVUTSMT.js} +24 -9
  15. package/dist/chunk-SXVUTSMT.js.map +1 -0
  16. package/dist/{chunk-7IYKUVC3.js → chunk-UJSF7PSC.js} +251 -107
  17. package/dist/chunk-UJSF7PSC.js.map +1 -0
  18. package/dist/{chunk-YALXP2PW.js → chunk-WH5BZC7W.js} +2 -2
  19. package/dist/{chunk-4XLXOEXQ.js → chunk-Y2HJO2VY.js} +25 -4
  20. package/dist/chunk-Y2HJO2VY.js.map +1 -0
  21. package/dist/{create-config-DwrnzwpM.d.ts → create-config-CAQcvjl6.d.ts} +2 -2
  22. package/dist/{index-DGsVBflk.d.ts → index-MlUK9AQE.d.ts} +2 -2
  23. package/dist/index.css +74 -28
  24. package/dist/index.css.map +1 -1
  25. package/dist/index.d.ts +4 -3
  26. package/dist/index.js +10 -4
  27. package/dist/{lowestListing-BQHIuvNF.d.ts → listTokenMetadata-DO4ChDjn.d.ts} +20 -2
  28. package/dist/{marketplaceConfig-B4Fdsmxu.d.ts → marketplaceConfig-D0MXemEl.d.ts} +1 -1
  29. package/dist/react/_internal/api/index.d.ts +3 -2
  30. package/dist/react/_internal/api/index.js +5 -1
  31. package/dist/react/_internal/databeat/index.js +11 -10
  32. package/dist/react/_internal/index.d.ts +6 -5
  33. package/dist/react/_internal/index.js +5 -1
  34. package/dist/react/_internal/wagmi/index.d.ts +3 -3
  35. package/dist/react/hooks/index.d.ts +11 -8
  36. package/dist/react/hooks/index.js +12 -9
  37. package/dist/react/hooks/options/index.d.ts +3 -3
  38. package/dist/react/hooks/options/index.js +3 -3
  39. package/dist/react/index.css +74 -28
  40. package/dist/react/index.css.map +1 -1
  41. package/dist/react/index.d.ts +11 -10
  42. package/dist/react/index.js +18 -13
  43. package/dist/react/queries/index.d.ts +3 -2
  44. package/dist/react/queries/index.js +6 -4
  45. package/dist/react/ssr/index.d.ts +2 -2
  46. package/dist/react/ssr/index.js +2 -2
  47. package/dist/react/ui/components/collectible-card/index.css +74 -28
  48. package/dist/react/ui/components/collectible-card/index.css.map +1 -1
  49. package/dist/react/ui/components/collectible-card/index.d.ts +24 -1
  50. package/dist/react/ui/components/collectible-card/index.js +18 -15
  51. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  52. package/dist/react/ui/icons/index.js +7 -6
  53. package/dist/react/ui/index.css +74 -28
  54. package/dist/react/ui/index.css.map +1 -1
  55. package/dist/react/ui/index.d.ts +1 -1
  56. package/dist/react/ui/index.js +16 -13
  57. package/dist/react/ui/modals/_internal/components/actionModal/index.js +11 -10
  58. package/dist/{sdk-config-txlivEKe.d.ts → sdk-config-onSPBxJj.d.ts} +1 -0
  59. package/dist/{services-BI_w8Eq4.d.ts → services-CMSb9ipU.d.ts} +5 -2
  60. package/dist/types/index.d.ts +2 -2
  61. package/dist/types/index.js +1 -1
  62. package/dist/{types-isjvwapz.d.ts → types-B8xzPEKX.d.ts} +2 -2
  63. package/dist/utils/abi/index.d.ts +1 -0
  64. package/dist/utils/abi/index.js +7 -1
  65. package/dist/utils/abi/primary-sale/index.d.ts +1054 -0
  66. package/dist/utils/abi/primary-sale/index.js +9 -0
  67. package/dist/utils/abi/primary-sale/index.js.map +1 -0
  68. package/dist/utils/index.d.ts +1 -0
  69. package/dist/utils/index.js +10 -4
  70. package/package.json +32 -31
  71. package/src/react/_internal/api/services.ts +12 -1
  72. package/src/react/hooks/index.ts +1 -0
  73. package/src/react/hooks/useList1155SaleSupplies.tsx +62 -0
  74. package/src/react/hooks/useListTokenMetadata.ts +19 -0
  75. package/src/react/queries/index.ts +1 -0
  76. package/src/react/queries/listTokenMetadata.ts +38 -0
  77. package/src/react/ui/components/ModelViewer.tsx +54 -0
  78. package/src/react/ui/components/_internals/custom-select/CustomSelect.tsx +0 -1
  79. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +7 -3
  80. package/src/react/ui/components/collectible-card/__tests__/{CollectibleAsset.test.tsx → Media.test.tsx} +9 -15
  81. package/src/react/ui/components/collectible-card/index.ts +1 -0
  82. package/src/react/ui/components/collectible-card/media/Media.tsx +206 -0
  83. package/src/react/ui/components/collectible-card/{collectible-asset/CollectibleAssetSkeleton.tsx → media/MediaSkeleton.tsx} +1 -1
  84. package/src/react/ui/components/collectible-card/media/types.ts +17 -0
  85. package/src/react/ui/components/collectible-card/{collectible-asset → media}/utils.ts +16 -7
  86. package/src/react/ui/index.ts +1 -0
  87. package/src/react/ui/modals/BuyModal/hooks/usePaymentModalParams.ts +28 -3
  88. package/src/react/ui/modals/SuccessfulPurchaseModal/index.tsx +9 -7
  89. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TokenQuantityInput.tsx +1 -1
  90. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.test.tsx +0 -1
  91. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +1 -1
  92. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +1 -2
  93. package/src/react/ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect.tsx +0 -1
  94. package/src/types/sdk-config.ts +1 -0
  95. package/src/utils/abi/index.ts +1 -0
  96. package/src/utils/abi/primary-sale/index.ts +2 -0
  97. package/src/utils/abi/primary-sale/sequence-1155-sales-contract.ts +450 -0
  98. package/src/utils/abi/primary-sale/sequence-721-sales-contract.ts +352 -0
  99. package/src/utils/abi/token/sequence-erc1155-items.ts +454 -0
  100. package/src/utils/fetchContentType.ts +11 -4
  101. package/tsconfig.tsbuildinfo +1 -1
  102. package/dist/chunk-4XLXOEXQ.js.map +0 -1
  103. package/dist/chunk-7IYKUVC3.js.map +0 -1
  104. package/dist/chunk-G3447GIP.js.map +0 -1
  105. package/dist/chunk-UISBTKFF.js +0 -1
  106. package/src/react/ui/components/collectible-card/collectible-asset/CollectibleAsset.tsx +0 -139
  107. /package/dist/{chunk-FMEEJFAF.js.map → chunk-5C6ZZ6WX.js.map} +0 -0
  108. /package/dist/{chunk-YEGD7PWE.js.map → chunk-5O44EPXZ.js.map} +0 -0
  109. /package/dist/{chunk-UISBTKFF.js.map → chunk-6CTFVBKU.js.map} +0 -0
  110. /package/dist/{chunk-MAD64DLJ.js.map → chunk-A7BVFBWB.js.map} +0 -0
  111. /package/dist/{chunk-YBOFRP65.js.map → chunk-FGM57QUU.js.map} +0 -0
  112. /package/dist/{chunk-HHYNOPPI.js.map → chunk-KTST7ORH.js.map} +0 -0
  113. /package/dist/{chunk-35WWD5V6.js.map → chunk-M6NJ73Y5.js.map} +0 -0
  114. /package/dist/{chunk-EODKQL6Y.js.map → chunk-RVIUUJTP.js.map} +0 -0
  115. /package/dist/{chunk-YALXP2PW.js.map → chunk-WH5BZC7W.js.map} +0 -0
@@ -0,0 +1,9 @@
1
+ import {
2
+ ERC1155_SALES_CONTRACT_ABI,
3
+ ERC721_SALE_ABI
4
+ } from "../../../chunk-Q3ECVC4F.js";
5
+ export {
6
+ ERC1155_SALES_CONTRACT_ABI,
7
+ ERC721_SALE_ABI
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,5 +1,6 @@
1
1
  export { EIP2981_ABI, SequenceMarketplaceV1_ABI, SequenceMarketplaceV2_ABI } from './abi/marketplace/index.js';
2
2
  export { ERC1155_ABI, ERC20_ABI, ERC721_ABI } from './abi/token/index.js';
3
+ export { ERC1155_SALES_CONTRACT_ABI, ERC721_SALE_ABI } from './abi/primary-sale/index.js';
3
4
  import { Image } from '@0xsequence/design-system';
4
5
  import { ComponentType } from 'react';
5
6
  import { M as MarketplaceKind } from '../marketplace.gen-DQzWciwC.js';
@@ -10,9 +10,13 @@ import {
10
10
  networkToWagmiChain,
11
11
  truncateEnd,
12
12
  truncateMiddle
13
- } from "../chunk-YEGD7PWE.js";
14
- import "../chunk-FMEEJFAF.js";
15
- import "../chunk-UISBTKFF.js";
13
+ } from "../chunk-5O44EPXZ.js";
14
+ import "../chunk-5C6ZZ6WX.js";
15
+ import "../chunk-6CTFVBKU.js";
16
+ import {
17
+ ERC1155_SALES_CONTRACT_ABI,
18
+ ERC721_SALE_ABI
19
+ } from "../chunk-Q3ECVC4F.js";
16
20
  import {
17
21
  ERC1155_ABI,
18
22
  ERC20_ABI,
@@ -25,14 +29,16 @@ import {
25
29
  } from "../chunk-XX4EVWBF.js";
26
30
  import "../chunk-2PSNAIAT.js";
27
31
  import "../chunk-DWTLVJAW.js";
28
- import "../chunk-KGM2WLSP.js";
32
+ import "../chunk-7F27CJZW.js";
29
33
  import "../chunk-D7RVSZAQ.js";
30
34
  import "../chunk-NX52D7NX.js";
31
35
  export {
32
36
  EIP2981_ABI,
33
37
  ERC1155_ABI,
38
+ ERC1155_SALES_CONTRACT_ABI,
34
39
  ERC20_ABI,
35
40
  ERC721_ABI,
41
+ ERC721_SALE_ABI,
36
42
  SequenceMarketplaceV1_ABI,
37
43
  SequenceMarketplaceV2_ABI,
38
44
  calculateEarningsAfterFees,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@0xsequence/marketplace-sdk",
3
3
  "private": false,
4
- "version": "0.8.8",
4
+ "version": "0.8.10",
5
5
  "type": "module",
6
6
  "sideEffects": [
7
7
  "**/*.css"
@@ -41,59 +41,60 @@
41
41
  "dependencies": {
42
42
  "@databeat/tracker": "^0.9.3",
43
43
  "@legendapp/state": "^3.0.0-beta.30",
44
- "@tailwindcss/postcss": "^4.0.15",
45
- "@xstate/store": "^3.4.3",
44
+ "@tailwindcss/postcss": "^4.1.6",
45
+ "@xstate/store": "^3.6.0",
46
46
  "class-variance-authority": "^0.7.1",
47
47
  "clsx": "^2.1.1",
48
48
  "date-fns": "^4.1.0",
49
49
  "dnum": "^2.14.0",
50
50
  "nuqs": "^2.4.3",
51
51
  "react-day-picker": "^9.6.7",
52
- "tailwind-merge": "^3.0.2",
53
- "zod": "^3.24.2"
52
+ "tailwind-merge": "^3.3.0",
53
+ "zod": "^3.24.4"
54
54
  },
55
55
  "peerDependencies": {
56
- "0xsequence": "^2.3.8",
57
- "@0xsequence/api": "^2.3.8",
58
- "@0xsequence/checkout": "^5.2.2",
59
- "@0xsequence/connect": "^5.2.2",
60
- "@0xsequence/design-system": "^2.1.6",
61
- "@0xsequence/indexer": "^2.3.8",
62
- "@0xsequence/metadata": "^2.3.8",
63
- "@0xsequence/network": "^2.3.8",
64
- "@tanstack/react-query": "^5.74.3",
56
+ "0xsequence": "^2.3.12",
57
+ "@0xsequence/api": "^2.3.12",
58
+ "@0xsequence/checkout": "^5.3.1",
59
+ "@0xsequence/connect": "^5.3.1",
60
+ "@0xsequence/design-system": "^2.1.12",
61
+ "@0xsequence/indexer": "^2.3.12",
62
+ "@0xsequence/metadata": "^2.3.12",
63
+ "@0xsequence/network": "^2.3.12",
64
+ "@tanstack/react-query": "^5.76.1",
65
65
  "react": "^19.1.0",
66
66
  "react-dom": "^19.1.0",
67
- "viem": "^2.27.0",
68
- "wagmi": "^2.14.16"
67
+ "viem": "^2.29.2",
68
+ "wagmi": "^2.15.3",
69
+ "@google/model-viewer": "^4.1.0"
69
70
  },
70
71
  "devDependencies": {
71
72
  "@biomejs/biome": "^1.9.4",
72
- "@changesets/cli": "^2.29.0",
73
- "@eslint/js": "^9.23.0",
73
+ "@changesets/cli": "^2.29.4",
74
+ "@eslint/js": "^9.26.0",
74
75
  "@testing-library/jest-dom": "6.4.7",
75
- "@testing-library/react": "^16.2.0",
76
- "@types/react": "^19.1.2",
77
- "@types/react-dom": "^19.1.2",
76
+ "@testing-library/react": "^16.3.0",
77
+ "@types/react": "^19.1.4",
78
+ "@types/react-dom": "^19.1.5",
78
79
  "@vitest/coverage-v8": "3.0.9",
79
80
  "ctix": "^2.7.1",
80
81
  "esbuild-plugin-preserve-directives": "^0.0.11",
81
- "eslint": "^9.23.0",
82
+ "eslint": "^9.26.0",
82
83
  "eslint-config-biome": "^1.9.4",
83
- "eslint-plugin-react": "^7.37.4",
84
+ "eslint-plugin-react": "^7.37.5",
84
85
  "eslint-plugin-react-hooks": "^5.2.0",
85
- "globals": "^16.0.0",
86
- "happy-dom": "^17.4.4",
87
- "jsdom": "^26.0.0",
88
- "msw": "^2.7.3",
86
+ "globals": "^16.1.0",
87
+ "happy-dom": "^17.4.7",
88
+ "jsdom": "^26.1.0",
89
+ "msw": "^2.8.2",
89
90
  "postcss": "^8.5.3",
90
- "prool": "^0.0.23",
91
- "tailwindcss": "^4.1.4",
91
+ "prool": "^0.0.24",
92
+ "tailwindcss": "^4.1.6",
92
93
  "tsup": "^8.4.0",
93
94
  "typescript": "^5.8.3",
94
- "typescript-eslint": "^8.27.0",
95
+ "typescript-eslint": "^8.32.1",
95
96
  "vite-tsconfig-paths": "^5.1.4",
96
- "vitest": "^3.0.9"
97
+ "vitest": "^3.1.3"
97
98
  },
98
99
  "scripts": {
99
100
  "build": "tsc -b && tsup",
@@ -1,3 +1,4 @@
1
+ import { SequenceAPIClient } from '@0xsequence/api';
1
2
  import { SequenceIndexer } from '@0xsequence/indexer';
2
3
  import { SequenceMetadata } from '@0xsequence/metadata';
3
4
  import { networks, stringTemplate } from '@0xsequence/network';
@@ -6,7 +7,7 @@ import { MissingConfigError } from '../../../utils/_internal/error/transaction';
6
7
  import { SequenceMarketplace } from './marketplace-api';
7
8
 
8
9
  const SERVICES = {
9
- sequenceApi: 'https://api.sequence.app',
10
+ sequenceApi: 'https://${prefix}api.sequence.app',
10
11
  metadata: 'https://${prefix}metadata.sequence.app',
11
12
  indexer: 'https://${prefix}${network}-indexer.sequence.app',
12
13
  marketplaceApi: 'https://${prefix}marketplace-api.sequence.app/${network}',
@@ -51,6 +52,11 @@ export const builderRpcApi = (env: Env = 'production') => {
51
52
  return stringTemplate(SERVICES.builderRpcApi, { prefix });
52
53
  };
53
54
 
55
+ export const sequenceApiUrl = (env: Env = 'production') => {
56
+ const prefix = getPrefix(env);
57
+ return stringTemplate(SERVICES.sequenceApi, { prefix });
58
+ };
59
+
54
60
  export const builderMarketplaceApi = (
55
61
  projectId: string,
56
62
  env: Env = 'production',
@@ -82,6 +88,11 @@ export const getMarketplaceClient = (
82
88
  projectAccessKey,
83
89
  );
84
90
  };
91
+ export const getSequenceApiClient = (config: SdkConfig) => {
92
+ const env = config._internal?.sequenceApiEnv || 'production';
93
+ const projectAccessKey = getAccessKey({ env, config });
94
+ return new SequenceAPIClient(sequenceApiUrl(env), projectAccessKey);
95
+ };
85
96
  const getAccessKey = ({ env, config }: { env: Env; config: SdkConfig }) => {
86
97
  switch (env) {
87
98
  case 'development':
@@ -36,3 +36,4 @@ export * from './useListCollections';
36
36
  export * from './useCancelOrder';
37
37
  export * from './useCollectionDetails';
38
38
  export * from './useCollectionDetailsPolling';
39
+ export * from './useListTokenMetadata';
@@ -0,0 +1,62 @@
1
+ import { getUnixTime } from 'date-fns';
2
+ import type { Address } from 'viem';
3
+ import { useReadContracts } from 'wagmi';
4
+ import { ERC1155_SALES_CONTRACT_ABI } from '../..';
5
+
6
+ interface UseSaleSupplyDataProps {
7
+ tokenIds: string[];
8
+ salesContractAddress: Address;
9
+ }
10
+
11
+ export function useList1155SaleSupplies({
12
+ tokenIds,
13
+ salesContractAddress,
14
+ }: UseSaleSupplyDataProps) {
15
+ const getReadContractsArgs = (tokenIds: string[]) =>
16
+ tokenIds.map((tokenId) => ({
17
+ address: salesContractAddress,
18
+ abi: ERC1155_SALES_CONTRACT_ABI,
19
+ functionName: 'tokenSaleDetails',
20
+ args: [tokenId],
21
+ }));
22
+
23
+ const {
24
+ data: supplyData,
25
+ isLoading: supplyDataLoading,
26
+ error: supplyDataError,
27
+ } = useReadContracts({
28
+ batchSize: 500_000, // Node gateway limit has a limit of 512kB, setting it to 500kB to be safe
29
+ contracts: getReadContractsArgs(tokenIds),
30
+ });
31
+
32
+ const extendedSupplyData = (supplyData || [])
33
+ .map((data, index) => ({
34
+ ...data,
35
+ tokenId: tokenIds[index],
36
+ }))
37
+ .filter((data) => data.status === 'success')
38
+ .filter((data) => {
39
+ if (typeof data.result !== 'object') return false;
40
+ const now = BigInt(getUnixTime(new Date()));
41
+ return data.result.endTime > now && data.result.startTime < now;
42
+ });
43
+
44
+ const getSupply = (tokenId: string): number | undefined => {
45
+ const found = extendedSupplyData.find((data) => data.tokenId === tokenId);
46
+ if (!found || typeof found.result !== 'object' || found.result === null)
47
+ return undefined;
48
+ const supply = found.result.supplyCap;
49
+ if (supply === undefined) return undefined;
50
+ // https://github.com/0xsequence/contracts-library/blob/ead1baf34270c76260d01cfc130bb7cc9d57518e/src/tokens/ERC1155/utility/sale/IERC1155Sale.sol#L8
51
+ // 0 means infinite
52
+ if (supply === 0n) return Number.POSITIVE_INFINITY;
53
+ return Number(supply);
54
+ };
55
+
56
+ return {
57
+ extendedSupplyData,
58
+ getSupply,
59
+ supplyDataLoading,
60
+ supplyDataError,
61
+ };
62
+ }
@@ -0,0 +1,19 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { useConfig } from './useConfig';
3
+
4
+ import {
5
+ type FetchTokenMetadataArgs,
6
+ tokenMetadataOptions,
7
+ } from '../queries/listTokenMetadata';
8
+
9
+ export const useListTokenMetadata = (args: FetchTokenMetadataArgs) => {
10
+ const config = useConfig();
11
+ const { chainId, contractAddress, tokenIds, query } = args;
12
+
13
+ return useQuery({
14
+ ...tokenMetadataOptions(
15
+ { chainId, contractAddress, tokenIds, query },
16
+ config,
17
+ ),
18
+ });
19
+ };
@@ -5,3 +5,4 @@ export * from './listCollectibles';
5
5
  export * from './highestOffer';
6
6
  export * from './listBalances';
7
7
  export * from './lowestListing';
8
+ export * from './listTokenMetadata';
@@ -0,0 +1,38 @@
1
+ import { queryOptions } from '@tanstack/react-query';
2
+ import type { SdkConfig } from '../../types';
3
+ import { getMetadataClient } from '../_internal';
4
+
5
+ export interface FetchTokenMetadataArgs {
6
+ chainId: number;
7
+ contractAddress: string;
8
+ tokenIds: string[];
9
+ query?: {
10
+ enabled?: boolean;
11
+ };
12
+ }
13
+
14
+ const fetchTokenMetadata = async (
15
+ { chainId, contractAddress, tokenIds }: FetchTokenMetadataArgs,
16
+ config: SdkConfig,
17
+ ) => {
18
+ const metadataClient = getMetadataClient(config);
19
+
20
+ const response = await metadataClient.getTokenMetadata({
21
+ chainID: chainId.toString(),
22
+ contractAddress: contractAddress,
23
+ tokenIDs: tokenIds,
24
+ });
25
+
26
+ return response.tokenMetadata;
27
+ };
28
+
29
+ export const tokenMetadataOptions = (
30
+ args: FetchTokenMetadataArgs,
31
+ config: SdkConfig,
32
+ ) => {
33
+ return queryOptions({
34
+ ...args.query,
35
+ queryKey: ['listTokenMetadata', args.chainId, args.contractAddress],
36
+ queryFn: () => fetchTokenMetadata(args, config),
37
+ });
38
+ };
@@ -0,0 +1,54 @@
1
+ import { Skeleton } from '@0xsequence/design-system';
2
+ import { Suspense, lazy } from 'react';
3
+
4
+ const ModelViewerComponent = lazy(() =>
5
+ import('@google/model-viewer').then(() => ({
6
+ default: ({
7
+ posterSrc,
8
+ src,
9
+ onLoad,
10
+ onError,
11
+ }: {
12
+ posterSrc: string;
13
+ src?: string;
14
+ onLoad?: () => void;
15
+ onError?: () => void;
16
+ }) => (
17
+ <div className="h-full w-full bg-background-raised">
18
+ {/* @ts-expect-error - This is a web component */}
19
+ <model-viewer
20
+ alt="3d model"
21
+ auto-rotate
22
+ autoplay
23
+ camera-controls
24
+ class="h-full w-full"
25
+ error={onError}
26
+ load={onLoad}
27
+ loading="eager"
28
+ poster={posterSrc}
29
+ reveal="auto"
30
+ shadow-intensity="1"
31
+ src={src}
32
+ touch-action="pan-y"
33
+ />
34
+ </div>
35
+ ),
36
+ })),
37
+ );
38
+
39
+ const ModelViewerLoading = () => <Skeleton className="h-full w-full" />;
40
+
41
+ const ModelViewer = (props: {
42
+ posterSrc: string;
43
+ src?: string;
44
+ onLoad?: () => void;
45
+ onError?: () => void;
46
+ }) => {
47
+ return (
48
+ <Suspense fallback={<ModelViewerLoading />}>
49
+ <ModelViewerComponent {...props} />
50
+ </Suspense>
51
+ );
52
+ };
53
+
54
+ export default ModelViewer;
@@ -62,7 +62,6 @@ export const CustomSelect = ({
62
62
  </div>
63
63
  }
64
64
  shape="circle"
65
- opacity="100"
66
65
  className={`bg-overlay-light py-1.5 pl-3 ${className || ''}`}
67
66
  data-testid={`${testId}-trigger`}
68
67
  />
@@ -12,7 +12,7 @@ import { useCurrency } from '../../../hooks';
12
12
  import { ActionButton } from '../_internals/action-button/ActionButton';
13
13
  import { CollectibleCardAction } from '../_internals/action-button/types';
14
14
  import { Footer } from './Footer';
15
- import { CollectibleAsset } from './collectible-asset/CollectibleAsset';
15
+ import { Media } from './media/Media';
16
16
 
17
17
  function CollectibleSkeleton() {
18
18
  return (
@@ -127,9 +127,13 @@ export function CollectibleCard({
127
127
  >
128
128
  <div className="group relative z-10 flex h-full w-full cursor-pointer flex-col items-start overflow-hidden rounded-xl border-none bg-none p-0 focus:outline-none [&:focus]:rounded-[10px] [&:focus]:outline-[3px] [&:focus]:outline-black [&:focus]:outline-offset-[-3px]">
129
129
  <article className="w-full rounded-xl">
130
- <CollectibleAsset
130
+ <Media
131
131
  name={collectibleMetadata?.name || ''}
132
- collectibleMetadata={collectibleMetadata}
132
+ assets={[
133
+ collectibleMetadata?.image,
134
+ collectibleMetadata?.video,
135
+ collectibleMetadata?.animation_url,
136
+ ]}
133
137
  assetSrcPrefixUrl={assetSrcPrefixUrl}
134
138
  />
135
139
 
@@ -2,10 +2,10 @@ import { render, screen, waitFor } from '@test/test-utils';
2
2
  import { describe, expect, it, vi } from 'vitest';
3
3
  import * as fetchContentTypeModule from '../../../../../utils/fetchContentType';
4
4
  import type { TokenMetadata } from '../../../../_internal';
5
- import { CollectibleAsset } from '../collectible-asset/CollectibleAsset';
6
- import * as contentTypeUtils from '../collectible-asset/utils';
5
+ import { Media } from '../media/Media';
6
+ import * as contentTypeUtils from '../media/utils';
7
7
 
8
- describe('CollectibleAsset', () => {
8
+ describe('Media', () => {
9
9
  it('renders image content correctly with proper loading states and fallback', async () => {
10
10
  const originalImage = window.Image;
11
11
 
@@ -30,10 +30,7 @@ describe('CollectibleAsset', () => {
30
30
 
31
31
  // Initial render should show the loading skeleton
32
32
  const { rerender } = render(
33
- <CollectibleAsset
34
- name="Test Collectible"
35
- collectibleMetadata={mockMetadata as TokenMetadata}
36
- />,
33
+ <Media name="Test Collectible" assets={[mockMetadata.image]} />,
37
34
  );
38
35
 
39
36
  // check if skeleton is rendered during loading
@@ -69,9 +66,9 @@ describe('CollectibleAsset', () => {
69
66
  };
70
67
 
71
68
  rerender(
72
- <CollectibleAsset
69
+ <Media
73
70
  name="Test Collectible"
74
- collectibleMetadata={mockMetadataWithBadImage as TokenMetadata}
71
+ assets={[mockMetadataWithBadImage.image]}
75
72
  />,
76
73
  );
77
74
 
@@ -127,10 +124,7 @@ describe('CollectibleAsset', () => {
127
124
  };
128
125
 
129
126
  render(
130
- <CollectibleAsset
131
- name="Video Collectible"
132
- collectibleMetadata={mockVideoMetadata as TokenMetadata}
133
- />,
127
+ <Media name="Video Collectible" assets={[mockVideoMetadata.video]} />,
134
128
  );
135
129
 
136
130
  await waitFor(() => {
@@ -192,9 +186,9 @@ describe('CollectibleAsset', () => {
192
186
  };
193
187
 
194
188
  render(
195
- <CollectibleAsset
189
+ <Media
196
190
  name="HTML Collectible"
197
- collectibleMetadata={mockHtmlMetadata as TokenMetadata}
191
+ assets={[mockHtmlMetadata.animation_url]}
198
192
  />,
199
193
  );
200
194
 
@@ -1 +1,2 @@
1
1
  export * from './CollectibleCard';
2
+ export * from './media/Media';