@zerodev/react-ui 0.0.3 → 0.0.4

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 (69) hide show
  1. package/dist/_types/components/ArrowCardPair/index.d.ts +2 -2
  2. package/dist/_types/components/ArrowCardPair/index.d.ts.map +1 -1
  3. package/dist/_types/components/Badge/index.d.ts +1 -1
  4. package/dist/_types/components/Badge/index.d.ts.map +1 -1
  5. package/dist/_types/components/BottomSheet/index.d.ts +17 -0
  6. package/dist/_types/components/BottomSheet/index.d.ts.map +1 -0
  7. package/dist/_types/components/Button/index.d.ts +1 -1
  8. package/dist/_types/components/Button/index.d.ts.map +1 -1
  9. package/dist/_types/components/Callout/index.d.ts +1 -1
  10. package/dist/_types/components/Callout/index.d.ts.map +1 -1
  11. package/dist/_types/components/DataRow/index.d.ts +2 -2
  12. package/dist/_types/components/DataRow/index.d.ts.map +1 -1
  13. package/dist/_types/components/Icon/index.d.ts +1 -1
  14. package/dist/_types/components/Icon/index.d.ts.map +1 -1
  15. package/dist/_types/components/IconButton/index.d.ts +1 -1
  16. package/dist/_types/components/IconButton/index.d.ts.map +1 -1
  17. package/dist/_types/components/Input/index.d.ts +1 -1
  18. package/dist/_types/components/Input/index.d.ts.map +1 -1
  19. package/dist/_types/components/ListItem/index.d.ts +32 -15
  20. package/dist/_types/components/ListItem/index.d.ts.map +1 -1
  21. package/dist/_types/components/Pill/index.d.ts +25 -0
  22. package/dist/_types/components/Pill/index.d.ts.map +1 -0
  23. package/dist/_types/components/PoweredBy/index.d.ts +6 -0
  24. package/dist/_types/components/PoweredBy/index.d.ts.map +1 -0
  25. package/dist/_types/components/Screen/EllipticalRadial.d.ts +23 -0
  26. package/dist/_types/components/Screen/EllipticalRadial.d.ts.map +1 -0
  27. package/dist/_types/components/Screen/MultiRadialBackground.d.ts +4 -0
  28. package/dist/_types/components/Screen/MultiRadialBackground.d.ts.map +1 -0
  29. package/dist/_types/components/Screen/index.d.ts +15 -0
  30. package/dist/_types/components/Screen/index.d.ts.map +1 -0
  31. package/dist/_types/components/Select/index.d.ts +28 -0
  32. package/dist/_types/components/Select/index.d.ts.map +1 -0
  33. package/dist/_types/components/Switch/index.d.ts +1 -1
  34. package/dist/_types/components/Switch/index.d.ts.map +1 -1
  35. package/dist/_types/components/Text/index.d.ts +1 -1
  36. package/dist/_types/components/Text/index.d.ts.map +1 -1
  37. package/dist/_types/components/TokenListItem/index.d.ts +33 -0
  38. package/dist/_types/components/TokenListItem/index.d.ts.map +1 -0
  39. package/dist/_types/components/TopNav/index.d.ts +20 -0
  40. package/dist/_types/components/TopNav/index.d.ts.map +1 -0
  41. package/dist/_types/components/WrappedPressable/index.d.ts +1 -1
  42. package/dist/_types/components/WrappedPressable/index.d.ts.map +1 -1
  43. package/dist/_types/components/Wrapper/index.d.ts +3 -2
  44. package/dist/_types/components/Wrapper/index.d.ts.map +1 -1
  45. package/dist/_types/components/ZeroDevLogo/index.d.ts +1 -1
  46. package/dist/_types/components/ZeroDevLogo/index.d.ts.map +1 -1
  47. package/dist/_types/index.d.ts +8 -1
  48. package/dist/_types/index.d.ts.map +1 -1
  49. package/dist/index.cjs +51 -7
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.mjs +6035 -1344
  52. package/dist/index.mjs.map +1 -1
  53. package/dist/styles.css +2 -2
  54. package/package.json +7 -5
  55. package/src/components/ArrowCardPair/index.tsx +25 -5
  56. package/src/components/BottomSheet/index.tsx +57 -0
  57. package/src/components/DataRow/index.tsx +2 -2
  58. package/src/components/ListItem/index.tsx +74 -79
  59. package/src/components/Pill/index.tsx +167 -0
  60. package/src/components/PoweredBy/index.tsx +29 -0
  61. package/src/components/Screen/EllipticalRadial.tsx +65 -0
  62. package/src/components/Screen/MultiRadialBackground.tsx +323 -0
  63. package/src/components/Screen/index.tsx +121 -0
  64. package/src/components/Select/index.tsx +153 -0
  65. package/src/components/TokenListItem/index.tsx +192 -0
  66. package/src/components/TopNav/index.tsx +67 -0
  67. package/src/components/Wrapper/index.tsx +4 -1
  68. package/src/index.ts +33 -0
  69. package/tailwind.config.ts +39 -0
