@0xsequence/marketplace-sdk 0.9.0 → 0.10.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.
Files changed (326) hide show
  1. package/.storybook/main.ts +63 -0
  2. package/.storybook/preview.ts +24 -0
  3. package/.storybook/vitest.setup.ts +6 -0
  4. package/CHANGELOG.md +77 -8
  5. package/dist/{CalendarIcon-DbQ7Vxcw.js → CalendarIcon-CqsuAuCm.js} +4 -51
  6. package/dist/CalendarIcon-CqsuAuCm.js.map +1 -0
  7. package/dist/{CollectibleCard-C8Ae64Ab.d.ts → CollectibleCard-Dd-CG6dE.d.ts} +8 -7
  8. package/dist/InfoIcon-v0w_Lu7t.js +53 -0
  9. package/dist/InfoIcon-v0w_Lu7t.js.map +1 -0
  10. package/dist/{_internal-BgWcRIak.js → _internal-C75gOSNo.js} +2 -10
  11. package/dist/_internal-C75gOSNo.js.map +1 -0
  12. package/dist/actionModal-CMUeVsFX.js +116 -0
  13. package/dist/actionModal-CMUeVsFX.js.map +1 -0
  14. package/dist/{alien_swap-B_76IMma.js → alien_swap-CYv6YlOF.js} +1 -1
  15. package/dist/{alien_swap-B_76IMma.js.map → alien_swap-CYv6YlOF.js.map} +1 -1
  16. package/dist/{api-DTIan01C.js → api-BiMGqWdz.js} +17 -34
  17. package/dist/api-BiMGqWdz.js.map +1 -0
  18. package/dist/{aqua-xyz-CMN_TFY5.js → aqua-xyz-Bzn5baeH.js} +1 -1
  19. package/dist/{aqua-xyz-CMN_TFY5.js.map → aqua-xyz-Bzn5baeH.js.map} +1 -1
  20. package/dist/{aura-Cye_TuHj.js → aura-DzIWh8WT.js} +1 -1
  21. package/dist/{aura-Cye_TuHj.js.map → aura-DzIWh8WT.js.map} +1 -1
  22. package/dist/base-DqaJPvfN.js +22 -0
  23. package/dist/base-DqaJPvfN.js.map +1 -0
  24. package/dist/{blur-DWDMyMpK.js → blur-DSH-Cbpj.js} +1 -1
  25. package/dist/{blur-DWDMyMpK.js.map → blur-DSH-Cbpj.js.map} +1 -1
  26. package/dist/{coinbase-ByA_XRB0.js → coinbase-Df8URNxq.js} +1 -1
  27. package/dist/{coinbase-ByA_XRB0.js.map → coinbase-Df8URNxq.js.map} +1 -1
  28. package/dist/{new-marketplace-types-Bfis0U4J.d.ts → create-config-DKJ-F0jc.d.ts} +402 -41
  29. package/dist/{wagmi-CDzEQbfk.js → create-config-fQ-jbJD1.js} +20 -10
  30. package/dist/create-config-fQ-jbJD1.js.map +1 -0
  31. package/dist/{element-b77CyXIZ.js → element-Cx6uJu5N.js} +1 -1
  32. package/dist/{element-b77CyXIZ.js.map → element-Cx6uJu5N.js.map} +1 -1
  33. package/dist/{foundation-DbOrKP9Y.js → foundation-D6U4aRLN.js} +1 -1
  34. package/dist/{foundation-DbOrKP9Y.js.map → foundation-D6U4aRLN.js.map} +1 -1
  35. package/dist/get-provider-CYYHfrlg.js +10 -0
  36. package/dist/get-provider-CYYHfrlg.js.map +1 -0
  37. package/dist/get-query-client-D19vvfJo.js +23 -0
  38. package/dist/get-query-client-D19vvfJo.js.map +1 -0
  39. package/dist/hooks-4pxIbLbM.js +4044 -0
  40. package/dist/hooks-4pxIbLbM.js.map +1 -0
  41. package/dist/{index-BL9RUSEK.d.ts → index-136YrWDH.d.ts} +1 -1
  42. package/dist/{index-D5v5iluA.d.ts → index-BAhaEfqY.d.ts} +1 -1
  43. package/dist/index-BKBin-rq.d.ts +979 -0
  44. package/dist/{index-BQsgAvtX.d.ts → index-BUWB_RXp.d.ts} +776 -570
  45. package/dist/{index-21LE7OhL.d.ts → index-BhVFc2rX.d.ts} +6 -3
  46. package/dist/{index-DXMfTZ1F.d.ts → index-C5aqo8xu.d.ts} +1 -1
  47. package/dist/{index-ByznONYE.d.ts → index-CKrYP7ot.d.ts} +20 -48
  48. package/dist/{index-DaE5ZNHb.d.ts → index-CUwMH7Ht.d.ts} +5 -5
  49. package/dist/{index-CLy8y5hm.d.ts → index-Cu70Lw-w.d.ts} +1 -1
  50. package/dist/index.css +414 -1
  51. package/dist/index.d.ts +8 -10
  52. package/dist/index.js +13 -9
  53. package/dist/{looks-rare-C1VqNcSM.js → looks-rare-ChBRBY-p.js} +1 -1
  54. package/dist/{looks-rare-C1VqNcSM.js.map → looks-rare-ChBRBY-p.js.map} +1 -1
  55. package/dist/{magic-eden-ea_AGCZr.js → magic-eden-D5U7N1xL.js} +1 -1
  56. package/dist/{magic-eden-ea_AGCZr.js.map → magic-eden-D5U7N1xL.js.map} +1 -1
  57. package/dist/{manifold-8y8J2sjT.js → manifold-CtLF52zU.js} +1 -1
  58. package/dist/{manifold-8y8J2sjT.js.map → manifold-CtLF52zU.js.map} +1 -1
  59. package/dist/{marketplace-nwnZv9Cb.js → marketplace-DmFiyBoS.js} +1 -1
  60. package/dist/{marketplace-nwnZv9Cb.js.map → marketplace-DmFiyBoS.js.map} +1 -1
  61. package/dist/{marketplace-logos-CSeGcPW4.js → marketplace-logos-Cd6W-qOq.js} +21 -21
  62. package/dist/{marketplace-logos-CSeGcPW4.js.map → marketplace-logos-Cd6W-qOq.js.map} +1 -1
  63. package/dist/{marketplace.gen-BSDIX7NZ.js → marketplace.gen-HpnpL5xU.js} +3 -3
  64. package/dist/marketplace.gen-HpnpL5xU.js.map +1 -0
  65. package/dist/{marketplaceConfig-C6X1SUik.js → marketplaceConfig-GQTTmihy.js} +3 -3
  66. package/dist/marketplaceConfig-GQTTmihy.js.map +1 -0
  67. package/dist/{mintify-LA68TzWg.js → mintify-Bi3Bce68.js} +1 -1
  68. package/dist/{mintify-LA68TzWg.js.map → mintify-Bi3Bce68.js.map} +1 -1
  69. package/dist/network-CGD0oKtS.js +15 -0
  70. package/dist/network-CGD0oKtS.js.map +1 -0
  71. package/dist/{nftx-D3Tc8nzd.js → nftx-BDQZjtkX.js} +1 -1
  72. package/dist/{nftx-D3Tc8nzd.js.map → nftx-BDQZjtkX.js.map} +1 -1
  73. package/dist/{okx-hbqg6oIJ.js → okx-D4meadLe.js} +1 -1
  74. package/dist/{okx-hbqg6oIJ.js.map → okx-D4meadLe.js.map} +1 -1
  75. package/dist/{open-sea-BccuK8-t.js → open-sea-DN0hgfVw.js} +1 -1
  76. package/dist/{open-sea-BccuK8-t.js.map → open-sea-DN0hgfVw.js.map} +1 -1
  77. package/dist/{primary-sale-C55ALnfQ.js → primary-sale-CmWxSfFQ.js} +1 -1
  78. package/dist/{primary-sale-C55ALnfQ.js.map → primary-sale-CmWxSfFQ.js.map} +1 -1
  79. package/dist/provider-DPGUA10G.js +125 -0
  80. package/dist/provider-DPGUA10G.js.map +1 -0
  81. package/dist/{queries-CUU65uYZ.js → queries-Ce_2othB.js} +165 -7
  82. package/dist/queries-Ce_2othB.js.map +1 -0
  83. package/dist/{rarible-BgTwwj9g.js → rarible-B0xlD88A.js} +1 -1
  84. package/dist/{rarible-BgTwwj9g.js.map → rarible-B0xlD88A.js.map} +1 -1
  85. package/dist/react/_internal/api/index.d.ts +2 -4
  86. package/dist/react/_internal/api/index.js +7 -4
  87. package/dist/react/_internal/databeat/index.d.ts +2 -73
  88. package/dist/react/_internal/databeat/index.js +4 -21
  89. package/dist/react/_internal/index.d.ts +2 -7
  90. package/dist/react/_internal/index.js +11 -6
  91. package/dist/react/_internal/wagmi/index.d.ts +2 -4
  92. package/dist/react/_internal/wagmi/index.js +5 -3
  93. package/dist/react/hooks/index.d.ts +12 -17
  94. package/dist/react/hooks/index.js +23 -19
  95. package/dist/react/hooks/options/index.d.ts +2 -3
  96. package/dist/react/hooks/options/index.js +12 -7
  97. package/dist/react/index.d.ts +12 -17
  98. package/dist/react/index.js +28 -19
  99. package/dist/react/queries/index.d.ts +9 -8
  100. package/dist/react/queries/index.js +20 -15
  101. package/dist/react/ssr/index.d.ts +7 -9
  102. package/dist/react/ssr/index.js +11 -6
  103. package/dist/react/ssr/index.js.map +1 -1
  104. package/dist/react/ui/components/marketplace-collectible-card/index.d.ts +3 -8
  105. package/dist/react/ui/components/marketplace-collectible-card/index.js +27 -18
  106. package/dist/react/ui/components/marketplace-collectible-card/utils/index.d.ts +2 -7
  107. package/dist/react/ui/components/marketplace-collectible-card/utils/index.js +11 -6
  108. package/dist/react/ui/components/marketplace-logos/index.d.ts +21 -21
  109. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  110. package/dist/react/ui/icons/index.js +13 -9
  111. package/dist/react/ui/index.d.ts +3 -8
  112. package/dist/react/ui/index.js +27 -18
  113. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +2 -2
  114. package/dist/react/ui/modals/_internal/components/actionModal/index.js +23 -18
  115. package/dist/{react-DAIicQPT.js → react-DP0M2Wfm.js} +799 -4306
  116. package/dist/react-DP0M2Wfm.js.map +1 -0
  117. package/dist/{react-BbHBl6gg.css → react-DeDyTgo7.css} +1 -1
  118. package/dist/{react-BbHBl6gg.css.map → react-DeDyTgo7.css.map} +1 -1
  119. package/dist/{sequence-Do3kzb4J.js → sequence-BIrOVRXO.js} +1 -1
  120. package/dist/{sequence-Do3kzb4J.js.map → sequence-BIrOVRXO.js.map} +1 -1
  121. package/dist/{sudo-swap-B6vPKxBz.js → sudo-swap-BPMon-M5.js} +1 -1
  122. package/dist/{sudo-swap-B6vPKxBz.js.map → sudo-swap-BPMon-M5.js.map} +1 -1
  123. package/dist/{super-rare-eCm1SE6O.js → super-rare-kPN6Ua8i.js} +1 -1
  124. package/dist/{super-rare-eCm1SE6O.js.map → super-rare-kPN6Ua8i.js.map} +1 -1
  125. package/dist/{token-Da4TdyUk.js → token-CHSBPYVG.js} +1 -1
  126. package/dist/{token-Da4TdyUk.js.map → token-CHSBPYVG.js.map} +1 -1
  127. package/dist/{transaction-CcVViHEL.js → transaction-CnctdNzS.js} +3 -21
  128. package/dist/transaction-CnctdNzS.js.map +1 -0
  129. package/dist/types/index.d.ts +2 -3
  130. package/dist/types/index.js +2 -2
  131. package/dist/{types-DwWE6xOF.js → types-Yw2ywj6j.js} +1 -1
  132. package/dist/{types-DwWE6xOF.js.map → types-Yw2ywj6j.js.map} +1 -1
  133. package/dist/utils/abi/index.d.ts +4 -4
  134. package/dist/utils/abi/index.js +4 -4
  135. package/dist/utils/abi/marketplace/index.d.ts +1 -1
  136. package/dist/utils/abi/marketplace/index.js +1 -1
  137. package/dist/utils/abi/primary-sale/index.d.ts +1 -1
  138. package/dist/utils/abi/primary-sale/index.js +1 -1
  139. package/dist/utils/abi/token/index.d.ts +1 -1
  140. package/dist/utils/abi/token/index.js +1 -1
  141. package/dist/utils/index.d.ts +7 -8
  142. package/dist/utils/index.js +12 -9
  143. package/dist/{utils-CW2NA5KG.js → utils-9RXDgcBl.js} +4 -11
  144. package/dist/utils-9RXDgcBl.js.map +1 -0
  145. package/dist/{utils-BPYfgDSL.js → utils-DjVJ9tov.js} +5 -6
  146. package/dist/utils-DjVJ9tov.js.map +1 -0
  147. package/dist/wagmi-Do_KW5ke.js +0 -0
  148. package/dist/{x2y2-DD17tT91.js → x2y2-BLz-_Q2O.js} +1 -1
  149. package/dist/{x2y2-DD17tT91.js.map → x2y2-BLz-_Q2O.js.map} +1 -1
  150. package/dist/{zora-BpSG9UzS.js → zora-UGhKs-aL.js} +1 -1
  151. package/dist/{zora-BpSG9UzS.js.map → zora-UGhKs-aL.js.map} +1 -1
  152. package/eslint.config.mjs +4 -0
  153. package/package.json +27 -14
  154. package/postcss.config.mjs +6 -0
  155. package/src/index.css +5 -4
  156. package/src/index.ts +1 -0
  157. package/src/react/__tests__/provider.test.tsx +4 -3
  158. package/src/react/_internal/api/__mocks__/indexer.msw.ts +16 -0
  159. package/src/react/_internal/api/__mocks__/laos.msw.ts +387 -0
  160. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +2 -0
  161. package/src/react/_internal/api/__tests__/laos-api.test.ts +756 -0
  162. package/src/react/_internal/api/laos-api.ts +3 -0
  163. package/src/react/_internal/api/marketplace.gen.ts +5 -3
  164. package/src/react/_internal/api/query-keys.ts +12 -4
  165. package/src/react/_internal/api/services.ts +2 -14
  166. package/src/react/_internal/databeat/index.ts +15 -14
  167. package/src/react/_internal/databeat/types.ts +22 -0
  168. package/src/react/_internal/databeat/utils.ts +26 -0
  169. package/src/react/_internal/utils.ts +4 -4
  170. package/src/react/_internal/wagmi/create-config.ts +28 -13
  171. package/src/react/_internal/wallet/wallet.ts +4 -4
  172. package/src/react/hooks/__tests__/useBalanceOfCollectible.laos.test.tsx +367 -0
  173. package/src/react/hooks/__tests__/useCheckoutOptions.test.tsx +158 -0
  174. package/src/react/hooks/__tests__/useCheckoutOptionsSalesContract.test.tsx +42 -65
  175. package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +17 -0
  176. package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +11 -3
  177. package/src/react/hooks/__tests__/useConvertPriceToUSD.test.tsx +3 -3
  178. package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +7 -3
  179. package/src/react/hooks/__tests__/useFilters.test.tsx +2 -2
  180. package/src/react/hooks/__tests__/useGetTokenRanges.test.tsx +111 -0
  181. package/src/react/hooks/__tests__/useListTokenMetadata.test.tsx +83 -57
  182. package/src/react/hooks/__tests__/useTransferTokens.test.tsx +469 -0
  183. package/src/react/hooks/index.ts +3 -1
  184. package/src/react/hooks/useCheckoutOptions.tsx +96 -0
  185. package/src/react/hooks/useCheckoutOptionsSalesContract.tsx +98 -57
  186. package/src/react/hooks/useCollectionBalanceDetails.tsx +95 -68
  187. package/src/react/hooks/useCollectionDetailsPolling.tsx +3 -7
  188. package/src/react/hooks/useComparePrices.tsx +90 -82
  189. package/src/react/hooks/useConvertPriceToUSD.tsx +85 -71
  190. package/src/react/hooks/useCurrencyBalance.tsx +132 -46
  191. package/src/react/hooks/useERC721SaleMintedTokens.tsx +8 -5
  192. package/src/react/hooks/useFilters.tsx +154 -111
  193. package/src/react/hooks/useGetCountOfPrimarySaleItems.tsx +48 -0
  194. package/src/react/hooks/useGetTokenRanges.tsx +83 -22
  195. package/src/react/hooks/useList1155ShopCardData.tsx +2 -0
  196. package/src/react/hooks/useList721ShopCardData.tsx +12 -7
  197. package/src/react/hooks/useListCollections.tsx +25 -25
  198. package/src/react/hooks/useListMarketCardData.tsx +2 -1
  199. package/src/react/hooks/useListPrimarySaleItems.tsx +66 -0
  200. package/src/react/hooks/useListTokenMetadata.ts +71 -0
  201. package/src/react/hooks/useOpenConnectModal.tsx +9 -0
  202. package/src/react/hooks/useTokenSaleDetailsBatch.tsx +3 -7
  203. package/src/react/hooks/useTokenSupplies.ts +81 -0
  204. package/src/react/hooks/useTransferTokens.tsx +2 -2
  205. package/src/react/provider.tsx +73 -9
  206. package/src/react/queries/__tests__/balanceOfCollectible.laos.test.ts +123 -0
  207. package/src/react/queries/__tests__/inventory.laos.test.ts +496 -0
  208. package/src/react/queries/balanceOfCollectible.ts +7 -4
  209. package/src/react/queries/checkoutOptions.ts +85 -0
  210. package/src/react/queries/checkoutOptionsSalesContract.ts +89 -0
  211. package/src/react/queries/collectionBalanceDetails.ts +92 -0
  212. package/src/react/queries/comparePrices.ts +108 -0
  213. package/src/react/queries/convertPriceToUSD.ts +92 -0
  214. package/src/react/queries/filters.ts +138 -0
  215. package/src/react/queries/getTokenRanges.ts +62 -0
  216. package/src/react/queries/index.ts +3 -0
  217. package/src/react/queries/inventory.ts +6 -0
  218. package/src/react/queries/listBalances.ts +4 -3
  219. package/src/react/queries/listCollections.ts +7 -3
  220. package/src/react/queries/listTokenMetadata.ts +2 -2
  221. package/src/react/queries/marketplaceConfig.ts +1 -1
  222. package/src/react/queries/primarySaleItems.ts +85 -0
  223. package/src/react/queries/primarySaleItemsCount.ts +64 -0
  224. package/src/react/queries/tokenSupplies.ts +93 -0
  225. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +66 -66
  226. package/src/react/ui/components/_internals/action-button/__tests__/ActionButtonBody.test.tsx +22 -4
  227. package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +5 -4
  228. package/src/react/ui/components/_internals/action-button/components/NonOwnerActions.tsx +3 -0
  229. package/src/react/ui/components/_internals/action-button/components/OwnerActions.tsx +4 -4
  230. package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +13 -8
  231. package/src/react/ui/components/_internals/action-button/store.ts +44 -34
  232. package/src/react/ui/components/_internals/custom-select/CustomSelect.stories.tsx +582 -0
  233. package/src/react/ui/components/_internals/pill/Pill.stories.tsx +83 -0
  234. package/src/react/ui/components/marketplace-collectible-card/Footer.tsx +11 -4
  235. package/src/react/ui/components/marketplace-collectible-card/components/ActionButtonWrapper.tsx +7 -4
  236. package/src/react/ui/components/marketplace-collectible-card/types.ts +4 -3
  237. package/src/react/ui/components/marketplace-collectible-card/utils/supplyStatus.ts +4 -7
  238. package/src/react/ui/components/marketplace-collectible-card/variants/ShopCard.tsx +5 -1
  239. package/src/react/ui/components/marketplace-logos/marketplace-logos.stories.tsx +199 -0
  240. package/src/react/ui/components/media/Media.stories.tsx +642 -0
  241. package/src/react/ui/components/media/Media.tsx +24 -19
  242. package/src/react/ui/components/media/types.ts +6 -0
  243. package/src/react/ui/modals/BuyModal/__tests__/BuyModalRouter.test.tsx +15 -0
  244. package/src/react/ui/modals/BuyModal/__tests__/ERC1155ShopModal.test.tsx +6 -0
  245. package/src/react/ui/modals/BuyModal/__tests__/Modal1155.test.tsx +7 -1
  246. package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +9 -1
  247. package/src/react/ui/modals/BuyModal/components/ERC1155QuantityModal.tsx +15 -8
  248. package/src/react/ui/modals/BuyModal/components/ERC1155ShopModal.tsx +3 -0
  249. package/src/react/ui/modals/BuyModal/hooks/__tests__/useERC1155Checkout.test.tsx +30 -27
  250. package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +2 -2
  251. package/src/react/ui/modals/BuyModal/hooks/useERC1155Checkout.ts +11 -2
  252. package/src/react/ui/modals/BuyModal/hooks/useERC721SalePaymentParams.ts +1 -1
  253. package/src/react/ui/modals/BuyModal/hooks/usePaymentModalParams.ts +7 -0
  254. package/src/react/ui/modals/BuyModal/index.tsx +9 -1
  255. package/src/react/ui/modals/BuyModal/store.ts +26 -0
  256. package/src/react/ui/modals/CreateListingModal/Modal.tsx +28 -11
  257. package/src/react/ui/modals/CreateListingModal/store.ts +3 -3
  258. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +30 -13
  259. package/src/react/ui/modals/MakeOfferModal/store.ts +3 -3
  260. package/src/react/ui/modals/SellModal/Modal.tsx +11 -8
  261. package/src/react/ui/modals/SellModal/store.ts +3 -3
  262. package/src/react/ui/modals/TransferModal/__tests__/__snapshots__/store.test.ts.snap +17 -0
  263. package/src/react/ui/modals/TransferModal/__tests__/store.test.ts +366 -0
  264. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/__tests__/useHandleTransfer.test.tsx +402 -0
  265. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TokenQuantityInput.tsx +51 -48
  266. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/TransferButton.tsx +39 -47
  267. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/_components/WalletAddressInput.tsx +9 -8
  268. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/index.tsx +31 -35
  269. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +19 -10
  270. package/src/react/ui/modals/TransferModal/index.tsx +28 -31
  271. package/src/react/ui/modals/TransferModal/messages.ts +1 -1
  272. package/src/react/ui/modals/TransferModal/store.ts +122 -0
  273. package/src/react/ui/modals/_internal/components/calendar/index.tsx +0 -1
  274. package/src/react/ui/modals/_internal/components/currencyImage/index.tsx +10 -14
  275. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +5 -2
  276. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +23 -17
  277. package/src/react/ui/modals/_internal/components/expirationDateSelect/index.tsx +10 -10
  278. package/src/react/ui/modals/_internal/components/floorPriceText/__tests__/FloorPriceText.test.tsx +6 -6
  279. package/src/react/ui/modals/_internal/components/priceInput/__tests__/PriceInput.test.tsx +13 -5
  280. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +41 -26
  281. package/src/react/ui/modals/_internal/components/quantityInput/__tests__/index.test.tsx +68 -59
  282. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +155 -20
  283. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/SelectWaasFeeOptions.test.tsx +339 -40
  284. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/index.tsx +95 -101
  285. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/store.ts +72 -14
  286. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/useWaasFeeOptionManager.tsx +29 -13
  287. package/src/react/ui/modals/_internal/components/tokenPreview/index.tsx +2 -2
  288. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +2 -2
  289. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +88 -89
  290. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +36 -10
  291. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +32 -20
  292. package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +91 -62
  293. package/src/react/ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect.tsx +43 -44
  294. package/src/react/ui/modals/_internal/types.ts +2 -2
  295. package/src/types/sdk-config.ts +6 -1
  296. package/src/utils/network.ts +15 -0
  297. package/test/test-utils.tsx +2 -0
  298. package/vitest.shims.d.ts +2 -0
  299. package/vitest.storybook.config.js +33 -0
  300. package/dist/CalendarIcon-DbQ7Vxcw.js.map +0 -1
  301. package/dist/_internal-BgWcRIak.js.map +0 -1
  302. package/dist/api-DTIan01C.js.map +0 -1
  303. package/dist/builder-api-C_zj5mr3.d.ts +0 -12
  304. package/dist/index-BUVWziLP.d.ts +0 -60
  305. package/dist/index-COt10OgI.d.ts +0 -24
  306. package/dist/index-DPNWNa7t.d.ts +0 -414
  307. package/dist/index-DsfCs3-x.d.ts +0 -122
  308. package/dist/index-dUb6wb4Y.d.ts +0 -22
  309. package/dist/marketplace.gen-BSDIX7NZ.js.map +0 -1
  310. package/dist/marketplaceConfig-C6X1SUik.js.map +0 -1
  311. package/dist/queries-CUU65uYZ.js.map +0 -1
  312. package/dist/react-DAIicQPT.js.map +0 -1
  313. package/dist/transaction-CcVViHEL.js.map +0 -1
  314. package/dist/utils-BPYfgDSL.js.map +0 -1
  315. package/dist/utils-CW2NA5KG.js.map +0 -1
  316. package/dist/wagmi-CDzEQbfk.js.map +0 -1
  317. package/src/react/hooks/__tests__/useGetTokenSuppliesMap.test.tsx +0 -104
  318. package/src/react/hooks/useGetTokenSuppliesMap.tsx +0 -73
  319. package/src/react/hooks/useListPrimarySaleItems.ts +0 -102
  320. package/src/react/queries/getTokenSuppliesMap.ts +0 -77
  321. package/src/react/ui/modals/TransferModal/_store.ts +0 -66
  322. package/src/react/ui/modals/_internal/components/quantityInput/QuantityInputBase.tsx +0 -166
  323. package/src/react/ui/modals/_internal/stores/accountModal.ts +0 -3
  324. /package/dist/{abi-BKyRjVcZ.js → abi-BMvgNbKQ.js} +0 -0
  325. /package/dist/{index-C39K_8SG.d.ts → index-CD2bj_xW.d.ts} +0 -0
  326. /package/dist/{options-B4QN7Xou.js → options-BBBR8u_4.js} +0 -0
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { createStore } from '@xstate/store';
2
4
  import { useSelector } from '@xstate/store/react';
