@shopify/shop-minis-react 0.1.4 → 0.1.6

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 (125) hide show
  1. package/dist/_virtual/index7.js +2 -3
  2. package/dist/_virtual/index7.js.map +1 -1
  3. package/dist/_virtual/index8.js +3 -2
  4. package/dist/_virtual/index8.js.map +1 -1
  5. package/dist/components/atoms/list.js +110 -48
  6. package/dist/components/atoms/list.js.map +1 -1
  7. package/dist/components/commerce/add-to-cart.js +82 -0
  8. package/dist/components/commerce/add-to-cart.js.map +1 -0
  9. package/dist/components/{atoms → commerce}/favorite-button.js +1 -1
  10. package/dist/components/commerce/favorite-button.js.map +1 -0
  11. package/dist/components/commerce/product-card.js +10 -10
  12. package/dist/components/commerce/product-card.js.map +1 -1
  13. package/dist/components/commerce/product-link.js +6 -6
  14. package/dist/components/commerce/product-link.js.map +1 -1
  15. package/dist/components/commerce/search.js +73 -77
  16. package/dist/components/commerce/search.js.map +1 -1
  17. package/dist/components/ui/accordion.js +1 -1
  18. package/dist/components/ui/alert-dialog.js +1 -1
  19. package/dist/components/ui/avatar.js +1 -1
  20. package/dist/components/ui/checkbox.js +1 -1
  21. package/dist/components/ui/dialog.js +1 -1
  22. package/dist/components/ui/label.js +1 -1
  23. package/dist/components/ui/progress.js +1 -1
  24. package/dist/components/ui/radio-group.js +1 -1
  25. package/dist/components/ui/scroll-area.js +1 -1
  26. package/dist/components/ui/select.js +1 -1
  27. package/dist/components/ui/separator.js +1 -1
  28. package/dist/components/ui/sheet.js +1 -1
  29. package/dist/index.js +276 -274
  30. package/dist/index.js.map +1 -1
  31. package/dist/internal/components/refresh-indicator.js +83 -0
  32. package/dist/internal/components/refresh-indicator.js.map +1 -0
  33. package/dist/internal/usePullToRefresh.js +149 -0
  34. package/dist/internal/usePullToRefresh.js.map +1 -0
  35. package/dist/internal/utils/virtuoso-dom.js +20 -0
  36. package/dist/internal/utils/virtuoso-dom.js.map +1 -0
  37. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-accordion@1.2.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19_krqvbhitcyb3vl2jzw3fp35uhu → @radix-ui_react-accordion@1.2.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types_re_c181f188656cfa5f16c2710ccd54e5dd}/node_modules/@radix-ui/react-accordion/dist/index.js +3 -3
  38. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-accordion@1.2.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19_krqvbhitcyb3vl2jzw3fp35uhu → @radix-ui_react-accordion@1.2.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types_re_c181f188656cfa5f16c2710ccd54e5dd}/node_modules/@radix-ui/react-accordion/dist/index.js.map +1 -1
  39. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-alert-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_5smkpul3xqqoqjowwwfk226yey → @radix-ui_react-alert-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_285ea9ce18742a8c4e84cbcde06e0b25}/node_modules/@radix-ui/react-alert-dialog/dist/index.js +1 -1
  40. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-alert-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_5smkpul3xqqoqjowwwfk226yey → @radix-ui_react-alert-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_285ea9ce18742a8c4e84cbcde06e0b25}/node_modules/@radix-ui/react-alert-dialog/dist/index.js.map +1 -1
  41. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-arrow@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6__tqbcahbocnte57ax4r75bgnpei → @radix-ui_react-arrow@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_37a4d12c56f285a88c8895f81bd600a0}/node_modules/@radix-ui/react-arrow/dist/index.js +1 -1
  42. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-arrow@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6__tqbcahbocnte57ax4r75bgnpei → @radix-ui_react-arrow@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_37a4d12c56f285a88c8895f81bd600a0}/node_modules/@radix-ui/react-arrow/dist/index.js.map +1 -1
  43. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-avatar@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1._hkz57sehyui4ndfh3rsqwxftli → @radix-ui_react-avatar@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_06170eb4026a170071caea5f0c82612e}/node_modules/@radix-ui/react-avatar/dist/index.js +1 -1
  44. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-avatar@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1._hkz57sehyui4ndfh3rsqwxftli → @radix-ui_react-avatar@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_06170eb4026a170071caea5f0c82612e}/node_modules/@radix-ui/react-avatar/dist/index.js.map +1 -1
  45. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-checkbox@1.3.2_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1_wopssf2yyhcdxk6apqq3fxlekq → @radix-ui_react-checkbox@1.3.2_@types_react-dom@19.1.6_@types_react@19.1.6__@types_reac_76c2d9960806d267f7566af463150dec}/node_modules/@radix-ui/react-checkbox/dist/index.js +2 -2
  46. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-checkbox@1.3.2_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1_wopssf2yyhcdxk6apqq3fxlekq → @radix-ui_react-checkbox@1.3.2_@types_react-dom@19.1.6_@types_react@19.1.6__@types_reac_76c2d9960806d267f7566af463150dec}/node_modules/@radix-ui/react-checkbox/dist/index.js.map +1 -1
  47. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-collapsible@1.1.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_4e7bghgww3y6lafncm5x7ie54a → @radix-ui_react-collapsible@1.1.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types__4a84ef457ec365b76d5b35ae363501b4}/node_modules/@radix-ui/react-collapsible/dist/index.js +2 -2
  48. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-collapsible@1.1.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_4e7bghgww3y6lafncm5x7ie54a → @radix-ui_react-collapsible@1.1.11_@types_react-dom@19.1.6_@types_react@19.1.6__@types__4a84ef457ec365b76d5b35ae363501b4}/node_modules/@radix-ui/react-collapsible/dist/index.js.map +1 -1
  49. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-collection@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19_5kif5qsljjcymh5vn5h26ovoye → @radix-ui_react-collection@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_re_773c2f41d00caf3f92b3d7605949da61}/node_modules/@radix-ui/react-collection/dist/index.js.map +1 -1
  50. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1._sjczexpvrqz6fttoobpwnns2oa → @radix-ui_react-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_00050fb27f6e4250402df169ba62a563}/node_modules/@radix-ui/react-dialog/dist/index.js +5 -5
  51. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1._sjczexpvrqz6fttoobpwnns2oa → @radix-ui_react-dialog@1.1.14_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_00050fb27f6e4250402df169ba62a563}/node_modules/@radix-ui/react-dialog/dist/index.js.map +1 -1
  52. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-dismissable-layer@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types__ipor64qsap4jnr6m7nflv4q5v4 → @radix-ui_react-dismissable-layer@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@_4b09e0704ece360f13e36cbb3765ea47}/node_modules/@radix-ui/react-dismissable-layer/dist/index.js +1 -1
  53. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-dismissable-layer@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types__ipor64qsap4jnr6m7nflv4q5v4 → @radix-ui_react-dismissable-layer@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@_4b09e0704ece360f13e36cbb3765ea47}/node_modules/@radix-ui/react-dismissable-layer/dist/index.js.map +1 -1
  54. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_zpdtvgogfsfavk62phevpdv4fu → @radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_r_b37fcafba5387ffb2fedae9e4476c837}/node_modules/@radix-ui/react-focus-scope/dist/index.js +1 -1
  55. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_zpdtvgogfsfavk62phevpdv4fu → @radix-ui_react-focus-scope@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_r_b37fcafba5387ffb2fedae9e4476c837}/node_modules/@radix-ui/react-focus-scope/dist/index.js.map +1 -1
  56. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-label@2.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6__a5hm3akpfjy2hepxrptadu7t6e → @radix-ui_react-label@2.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_85b8c95b65bf0dd4cc21629f4084a5b6}/node_modules/@radix-ui/react-label/dist/index.js +1 -1
  57. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-label@2.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6__a5hm3akpfjy2hepxrptadu7t6e → @radix-ui_react-label@2.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_85b8c95b65bf0dd4cc21629f4084a5b6}/node_modules/@radix-ui/react-label/dist/index.js.map +1 -1
  58. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-popper@1.2.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_2sktqq4blwmd3t7e5jqffehtuu → @radix-ui_react-popper@1.2.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_7f041a511b7212d213e8dcc35ea98be2}/node_modules/@radix-ui/react-popper/dist/index.js +2 -2
  59. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-popper@1.2.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_2sktqq4blwmd3t7e5jqffehtuu → @radix-ui_react-popper@1.2.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_7f041a511b7212d213e8dcc35ea98be2}/node_modules/@radix-ui/react-popper/dist/index.js.map +1 -1
  60. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-portal@1.1.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_sr45arufxpp6hzdn2l7kcrtvqe → @radix-ui_react-portal@1.1.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_dbd1c487dbf0f36d89874abfade43936}/node_modules/@radix-ui/react-portal/dist/index.js +1 -1
  61. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-portal@1.1.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_sr45arufxpp6hzdn2l7kcrtvqe → @radix-ui_react-portal@1.1.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_dbd1c487dbf0f36d89874abfade43936}/node_modules/@radix-ui/react-portal/dist/index.js.map +1 -1
  62. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-presence@1.1.4_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1_5ga5lr7i6zouk7rhd63vbsmjyu → @radix-ui_react-presence@1.1.4_@types_react-dom@19.1.6_@types_react@19.1.6__@types_reac_14564cac32122309a7cc56096494b6e8}/node_modules/@radix-ui/react-presence/dist/index.js.map +1 -1
  63. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-primitive@2.1.3_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19._5iu4xtybujtep4zwi6jviky6tu → @radix-ui_react-primitive@2.1.3_@types_react-dom@19.1.6_@types_react@19.1.6__@types_rea_ec571b14c8dc7e1c1fa1383d9a1e10bd}/node_modules/@radix-ui/react-primitive/dist/index.js.map +1 -1
  64. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-progress@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1_psrnvm437duefd2y5sh3bqj3sm → @radix-ui_react-progress@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_reac_fa1ba230d1dfc5fe2a0cedd9ff78309e}/node_modules/@radix-ui/react-progress/dist/index.js +1 -1
  65. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-progress@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1_psrnvm437duefd2y5sh3bqj3sm → @radix-ui_react-progress@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_reac_fa1ba230d1dfc5fe2a0cedd9ff78309e}/node_modules/@radix-ui/react-progress/dist/index.js.map +1 -1
  66. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-radio-group@1.3.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_b6vd3n6tkje342bk7jtbsrqyfe → @radix-ui_react-radio-group@1.3.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_r_4bdbb04c93e325d7f20e33cc8e004c83}/node_modules/@radix-ui/react-radio-group/dist/index.js +3 -3
  67. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-radio-group@1.3.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_b6vd3n6tkje342bk7jtbsrqyfe → @radix-ui_react-radio-group@1.3.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_r_4bdbb04c93e325d7f20e33cc8e004c83}/node_modules/@radix-ui/react-radio-group/dist/index.js.map +1 -1
  68. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-roving-focus@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_g7ajeb2xgflky4nc3ccraxd5vi → @radix-ui_react-roving-focus@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_2d3f19e691372edf0bc25a87278ce401}/node_modules/@radix-ui/react-roving-focus/dist/index.js +2 -2
  69. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-roving-focus@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react_g7ajeb2xgflky4nc3ccraxd5vi → @radix-ui_react-roving-focus@1.1.10_@types_react-dom@19.1.6_@types_react@19.1.6__@types_2d3f19e691372edf0bc25a87278ce401}/node_modules/@radix-ui/react-roving-focus/dist/index.js.map +1 -1
  70. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-scroll-area@1.2.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_na6tcikkwmgt5sgxl6ezf7zaf4 → @radix-ui_react-scroll-area@1.2.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_r_b5d13464c21f88022505288dd3198025}/node_modules/@radix-ui/react-scroll-area/dist/index.js +2 -2
  71. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-scroll-area@1.2.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@1_na6tcikkwmgt5sgxl6ezf7zaf4 → @radix-ui_react-scroll-area@1.2.9_@types_react-dom@19.1.6_@types_react@19.1.6__@types_r_b5d13464c21f88022505288dd3198025}/node_modules/@radix-ui/react-scroll-area/dist/index.js.map +1 -1
  72. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-select@2.2.5_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_pvbs4vbfxc35gflcf62ix5b3oy → @radix-ui_react-select@2.2.5_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_8c539485311b2ef067a182d5db805374}/node_modules/@radix-ui/react-select/dist/index.js +7 -7
  73. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-select@2.2.5_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_pvbs4vbfxc35gflcf62ix5b3oy → @radix-ui_react-select@2.2.5_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@_8c539485311b2ef067a182d5db805374}/node_modules/@radix-ui/react-select/dist/index.js.map +1 -1
  74. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-separator@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19._v5c7fe2eicmnfbsit6liht3cja → @radix-ui_react-separator@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_rea_c3003570fa0d6f9943d03ab6b06417ce}/node_modules/@radix-ui/react-separator/dist/index.js +1 -1
  75. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-separator@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19._v5c7fe2eicmnfbsit6liht3cja → @radix-ui_react-separator@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_rea_c3003570fa0d6f9943d03ab6b06417ce}/node_modules/@radix-ui/react-separator/dist/index.js.map +1 -1
  76. package/dist/shop-minis-react/node_modules/.pnpm/@radix-ui_react-use-is-hydrated@0.1.0_@types_react@19.1.6_react@19.1.0/node_modules/@radix-ui/react-use-is-hydrated/dist/index.js +1 -1
  77. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.1.6_@types_react@19.1.6__@types_rea_3rnyx4jgemf4vn7spx7uohk4ne → @radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.1.6_@types_react@19.1.6__@typ_4a5a40fef19214ea28d77d9af27dab61}/node_modules/@radix-ui/react-visually-hidden/dist/index.js +1 -1
  78. package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.1.6_@types_react@19.1.6__@types_rea_3rnyx4jgemf4vn7spx7uohk4ne → @radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.1.6_@types_react@19.1.6__@typ_4a5a40fef19214ea28d77d9af27dab61}/node_modules/@radix-ui/react-visually-hidden/dist/index.js.map +1 -1
  79. package/dist/shop-minis-react/node_modules/.pnpm/color-string@1.9.1/node_modules/color-string/index.js +1 -1
  80. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/PopChild.js +55 -0
  81. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/PopChild.js.map +1 -0
  82. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/PresenceChild.js +35 -0
  83. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/PresenceChild.js.map +1 -0
  84. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/index.js +46 -0
  85. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/index.js.map +1 -0
  86. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/utils.js +13 -0
  87. package/dist/shop-minis-react/node_modules/.pnpm/motion@12.17.3_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/motion/dist/es/framer-motion/dist/es/components/AnimatePresence/utils.js.map +1 -0
  88. package/dist/shop-minis-react/node_modules/.pnpm/react-virtuoso@4.14.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-virtuoso/dist/index.js +3132 -0
  89. package/dist/shop-minis-react/node_modules/.pnpm/react-virtuoso@4.14.0_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-virtuoso/dist/index.js.map +1 -0
  90. package/dist/shop-minis-react/node_modules/.pnpm/simple-swizzle@0.2.2/node_modules/simple-swizzle/index.js +1 -1
  91. package/dist/shop-minis-react/node_modules/.pnpm/use-sync-external-store@1.5.0_react@19.1.0/node_modules/use-sync-external-store/shim/index.js +1 -1
  92. package/dist/shop-minis-react/node_modules/.pnpm/vaul@1.1.2_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1.6_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/vaul/dist/index.js +1 -1
  93. package/package.json +2 -2
  94. package/src/components/atoms/list.tsx +115 -66
  95. package/src/components/commerce/add-to-cart.test.tsx +73 -0
  96. package/src/components/commerce/add-to-cart.tsx +132 -0
  97. package/src/components/{atoms → commerce}/favorite-button.tsx +1 -1
  98. package/src/components/commerce/product-card.tsx +2 -1
  99. package/src/components/commerce/product-link.tsx +2 -1
  100. package/src/components/commerce/search.tsx +0 -6
  101. package/src/components/index.ts +2 -1
  102. package/src/internal/components/refresh-indicator.tsx +103 -0
  103. package/src/internal/usePullToRefresh.ts +286 -0
  104. package/src/internal/utils/virtuoso-dom.ts +26 -0
  105. package/src/stories/AddToCart.stories.tsx +186 -0
  106. package/src/stories/FavoriteButton.stories.tsx +2 -2
  107. package/src/stories/List.stories.tsx +0 -4
  108. package/src/stories/PullToRefreshList.stories.tsx +122 -0
  109. package/src/styles/animations.css +54 -0
  110. package/src/test-setup.ts +68 -0
  111. package/dist/components/atoms/favorite-button.js.map +0 -1
  112. package/dist/shop-minis-react/node_modules/.pnpm/@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js +0 -8
  113. package/dist/shop-minis-react/node_modules/.pnpm/@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js.map +0 -1
  114. package/dist/shop-minis-react/node_modules/.pnpm/@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/inheritsLoose.js +0 -8
  115. package/dist/shop-minis-react/node_modules/.pnpm/@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/inheritsLoose.js.map +0 -1
  116. package/dist/shop-minis-react/node_modules/.pnpm/@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js +0 -9
  117. package/dist/shop-minis-react/node_modules/.pnpm/@babel_runtime@7.27.6/node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js.map +0 -1
  118. package/dist/shop-minis-react/node_modules/.pnpm/memoize-one@5.2.1/node_modules/memoize-one/dist/memoize-one.esm.js +0 -28
  119. package/dist/shop-minis-react/node_modules/.pnpm/memoize-one@5.2.1/node_modules/memoize-one/dist/memoize-one.esm.js.map +0 -1
  120. package/dist/shop-minis-react/node_modules/.pnpm/react-window@1.8.11_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-window/dist/index.esm.js +0 -375
  121. package/dist/shop-minis-react/node_modules/.pnpm/react-window@1.8.11_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/react-window/dist/index.esm.js.map +0 -1
  122. /package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-collection@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19_5kif5qsljjcymh5vn5h26ovoye → @radix-ui_react-collection@1.1.7_@types_react-dom@19.1.6_@types_react@19.1.6__@types_re_773c2f41d00caf3f92b3d7605949da61}/node_modules/@radix-ui/react-collection/dist/index.js +0 -0
  123. /package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-presence@1.1.4_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19.1_5ga5lr7i6zouk7rhd63vbsmjyu → @radix-ui_react-presence@1.1.4_@types_react-dom@19.1.6_@types_react@19.1.6__@types_reac_14564cac32122309a7cc56096494b6e8}/node_modules/@radix-ui/react-presence/dist/index.js +0 -0
  124. /package/dist/shop-minis-react/node_modules/.pnpm/{@radix-ui_react-primitive@2.1.3_@types_react-dom@19.1.6_@types_react@19.1.6__@types_react@19._5iu4xtybujtep4zwi6jviky6tu → @radix-ui_react-primitive@2.1.3_@types_react-dom@19.1.6_@types_react@19.1.6__@types_rea_ec571b14c8dc7e1c1fa1383d9a1e10bd}/node_modules/@radix-ui/react-primitive/dist/index.js +0 -0
  125. /package/src/components/{atoms → commerce}/favorite-button.test.tsx +0 -0