@@ -0,0 +1,192 @@
1
+ import type { ButtonHTMLAttributes, HTMLAttributes } from 'react'
2
+
3
+ import { cn } from '../../utils/common'
4
+ import { Icon, type IconName } from '../Icon'
5
+ import { Text } from '../Text'
6
+
7
+ export type TokenListItemIconVariant = 'token' | 'network'
8
+
9
+ interface CommonProps {
10
+ /** Primary text — usually a token symbol like "ETH". */
11
+ symbol: string
12
+ /** Subtitle text under the symbol (e.g. "3 networks" or "Arbitrum"). */
13
+ subtitle?: string
14
+ /** Kit `Icon` name for the main slot (preferred for known chains/tokens). */
15
+ iconName?: IconName
16
+ /** URL of the main icon image (token logo). Used when `iconName` is absent. */
17
+ imageSource?: string
18
+ /** Kit `Icon` name rendered inline before the subtitle text (e.g. chain logo). */
19
+ subtitleIcon?: IconName
20
+ /** Right-aligned value (e.g. "$0.00"). */
21
+ value?: string
22
+ /** Right-aligned percentage change. Coloured green by default, red when
23
+ * the string starts with a leading "-". */
24
+ change?: string
25
+ /** Shape of the main icon. `'token'` = 44x44 rounded square (default),
26
+ * `'network'` = 36x36 circle. */
27
+ iconVariant?: TokenListItemIconVariant
28
+ /** Render a skeleton placeholder instead of the content. */
29
+ loading?: boolean
30
+ }
31
+
32
+ export type TokenListItemProps = CommonProps &
33
+ (
34
+ | ({ onClick: ButtonHTMLAttributes<HTMLButtonElement>['onClick'] } & Omit<
35
+ ButtonHTMLAttributes<HTMLButtonElement>,
36
+ keyof CommonProps | 'children'
37
+ >)
38
+ | ({ onClick?: undefined } & Omit<
39
+ HTMLAttributes<HTMLDivElement>,
40
+ keyof CommonProps | 'children'
41
+ >)
42
+ )
43
+
44
+ function IconBlock({
45
+ iconName,
46
+ imageSource,
47
+ variant,
48
+ }: {
49
+ iconName?: IconName
50
+ imageSource?: string
51
+ variant: TokenListItemIconVariant
52
+ }) {
53
+ const isNetwork = variant === 'network'
54
+ return (
55
+ <div
56
+ className={cn(
57
+ 'zd:shrink-0 zd:bg-white zd:flex zd:items-center zd:justify-center zd:overflow-hidden',
58
+ isNetwork
59
+ ? 'zd:w-9 zd:h-9 zd:rounded-full'
60
+ : 'zd:w-11 zd:h-11 zd:rounded-2xl',
61
+ )}
62
+ >
63
+ {iconName ? (
64
+ <Icon name={iconName} className="zd:w-6 zd:h-6" />
65
+ ) : imageSource ? (
66
+ <img
67
+ src={imageSource}
68
+ alt=""
69
+ className="zd:w-6 zd:h-6 zd:object-contain"
70
+ />
71
+ ) : null}
72
+ </div>
73
+ )
74
+ }
75
+
76
+ function TokenListItemSkeleton({
77
+ className,
78
+ }: {
79
+ className?: string | undefined
80
+ }) {
81
+ return (
82
+ <div
83
+ className={cn(
84
+ 'zd:w-full zd:p-2 zd:flex zd:flex-row zd:items-center zd:justify-between zd:gap-2',
85
+ className,
86
+ )}
87
+ >
88
+ <div className="zd:flex zd:flex-row zd:items-center zd:gap-2 zd:min-w-0">
89
+ <div className="zd:w-11 zd:h-11 zd:shrink-0 zd:rounded-2xl zd:bg-greyScale/15 zd:animate-skel-pulse" />
90
+ <div className="zd:flex zd:flex-col zd:gap-2">
91
+ <div className="zd:h-3 zd:w-14 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse" />
92
+ <div className="zd:h-3 zd:w-10 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse" />
93
+ </div>
94
+ </div>
95
+ <div className="zd:flex zd:flex-col zd:items-end zd:gap-2 zd:shrink-0">
96
+ <div className="zd:h-3 zd:w-12 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse" />
97
+ <div className="zd:h-3 zd:w-10 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse" />
98
+ </div>
99
+ </div>
100
+ )
101
+ }
102
+
103
+ export function TokenListItem({
104
+ symbol,
105
+ subtitle,
106
+ iconName,
107
+ imageSource,
108
+ subtitleIcon,
109
+ value,
110
+ change,
111
+ iconVariant = 'token',
112
+ loading = false,
113
+ className,
114
+ onClick,
115
+ ...rest
116
+ }: TokenListItemProps) {
117
+ if (loading) return <TokenListItemSkeleton className={className} />
118
+
119
+ const changeColor = change?.startsWith('-')
120
+ ? 'zd:text-negative'
121
+ : 'zd:text-positive'
122
+
123
+ const content = (
124
+ <>
125
+ <div className="zd:flex zd:flex-row zd:items-center zd:gap-2 zd:min-w-0">
126
+ <IconBlock
127
+ {...(iconName && { iconName })}
128
+ {...(imageSource && { imageSource })}
129
+ variant={iconVariant}
130
+ />
131
+ <div className="zd:flex zd:flex-col zd:items-start zd:gap-2 zd:min-w-0">
132
+ <Text className="zd:text-body1 zd:truncate">{symbol}</Text>
133
+ {subtitle && (
134
+ <div className="zd:flex zd:flex-row zd:items-center zd:gap-1 zd:min-w-0">
135
+ {subtitleIcon && (
136
+ <span className="zd:inline-flex zd:w-3 zd:h-3 zd:rounded-full zd:bg-offWhite/50 zd:overflow-hidden zd:shrink-0 zd:items-center zd:justify-center">
137
+ <Icon name={subtitleIcon} className="zd:w-full zd:h-full" />
138
+ </span>
139
+ )}
140
+ <Text className="zd:text-body3 zd:text-greyScale/50 zd:truncate">
141
+ {subtitle}
142
+ </Text>
143
+ </div>
144
+ )}
145
+ </div>
146
+ </div>
147
+ {(value || change) && (
148
+ <div className="zd:flex zd:flex-col zd:items-end zd:gap-2 zd:shrink-0">
149
+ {value && <Text className="zd:text-body1 zd:truncate">{value}</Text>}
150
+ {change && (
151
+ <Text className={cn('zd:text-body3 zd:truncate', changeColor)}>
152
+ {change}
153
+ </Text>
154
+ )}
155
+ </div>
156
+ )}
157
+ </>
158
+ )
159
+
160
+ const baseClassName = cn(
161
+ 'zd:w-full zd:p-2 zd:flex zd:flex-row zd:items-center zd:justify-between zd:gap-2 zd:text-left',
162
+ className,
163
+ )
164
+
165
+ if (onClick) {
166
+ return (
167
+ <button
168
+ type="button"
169
+ onClick={onClick}
170
+ className={cn(
171
+ baseClassName,
172
+ 'zd:transition-colors zd:rounded-xl',
173
+ (rest as ButtonHTMLAttributes<HTMLButtonElement>).disabled
174
+ ? 'zd:opacity-50 zd:cursor-not-allowed'
175
+ : 'zd:cursor-pointer zd:hover:bg-offWhite/40',
176
+ )}
177
+ {...(rest as ButtonHTMLAttributes<HTMLButtonElement>)}
178
+ >
179
+ {content}
180
+ </button>
181
+ )
182
+ }
183
+
184
+ return (
185
+ <div
186
+ className={baseClassName}
187
+ {...(rest as HTMLAttributes<HTMLDivElement>)}
188
+ >
189
+ {content}
190
+ </div>
191
+ )
192
+ }
@@ -0,0 +1,67 @@
1
+ import type { ReactNode } from 'react'
2
+ import { cn } from '../../utils/common'
3
+ import type { IconName } from '../Icon'
4
+ import { IconButton } from '../IconButton'
5
+ import { Text } from '../Text'
6
+
7
+ export const TOP_NAV_HEIGHT = 52
8
+
9
+ export interface TopNavProps {
10
+ /** Handler for the left icon button. When omitted, the left slot renders
11
+ * an empty spacer so the title/logo stays centred. */
12
+ onLeftButtonClick?: () => void
13
+ /** Handler for the right icon button. When omitted, the right slot
14
+ * renders an empty spacer. */
15
+ onRightButtonClick?: () => void
16
+ /** Icon rendered in the left slot. Defaults to `'chevronLeft'` (back). */
17
+ leftButtonIcon?: IconName
18
+ /** Icon rendered in the right slot. Defaults to `'x'` (close). */
19
+ rightButtonIcon?: IconName
20
+ title?: string
21
+ logo?: ReactNode
22
+ className?: string
23
+ }
24
+
25
+ export function TopNav({
26
+ onLeftButtonClick,
27
+ onRightButtonClick,
28
+ leftButtonIcon = 'chevronLeft',
29
+ rightButtonIcon = 'x',
30
+ title,
31
+ logo,
32
+ className,
33
+ }: TopNavProps) {
34
+ return (
35
+ <div
36
+ className={cn(
37
+ 'zd:absolute zd:top-4 zd:left-0 zd:right-0 zd:flex zd:flex-row zd:items-center zd:justify-between',
38
+ className,
39
+ )}
40
+ // Scale via --zd-spacing (the 4px base) like every spacing utility, so
41
+ // the nav height tracks the density variants and doesn't eat a
42
+ // disproportionate share of the shrunken frame at smaller sizes.
43
+ style={{ height: `calc(${TOP_NAV_HEIGHT / 4} * var(--zd-spacing))` }}
44
+ >
45
+ {onLeftButtonClick ? (
46
+ <IconButton iconName={leftButtonIcon} onClick={onLeftButtonClick} />
47
+ ) : (
48
+ <div className="zd:h-13 zd:w-13" />
49
+ )}
50
+ {logo && (
51
+ <div className="zd:absolute zd:left-0 zd:right-0 zd:flex zd:items-center zd:justify-center zd:pointer-events-none">
52
+ {logo}
53
+ </div>
54
+ )}
55
+ {title && (
56
+ <div className="zd:absolute zd:left-0 zd:right-0 zd:flex zd:items-center zd:justify-center zd:pointer-events-none">
57
+ <Text className="zd:text-body1">{title}</Text>
58
+ </div>
59
+ )}
60
+ {onRightButtonClick ? (
61
+ <IconButton iconName={rightButtonIcon} onClick={onRightButtonClick} />
62
+ ) : (
63
+ <div className="zd:h-13 zd:w-13" />
64
+ )}
65
+ </div>
66
+ )
67
+ }
@@ -1,4 +1,4 @@
1
- import type { HTMLAttributes, PropsWithChildren } from 'react'
1
+ import type { HTMLAttributes, PropsWithChildren, Ref } from 'react'
2
2
 