3
5
  import type { CollectibleCardAction } from '../../../../../types';
@@ -9,10 +11,14 @@ type PendingAction = {
9
11
  timestamp: number;
10
12
  };
11
13
 
14
+ interface ActionButtonContext {
15
+ pendingAction: PendingAction | null;
16
+ }
17
+
12
18
  export const actionButtonStore = createStore({
13
19
  context: {
14
- pendingAction: null as PendingAction | null,
15
- },
20
+ pendingAction: null,
21
+ } as ActionButtonContext,
16
22
  on: {
17
23
  setPendingAction: (
18
24
  context,
@@ -37,39 +43,43 @@ export const actionButtonStore = createStore({
37
43
  },
38
44
  });
39
45
 
40
- export const setPendingAction = (
41
- action: CollectibleCardAction.BUY | CollectibleCardAction.OFFER,
42
- onPendingActionExecuted: () => void,
43
- tokenId: string,
44
- ) => {
45
- actionButtonStore.send({
46
- type: 'setPendingAction',
47
- action,
48
- onPendingActionExecuted,
49
- tokenId,
50
- });
51
- };
52
-
53
- // Selector hooks
54
- export const usePendingAction = () =>
55
- useSelector(actionButtonStore, (state) => state.context.pendingAction);
56
-
57
- export const clearPendingAction = () => {
58
- actionButtonStore.send({ type: 'clearPendingAction' });
59
- };
46
+ export const useActionButtonStore = () => {
47
+ const pendingAction = useSelector(
48
+ actionButtonStore,
49
+ (state) => state.context.pendingAction,
50
+ );
60
51
 
61
- export const executePendingAction = (pendingAction: PendingAction | null) => {
62
- if (!pendingAction) return;
52
+ return {
53
+ pendingAction,
54
+ setPendingAction: (
55
+ action: CollectibleCardAction.BUY | CollectibleCardAction.OFFER,
56
+ onPendingActionExecuted: () => void,
57
+ tokenId: string,
58
+ ) => {
59
+ actionButtonStore.send({
60
+ type: 'setPendingAction',
61
+ action,
62
+ onPendingActionExecuted,
63
+ tokenId,
64
+ });
65
+ },
66
+ clearPendingAction: () => {
67
+ actionButtonStore.send({ type: 'clearPendingAction' });
68
+ },
69
+ executePendingAction: () => {
70
+ if (!pendingAction) return;
63
71
 
64
- const { timestamp, callback } = pendingAction;
72
+ const { timestamp, callback } = pendingAction;
65
73
 
66
- if (timestamp && callback) {
67
- // Only execute if the pending action is less than 5 minutes old
68
- if (
69
- Date.now() - timestamp < 5 * 60 * 1000 &&
70
- typeof callback === 'function'
71
- ) {
72
- callback();
73
- }
74
- }
74
+ if (timestamp && callback) {
75
+ // Only execute if the pending action is less than 5 minutes old
76
+ if (
77
+ Date.now() - timestamp < 5 * 60 * 1000 &&
78
+ typeof callback === 'function'
79
+ ) {
80
+ callback();
81
+ }
82
+ }
83
+ },
84
+ };
75
85
  };
@@ -0,0 +1,582 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { expect, fn, userEvent, within } from 'storybook/test';
3
+ import { CustomSelect } from './CustomSelect';
4
+
5
+ const meta: Meta<typeof CustomSelect> = {
6
+ title: 'Internals/Custom Select',
7
+ component: CustomSelect,
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component: `
13
+ A custom dropdown select component with support for string and ReactNode content. Includes keyboard navigation, disabled states, and customizable styling.
14
+ `,
15
+ },
16
+ },
17
+ },
18
+ argTypes: {
19
+ items: {
20
+ control: 'object',
21
+ description: 'Array of selectable items',
22
+ },
23
+ placeholder: {
24
+ control: 'text',
25
+ description: 'Placeholder text when no item is selected',
26
+ },
27
+ disabled: {
28
+ control: 'boolean',
29
+ description: 'Whether the select is disabled',
30
+ },
31
+ onValueChange: {
32
+ action: 'value changed',
33
+ description: 'Callback when selection changes',
34
+ },
35
+ },
36
+ decorators: [
37
+ (Story) => (
38
+ <div style={{ padding: '1rem', width: '300px' }}>
39
+ <Story />
40
+ </div>
41
+ ),
42
+ ],
43
+ };
44
+
45
+ export default meta;
46
+ type Story = StoryObj<typeof CustomSelect>;
47
+
48
+ const basicItems = [
49
+ { value: 'option1', content: 'Option 1' },
50
+ { value: 'option2', content: 'Option 2' },
51
+ { value: 'option3', content: 'Option 3' },
52
+ ];
53
+
54
+ const manyItems = [
55
+ { value: 'apple', content: 'Apple' },
56
+ { value: 'banana', content: 'Banana' },
57
+ { value: 'cherry', content: 'Cherry' },
58
+ { value: 'date', content: 'Date' },
59
+ { value: 'elderberry', content: 'Elderberry' },
60
+ { value: 'fig', content: 'Fig' },
61
+ { value: 'grape', content: 'Grape' },
62
+ { value: 'honeydew', content: 'Honeydew' },
63
+ ];
64
+
65
+ const itemsWithDisabled = [
66
+ { value: 'available1', content: 'Available Option 1' },
67
+ { value: 'disabled1', content: 'Disabled Option 1', disabled: true },
68
+ { value: 'available2', content: 'Available Option 2' },
69
+ { value: 'disabled2', content: 'Disabled Option 2', disabled: true },
70
+ { value: 'available3', content: 'Available Option 3' },
71
+ ];
72
+
73
+ export const Default: Story = {
74
+ args: {
75
+ items: basicItems,
76
+ placeholder: 'Select an option',
77
+ backgroundColor: '#020000',
78
+ },
79
+ };
80
+
81
+ export const WithDefaultValue: Story = {
82
+ args: {
83
+ items: basicItems,
84
+ defaultValue: basicItems[1],
85
+ placeholder: 'Select an option',
86
+ },
87
+ };
88
+
89
+ export const Disabled: Story = {
90
+ args: {
91
+ items: basicItems,
92
+ placeholder: 'Select an option',
93
+ disabled: true,
94
+ },
95
+ };
96
+
97
+ export const ManyOptions: Story = {
98
+ args: {
99
+ items: manyItems,
100
+ placeholder: 'Choose a fruit',
101
+ },
102
+ };
103
+
104
+ export const WithDisabledItems: Story = {
105
+ args: {
106
+ items: itemsWithDisabled,
107
+ placeholder: 'Select an option',
108
+ },
109
+ };
110
+
111
+ export const CustomPlaceholder: Story = {
112
+ args: {
113
+ items: [
114
+ { value: 'eth', content: 'Ethereum' },
115
+ { value: 'btc', content: 'Bitcoin' },
116
+ { value: 'ada', content: 'Cardano' },
117
+ ],
118
+ placeholder: 'Choose cryptocurrency',
119
+ },
120
+ };
121
+
122
+ export const WithReactNodeContent: Story = {
123
+ args: {
124
+ items: [
125
+ {
126
+ value: 'user1',
127
+ content: (
128
+ <div className="flex items-center gap-2">
129
+ <div className="h-4 w-4 rounded-full bg-blue-500" />
130
+ <span>John Doe</span>
131
+ </div>
132
+ ),
133
+ },
134
+ {
135
+ value: 'user2',
136
+ content: (
137
+ <div className="flex items-center gap-2">
138
+ <div className="h-4 w-4 rounded-full bg-green-500" />
139
+ <span>Jane Smith</span>
140
+ </div>
141
+ ),
142
+ },
143
+ {
144
+ value: 'user3',
145
+ content: (
146
+ <div className="flex items-center gap-2">
147
+ <div className="h-4 w-4 rounded-full bg-red-500" />
148
+ <span>Bob Johnson</span>
149
+ </div>
150
+ ),
151
+ },
152
+ ],
153
+ placeholder: 'Select a user',
154
+ },
155
+ };
156
+
157
+ // Showcase different configurations
158
+ export const SelectShowcase: Story = {
159
+ render: () => (
160
+ <div className="space-y-4">
161
+ <div>
162
+ <h3 className="mb-2 font-medium text-sm">Basic Select</h3>
163
+ <CustomSelect items={basicItems} placeholder="Select an option" />
164
+ </div>
165
+ <div>
166
+ <h3 className="mb-2 font-medium text-sm">With Default Value</h3>
167
+ <CustomSelect
168
+ items={basicItems}
169
+ defaultValue={basicItems[0]}
170
+ placeholder="Select an option"
171
+ />
172
+ </div>
173
+ <div>
174
+ <h3 className="mb-2 font-medium text-sm">Disabled</h3>
175
+ <CustomSelect
176
+ items={basicItems}
177
+ placeholder="Select an option"
178
+ disabled={true}
179
+ />
180
+ </div>
181
+ <div>
182
+ <h3 className="mb-2 font-medium text-sm">With Some Disabled Items</h3>
183
+ <CustomSelect
184
+ items={itemsWithDisabled}
185
+ placeholder="Select an option"
186
+ />
187
+ </div>
188
+ </div>
189
+ ),
190
+ };
191
+
192
+ // ========================================
193
+ // INTERACTION TESTS - Hidden from UI
194
+ // ========================================
195
+
196
+ export const BasicInteractionTest: Story = {
197
+ tags: ['!dev', '!autodocs'],
198
+ args: {
199
+ items: basicItems,
200
+ placeholder: 'Select an option',
201
+ onValueChange: fn(),
202
+ testId: 'basic-select',
203
+ },
204
+ play: async ({ args, canvasElement, step }) => {
205
+ const canvas = within(canvasElement);
206
+ const body = within(document.body);
207
+
208
+ await step('Verify initial render with placeholder', async () => {
209
+ const trigger = canvas.getByTestId('basic-select-trigger');
210
+ await expect(trigger).toBeInTheDocument();
211
+ await expect(trigger).toHaveTextContent('Select an option');
212
+ });
213
+
214
+ await step('Open dropdown by clicking trigger', async () => {
215
+ const trigger = canvas.getByTestId('basic-select-trigger');
216
+ await userEvent.click(trigger);
217
+
218
+ // Content is rendered in a portal, so search in body
219
+ const content = await body.findByTestId('basic-select-content');
220
+ await expect(content).toBeInTheDocument();
221
+ });
222
+
223
+ await step('Verify all options are visible', async () => {
224
+ for (const item of basicItems) {
225
+ const option = body.getByTestId(`basic-select-option-${item.value}`);
226
+ await expect(option).toBeInTheDocument();
227
+ await expect(option).toHaveTextContent(item.content as string);
228
+ }
229
+ });
230
+
231
+ await step('Select an option and verify callback', async () => {
232
+ const optionToSelect = body.getByTestId('basic-select-option-option2');
233
+ await userEvent.click(optionToSelect);
234
+
235
+ await expect(args.onValueChange).toHaveBeenCalledWith('option2');
236
+
237
+ // Verify selected option is displayed in trigger
238
+ const trigger = canvas.getByTestId('basic-select-trigger');
239
+ await expect(trigger).toHaveTextContent('Option 2');
240
+ });
241
+ },
242
+ };
243
+
244
+ export const DefaultValueTest: Story = {
245
+ tags: ['!dev', '!autodocs'],
246
+ args: {
247
+ items: basicItems,
248
+ defaultValue: basicItems[1], // Option 2
249
+ placeholder: 'Select an option',
250
+ onValueChange: fn(),
251
+ testId: 'default-value-select',
252
+ },
253
+ play: async ({ canvasElement, step }) => {
254
+ const canvas = within(canvasElement);
255
+ const body = within(document.body);
256
+
257
+ await step('Verify default value is displayed', async () => {
258
+ const trigger = canvas.getByTestId('default-value-select-trigger');
259
+ await expect(trigger).toBeInTheDocument();
260
+ await expect(trigger).toHaveTextContent('Option 2');
261
+ });
262
+
263
+ await step('Open dropdown and verify default selection', async () => {
264
+ const trigger = canvas.getByTestId('default-value-select-trigger');
265
+ await userEvent.click(trigger);
266
+
267
+ const selectedOption = await body.findByTestId(
268
+ 'default-value-select-option-option2',
269
+ );
270
+ await expect(selectedOption).toBeInTheDocument();
271
+ // Note: The visual indication of selection would depend on the component's styling
272
+ });
273
+ },
274
+ };
275
+
276
+ export const DisabledStateTest: Story = {
277
+ tags: ['!dev', '!autodocs'],
278
+ args: {
279
+ items: basicItems,
280
+ placeholder: 'Select an option',
281
+ disabled: true,
282
+ onValueChange: fn(),
283
+ testId: 'disabled-select',
284
+ },
285
+ play: async ({ args, canvasElement, step }) => {
286
+ const canvas = within(canvasElement);
287
+ const body = within(document.body);
288
+
289
+ await step('Verify disabled trigger cannot be clicked', async () => {
290
+ const trigger = canvas.getByTestId('disabled-select-trigger');
291
+ await expect(trigger).toBeInTheDocument();
292
+ await expect(trigger).toBeDisabled();
293
+ });
294
+
295
+ await step('Attempt to click disabled trigger', async () => {
296
+ const trigger = canvas.getByTestId('disabled-select-trigger');
297
+ await userEvent.click(trigger);
298
+
299
+ // Dropdown should not open
300
+ const content = body.queryByTestId('disabled-select-content');
301
+ await expect(content).not.toBeInTheDocument();
302
+
303
+ // Callback should not be called
304
+ await expect(args.onValueChange).not.toHaveBeenCalled();
305
+ });
306
+ },
307
+ };
308
+
309
+ export const DisabledItemsTest: Story = {
310
+ tags: ['!dev', '!autodocs'],
311
+ args: {
312
+ items: itemsWithDisabled,
313
+ placeholder: 'Select an option',
314
+ onValueChange: fn(),
315
+ testId: 'disabled-items-select',
316
+ },
317
+ play: async ({ args, canvasElement, step }) => {
318
+ const canvas = within(canvasElement);
319
+ const body = within(document.body);
320
+
321
+ await step('Open dropdown', async () => {
322
+ const trigger = canvas.getByTestId('disabled-items-select-trigger');
323
+ await userEvent.click(trigger);
324
+
325
+ const content = await body.findByTestId('disabled-items-select-content');
326
+ await expect(content).toBeInTheDocument();
327
+ });
328
+
329
+ await step('Verify disabled items cannot be selected', async () => {
330
+ const disabledOption = body.getByTestId(
331
+ 'disabled-items-select-option-disabled1',
332
+ );
333
+ await expect(disabledOption).toBeInTheDocument();
334
+
335
+ // Verify disabled option has disabled attributes
336
+ await expect(disabledOption).toHaveAttribute('data-disabled', '');
337
+
338
+ // Try to click disabled option (this should not work due to pointer-events: none)
339
+ try {
340
+ await userEvent.click(disabledOption);
341
+ } catch (error) {
342
+ // Expected to fail due to pointer-events: none
343
+ expect((error as Error).message).toContain('pointer-events: none');
344
+ }
345
+
346
+ // Should not trigger callback for disabled item
347
+ await expect(args.onValueChange).not.toHaveBeenCalledWith('disabled1');
348
+ });
349
+
350
+ await step('Verify enabled items can be selected', async () => {
351
+ const enabledOption = body.getByTestId(
352
+ 'disabled-items-select-option-available1',
353
+ );
354
+ await userEvent.click(enabledOption);
355
+
356
+ await expect(args.onValueChange).toHaveBeenCalledWith('available1');
357
+ });
358
+ },
359
+ };
360
+
361
+ export const ReactNodeContentTest: Story = {
362
+ tags: ['!dev', '!autodocs'],
363
+ args: {
364
+ items: [
365
+ {
366
+ value: 'user1',
367
+ content: (
368
+ <div className="flex items-center gap-2">
369
+ <div className="h-4 w-4 rounded-full bg-blue-500" />
370
+ <span>John Doe</span>
371
+ </div>
372
+ ),
373
+ },
374
+ {
375
+ value: 'user2',
376
+ content: (
377
+ <div className="flex items-center gap-2">
378
+ <div className="h-4 w-4 rounded-full bg-green-500" />
379
+ <span>Jane Smith</span>
380
+ </div>
381
+ ),
382
+ },
383
+ ],
384
+ placeholder: 'Select a user',
385
+ onValueChange: fn(),
386
+ testId: 'react-node-select',
387
+ },
388
+ play: async ({ args, canvasElement, step }) => {
389
+ const canvas = within(canvasElement);
390
+ const body = within(document.body);
391
+
392
+ await step('Open dropdown with ReactNode content', async () => {
393
+ const trigger = canvas.getByTestId('react-node-select-trigger');
394
+ await userEvent.click(trigger);
395
+
396
+ const content = await body.findByTestId('react-node-select-content');
397
+ await expect(content).toBeInTheDocument();
398
+ });
399
+
400
+ await step('Verify ReactNode content is rendered', async () => {
401
+ const user1Option = body.getByTestId(
402
+ 'react-node-select-option-content-user1',
403
+ );
404
+ await expect(user1Option).toBeInTheDocument();
405
+
406
+ const user2Option = body.getByTestId(
407
+ 'react-node-select-option-content-user2',
408
+ );
409
+ await expect(user2Option).toBeInTheDocument();
410
+ });
411
+
412
+ await step('Select ReactNode option', async () => {
413
+ const user1Option = body.getByTestId('react-node-select-option-user1');
414
+ await userEvent.click(user1Option);
415
+
416
+ await expect(args.onValueChange).toHaveBeenCalledWith('user1');
417
+ });
418
+ },
419
+ };
420
+
421
+ export const KeyboardNavigationTest: Story = {
422
+ tags: ['!dev', '!autodocs'],
423
+ args: {
424
+ items: basicItems,
425
+ placeholder: 'Select an option',
426
+ onValueChange: fn(),
427
+ testId: 'keyboard-select',
428
+ },
429
+ play: async ({ args, canvasElement, step }) => {
430
+ const canvas = within(canvasElement);
431
+ const body = within(document.body);
432
+
433
+ await step('Focus trigger with keyboard', async () => {
434
+ const trigger = canvas.getByTestId('keyboard-select-trigger');
435
+ trigger.focus();
436
+ await expect(trigger).toHaveFocus();
437
+ });
438
+
439
+ await step('Open dropdown with Enter key', async () => {
440
+ await userEvent.keyboard('{Enter}');
441
+
442
+ const content = await body.findByTestId('keyboard-select-content');
443
+ await expect(content).toBeInTheDocument();
444
+ });
445
+
446
+ await step('Navigate with arrow keys', async () => {
447
+ // Test arrow key navigation
448
+ await userEvent.keyboard('{ArrowDown}');
449
+ await userEvent.keyboard('{ArrowDown}');
450
+
451
+ // Select with Enter
452
+ await userEvent.keyboard('{Enter}');
453
+
454
+ // Should have selected an option
455
+ await expect(args.onValueChange).toHaveBeenCalled();
456
+ });
457
+ },
458
+ };
459
+
460
+ export const MultipleSelectionsTest: Story = {
461
+ tags: ['!dev', '!autodocs'],
462
+ args: {
463
+ items: basicItems,
464
+ placeholder: 'Select an option',
465
+ onValueChange: fn(),
466
+ testId: 'multiple-select',
467
+ },
468
+ play: async ({ args, canvasElement, step }) => {
469
+ const canvas = within(canvasElement);
470
+ const body = within(document.body);
471
+
472
+ await step('Select first option', async () => {
473
+ const trigger = canvas.getByTestId('multiple-select-trigger');
474
+ await userEvent.click(trigger);
475
+
476
+ const option1 = await body.findByTestId('multiple-select-option-option1');
477
+ await userEvent.click(option1);
478
+
479
+ await expect(args.onValueChange).toHaveBeenCalledWith('option1');
480
+ });
481
+
482
+ await step('Change selection to different option', async () => {
483
+ const trigger = canvas.getByTestId('multiple-select-trigger');
484
+ await userEvent.click(trigger);
485
+
486
+ const option3 = await body.findByTestId('multiple-select-option-option3');
487
+ await userEvent.click(option3);
488
+
489
+ await expect(args.onValueChange).toHaveBeenCalledWith('option3');
490
+
491
+ // Verify trigger shows new selection
492
+ await expect(trigger).toHaveTextContent('Option 3');
493
+ });
494
+ },
495
+ };
496
+
497
+ export const PerformanceTest: Story = {
498
+ tags: ['!dev', '!autodocs'],
499
+ args: {
500
+ items: manyItems,
501
+ placeholder: 'Choose a fruit',
502
+ onValueChange: fn(),
503
+ testId: 'performance-select',
504
+ },
505
+ play: async ({ canvasElement, step }) => {
506
+ const canvas = within(canvasElement);
507
+ const body = within(document.body);
508
+
509
+ await step('Measure dropdown open performance', async () => {
510
+ const startTime = performance.now();
511
+
512
+ const trigger = canvas.getByTestId('performance-select-trigger');
513
+ await userEvent.click(trigger);
514
+
515
+ const content = await body.findByTestId('performance-select-content');
516
+ await expect(content).toBeInTheDocument();
517
+
518
+ const endTime = performance.now();
519
+ const renderTime = endTime - startTime;
520
+
521
+ console.log(`CustomSelect dropdown render time: ${renderTime}ms`);
522
+
523
+ // Verify reasonable render time (less than 100ms for 8 items)
524
+ expect(renderTime).toBeLessThan(100);
525
+ });
526
+
527
+ await step('Verify all items rendered', async () => {
528
+ for (const item of manyItems) {
529
+ const option = body.getByTestId(
530
+ `performance-select-option-${item.value}`,
531
+ );
532
+ await expect(option).toBeInTheDocument();
533
+ }
534
+ });
535
+ },
536
+ };
537
+
538
+ export const AccessibilityTest: Story = {
539
+ tags: ['!dev', '!autodocs'],
540
+ args: {
541
+ items: basicItems,
542
+ placeholder: 'Select an option',
543
+ onValueChange: fn(),
544
+ testId: 'accessibility-select',
545
+ },
546
+ play: async ({ canvasElement, step }) => {
547
+ const canvas = within(canvasElement);
548
+ const body = within(document.body);
549
+
550
+ await step('Verify ARIA attributes', async () => {
551
+ const trigger = canvas.getByTestId('accessibility-select-trigger');
552
+ await expect(trigger).toBeInTheDocument();
553
+
554
+ // Check that it's a button element (no need for explicit role="button")
555
+ await expect(trigger.tagName).toBe('BUTTON');
556
+
557
+ // Check for ARIA attributes
558
+ await expect(trigger).toHaveAttribute('aria-haspopup', 'menu');
559
+ });
560
+
561
+ await step('Verify keyboard accessibility', async () => {
562
+ const trigger = canvas.getByTestId('accessibility-select-trigger');
563
+
564
+ // Test tab navigation
565
+ trigger.focus();
566
+ await expect(trigger).toHaveFocus();
567
+
568
+ // Test space bar to open
569
+ await userEvent.keyboard(' ');
570
+
571
+ const content = await body.findByTestId('accessibility-select-content');
572
+ await expect(content).toBeInTheDocument();
573
+ });
574
+
575
+ await step('Test Escape key to close', async () => {
576
+ await userEvent.keyboard('{Escape}');
577
+
578
+ const content = body.queryByTestId('accessibility-select-content');
579
+ await expect(content).not.toBeInTheDocument();
580
+ });
581
+ },
582
+ };