@zerodev/react-ui 0.0.3 → 0.0.5
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.
- package/dist/_types/components/ArrowCardPair/index.d.ts +2 -2
- package/dist/_types/components/ArrowCardPair/index.d.ts.map +1 -1
- package/dist/_types/components/Badge/index.d.ts +1 -1
- package/dist/_types/components/Badge/index.d.ts.map +1 -1
- package/dist/_types/components/BottomSheet/index.d.ts +17 -0
- package/dist/_types/components/BottomSheet/index.d.ts.map +1 -0
- package/dist/_types/components/Button/index.d.ts +1 -1
- package/dist/_types/components/Button/index.d.ts.map +1 -1
- package/dist/_types/components/Callout/index.d.ts +1 -1
- package/dist/_types/components/Callout/index.d.ts.map +1 -1
- package/dist/_types/components/DataRow/index.d.ts +6 -2
- package/dist/_types/components/DataRow/index.d.ts.map +1 -1
- package/dist/_types/components/Icon/index.d.ts +1 -1
- package/dist/_types/components/Icon/index.d.ts.map +1 -1
- package/dist/_types/components/IconButton/index.d.ts +1 -1
- package/dist/_types/components/IconButton/index.d.ts.map +1 -1
- package/dist/_types/components/InfoCard/index.d.ts +17 -0
- package/dist/_types/components/InfoCard/index.d.ts.map +1 -0
- package/dist/_types/components/Input/index.d.ts +1 -1
- package/dist/_types/components/Input/index.d.ts.map +1 -1
- package/dist/_types/components/ListItem/index.d.ts +32 -15
- package/dist/_types/components/ListItem/index.d.ts.map +1 -1
- package/dist/_types/components/Pill/index.d.ts +25 -0
- package/dist/_types/components/Pill/index.d.ts.map +1 -0
- package/dist/_types/components/PoweredBy/index.d.ts +6 -0
- package/dist/_types/components/PoweredBy/index.d.ts.map +1 -0
- package/dist/_types/components/Screen/EllipticalRadial.d.ts +23 -0
- package/dist/_types/components/Screen/EllipticalRadial.d.ts.map +1 -0
- package/dist/_types/components/Screen/MultiRadialBackground.d.ts +4 -0
- package/dist/_types/components/Screen/MultiRadialBackground.d.ts.map +1 -0
- package/dist/_types/components/Screen/index.d.ts +15 -0
- package/dist/_types/components/Screen/index.d.ts.map +1 -0
- package/dist/_types/components/Section/MessageDetails/index.d.ts +5 -0
- package/dist/_types/components/Section/MessageDetails/index.d.ts.map +1 -0
- package/dist/_types/components/Section/index.d.ts +11 -0
- package/dist/_types/components/Section/index.d.ts.map +1 -0
- package/dist/_types/components/Select/index.d.ts +28 -0
- package/dist/_types/components/Select/index.d.ts.map +1 -0
- package/dist/_types/components/Switch/index.d.ts +1 -1
- package/dist/_types/components/Switch/index.d.ts.map +1 -1
- package/dist/_types/components/Text/index.d.ts +1 -1
- package/dist/_types/components/Text/index.d.ts.map +1 -1
- package/dist/_types/components/TokenListItem/index.d.ts +33 -0
- package/dist/_types/components/TokenListItem/index.d.ts.map +1 -0
- package/dist/_types/components/Tooltip/index.d.ts +43 -0
- package/dist/_types/components/Tooltip/index.d.ts.map +1 -0
- package/dist/_types/components/TopNav/index.d.ts +20 -0
- package/dist/_types/components/TopNav/index.d.ts.map +1 -0
- package/dist/_types/components/WrappedPressable/index.d.ts +1 -1
- package/dist/_types/components/WrappedPressable/index.d.ts.map +1 -1
- package/dist/_types/components/Wrapper/index.d.ts +3 -2
- package/dist/_types/components/Wrapper/index.d.ts.map +1 -1
- package/dist/_types/components/ZeroDevLogo/index.d.ts +1 -1
- package/dist/_types/components/ZeroDevLogo/index.d.ts.map +1 -1
- package/dist/_types/index.d.ts +13 -2
- package/dist/_types/index.d.ts.map +1 -1
- package/dist/_types/utils/common.d.ts +4 -0
- package/dist/_types/utils/common.d.ts.map +1 -1
- package/dist/index.cjs +51 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +6538 -1341
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +2 -2
- package/package.json +7 -5
- package/src/components/ArrowCardPair/index.tsx +25 -5
- package/src/components/BottomSheet/index.tsx +57 -0
- package/src/components/DataRow/index.tsx +55 -29
- package/src/components/InfoCard/index.tsx +104 -0
- package/src/components/ListItem/index.tsx +74 -79
- package/src/components/Pill/index.tsx +167 -0
- package/src/components/PoweredBy/index.tsx +29 -0
- package/src/components/Screen/EllipticalRadial.tsx +65 -0
- package/src/components/Screen/MultiRadialBackground.tsx +323 -0
- package/src/components/Screen/index.tsx +121 -0
- package/src/components/Section/MessageDetails/index.tsx +19 -0
- package/src/components/Section/index.tsx +50 -0
- package/src/components/Select/index.tsx +153 -0
- package/src/components/TokenListItem/index.tsx +192 -0
- package/src/components/Tooltip/index.tsx +94 -0
- package/src/components/TopNav/index.tsx +67 -0
- package/src/components/Wrapper/index.tsx +4 -1
- package/src/index.ts +54 -1
- package/src/utils/common.ts +15 -0
- package/tailwind.config.ts +47 -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,94 @@
|
|
|
1
|
+
import { Tooltip as TooltipPrimitive } from 'radix-ui'
|
|
2
|
+
import type { ComponentProps, ReactNode, Ref } from 'react'
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../utils/common'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Floating tooltip wrapping the Radix primitive with our token palette.
|
|
8
|
+
*
|
|
9
|
+
* The primitive is unopinionated about presentation — this file adds:
|
|
10
|
+
* - default styling (dark ink bg, white text, 8px offset, subtle shadow)
|
|
11
|
+
* - a bundled `Provider` so the common case (a single tooltip in a row)
|
|
12
|
+
* doesn't require the consumer to remember to wrap the tree
|
|
13
|
+
* - a Portal render so tooltips escape overflow-hidden ancestors
|
|
14
|
+
*
|
|
15
|
+
* For dense trees where mount overhead matters, use `TooltipProvider` at
|
|
16
|
+
* the app root and drop the internal Provider by importing `TooltipRoot`
|
|
17
|
+
* / `TooltipTrigger` / `TooltipContent` directly.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const TooltipProvider = TooltipPrimitive.Provider
|
|
21
|
+
export const TooltipRoot = TooltipPrimitive.Root
|
|
22
|
+
export const TooltipTrigger = TooltipPrimitive.Trigger
|
|
23
|
+
export const TooltipPortal = TooltipPrimitive.Portal
|
|
24
|
+
|
|
25
|
+
export interface TooltipContentProps
|
|
26
|
+
extends ComponentProps<typeof TooltipPrimitive.Content> {
|
|
27
|
+
ref?: Ref<HTMLDivElement>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Styled content surface — dark chip, ~11.5px semibold copy, arrow-less. */
|
|
31
|
+
export function TooltipContent({
|
|
32
|
+
ref,
|
|
33
|
+
className,
|
|
34
|
+
sideOffset = 8,
|
|
35
|
+
...props
|
|
36
|
+
}: TooltipContentProps) {
|
|
37
|
+
return (
|
|
38
|
+
<TooltipPrimitive.Content
|
|
39
|
+
ref={ref}
|
|
40
|
+
sideOffset={sideOffset}
|
|
41
|
+
className={cn(
|
|
42
|
+
'zd:z-50 zd:max-w-[220px] zd:rounded-lg zd:px-2 zd:py-1.5',
|
|
43
|
+
'zd:text-body3 zd:font-semibold zd:text-white zd:text-center',
|
|
44
|
+
'zd:shadow-[0_8px_22px_-10px_rgba(25,17,11,0.45)]',
|
|
45
|
+
// Match the popper-in animation used by Select so all our floating
|
|
46
|
+
// surfaces share one motion vocabulary.
|
|
47
|
+
'zd:data-[state=delayed-open]:animate-popper-in',
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
style={{ backgroundColor: 'rgba(25, 17, 11, 0.94)' }}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface TooltipProps {
|
|
57
|
+
/** Trigger element — receives Radix's ref + event handlers via `asChild`. */
|
|
58
|
+
children: ReactNode
|
|
59
|
+
/** Tooltip copy. When omitted, the trigger renders without a tooltip. */
|
|
60
|
+
content?: ReactNode
|
|
61
|
+
/** Delay before the tooltip appears on hover. Defaults to 200ms. */
|
|
62
|
+
delayDuration?: number
|
|
63
|
+
/** Side to render on. Defaults to `top`. */
|
|
64
|
+
side?: ComponentProps<typeof TooltipPrimitive.Content>['side']
|
|
65
|
+
/** Alignment along `side`. Defaults to `center`. */
|
|
66
|
+
align?: ComponentProps<typeof TooltipPrimitive.Content>['align']
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Opinionated one-shot tooltip. Wraps its child in a Radix Trigger and mounts
|
|
71
|
+
* a portalled content surface; no-op when `content` is empty so callers can
|
|
72
|
+
* pass an optional string without conditional rendering.
|
|
73
|
+
*/
|
|
74
|
+
export function Tooltip({
|
|
75
|
+
children,
|
|
76
|
+
content,
|
|
77
|
+
delayDuration = 200,
|
|
78
|
+
side = 'top',
|
|
79
|
+
align = 'center',
|
|
80
|
+
}: TooltipProps) {
|
|
81
|
+
if (!content) return <>{children}</>
|
|
82
|
+
return (
|
|
83
|
+
<TooltipProvider delayDuration={delayDuration}>
|
|
84
|
+
<TooltipRoot>
|
|
85
|
+
<TooltipTrigger asChild>{children}</TooltipTrigger>
|
|
86
|
+
<TooltipPortal>
|
|
87
|
+
<TooltipContent side={side} align={align}>
|
|
88
|
+
{content}
|
|
89
|
+
</TooltipContent>
|
|
90
|
+
</TooltipPortal>
|
|
91
|
+
</TooltipRoot>
|
|
92
|
+
</TooltipProvider>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
@@ -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 {
|
|
@@ -24,14 +30,61 @@ export {
|
|
|
24
30
|
icons,
|
|
25
31
|
} from './components/Icon'
|
|
26
32
|
export { IconButton, type IconButtonProps } from './components/IconButton'
|
|
33
|
+
export {
|
|
34
|
+
InfoCard,
|
|
35
|
+
type InfoCardImageStyle,
|
|
36
|
+
type InfoCardProps,
|
|
37
|
+
} from './components/InfoCard'
|
|
27
38
|
export { Input, type InputProps } from './components/Input'
|
|
28
39
|
export {
|
|
29
40
|
ListItem,
|
|
41
|
+
ListItemChevron,
|
|
42
|
+
ListItemIcon,
|
|
43
|
+
type ListItemIconProps,
|
|
30
44
|
type ListItemProps,
|
|
31
45
|
ListItemSkeleton,
|
|
32
46
|
} from './components/ListItem'
|
|
47
|
+
export {
|
|
48
|
+
Pill,
|
|
49
|
+
type PillProps,
|
|
50
|
+
PillSkeleton,
|
|
51
|
+
} from './components/Pill'
|
|
52
|
+
export { PoweredBy } from './components/PoweredBy'
|
|
53
|
+
export { Screen } from './components/Screen'
|
|
54
|
+
export { Section, type SectionProps } from './components/Section'
|
|
55
|
+
export {
|
|
56
|
+
MessageDetails,
|
|
57
|
+
type MessageDetailsProps,
|
|
58
|
+
} from './components/Section/MessageDetails'
|
|
59
|
+
export {
|
|
60
|
+
Select,
|
|
61
|
+
SelectContent,
|
|
62
|
+
SelectGroup,
|
|
63
|
+
SelectIcon,
|
|
64
|
+
SelectItem,
|
|
65
|
+
SelectItemText,
|
|
66
|
+
SelectSeparator,
|
|
67
|
+
SelectTrigger,
|
|
68
|
+
SelectValue,
|
|
69
|
+
} from './components/Select'
|
|
33
70
|
export { Switch, type SwitchProps } from './components/Switch'
|
|
34
71
|
export { Text, type TextProps } from './components/Text'
|
|
72
|
+
export {
|
|
73
|
+
TokenListItem,
|
|
74
|
+
type TokenListItemIconVariant,
|
|
75
|
+
type TokenListItemProps,
|
|
76
|
+
} from './components/TokenListItem'
|
|
77
|
+
export {
|
|
78
|
+
Tooltip,
|
|
79
|
+
TooltipContent,
|
|
80
|
+
type TooltipContentProps,
|
|
81
|
+
TooltipPortal,
|
|
82
|
+
type TooltipProps,
|
|
83
|
+
TooltipProvider,
|
|
84
|
+
TooltipRoot,
|
|
85
|
+
TooltipTrigger,
|
|
86
|
+
} from './components/Tooltip'
|
|
87
|
+
export { TopNav, type TopNavProps } from './components/TopNav'
|
|
35
88
|
export {
|
|
36
89
|
WrappedPressable,
|
|
37
90
|
type WrappedPressableProps,
|
|
@@ -47,4 +100,4 @@ export {
|
|
|
47
100
|
ZeroDevLogo,
|
|
48
101
|
type ZeroDevLogoProps,
|
|
49
102
|
} from './components/ZeroDevLogo'
|
|
50
|
-
export { cn } from './utils/common'
|
|
103
|
+
export { camelCaseToTitle, cn } from './utils/common'
|
package/src/utils/common.ts
CHANGED
|
@@ -15,3 +15,18 @@ const customTwMerge = extendTailwindMerge({
|
|
|
15
15
|
export function cn(...inputs: ClassValue[]) {
|
|
16
16
|
return customTwMerge(clsx(inputs))
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
/** Turn `"fromAddress"` into `"From Address"`. Leaves strings that already
|
|
20
|
+
* start with uppercase (i.e. already display-cased) untouched, so callers can
|
|
21
|
+
* pass either camelCase keys or human-readable labels through unchanged. */
|
|
22
|
+
export function camelCaseToTitle(str: string): string {
|
|
23
|
+
if (str.length === 0 || str.at(0) === str.at(0)?.toUpperCase()) {
|
|
24
|
+
return str
|
|
25
|
+
}
|
|
26
|
+
return str
|
|
27
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
28
|
+
.trim()
|
|
29
|
+
.split(' ')
|
|
30
|
+
.map((word) => (word.at(0) ?? '').toUpperCase() + word.slice(1))
|
|
31
|
+
.join(' ')
|
|
32
|
+
}
|
package/tailwind.config.ts
CHANGED
|
@@ -57,6 +57,53 @@ 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
|
+
// Fresh-value flash for live-updating fee estimates: fades and lifts
|
|
91
|
+
// in when the underlying quote changes, so a route swap visibly
|
|
92
|
+
// recalculates rather than silently snapping.
|
|
93
|
+
'fee-flash': {
|
|
94
|
+
from: { opacity: '0', transform: 'translateY(-3px) scale(0.96)' },
|
|
95
|
+
to: { opacity: '1', transform: 'none' },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
animation: {
|
|
99
|
+
'sheet-in': 'sheet-in 300ms cubic-bezier(0.32, 0.72, 0, 1) forwards',
|
|
100
|
+
'sheet-out': 'sheet-out 250ms cubic-bezier(0.32, 0.72, 0, 1) forwards',
|
|
101
|
+
'backdrop-in': 'backdrop-in 200ms ease-out forwards',
|
|
102
|
+
'backdrop-out': 'backdrop-out 200ms ease-out forwards',
|
|
103
|
+
'skel-pulse': 'skel-pulse 1.1s ease-in-out infinite',
|
|
104
|
+
'popper-in': 'popper-in 160ms ease-out both',
|
|
105
|
+
'fee-flash': 'fee-flash 420ms cubic-bezier(0.2, 0.9, 0.3, 1) both',
|
|
106
|
+
},
|
|
60
107
|
},
|
|
61
108
|
},
|
|
62
109
|
plugins: [],
|