@@ -0,0 +1,286 @@
1
+ import {useCallback, useEffect, useRef, useState} from 'react'
2
+
3
+ const DEFAULT_REFRESH_PULL_THRESHOLD = 200
4
+ const ANIMATION_DURATION = 400
5
+
6
+ export interface UsePullToRefreshOptions {
7
+ onRefresh?: () => Promise<void>
8
+ threshold?: number
9
+ indicatorThreshold?: number
10
+ enabled?: boolean
11
+ }
12
+
13
+ export interface PullToRefreshState {
14
+ isPulling: boolean
15
+ pullDistance: number
16
+ canRefresh: boolean
17
+ }
18
+
19
+ export function usePullToRefresh({
20
+ onRefresh,
21
+ threshold = DEFAULT_REFRESH_PULL_THRESHOLD,
22
+ indicatorThreshold = 0,
23
+ enabled = false,
24
+ }: UsePullToRefreshOptions) {
25
+ const [state, setState] = useState<PullToRefreshState>({
26
+ isPulling: false,
27
+ pullDistance: 0,
28
+ canRefresh: false,
29
+ })
30
+
31
+ const startY = useRef(0)
32
+ const currentY = useRef(0)
33
+ const containerRef = useRef<HTMLElement | null>(null)
34
+ const animationRef = useRef<number | null>(null)
35
+ const isRefreshingRef = useRef(false)
36
+
37
+ const handleTouchStart = useCallback(
38
+ (event: TouchEvent) => {
39
+ if (!enabled || !containerRef.current || isRefreshingRef.current) return
40
+
41
+ if (animationRef.current) {
42
+ cancelAnimationFrame(animationRef.current)
43
+ animationRef.current = null
44
+ }
45
+
46
+ setState(prev => {
47
+ const container = containerRef.current
48
+ if (!container) return prev
49
+
50
+ const isAtTop = container.scrollTop <= 0
51
+
52
+ if (isAtTop) {
53
+ const touch = event.touches[0]
54
+ startY.current = touch.clientY
55
+ } else {
56
+ startY.current = 0
57
+ return {
58
+ ...prev,
59
+ isPulling: false,
60
+ pullDistance: 0,
61
+ canRefresh: false,
62
+ }
63
+ }
64
+
65
+ return prev
66
+ })
67
+ },
68
+ [enabled]
69
+ )
70
+
71
+ const handleMove = useCallback(
72
+ (clientY: number, preventDefault?: () => void) => {
73
+ if (!enabled || !containerRef.current || startY.current === 0) {
74
+ return
75
+ }
76
+
77
+ setState(prev => {
78
+ if (isRefreshingRef.current) {
79
+ return prev
80
+ }
81
+
82
+ const container = containerRef.current
83
+ if (!container) return prev
84
+
85
+ const isAtTop = container.scrollTop <= 0
86
+ currentY.current = clientY
87
+ const deltaY = currentY.current - startY.current
88
+ const isValidPull = isAtTop && deltaY > 0
89
+
90
+ if (isValidPull) {
91
+ const pullDistance = deltaY
92
+ const shouldShowIndicator = pullDistance >= indicatorThreshold
93
+
94
+ if (shouldShowIndicator && preventDefault) {
95
+ preventDefault()
96
+ }
97
+
98
+ if (shouldShowIndicator || prev.isPulling) {
99
+ const elasticDistance =
100
+ pullDistance > threshold
101
+ ? threshold + (pullDistance - threshold) * 0.5
102
+ : pullDistance
103
+
104
+ return {
105
+ ...prev,
106
+ isPulling: shouldShowIndicator,
107
+ pullDistance: elasticDistance,
108
+ canRefresh: pullDistance >= threshold,
109
+ }
110
+ }
111
+
112
+ return prev
113
+ } else if (prev.isPulling) {
114
+ return {
115
+ ...prev,
116
+ isPulling: false,
117
+ pullDistance: 0,
118
+ canRefresh: false,
119
+ }
120
+ }
121
+
122
+ return prev
123
+ })
124
+ },
125
+ [threshold, indicatorThreshold, enabled]
126
+ )
127
+
128
+ const handleTouchMove = useCallback(
129
+ (event: TouchEvent) => {
130
+ if (isRefreshingRef.current) return
131
+
132
+ const touch = event.touches[0]
133
+ if (!touch) return
134
+
135
+ if (startY.current !== 0) {
136
+ handleMove(touch.clientY, () => event.preventDefault())
137
+ }
138
+ },
139
+ [handleMove]
140
+ )
141
+
142
+ const resetRefreshingState = useCallback(() => {
143
+ isRefreshingRef.current = false
144
+ }, [])
145
+
146
+ const animatePullDistanceToZero = useCallback((fromDistance?: number) => {
147
+ if (animationRef.current) {
148
+ cancelAnimationFrame(animationRef.current)
149
+ animationRef.current = null
150
+ }
151
+
152
+ let startDistance = fromDistance
153
+ if (startDistance === undefined) {
154
+ setState(prev => {
155
+ startDistance = prev.pullDistance
156
+ return prev
157
+ })
158
+ }
159
+
160
+ if (!startDistance || startDistance <= 0) {
161
+ setState(prev => ({
162
+ ...prev,
163
+ pullDistance: 0,
164
+ canRefresh: false,
165
+ isPulling: false,
166
+ }))
167
+ return
168
+ }
169
+
170
+ const duration = ANIMATION_DURATION
171
+ const startTime = Date.now()
172
+
173
+ const animate = () => {
174
+ const elapsed = Date.now() - startTime
175
+ const progress = Math.min(elapsed / duration, 1)
176
+
177
+ const easeOut = 1 - (1 - progress) ** 3
178
+ const currentDistance = startDistance! * (1 - easeOut)
179
+
180
+ setState(prev => ({
181
+ ...prev,
182
+ pullDistance: currentDistance,
183
+ canRefresh: progress < 1 ? prev.canRefresh : false,
184
+ }))
185
+
186
+ if (progress < 1) {
187
+ animationRef.current = requestAnimationFrame(animate)
188
+ } else {
189
+ animationRef.current = null
190
+ setState(prev => ({
191
+ ...prev,
192
+ pullDistance: 0,
193
+ canRefresh: false,
194
+ isPulling: false,
195
+ }))
196
+ }
197
+ }
198
+
199
+ animationRef.current = requestAnimationFrame(animate)
200
+ }, [])
201
+
202
+ const handleEnd = useCallback(async () => {
203
+ if (isRefreshingRef.current) {
204
+ startY.current = 0
205
+ return
206
+ }
207
+
208
+ startY.current = 0
209
+
210
+ if (animationRef.current) {
211
+ cancelAnimationFrame(animationRef.current)
212
+ animationRef.current = null
213
+ }
214
+
215
+ let shouldRefresh = false
216
+ let currentPullDistance = 0
217
+ const wasRefreshing = isRefreshingRef.current
218
+
219
+ setState(prev => {
220
+ shouldRefresh = prev.canRefresh && !wasRefreshing
221
+ currentPullDistance = prev.pullDistance
222
+
223
+ return {
224
+ ...prev,
225
+ isPulling: false,
226
+ }
227
+ })
228
+
229
+ if (currentPullDistance <= 0) {
230
+ setState(prev => ({
231
+ ...prev,
232
+ pullDistance: 0,
233
+ canRefresh: false,
234
+ }))
235
+ return
236
+ }
237
+
238
+ if (shouldRefresh && onRefresh) {
239
+ isRefreshingRef.current = true
240
+ try {
241
+ await onRefresh()
242
+ } catch (error) {
243
+ console.error('Pull to refresh failed:', error)
244
+ }
245
+ resetRefreshingState()
246
+ }
247
+
248
+ animatePullDistanceToZero(currentPullDistance)
249
+ }, [onRefresh, animatePullDistanceToZero, resetRefreshingState])
250
+
251
+ const bindToElement = useCallback(
252
+ (element: HTMLElement | null) => {
253
+ if (!element) return
254
+
255
+ containerRef.current = element
256
+
257
+ element.addEventListener('touchstart', handleTouchStart, {passive: false})
258
+ element.addEventListener('touchmove', handleTouchMove, {passive: false})
259
+ element.addEventListener('touchend', handleEnd)
260
+ element.addEventListener('touchcancel', handleEnd)
261
+
262
+ return () => {
263
+ element.removeEventListener('touchstart', handleTouchStart)
264
+ element.removeEventListener('touchmove', handleTouchMove)
265
+ element.removeEventListener('touchend', handleEnd)
266
+ element.removeEventListener('touchcancel', handleEnd)
267
+ }
268
+ },
269
+ [handleTouchStart, handleTouchMove, handleEnd]
270
+ )
271
+
272
+ useEffect(() => {
273
+ return () => {
274
+ if (animationRef.current) {
275
+ cancelAnimationFrame(animationRef.current)
276
+ animationRef.current = null
277
+ }
278
+ }
279
+ }, [])
280
+
281
+ return {
282
+ state,
283
+ bindToElement,
284
+ containerRef,
285
+ }
286
+ }
@@ -0,0 +1,26 @@
1
+ // For finding the scrollable element within a container for pull-to-refresh functionality.
2
+
3
+ export const findVirtuosoScrollableElement = (
4
+ container: HTMLElement
5
+ ): HTMLElement => {
6
+ const selector = '[data-virtuoso-scroller]'
7
+
8
+ let scrollableElement: HTMLElement | null = null
9
+
10
+ scrollableElement = container.querySelector(selector) as HTMLElement
11
+
12
+ if (scrollableElement) return scrollableElement
13
+
14
+ if (!scrollableElement) {
15
+ const allDivs = Array.from(container.querySelectorAll('div'))
16
+ for (const div of allDivs) {
17
+ const style = window.getComputedStyle(div)
18
+ if (style.overflowY === 'auto' || style.overflowY === 'scroll') {
19
+ scrollableElement = div as HTMLElement
20
+ break
21
+ }
22
+ }
23
+ }
24
+
25
+ return scrollableElement || container
26
+ }
@@ -0,0 +1,186 @@
1
+ import {AddToCartButton} from '../components/commerce/add-to-cart'
2
+
3
+ import type {Meta, StoryObj} from '@storybook/react-vite'
4
+
5
+ const meta = {
6
+ title: 'Commerce/AddToCartButton',
7
+ component: AddToCartButton,
8
+ parameters: {},
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ size: {
12
+ control: 'radio',
13
+ options: ['sm', 'default', 'lg'],
14
+ description: 'Button size',
15
+ },
16
+ disabled: {
17
+ control: 'boolean',
18
+ description: 'Whether the button is disabled',
19
+ },
20
+ className: {
21
+ control: 'text',
22
+ description: 'Additional CSS classes',
23
+ },
24
+ productId: {
25
+ control: 'text',
26
+ description: 'The GID of the product (e.g. gid://shopify/Product/123)',
27
+ },
28
+ productVariantId: {
29
+ control: 'text',
30
+ description:
31
+ 'The GID of the product variant (e.g. gid://shopify/ProductVariant/456)',
32
+ },
33
+ discountCodes: {
34
+ control: 'object',
35
+ description: 'Array of discount codes to apply',
36
+ },
37
+ },
38
+ args: {
39
+ disabled: false,
40
+ size: 'default',
41
+ productId: 'gid://shopify/Product/123',
42
+ productVariantId: 'gid://shopify/ProductVariant/456',
43
+ },
44
+ } satisfies Meta<typeof AddToCartButton>
45
+
46
+ export default meta
47
+ type Story = StoryObj<typeof meta>
48
+
49
+ export const Default: Story = {
50
+ args: {},
51
+ render: args => {
52
+ return <AddToCartButton {...args} />
53
+ },
54
+ }
55
+
56
+ export const SmallSize: Story = {
57
+ args: {
58
+ size: 'sm',
59
+ },
60
+ render: args => {
61
+ return <AddToCartButton {...args} />
62
+ },
63
+ }
64
+
65
+ export const LargeSize: Story = {
66
+ args: {
67
+ size: 'lg',
68
+ },
69
+ render: args => {
70
+ return <AddToCartButton {...args} />
71
+ },
72
+ }
73
+
74
+ export const WithDiscountCodes: Story = {
75
+ args: {
76
+ discountCodes: ['SUMMER20', 'FREESHIP'],
77
+ },
78
+ render: args => {
79
+ return (
80
+ <div className="space-y-2">
81
+ <p className="text-sm text-gray-600">
82
+ This button will apply discount codes:{' '}
83
+ {args.discountCodes?.join(', ')}
84
+ </p>
85
+ <AddToCartButton {...args} />
86
+ </div>
87
+ )
88
+ },
89
+ }
90
+
91
+ export const Disabled: Story = {
92
+ args: {
93
+ disabled: true,
94
+ },
95
+ render: args => {
96
+ return <AddToCartButton {...args} />
97
+ },
98
+ }
99
+
100
+ export const CustomStyling: Story = {
101
+ args: {
102
+ className: 'bg-purple-600 hover:bg-purple-700 text-white rounded-full px-8',
103
+ },
104
+ render: args => {
105
+ return (
106
+ <div className="space-y-2">
107
+ <p className="text-sm text-gray-600">
108
+ Custom styled button with additional classes
109
+ </p>
110
+ <AddToCartButton {...args} />
111
+ </div>
112
+ )
113
+ },
114
+ }
115
+
116
+ export const AllSizes: Story = {
117
+ render: () => {
118
+ return (
119
+ <div className="flex flex-col items-center space-y-4">
120
+ <h3 className="text-lg font-semibold">Button Sizes</h3>
121
+ <div className="flex gap-4 items-center">
122
+ <AddToCartButton
123
+ productId="gid://shopify/Product/123"
124
+ productVariantId="gid://shopify/ProductVariant/456"
125
+ size="sm"
126
+ />
127
+ <AddToCartButton
128
+ productId="gid://shopify/Product/123"
129
+ productVariantId="gid://shopify/ProductVariant/456"
130
+ size="default"
131
+ />
132
+ <AddToCartButton
133
+ productId="gid://shopify/Product/123"
134
+ productVariantId="gid://shopify/ProductVariant/456"
135
+ size="lg"
136
+ />
137
+ </div>
138
+ </div>
139
+ )
140
+ },
141
+ }
142
+
143
+ export const InteractiveExample: Story = {
144
+ render: () => {
145
+ return (
146
+ <div className="flex flex-col items-center space-y-6 p-8">
147
+ <div className="text-center">
148
+ <h3 className="text-lg font-semibold">Interactive Demo</h3>
149
+ <p className="text-sm text-gray-600 mt-2">
150
+ Click the buttons below to see the add to cart animation
151
+ </p>
152
+ </div>
153
+
154
+ <div className="grid gap-4">
155
+ <div className="text-center">
156
+ <p className="text-xs text-gray-500 mb-2">Product A</p>
157
+ <AddToCartButton
158
+ productId="gid://shopify/Product/111"
159
+ productVariantId="gid://shopify/ProductVariant/111"
160
+ />
161
+ </div>
162
+
163
+ <div className="text-center">
164
+ <p className="text-xs text-gray-500 mb-2">
165
+ Product B (with discount)
166
+ </p>
167
+ <AddToCartButton
168
+ productId="gid://shopify/Product/222"
169
+ productVariantId="gid://shopify/ProductVariant/222"
170
+ discountCodes={['SAVE10']}
171
+ />
172
+ </div>
173
+
174
+ <div className="text-center">
175
+ <p className="text-xs text-gray-500 mb-2">Product C (small size)</p>
176
+ <AddToCartButton
177
+ productId="gid://shopify/Product/333"
178
+ productVariantId="gid://shopify/ProductVariant/333"
179
+ size="sm"
180
+ />
181
+ </div>
182
+ </div>
183
+ </div>
184
+ )
185
+ },
186
+ }
@@ -1,11 +1,11 @@
1
1
  import {fn} from 'storybook/test'
