@zerodev/smart-routing-address-react-ui 0.0.1

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 (100) hide show
  1. package/README.md +117 -0
  2. package/dist/_types/components/AddressDisplay/index.d.ts +43 -0
  3. package/dist/_types/components/AddressDisplay/index.d.ts.map +1 -0
  4. package/dist/_types/components/ErrorRetryCard/index.d.ts +21 -0
  5. package/dist/_types/components/ErrorRetryCard/index.d.ts.map +1 -0
  6. package/dist/_types/components/FeeBreakdown/feeInfo.d.ts +24 -0
  7. package/dist/_types/components/FeeBreakdown/feeInfo.d.ts.map +1 -0
  8. package/dist/_types/components/FeeBreakdown/index.d.ts +28 -0
  9. package/dist/_types/components/FeeBreakdown/index.d.ts.map +1 -0
  10. package/dist/_types/components/LoadingCard/index.d.ts +6 -0
  11. package/dist/_types/components/LoadingCard/index.d.ts.map +1 -0
  12. package/dist/_types/components/PendingDeposits/index.d.ts +14 -0
  13. package/dist/_types/components/PendingDeposits/index.d.ts.map +1 -0
  14. package/dist/_types/components/QrSheet/QrCode.d.ts +28 -0
  15. package/dist/_types/components/QrSheet/QrCode.d.ts.map +1 -0
  16. package/dist/_types/components/QrSheet/index.d.ts +16 -0
  17. package/dist/_types/components/QrSheet/index.d.ts.map +1 -0
  18. package/dist/_types/components/TxnItem/ExplorerLink.d.ts +16 -0
  19. package/dist/_types/components/TxnItem/ExplorerLink.d.ts.map +1 -0
  20. package/dist/_types/components/TxnItem/index.d.ts +19 -0
  21. package/dist/_types/components/TxnItem/index.d.ts.map +1 -0
  22. package/dist/_types/constants.d.ts +20 -0
  23. package/dist/_types/constants.d.ts.map +1 -0
  24. package/dist/_types/context/SmartRoutingAddressContext.d.ts +32 -0
  25. package/dist/_types/context/SmartRoutingAddressContext.d.ts.map +1 -0
  26. package/dist/_types/context/SmartRoutingAddressProvider.d.ts +13 -0
  27. package/dist/_types/context/SmartRoutingAddressProvider.d.ts.map +1 -0
  28. package/dist/_types/hooks/useCreateSmartRoutingAddress.d.ts +23 -0
  29. package/dist/_types/hooks/useCreateSmartRoutingAddress.d.ts.map +1 -0
  30. package/dist/_types/hooks/useDepositStatus.d.ts +25 -0
  31. package/dist/_types/hooks/useDepositStatus.d.ts.map +1 -0
  32. package/dist/_types/hooks/useNewDeposits.d.ts +8 -0
  33. package/dist/_types/hooks/useNewDeposits.d.ts.map +1 -0
  34. package/dist/_types/hooks/useProviderFees.d.ts +22 -0
  35. package/dist/_types/hooks/useProviderFees.d.ts.map +1 -0
  36. package/dist/_types/hooks/useSmartRoutingAddress.d.ts +20 -0
  37. package/dist/_types/hooks/useSmartRoutingAddress.d.ts.map +1 -0
  38. package/dist/_types/iconAssets.d.ts +7 -0
  39. package/dist/_types/iconAssets.d.ts.map +1 -0
  40. package/dist/_types/index.d.ts +14 -0
  41. package/dist/_types/index.d.ts.map +1 -0
  42. package/dist/_types/pages/Deposit.d.ts +12 -0
  43. package/dist/_types/pages/Deposit.d.ts.map +1 -0
  44. package/dist/_types/pages/PastDeposits.d.ts +14 -0
  45. package/dist/_types/pages/PastDeposits.d.ts.map +1 -0
  46. package/dist/_types/pages/TransactionDetails.d.ts +11 -0
  47. package/dist/_types/pages/TransactionDetails.d.ts.map +1 -0
  48. package/dist/_types/pages/index.d.ts +25 -0
  49. package/dist/_types/pages/index.d.ts.map +1 -0
  50. package/dist/_types/types.d.ts +75 -0
  51. package/dist/_types/types.d.ts.map +1 -0
  52. package/dist/_types/utils/chains.d.ts +8 -0
  53. package/dist/_types/utils/chains.d.ts.map +1 -0
  54. package/dist/_types/utils/config.d.ts +35 -0
  55. package/dist/_types/utils/config.d.ts.map +1 -0
  56. package/dist/_types/utils/deposits.d.ts +29 -0
  57. package/dist/_types/utils/deposits.d.ts.map +1 -0
  58. package/dist/_types/utils/fees.d.ts +14 -0
  59. package/dist/_types/utils/fees.d.ts.map +1 -0
  60. package/dist/_types/utils/format.d.ts +27 -0
  61. package/dist/_types/utils/format.d.ts.map +1 -0
  62. package/dist/_types/utils/providerFees.d.ts +103 -0
  63. package/dist/_types/utils/providerFees.d.ts.map +1 -0
  64. package/dist/index.cjs +2 -0
  65. package/dist/index.cjs.map +1 -0
  66. package/dist/index.mjs +2180 -0
  67. package/dist/index.mjs.map +1 -0
  68. package/dist/styles.css +2 -0
  69. package/package.json +91 -0
  70. package/src/components/AddressDisplay/index.tsx +108 -0
  71. package/src/components/ErrorRetryCard/index.tsx +68 -0
  72. package/src/components/FeeBreakdown/feeInfo.ts +25 -0
  73. package/src/components/FeeBreakdown/index.tsx +218 -0
  74. package/src/components/LoadingCard/index.tsx +27 -0
  75. package/src/components/PendingDeposits/index.tsx +152 -0
  76. package/src/components/QrSheet/QrCode.tsx +163 -0
  77. package/src/components/QrSheet/index.tsx +80 -0
  78. package/src/components/TxnItem/ExplorerLink.tsx +37 -0
  79. package/src/components/TxnItem/index.tsx +178 -0
  80. package/src/constants.ts +102 -0
  81. package/src/context/SmartRoutingAddressContext.ts +48 -0
  82. package/src/context/SmartRoutingAddressProvider.tsx +145 -0
  83. package/src/hooks/useCreateSmartRoutingAddress.ts +28 -0
  84. package/src/hooks/useDepositStatus.ts +110 -0
  85. package/src/hooks/useNewDeposits.ts +25 -0
  86. package/src/hooks/useProviderFees.ts +235 -0
  87. package/src/hooks/useSmartRoutingAddress.ts +25 -0
  88. package/src/iconAssets.ts +130 -0
  89. package/src/index.ts +27 -0
  90. package/src/pages/Deposit.tsx +605 -0
  91. package/src/pages/PastDeposits.tsx +232 -0
  92. package/src/pages/TransactionDetails.tsx +466 -0
  93. package/src/pages/index.tsx +165 -0
  94. package/src/types.ts +84 -0
  95. package/src/utils/chains.ts +26 -0
  96. package/src/utils/config.ts +142 -0
  97. package/src/utils/deposits.ts +106 -0
  98. package/src/utils/fees.ts +51 -0
  99. package/src/utils/format.ts +108 -0
  100. package/src/utils/providerFees.ts +301 -0
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--zd-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--zd-color-gray-700:oklch(37.3% .034 259.733);--zd-color-gray-900:oklch(21% .034 264.665);--zd-color-white:#fff;--zd-spacing:.25rem;--zd-text-sm--line-height:calc(1.25 / .875);--zd-text-base--line-height:calc(1.5 / 1);--zd-text-lg--line-height:calc(1.75 / 1.125);--zd-text-2xl--line-height:calc(2 / 1.5);--zd-font-weight-medium:500;--zd-font-weight-semibold:600;--zd-font-weight-bold:700;--zd-radius-sm:.25rem;--zd-radius-md:.375rem;--zd-radius-lg:.5rem;--zd-radius-xl:.75rem;--zd-radius-2xl:1rem;--zd-radius-3xl:1.5rem;--zd-radius-4xl:2rem;--zd-animate-spin:spin 1s linear infinite;--zd-default-transition-duration:.15s;--zd-default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--zd-default-font-family:sans-serif;--zd-default-mono-font-family:var(--zd-font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--zd-default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--zd-default-font-feature-settings,normal);font-variation-settings:var(--zd-default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--zd-default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--zd-default-mono-font-feature-settings,normal);font-variation-settings:var(--zd-default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.zd\:pointer-events-none{pointer-events:none}.zd\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.zd\:absolute{position:absolute}.zd\:relative{position:relative}.zd\:inset-0{inset:0}.zd\:top-0{top:0}.zd\:top-1\/2{top:50%}.zd\:right-0{right:0}.zd\:right-1{right:var(--zd-spacing)}.zd\:right-3{right:calc(var(--zd-spacing) * 3)}.zd\:bottom-0{bottom:0}.zd\:bottom-1{bottom:var(--zd-spacing)}.zd\:left-0{left:0}.zd\:left-1{left:var(--zd-spacing)}.zd\:left-1\/2{left:50%}.zd\:isolate{isolation:isolate}.zd\:z-0{z-index:0}.zd\:z-10{z-index:10}.zd\:z-20{z-index:20}.zd\:z-50{z-index:50}.zd\:m-1\.5{margin:calc(var(--zd-spacing) * 1.5)}.zd\:-mx-4{margin-inline:calc(var(--zd-spacing) * -4)}.zd\:mx-2{margin-inline:calc(var(--zd-spacing) * 2)}.zd\:my-1{margin-block:var(--zd-spacing)}.zd\:mt-1{margin-top:var(--zd-spacing)}.zd\:mb-2{margin-bottom:calc(var(--zd-spacing) * 2)}.zd\:-ml-4{margin-left:calc(var(--zd-spacing) * -4)}.zd\:block{display:block}.zd\:flex{display:flex}.zd\:inline-block{display:inline-block}.zd\:inline-flex{display:inline-flex}.zd\:size-3{width:calc(var(--zd-spacing) * 3);height:calc(var(--zd-spacing) * 3)}.zd\:size-3\.5{width:calc(var(--zd-spacing) * 3.5);height:calc(var(--zd-spacing) * 3.5)}.zd\:size-4{width:calc(var(--zd-spacing) * 4);height:calc(var(--zd-spacing) * 4)}.zd\:size-5{width:calc(var(--zd-spacing) * 5);height:calc(var(--zd-spacing) * 5)}.zd\:size-8\.5{width:calc(var(--zd-spacing) * 8.5);height:calc(var(--zd-spacing) * 8.5)}.zd\:size-11{width:calc(var(--zd-spacing) * 11);height:calc(var(--zd-spacing) * 11)}.zd\:size-full{width:100%;height:100%}.zd\:h-2\.5{height:calc(var(--zd-spacing) * 2.5)}.zd\:h-3{height:calc(var(--zd-spacing) * 3)}.zd\:h-3\.5{height:calc(var(--zd-spacing) * 3.5)}.zd\:h-4{height:calc(var(--zd-spacing) * 4)}.zd\:h-4\.5{height:calc(var(--zd-spacing) * 4.5)}.zd\:h-5{height:calc(var(--zd-spacing) * 5)}.zd\:h-6{height:calc(var(--zd-spacing) * 6)}.zd\:h-7{height:calc(var(--zd-spacing) * 7)}.zd\:h-9{height:calc(var(--zd-spacing) * 9)}.zd\:h-10{height:calc(var(--zd-spacing) * 10)}.zd\:h-11{height:calc(var(--zd-spacing) * 11)}.zd\:h-12{height:calc(var(--zd-spacing) * 12)}.zd\:h-13{height:calc(var(--zd-spacing) * 13)}.zd\:h-16{height:calc(var(--zd-spacing) * 16)}.zd\:h-17{height:calc(var(--zd-spacing) * 17)}.zd\:h-32{height:calc(var(--zd-spacing) * 32)}.zd\:h-202\.5{height:calc(var(--zd-spacing) * 202.5)}.zd\:h-\[52px\]{height:52px}.zd\:h-\[68px\]{height:68px}.zd\:h-\[84px\]{height:84px}.zd\:h-\[240px\]{height:240px}.zd\:h-full{height:100%}.zd\:h-px{height:1px}.zd\:max-h-80{max-height:calc(var(--zd-spacing) * 80)}.zd\:max-h-full{max-height:100%}.zd\:min-h-0{min-height:0}.zd\:min-h-11{min-height:calc(var(--zd-spacing) * 11)}.zd\:w-2\.5{width:calc(var(--zd-spacing) * 2.5)}.zd\:w-3{width:calc(var(--zd-spacing) * 3)}.zd\:w-3\.5{width:calc(var(--zd-spacing) * 3.5)}.zd\:w-4{width:calc(var(--zd-spacing) * 4)}.zd\:w-5{width:calc(var(--zd-spacing) * 5)}.zd\:w-6{width:calc(var(--zd-spacing) * 6)}.zd\:w-9{width:calc(var(--zd-spacing) * 9)}.zd\:w-10{width:calc(var(--zd-spacing) * 10)}.zd\:w-11{width:calc(var(--zd-spacing) * 11)}.zd\:w-12{width:calc(var(--zd-spacing) * 12)}.zd\:w-13{width:calc(var(--zd-spacing) * 13)}.zd\:w-14{width:calc(var(--zd-spacing) * 14)}.zd\:w-16{width:calc(var(--zd-spacing) * 16)}.zd\:w-20{width:calc(var(--zd-spacing) * 20)}.zd\:w-24{width:calc(var(--zd-spacing) * 24)}.zd\:w-72{width:calc(var(--zd-spacing) * 72)}.zd\:w-80{width:calc(var(--zd-spacing) * 80)}.zd\:w-100{width:calc(var(--zd-spacing) * 100)}.zd\:w-\[52px\]{width:52px}.zd\:w-\[240px\]{width:240px}.zd\:w-auto{width:auto}.zd\:w-full{width:100%}.zd\:w-px{width:1px}.zd\:max-w-\[220px\]{max-width:220px}.zd\:max-w-\[230px\]{max-width:230px}.zd\:max-w-\[300px\]{max-width:300px}.zd\:max-w-full{max-width:100%}.zd\:min-w-0{min-width:0}.zd\:flex-1{flex:1}.zd\:shrink-0{flex-shrink:0}.zd\:-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.zd\:-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.zd\:animate-fee-flash{animation:.42s cubic-bezier(.2,.9,.3,1) both fee-flash}.zd\:animate-skel-pulse{animation:1.1s ease-in-out infinite skel-pulse}.zd\:animate-spin{animation:var(--zd-animate-spin)}.zd\:cursor-help{cursor:help}.zd\:cursor-not-allowed{cursor:not-allowed}.zd\:cursor-pointer{cursor:pointer}.zd\:resize-none{resize:none}.zd\:flex-col{flex-direction:column}.zd\:flex-row{flex-direction:row}.zd\:flex-wrap{flex-wrap:wrap}.zd\:items-center{align-items:center}.zd\:items-end{align-items:flex-end}.zd\:items-start{align-items:flex-start}.zd\:justify-between{justify-content:space-between}.zd\:justify-center{justify-content:center}.zd\:justify-start{justify-content:flex-start}.zd\:gap-1{gap:var(--zd-spacing)}.zd\:gap-1\.5{gap:calc(var(--zd-spacing) * 1.5)}.zd\:gap-2{gap:calc(var(--zd-spacing) * 2)}.zd\:gap-3{gap:calc(var(--zd-spacing) * 3)}.zd\:gap-4{gap:calc(var(--zd-spacing) * 4)}.zd\:gap-6{gap:calc(var(--zd-spacing) * 6)}.zd\:gap-\[5px\]{gap:5px}.zd\:self-end{align-self:flex-end}.zd\:self-start{align-self:flex-start}.zd\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.zd\:overflow-hidden{overflow:hidden}.zd\:overflow-x-hidden{overflow-x:hidden}.zd\:overflow-y-auto{overflow-y:auto}.zd\:rounded-2xl{border-radius:var(--zd-radius-2xl)}.zd\:rounded-3xl{border-radius:var(--zd-radius-3xl)}.zd\:rounded-4xl{border-radius:var(--zd-radius-4xl)}.zd\:rounded-\[4px\]{border-radius:4px}.zd\:rounded-\[14px\]{border-radius:14px}.zd\:rounded-\[32px\]{border-radius:32px}.zd\:rounded-\[38px\]{border-radius:38px}.zd\:rounded-full{border-radius:3.40282e38px}.zd\:rounded-lg{border-radius:var(--zd-radius-lg)}.zd\:rounded-md{border-radius:var(--zd-radius-md)}.zd\:rounded-sm{border-radius:var(--zd-radius-sm)}.zd\:rounded-xl{border-radius:var(--zd-radius-xl)}.zd\:rounded-tl-lg{border-top-left-radius:var(--zd-radius-lg)}.zd\:rounded-tr-lg{border-top-right-radius:var(--zd-radius-lg)}.zd\:rounded-br-lg{border-bottom-right-radius:var(--zd-radius-lg)}.zd\:rounded-bl-lg{border-bottom-left-radius:var(--zd-radius-lg)}.zd\:border{border-style:var(--tw-border-style);border-width:1px}.zd\:border-\[0\.3px\]{border-style:var(--tw-border-style);border-width:.3px}.zd\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.zd\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.zd\:border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.zd\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.zd\:border-greyScale\/10{border-color:oklab(16.9052% .00636494 .00836386/.1)}.zd\:border-greyScale\/30{border-color:oklab(16.9052% .00636494 .00836386/.3)}.zd\:border-offWhite{border-color:#f7f5f0}.zd\:border-white\/0{border-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:border-white\/0{border-color:color-mix(in oklab, var(--zd-color-white) 0%, transparent)}}.zd\:bg-greyScale\/10{background-color:oklab(16.9052% .00636494 .00836386/.1)}.zd\:bg-greyScale\/15{background-color:oklab(16.9052% .00636494 .00836386/.15)}.zd\:bg-greyScale\/20{background-color:oklab(16.9052% .00636494 .00836386/.2)}.zd\:bg-greyScale\/30{background-color:oklab(16.9052% .00636494 .00836386/.3)}.zd\:bg-negative\/10{background-color:oklab(65.8731% .193785 .122031/.1)}.zd\:bg-offWhite\/50{background-color:oklab(97.0302% .000165075 .00696582/.5)}.zd\:bg-orange\/10{background-color:oklab(70.9342% .114827 .116983/.1)}.zd\:bg-positive\/15{background-color:oklab(53.3447% -.133422 .110405/.15)}.zd\:bg-solarOrange{background-color:#e76000}.zd\:bg-solarOrange\/60{background-color:oklab(65.138% .131584 .131685/.6)}.zd\:bg-transparent{background-color:#0000}.zd\:bg-white,.zd\:bg-white\/20{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:bg-white\/20{background-color:color-mix(in oklab, var(--zd-color-white) 20%, transparent)}}.zd\:bg-white\/40{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:bg-white\/40{background-color:color-mix(in oklab, var(--zd-color-white) 40%, transparent)}}.zd\:bg-white\/60{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:bg-white\/60{background-color:color-mix(in oklab, var(--zd-color-white) 60%, transparent)}}.zd\:bg-white\/70{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:bg-white\/70{background-color:color-mix(in oklab, var(--zd-color-white) 70%, transparent)}}.zd\:object-contain{object-fit:contain}.zd\:object-cover{object-fit:cover}.zd\:p-0{padding:0}.zd\:p-1{padding:var(--zd-spacing)}.zd\:p-1\.5{padding:calc(var(--zd-spacing) * 1.5)}.zd\:p-2{padding:calc(var(--zd-spacing) * 2)}.zd\:p-4{padding:calc(var(--zd-spacing) * 4)}.zd\:p-5{padding:calc(var(--zd-spacing) * 5)}.zd\:p-6{padding:calc(var(--zd-spacing) * 6)}.zd\:p-px{padding:1px}.zd\:px-0{padding-inline:0}.zd\:px-1{padding-inline:var(--zd-spacing)}.zd\:px-2{padding-inline:calc(var(--zd-spacing) * 2)}.zd\:px-3{padding-inline:calc(var(--zd-spacing) * 3)}.zd\:px-4{padding-inline:calc(var(--zd-spacing) * 4)}.zd\:px-5{padding-inline:calc(var(--zd-spacing) * 5)}.zd\:px-6{padding-inline:calc(var(--zd-spacing) * 6)}.zd\:py-1{padding-block:var(--zd-spacing)}.zd\:py-1\.5{padding-block:calc(var(--zd-spacing) * 1.5)}.zd\:py-2{padding-block:calc(var(--zd-spacing) * 2)}.zd\:py-3{padding-block:calc(var(--zd-spacing) * 3)}.zd\:py-3\.5{padding-block:calc(var(--zd-spacing) * 3.5)}.zd\:py-4{padding-block:calc(var(--zd-spacing) * 4)}.zd\:py-5{padding-block:calc(var(--zd-spacing) * 5)}.zd\:py-8{padding-block:calc(var(--zd-spacing) * 8)}.zd\:pt-0\.5{padding-top:calc(var(--zd-spacing) * .5)}.zd\:pt-4{padding-top:calc(var(--zd-spacing) * 4)}.zd\:pt-6{padding-top:calc(var(--zd-spacing) * 6)}.zd\:pr-1{padding-right:var(--zd-spacing)}.zd\:pr-2{padding-right:calc(var(--zd-spacing) * 2)}.zd\:pb-3{padding-bottom:calc(var(--zd-spacing) * 3)}.zd\:pb-4{padding-bottom:calc(var(--zd-spacing) * 4)}.zd\:pb-6{padding-bottom:calc(var(--zd-spacing) * 6)}.zd\:pl-1{padding-left:var(--zd-spacing)}.zd\:pl-2{padding-left:calc(var(--zd-spacing) * 2)}.zd\:pl-4{padding-left:calc(var(--zd-spacing) * 4)}.zd\:text-center{text-align:center}.zd\:text-left{text-align:left}.zd\:font-roboto{font-family:Roboto,sans-serif}.zd\:font-sans{font-family:sans-serif}.zd\:text-2xl{font-size:calc(20px * var(--zd-density));line-height:var(--tw-leading,var(--zd-text-2xl--line-height))}.zd\:text-base{font-size:calc(14px * var(--zd-density));line-height:var(--tw-leading,var(--zd-text-base--line-height))}.zd\:text-body1{font-size:calc(16px * var(--zd-density));line-height:var(--tw-leading,130%)}.zd\:text-body2{font-size:calc(14px * var(--zd-density));line-height:var(--tw-leading,130%)}.zd\:text-body3{font-size:calc(12px * var(--zd-density));line-height:var(--tw-leading,130%)}.zd\:text-body4{font-size:calc(10px * var(--zd-density));line-height:var(--tw-leading,130%)}.zd\:text-h1{font-size:calc(42px * var(--zd-density));line-height:var(--tw-leading,110%)}.zd\:text-h2{font-size:calc(28px * var(--zd-density));line-height:var(--tw-leading,110%)}.zd\:text-h3{font-size:calc(18px * var(--zd-density));line-height:var(--tw-leading,130%)}.zd\:text-lg{font-size:calc(16px * var(--zd-density));line-height:var(--tw-leading,var(--zd-text-lg--line-height))}.zd\:text-sm{font-size:calc(12px * var(--zd-density));line-height:var(--tw-leading,var(--zd-text-sm--line-height))}.zd\:leading-none{--tw-leading:1;line-height:1}.zd\:font-bold{--tw-font-weight:var(--zd-font-weight-bold);font-weight:var(--zd-font-weight-bold)}.zd\:font-medium{--tw-font-weight:var(--zd-font-weight-medium);font-weight:var(--zd-font-weight-medium)}.zd\:font-semibold{--tw-font-weight:var(--zd-font-weight-semibold);font-weight:var(--zd-font-weight-semibold)}.zd\:break-all{word-break:break-all}.zd\:whitespace-nowrap{white-space:nowrap}.zd\:text-gray-700{color:var(--zd-color-gray-700)}.zd\:text-gray-900{color:var(--zd-color-gray-900)}.zd\:text-greyScale{color:#130e0b}.zd\:text-greyScale\/50{color:oklab(16.9052% .00636494 .00836386/.5)}.zd\:text-greyScale\/60{color:oklab(16.9052% .00636494 .00836386/.6)}.zd\:text-greyScale\/70{color:oklab(16.9052% .00636494 .00836386/.7)}.zd\:text-greyScale\/90{color:oklab(16.9052% .00636494 .00836386/.9)}.zd\:text-negative{color:#ff4221}.zd\:text-orange{color:#f27b3e}.zd\:text-positive{color:#228300}.zd\:text-solarOrange{color:#e76000}.zd\:text-white{color:var(--zd-color-white)}.zd\:caret-gray-900{caret-color:var(--zd-color-gray-900)}.zd\:opacity-50{opacity:.5}.zd\:shadow-\[0_8px_22px_-10px_rgba\(25\,17\,11\,0\.45\)\]{--tw-shadow:0 8px 22px -10px var(--tw-shadow-color,#19110b73);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.zd\:shadow-\[inset_0_-4px_4px_0_rgba\(255\,255\,255\,0\.1\)\,inset_0_3px_4px_0_rgba\(0\,0\,0\,0\.02\)\],.zd\:shadow-\[inset_0_-4px_4px_0_rgba\(255\,255\,255\,0\.10\)\,inset_0_3px_4px_0_rgba\(0\,0\,0\,0\.02\)\]{--tw-shadow:inset 0 -4px 4px 0 var(--tw-shadow-color,#ffffff1a), inset 0 3px 4px 0 var(--tw-shadow-color,#00000005);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.zd\:shadow-\[inset_0_3px_4px_0_rgba\(0\,0\,0\,0\.02\)\,inset_0_-4px_4px_0_rgba\(255\,255\,255\,0\.1\)\]{--tw-shadow:inset 0 3px 4px 0 var(--tw-shadow-color,#00000005), inset 0 -4px 4px 0 var(--tw-shadow-color,#ffffff1a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.zd\:shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.zd\:backdrop-blur-\[15px\]{--tw-backdrop-blur:blur(15px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.zd\:backdrop-blur-\[30px\]{--tw-backdrop-blur:blur(30px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.zd\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--zd-default-transition-timing-function));transition-duration:var(--tw-duration,var(--zd-default-transition-duration))}.zd\:outline-none{--tw-outline-style:none;outline-style:none}.zd\:placeholder\:text-gray-900\/50::placeholder{color:var(--zd-color-gray-900)}@supports (color:color-mix(in lab, red, red)){.zd\:placeholder\:text-gray-900\/50::placeholder{color:color-mix(in oklab, var(--zd-color-gray-900) 50%, transparent)}}@media (hover:hover){.zd\:hover\:bg-negative\/20:hover{background-color:oklab(65.8731% .193785 .122031/.2)}.zd\:hover\:bg-offWhite\/40:hover{background-color:oklab(97.0302% .000165075 .00696582/.4)}.zd\:hover\:bg-white\/5:hover{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:hover\:bg-white\/5:hover{background-color:color-mix(in oklab, var(--zd-color-white) 5%, transparent)}}.zd\:hover\:bg-white\/20:hover{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:hover\:bg-white\/20:hover{background-color:color-mix(in oklab, var(--zd-color-white) 20%, transparent)}}.zd\:hover\:bg-white\/30:hover{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:hover\:bg-white\/30:hover{background-color:color-mix(in oklab, var(--zd-color-white) 30%, transparent)}}.zd\:hover\:bg-white\/40:hover{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:hover\:bg-white\/40:hover{background-color:color-mix(in oklab, var(--zd-color-white) 40%, transparent)}}.zd\:hover\:text-greyScale:hover{color:#130e0b}.zd\:hover\:text-solarOrange:hover{color:#e76000}.zd\:hover\:underline:hover{text-decoration-line:underline}}.zd\:active\:bg-white\/10:active{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:active\:bg-white\/10:active{background-color:color-mix(in oklab, var(--zd-color-white) 10%, transparent)}}.zd\:active\:bg-white\/30:active{background-color:var(--zd-color-white)}@supports (color:color-mix(in lab, red, red)){.zd\:active\:bg-white\/30:active{background-color:color-mix(in oklab, var(--zd-color-white) 30%, transparent)}}.zd\:disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.zd\:disabled\:opacity-50:disabled{opacity:.5}.zd\:data-\[highlighted\]\:bg-offWhite\/40[data-highlighted]{background-color:oklab(97.0302% .000165075 .00696582/.4)}.zd\:data-\[state\=checked\]\:bg-offWhite\/60[data-state=checked]{background-color:oklab(97.0302% .000165075 .00696582/.6)}.zd\:data-\[state\=closed\]\:animate-backdrop-out[data-state=closed]{animation:.2s ease-out forwards backdrop-out}.zd\:data-\[state\=closed\]\:animate-sheet-out[data-state=closed]{animation:.25s cubic-bezier(.32,.72,0,1) forwards sheet-out}.zd\:data-\[state\=delayed-open\]\:animate-popper-in[data-state=delayed-open]{animation:.16s ease-out both popper-in}.zd\:data-\[state\=open\]\:pointer-events-auto[data-state=open]{pointer-events:auto}.zd\:data-\[state\=open\]\:animate-backdrop-in[data-state=open]{animation:.2s ease-out forwards backdrop-in}.zd\:data-\[state\=open\]\:animate-popper-in[data-state=open]{animation:.16s ease-out both popper-in}.zd\:data-\[state\=open\]\:animate-sheet-in[data-state=open]{animation:.3s cubic-bezier(.32,.72,0,1) forwards sheet-in}}:root{--zd-density:1}[data-zd-size]{--zd-spacing:calc(.25rem * var(--zd-density))}[data-zd-size=sm]{--zd-density:.8}[data-zd-size=md]{--zd-density:.9}[data-zd-size=lg]{--zd-density:1}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes sheet-in{0%{transform:translateY(100%)}to{transform:translateY(0)}}@keyframes sheet-out{0%{transform:translateY(0)}to{transform:translateY(100%)}}@keyframes backdrop-in{0%{opacity:0}to{opacity:1}}@keyframes backdrop-out{0%{opacity:1}to{opacity:0}}@keyframes skel-pulse{0%,to{opacity:.65}50%{opacity:1}}@keyframes popper-in{0%{opacity:0;transform:scale(.97)translateY(-3px)}to{opacity:1;transform:scale(1)translateY(0)}}@keyframes fee-flash{0%{opacity:0;transform:translateY(-3px)scale(.96)}to{opacity:1;transform:none}}
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@zerodev/smart-routing-address-react-ui",
3
+ "version": "0.0.1",
4
+ "description": "React hooks, provider, and UI for ZeroDev Smart Routing Address deposits",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/zerodevapp/zerodev-wallet-sdk.git",
8
+ "directory": "packages/smart-routing-address-react-ui"
9
+ },
10
+ "sideEffects": [
11
+ "**/*.css"
12
+ ],
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.mjs",
15
+ "types": "./dist/_types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/_types/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.cjs"
21
+ },
22
+ "./styles.css": "./dist/styles.css"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "src/**/*.ts",
27
+ "src/**/*.tsx",
28
+ "!dist/**/*.tsbuildinfo",
29
+ "!src/**/*.test.ts",
30
+ "!src/**/*.test.tsx",
31
+ "!src/**/*.stories.ts",
32
+ "!src/**/*.stories.tsx",
33
+ "!src/test/**"
34
+ ],
35
+ "keywords": [
36
+ "react",
37
+ "hooks",
38
+ "components",
39
+ "smart-routing",
40
+ "deposit",
41
+ "zerodev",
42
+ "web3"
43
+ ],
44
+ "dependencies": {
45
+ "@zerodev/smart-routing-address": "^0.2.5",
46
+ "uqr": "^0.1.2",
47
+ "zod": "^4.4.3",
48
+ "@zerodev/react-ui": "0.0.5"
49
+ },
50
+ "peerDependencies": {
51
+ "react": "^18.0.0 || ^19.0.0",
52
+ "react-dom": "^18.0.0 || ^19.0.0",
53
+ "viem": "^2.47.18"
54
+ },
55
+ "devDependencies": {
56
+ "@storybook/addon-a11y": "^10.3.3",
57
+ "@storybook/addon-docs": "^10.3.3",
58
+ "@storybook/react-vite": "^10.3.3",
59
+ "@tailwindcss/cli": "^4.2.2",
60
+ "@tailwindcss/postcss": "^4.2.2",
61
+ "@testing-library/react": "^16.3.0",
62
+ "@types/react": "~19.2.14",
63
+ "@types/react-dom": "^19",
64
+ "@vitejs/plugin-react": "^4.7.0",
65
+ "@vitest/coverage-v8": "^4.0.18",
66
+ "happy-dom": "^20.6.0",
67
+ "postcss": "^8.5.8",
68
+ "react": "19.2.0",
69
+ "react-dom": "19.2.0",
70
+ "storybook": "^10.3.3",
71
+ "tailwindcss": "^4.2.2",
72
+ "typescript": "5.9.3",
73
+ "viem": "^2.47.18",
74
+ "vite": "^6.4.1",
75
+ "vitest": "^4.0.18"
76
+ },
77
+ "scripts": {
78
+ "build": "pnpm run clean && pnpm run build:css && pnpm run build:js && pnpm run build:types",
79
+ "build:css": "npx @tailwindcss/cli -i ./src/styles.css -o ./dist/styles.css --minify",
80
+ "build:js": "vite build",
81
+ "build:types": "tsc --project ./tsconfig.build.json --outDir ./dist/_types --emitDeclarationOnly --declaration --declarationMap",
82
+ "dev": "tsc --watch",
83
+ "dev:css": "npx @tailwindcss/cli -i ./src/styles.css -o ./dist/styles.css --watch",
84
+ "typecheck": "tsc --noEmit --project ./tsconfig.build.json",
85
+ "clean": "rm -rf dist",
86
+ "test": "vitest run",
87
+ "test:watch": "vitest",
88
+ "storybook": "storybook dev -p 6008",
89
+ "build-storybook": "storybook build"
90
+ }
91
+ }
@@ -0,0 +1,108 @@
1
+ import { cn, Icon, Text, Wrapper } from '@zerodev/react-ui'
2
+ import type { AddressState } from '../../types'
3
+ import { LoadingCard } from '../LoadingCard'
4
+
5
+ /**
6
+ * The card that renders the deposit address in the SRA "Deposit funds" screen.
7
+ *
8
+ * Two visual states, each mapped 1:1 to a Figma node:
9
+ * - Loading (Figma 17634:104343, "Smart Funding" card): delegates to
10
+ * `LoadingCard`, which is the shared spinner+text pill used elsewhere in
11
+ * the SRA flow (e.g., SmartFunding's "Watching for deposit" state).
12
+ * - Ready (Figma 17762:78875, address+QR row): 14px radius, 40% offWhite
13
+ * surface, left-aligned address text + a 52×52 white QR button on the
14
+ * right. Rendered when `address` is supplied.
15
+ *
16
+ * The two states have deliberately different visuals; they share this
17
+ * component because the parent renders the same slot in both cases.
18
+ */
19
+ export interface AddressDisplayUIProps {
20
+ /** Deposit address to render; when omitted, the loading variant is shown. */
21
+ address?: string
22
+ /**
23
+ * Message rendered in the loading variant. Include chain-specific context
24
+ * from the caller, e.g., `Watching for your deposit on Base…`.
25
+ */
26
+ loadingText?: string
27
+ /** Handler for the QR icon button (ready variant). */
28
+ onQrClick?: (() => void) | undefined
29
+ className?: string
30
+ }
31
+
32
+ export function AddressDisplayUI({
33
+ address,
34
+ loadingText = 'Watching for your deposit…',
35
+ onQrClick,
36
+ className,
37
+ }: AddressDisplayUIProps) {
38
+ if (address === undefined) {
39
+ return (
40
+ <LoadingCard
41
+ text={loadingText}
42
+ className={className}
43
+ data-testid="address-display-loading"
44
+ />
45
+ )
46
+ }
47
+
48
+ return (
49
+ <Wrapper
50
+ variant="ghost"
51
+ // Figma's 40% offWhite surface — none of Wrapper's white-only variants
52
+ // hit this tint, so override the backgroundColor. Inline style wins
53
+ // over Wrapper's own style prop.
54
+ style={{ backgroundColor: 'rgba(247, 245, 240, 0.4)' }}
55
+ className={cn(
56
+ // Figma: rounded-[14px], pl-16 pr-8 py-8, gap-12 items-center.
57
+ // Height pinned to 68px so the loading and ready variants swap without
58
+ // the layout jumping.
59
+ 'zd:relative zd:flex zd:h-[68px] zd:w-full zd:items-center zd:gap-3 zd:overflow-hidden zd:rounded-[14px] zd:pl-4 zd:pr-2 zd:py-2',
60
+ 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',
61
+ className,
62
+ )}
63
+ data-testid="address-display-ready"
64
+ >
65
+ <Text
66
+ className="zd:min-w-0 zd:flex-1 zd:break-all zd:text-body2"
67
+ data-testid="address-display-address"
68
+ >
69
+ {address}
70
+ </Text>
71
+ <button
72
+ type="button"
73
+ onClick={onQrClick}
74
+ aria-label="Show QR code"
75
+ className="zd:flex zd:w-13 zd:h-13 zd:shrink-0 zd:cursor-pointer zd:items-center zd:justify-center zd:rounded-2xl zd:bg-white"
76
+ data-testid="address-display-qr-button"
77
+ >
78
+ <Icon name="qrCode" className="zd:w-5 zd:h-5 zd:text-greyScale" />
79
+ </button>
80
+ </Wrapper>
81
+ )
82
+ }
83
+
84
+ export interface AddressDisplayProps {
85
+ /** Current address-generation state from the SRA context. */
86
+ status: AddressState['status']
87
+ /** Deposit address, present when `status === 'success'`. */
88
+ address?: string | undefined
89
+ /** Handler for the QR icon button (only meaningful once `address` resolves). */
90
+ onQrClick?: (() => void) | undefined
91
+ }
92
+
93
+ /**
94
+ * State-driven wrapper around `AddressDisplayUI`. Picks the right variant
95
+ * (loading / ready) based on the SRA address-generation status; the parent
96
+ * page renders `ErrorRetryCard` in the error case instead of this component.
97
+ */
98
+ export function AddressDisplay({
99
+ status,
100
+ address,
101
+ onQrClick,
102
+ }: AddressDisplayProps) {
103
+ if (status === 'error') return null
104
+ if (status === 'success' && address !== undefined) {
105
+ return <AddressDisplayUI address={address} onQrClick={onQrClick} />
106
+ }
107
+ return <AddressDisplayUI loadingText="Generating deposit address…" />
108
+ }
@@ -0,0 +1,68 @@
1
+ import { cn, Icon, Text } from '@zerodev/react-ui'
2
+
3
+ export interface ErrorRetryCardProps {
4
+ /** Error copy shown on the left side, e.g. "Failed to create deposit
5
+ * address…" — kept short (Figma design truncates on one line). */
6
+ message: string
7
+ /** Called when the user clicks the refresh affordance. */
8
+ onRetry: () => void
9
+ /** Marks the button as busy while a retry is in flight — disables clicks
10
+ * and spins the icon so back-to-back taps don't stack requests. */
11
+ busy?: boolean
12
+ /** Accessible label for the icon-only refresh button. Defaults to "Retry". */
13
+ retryLabel?: string
14
+ className?: string
15
+ }
16
+
17
+ /**
18
+ * Error banner with an inline retry affordance. Renders as a compact pill
19
+ * matching the Figma spec (`bg-negative/10`, error-red text, right-hand
20
+ * 52×52 refresh button). Used above the "Min deposit" row in the deposit UI
21
+ * to surface address-creation, empty-route and polling failures.
22
+ */
23
+ export function ErrorRetryCard({
24
+ message,
25
+ onRetry,
26
+ busy,
27
+ retryLabel = 'Retry',
28
+ className,
29
+ }: ErrorRetryCardProps) {
30
+ return (
31
+ <div
32
+ role="alert"
33
+ className={cn(
34
+ 'zd:relative zd:flex zd:w-full zd:items-center zd:justify-center zd:gap-3',
35
+ 'zd:overflow-hidden zd:rounded-[14px] zd:border-[0.3px] zd:border-offWhite',
36
+ 'zd:bg-negative/10 zd:backdrop-blur-[15px] zd:py-2 zd:pr-2 zd:pl-4',
37
+ 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',
38
+ className,
39
+ )}
40
+ >
41
+ <Text className="zd:flex-1 zd:min-w-0 zd:text-body1 zd:font-medium zd:text-negative">
42
+ {message}
43
+ </Text>
44
+ <button
45
+ type="button"
46
+ onClick={onRetry}
47
+ disabled={busy}
48
+ aria-label={retryLabel}
49
+ aria-busy={busy}
50
+ className={cn(
51
+ 'zd:inline-flex zd:h-[52px] zd:w-[52px] zd:shrink-0 zd:items-center zd:justify-center',
52
+ 'zd:rounded-2xl zd:bg-negative/10 zd:text-negative zd:cursor-pointer',
53
+ 'zd:transition-colors zd:hover:bg-negative/20',
54
+ 'zd:disabled:cursor-not-allowed zd:disabled:opacity-50',
55
+ )}
56
+ >
57
+ <Icon
58
+ name="rotateRight"
59
+ className={cn(
60
+ 'zd:h-6 zd:w-6 zd:text-negative',
61
+ busy && 'zd:animate-spin',
62
+ )}
63
+ aria-hidden
64
+ />
65
+ </button>
66
+ </div>
67
+ )
68
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Plain-language explanations for each fee/route line, surfaced as tooltips
3
+ * on the info icons in the fee section so users understand what they're
4
+ * charged.
5
+ */
6
+ export const FEE_INFO = {
7
+ minDeposit: 'Smallest amount this route can process after fees.',
8
+ maxSlippage: 'Maximum price movement allowed during the swap.',
9
+ estimatedFee: 'Estimated swap, bridge, and network costs.',
10
+ readyIn: 'Estimated arrival after the deposit is detected.',
11
+ // Breakdown legs
12
+ provider: 'Bridge provider selected for this route.',
13
+ execution: 'Cost to execute and deliver funds on the destination chain.',
14
+ capital: 'Relayer cost for fronting capital while bridging.',
15
+ destGas: 'Gas to complete delivery on the destination chain.',
16
+ lp: 'Bridge liquidity-provider fee.',
17
+ service: 'Solver fee for filling the route.',
18
+ originGas: 'Gas to submit from the source chain.',
19
+ app: 'Optional application fee.',
20
+ // Transaction progress steps (transaction-details view)
21
+ detected: 'Deposit detected on the source chain.',
22
+ routing: 'Bridge and swap are in progress.',
23
+ completed: 'Funds arrived in the delivery account.',
24
+ failed: 'Deposit could not be completed.',
25
+ } as const
@@ -0,0 +1,218 @@
1
+ import { cn, Icon, Text, Tooltip } from '@zerodev/react-ui'
2
+ import type { ReactNode } from 'react'
3
+ import { PROVIDER_ICONS } from '../../iconAssets'
4
+ import type { FeeBreakdown, FeeLine } from '../../utils/providerFees'
5
+ import { formatFeePct, formatFeeUsd } from '../../utils/providerFees'
6
+ import { FEE_INFO } from './feeInfo'
7
+
8
+ /** Home pages for supported providers, so the name links out */
9
+ const PROVIDER_URLS: Record<string, string> = {
10
+ Across: 'https://across.to',
11
+ Relay: 'https://relay.link',
12
+ }
13
+
14
+ export type LiveValueProps = {
15
+ /** While true, the value is being re-quoted: show a spinner */
16
+ loading: boolean
17
+ /** Changes with the value so the flash-in animation re-triggers */
18
+ flashKey: string | number
19
+ children: ReactNode
20
+ }
21
+
22
+ /**
23
+ * A value that swaps to a spinner while its route is re-quoting, then flashes
24
+ * the fresh value in. Used so a route change visibly recalculates the min
25
+ * deposit / estimated fee rather than silently snapping to new numbers.
26
+ */
27
+ export function LiveValue({ loading, flashKey, children }: LiveValueProps) {
28
+ if (loading) {
29
+ return (
30
+ <span
31
+ className="zd:inline-flex zd:items-center zd:justify-center zd:text-orange"
32
+ role="img"
33
+ aria-label="Updating estimate"
34
+ >
35
+ <Icon
36
+ name="loading"
37
+ className="zd:w-3.5 zd:h-3.5 zd:animate-spin zd:text-orange"
38
+ aria-hidden
39
+ />
40
+ </span>
41
+ )
42
+ }
43
+ return (
44
+ <span
45
+ key={flashKey}
46
+ className="zd:inline-flex zd:items-center zd:gap-1.5 zd:animate-fee-flash"
47
+ >
48
+ {children}
49
+ </span>
50
+ )
51
+ }
52
+
53
+ /** Combined fee value: proportional rate (emphasised) + fixed USD cost */
54
+ export function FeeSummary({ breakdown }: { breakdown: FeeBreakdown }) {
55
+ // When the SRA fee can't be priced in USD (non-stable token), show it as a
56
+ // token amount — the partial USD bridge legs must not headline as the total.
57
+ if (breakdown.totalText) {
58
+ return (
59
+ <Text className="zd:whitespace-nowrap zd:font-medium">
60
+ {breakdown.totalText}
61
+ </Text>
62
+ )
63
+ }
64
+ const pct =
65
+ breakdown.ratePct !== null && breakdown.ratePct > 0
66
+ ? formatFeePct(breakdown.ratePct)
67
+ : null
68
+ const usd =
69
+ breakdown.flatUsd !== null ? formatFeeUsd(breakdown.flatUsd) : null
70
+ if (!pct && !usd) {
71
+ return <Text className="zd:whitespace-nowrap">—</Text>
72
+ }
73
+ return (
74
+ <span className="zd:inline-flex zd:items-center zd:gap-1 zd:leading-none">
75
+ {pct && (
76
+ <b className="zd:text-body2 zd:font-bold zd:text-greyScale zd:leading-none">
77
+ {pct}
78
+ </b>
79
+ )}
80
+ {pct && usd && (
81
+ <span className="zd:text-body2 zd:text-greyScale/50 zd:leading-none">
82
+ +
83
+ </span>
84
+ )}
85
+ {usd && (
86
+ <span className="zd:text-body2 zd:font-medium zd:text-greyScale/70 zd:leading-none">
87
+ {usd}
88
+ </span>
89
+ )}
90
+ </span>
91
+ )
92
+ }
93
+
94
+ /** Provider name + brand icon, linked to the provider's site when known */
95
+ export function ProviderValue({ provider }: { provider: string }) {
96
+ const url = PROVIDER_URLS[provider]
97
+ const iconUrl = PROVIDER_ICONS[provider]
98
+ const inner = (
99
+ <>
100
+ <Text className="zd:whitespace-nowrap zd:font-medium">{provider}</Text>
101
+ {iconUrl && (
102
+ <img
103
+ src={iconUrl}
104
+ alt=""
105
+ aria-hidden
106
+ className="zd:size-3.5 zd:shrink-0 zd:rounded-[4px] zd:object-cover"
107
+ />
108
+ )}
109
+ </>
110
+ )
111
+ if (!url) {
112
+ return (
113
+ <span className="zd:inline-flex zd:items-center zd:gap-1">{inner}</span>
114
+ )
115
+ }
116
+ return (
117
+ <a
118
+ className="zd:inline-flex zd:items-center zd:gap-1 zd:text-greyScale zd:hover:underline"
119
+ href={url}
120
+ target="_blank"
121
+ rel="noreferrer"
122
+ >
123
+ {inner}
124
+ </a>
125
+ )
126
+ }
127
+
128
+ function InfoMark({ info }: { info: string }) {
129
+ // Real DOM element so Radix's `Tooltip` (via `asChild`) can attach hover /
130
+ // focus handlers and wire `aria-describedby` to its content. Focusable so
131
+ // keyboard users can trigger the tooltip.
132
+ return (
133
+ <Tooltip content={info}>
134
+ {/* button (not span+tabIndex): natively focusable, so keyboard users
135
+ can trigger the tooltip; Radix wires aria-describedby to the
136
+ tooltip copy on hover / focus. `type="button"` keeps it inert
137
+ inside forms. */}
138
+ <button
139
+ type="button"
140
+ aria-label="More info"
141
+ className="zd:inline-flex zd:items-center zd:justify-center zd:cursor-help zd:outline-none zd:bg-transparent"
142
+ >
143
+ <Icon
144
+ name="info"
145
+ className="zd:w-3 zd:h-3 zd:text-greyScale/50"
146
+ aria-hidden
147
+ />
148
+ </button>
149
+ </Tooltip>
150
+ )
151
+ }
152
+
153
+ function LineValue({ line }: { line: FeeLine }) {
154
+ if (line.sponsored) {
155
+ return (
156
+ <Text className="zd:whitespace-nowrap zd:font-medium">Sponsored</Text>
157
+ )
158
+ }
159
+ // Rates are amount-invariant → show percent; flat costs → show USD; fall
160
+ // back to a raw token amount when neither is available.
161
+ const value =
162
+ line.kind === 'rate' && line.pct !== null
163
+ ? formatFeePct(line.pct)
164
+ : line.usd !== null
165
+ ? formatFeeUsd(line.usd)
166
+ : line.pct !== null
167
+ ? formatFeePct(line.pct)
168
+ : (line.text ?? '—')
169
+ return <Text className="zd:whitespace-nowrap zd:font-medium">{value}</Text>
170
+ }
171
+
172
+ function BreakdownRow({
173
+ label,
174
+ info,
175
+ children,
176
+ className,
177
+ }: {
178
+ label: string
179
+ info?: string
180
+ children: ReactNode
181
+ className?: string
182
+ }) {
183
+ return (
184
+ <div
185
+ className={cn(
186
+ 'zd:flex zd:w-full zd:items-center zd:gap-1 zd:py-1',
187
+ className,
188
+ )}
189
+ >
190
+ <Text className="zd:whitespace-nowrap zd:text-greyScale/60">{label}</Text>
191
+ {info && <InfoMark info={info} />}
192
+ <div className="zd:min-w-0 zd:flex-1" />
193
+ {children}
194
+ </div>
195
+ )
196
+ }
197
+
198
+ /** Itemised fee rows: provider + each fee leg */
199
+ export function FeeBreakdownRows({ breakdown }: { breakdown: FeeBreakdown }) {
200
+ return (
201
+ <div className="zd:flex zd:w-full zd:flex-col zd:pl-2">
202
+ {breakdown.provider && (
203
+ <BreakdownRow label="Provider" info={FEE_INFO.provider}>
204
+ <ProviderValue provider={breakdown.provider} />
205
+ </BreakdownRow>
206
+ )}
207
+ {breakdown.lines.map((line) => (
208
+ <BreakdownRow
209
+ key={line.key}
210
+ label={line.label}
211
+ info={FEE_INFO[line.key as keyof typeof FEE_INFO]}
212
+ >
213
+ <LineValue line={line} />
214
+ </BreakdownRow>
215
+ ))}
216
+ </div>
217
+ )
218
+ }
@@ -0,0 +1,27 @@
1
+ import { cn, Icon, Text, Wrapper } from '@zerodev/react-ui'
2
+ import type { HTMLAttributes } from 'react'
3
+
4
+ export interface LoadingCardProps extends HTMLAttributes<HTMLDivElement> {
5
+ text: string
6
+ }
7
+
8
+ export function LoadingCard({ text, className, ...rest }: LoadingCardProps) {
9
+ return (
10
+ <Wrapper
11
+ variant="ghost"
12
+ className={cn(
13
+ 'zd:relative zd:flex zd:h-[68px] zd:w-full zd:items-center zd:justify-start zd:gap-2 zd:overflow-hidden zd:rounded-2xl zd:px-4',
14
+ 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',
15
+ className,
16
+ )}
17
+ {...rest}
18
+ >
19
+ <Icon
20
+ name="loading"
21
+ className="zd:w-4 zd:h-4 zd:animate-spin zd:text-orange"
22
+ data-testid="loading-card-icon"
23
+ />
24
+ <Text className="zd:text-body1 zd:text-greyScale/50">{text}</Text>
25
+ </Wrapper>
26
+ )
27
+ }