3
3
  import { cn } from '../../utils/common'
4
4
 
@@ -6,6 +6,7 @@ export type WrapperVariant = 'ghost' | 'soft' | 'solid'
6
6
 
7
7
  export interface WrapperProps extends HTMLAttributes<HTMLDivElement> {
8
8
  variant?: WrapperVariant
9
+ ref?: Ref<HTMLDivElement> | undefined
9
10
  }
10
11
 
11
12
  function getBackgroundAlpha(variant: WrapperVariant): number {
@@ -23,6 +24,7 @@ export function Wrapper({
23
24
  className,
24
25
  children,
25
26
  variant = 'soft',
27
+ ref,
26
28
  ...rest
27
29
  }: PropsWithChildren<WrapperProps>) {
28
30
  const backgroundAlpha = getBackgroundAlpha(variant)
@@ -30,6 +32,7 @@ export function Wrapper({
30
32
 
31
33
  return (
32
34
  <div
35
+ ref={ref}
33
36
  className={cn(
34
37
  'zd:overflow-hidden zd:border-offWhite zd:border-[0.3px] zd:backdrop-blur-[15px]',
35
38
  className,
package/src/index.ts CHANGED
@@ -9,6 +9,12 @@ export {
9
9
  ArrowView,
10
10
  } from './components/ArrowCardPair'
11
11
  export { Badge, type BadgeProps } from './components/Badge'
12
+ export {
13
+ BottomSheet,
14
+ BottomSheetClose,
15
+ BottomSheetContent,
16
+ BottomSheetTitle,
17
+ } from './components/BottomSheet'
12
18
  export { Button, type ButtonProps } from './components/Button'
13
19
  export { Callout, type CalloutProps } from './components/Callout'
14
20
  export {
@@ -27,11 +33,38 @@ export { IconButton, type IconButtonProps } from './components/IconButton'
27
33
  export { Input, type InputProps } from './components/Input'
28
34
  export {
29
35
  ListItem,
36
+ ListItemChevron,
37
+ ListItemIcon,
38
+ type ListItemIconProps,
30
39
  type ListItemProps,
31
40
  ListItemSkeleton,
32
41
  } from './components/ListItem'
42
+ export {
43
+ Pill,
44
+ type PillProps,
45
+ PillSkeleton,
46
+ } from './components/Pill'
47
+ export { PoweredBy } from './components/PoweredBy'
48
+ export { Screen } from './components/Screen'
49
+ export {
50
+ Select,
51
+ SelectContent,
52
+ SelectGroup,
53
+ SelectIcon,
54
+ SelectItem,
55
+ SelectItemText,
56
+ SelectSeparator,
57
+ SelectTrigger,
58
+ SelectValue,
59
+ } from './components/Select'
33
60
  export { Switch, type SwitchProps } from './components/Switch'
34
61
  export { Text, type TextProps } from './components/Text'
62
+ export {
63
+ TokenListItem,
64
+ type TokenListItemIconVariant,
65
+ type TokenListItemProps,
66
+ } from './components/TokenListItem'
67
+ export { TopNav, type TopNavProps } from './components/TopNav'
35
68
  export {
36
69
  WrappedPressable,
37
70
  type WrappedPressableProps,
@@ -57,6 +57,45 @@ const config: Config = {
57
57
  mono: undefined,
58
58
  roboto: ['Roboto', 'sans-serif'],
59
59
  },
60
+ // Sheet / overlay animations bound to Radix's `data-state=open|closed`
61
+ // attributes. Defined here (not in the CSS) so downstream packages that
62
+ // `@config` this file inherit them without duplication.
63
+ keyframes: {
64
+ 'sheet-in': {
65
+ from: { transform: 'translateY(100%)' },
66
+ to: { transform: 'translateY(0)' },
67
+ },
68
+ 'sheet-out': {
69
+ from: { transform: 'translateY(0)' },
70
+ to: { transform: 'translateY(100%)' },
71
+ },
72
+ 'backdrop-in': {
73
+ from: { opacity: '0' },
74
+ to: { opacity: '1' },
75
+ },
76
+ 'backdrop-out': {
77
+ from: { opacity: '1' },
78
+ to: { opacity: '0' },
79
+ },
80
+ // Gentle opacity pulse for loading skeletons — softer than Tailwind's
81
+ // default `pulse` (which dips to 50% and looks jittery on greys).
82
+ 'skel-pulse': {
83
+ '0%, 100%': { opacity: '0.65' },
84
+ '50%': { opacity: '1' },
85
+ },
86
+ 'popper-in': {
87
+ from: { opacity: '0', transform: 'scale(0.97) translateY(-3px)' },
88
+ to: { opacity: '1', transform: 'scale(1) translateY(0)' },
89
+ },
90
+ },
91
+ animation: {
92
+ 'sheet-in': 'sheet-in 300ms cubic-bezier(0.32, 0.72, 0, 1) forwards',
93
+ 'sheet-out': 'sheet-out 250ms cubic-bezier(0.32, 0.72, 0, 1) forwards',
94
+ 'backdrop-in': 'backdrop-in 200ms ease-out forwards',
95
+ 'backdrop-out': 'backdrop-out 200ms ease-out forwards',
96
+ 'skel-pulse': 'skel-pulse 1.1s ease-in-out infinite',
97
+ 'popper-in': 'popper-in 160ms ease-out both',
98
+ },
60
99
  },
61
100
  },
62
101
  plugins: [],