2
2
 
3
- import {FavoriteButton} from '../components/atoms/favorite-button'
3
+ import {FavoriteButton} from '../components/commerce/favorite-button'
4
4
 
5
5
  import type {Meta, StoryObj} from '@storybook/react-vite'
6
6
 
7
7
  const meta = {
8
- title: 'Atoms/FavoriteButton',
8
+ title: 'Commerce/FavoriteButton',
9
9
  component: FavoriteButton,
10
10
  parameters: {},
11
11
  tags: ['autodocs'],
@@ -19,10 +19,6 @@ const meta = {
19
19
  control: 'number',
20
20
  description: 'Height of the virtualized list container',
21
21
  },
22
- itemSizeForRow: {
23
- control: 'number',
24
- description: 'Height of each item in the list',
25
- },
26
22
  },
27
23
  tags: ['autodocs'],
28
24
  } satisfies Meta<typeof List>
@@ -0,0 +1,122 @@
1
+ import {useState, useCallback} from 'react'
2
+
3
+ import {fn} from 'storybook/test'
4
+
5
+ import {List} from '../components/atoms/list'
6
+ import {ProductCard} from '../components/commerce/product-card'
7
+ import {ProductLink} from '../components/commerce/product-link'
8
+ import {createProduct, injectMocks} from '../mocks'
9
+
10
+ import type {Product} from '@shopify/shop-minis-platform'
11
+ import type {Meta, StoryObj} from '@storybook/react-vite'
12
+
13
+ const meta = {
14
+ title: 'Atoms/PullToRefreshList',
15
+ component: List as any,
16
+ parameters: {
17
+ layout: 'padded',
18
+ },
19
+ argTypes: {
20
+ height: {
21
+ control: 'number',
22
+ description: 'Height of the virtualized list container',
23
+ },
24
+ enablePullToRefresh: {
25
+ control: 'boolean',
26
+ description: 'Enable pull-to-refresh functionality',
27
+ defaultValue: true,
28
+ },
29
+ },
30
+ tags: ['autodocs'],
31
+ } satisfies Meta<typeof List>
32
+
33
+ export default meta
34
+ type Story = StoryObj<typeof meta>
35
+
36
+ injectMocks()
37
+
38
+ const createProductList = (count: number) => {
39
+ return Array.from({length: count}, (_, index) =>
40
+ createProduct(`product-${index + 1}`, `Product ${index + 1}`, '9.99')
41
+ )
42
+ }
43
+
44
+ const PullToRefreshListWrapper = ({
45
+ initialItems,
46
+ renderItem,
47
+ ...props
48
+ }: any) => {
49
+ const [items, setItems] = useState(initialItems)
50
+ const [refreshing, setRefreshing] = useState(false)
51
+
52
+ const handleRefresh = useCallback(async () => {
53
+ setRefreshing(true)
54
+
55
+ await new Promise(resolve => setTimeout(resolve, 2000))
56
+
57
+ const newItems = Array.from({length: 5}, (_, index) =>
58
+ createProduct(
59
+ `fresh-${Date.now()}-${index}`,
60
+ `Fresh Product ${index + 1}`,
61
+ '12.99'
62
+ )
63
+ )
64
+
65
+ setItems([...newItems, ...initialItems])
66
+ setRefreshing(false)
67
+ }, [initialItems])
68
+
69
+ return (
70
+ <List
71
+ {...props}
72
+ items={items}
73
+ renderItem={renderItem}
74
+ onRefresh={handleRefresh}
75
+ refreshing={refreshing}
76
+ enablePullToRefresh
77
+ />
78
+ )
79
+ }
80
+
81
+ const ProductLinkWithRefreshComponent = (args: any) => (
82
+ <PullToRefreshListWrapper
83
+ {...args}
84
+ initialItems={createProductList(20)}
85
+ renderItem={(product: Product) => (
86
+ <div className="p-4">
87
+ <ProductLink product={product} />
88
+ </div>
89
+ )}
90
+ />
91
+ )
92
+
93
+ export const ProductLinkWithRefresh: Story = {
94
+ render: ProductLinkWithRefreshComponent,
95
+ args: {
96
+ height: 600,
97
+ itemSizeForRow: () => 100,
98
+ showScrollbar: true,
99
+ },
100
+ }
101
+
102
+ const ProductGridWithRefreshComponent = (args: any) => (
103
+ <PullToRefreshListWrapper
104
+ {...args}
105
+ initialItems={createProductList(15)}
106
+ renderItem={(product: Product) => (
107
+ <div className="grid grid-cols-2 gap-4">
108
+ <ProductCard product={product} onFavoriteToggled={fn()} />
109
+ <ProductCard product={product} onFavoriteToggled={fn()} />
110
+ </div>
111
+ )}
112
+ />
113
+ )
114
+
115
+ export const ProductGridWithRefresh: Story = {
116
+ render: ProductGridWithRefreshComponent,
117
+ args: {
118
+ height: 600,
119
+ itemSizeForRow: () => 220,
120
+ showScrollbar: true,
121
+ },
122
+ }
@@ -48,6 +48,60 @@
48
48
  }
49
49
  }
50
50
 
51
+ @keyframes bump {
52
+ 0% {
53
+ transform: scale(1);
54
+ }
55
+ 16.7% {
56
+ transform: scale(1.16);
57
+ }
58
+ 38.9% {
59
+ transform: scale(1.16);
60
+ }
61
+ 100% {
62
+ transform: scale(1);
63
+ }
64
+ }
65
+
66
+ @keyframes shop-spin {
67
+ from {
68
+ stroke-dashoffset: 136;
69
+ }
70
+ to {
71
+ stroke-dashoffset: -272;
72
+ }
73
+ }
74
+
75
+ @keyframes shop-continuous-fill {
76
+ 0% {
77
+ stroke-dashoffset: 204;
78
+ }
79
+ 100% {
80
+ stroke-dashoffset: 0;
81
+ }
82
+ }
83
+
84
+ @media not (prefers-reduced-motion: reduce) {
85
+ .animate-bump {
86
+ animation: bump 360ms cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
87
+ }
88
+
89
+ .animate-shop-spin {
90
+ animation: shop-continuous-fill 1.5s linear infinite;
91
+ stroke-dasharray: 68 136 !important;
92
+ }
93
+ }
94
+
95
+ .shop-spinner-path {
96
+ stroke-dasharray: 136;
97
+ stroke-dashoffset: 0;
98
+ }
99
+
100
+ .shop-spinner-progress {
101
+ stroke-dashoffset: calc(136 - (136 * var(--spinner-progress, 0.54)));
102
+ transition: stroke-dashoffset 0.1s ease-out;
103
+ }
104
+
51
105
  /* --- View Transition Animations --- */
52
106
  @media not (prefers-reduced-motion: reduce) {
53
107
  /* FORWARD navigation animation */