@luxfi/ui 6.1.2 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/dist/accordion.cjs +213 -0
  2. package/dist/accordion.d.cts +74 -0
  3. package/dist/accordion.d.ts +74 -0
  4. package/dist/accordion.js +186 -0
  5. package/dist/alert.cjs +553 -0
  6. package/dist/alert.d.cts +30 -0
  7. package/dist/alert.d.ts +30 -0
  8. package/dist/alert.js +531 -0
  9. package/dist/avatar.cjs +149 -0
  10. package/dist/avatar.d.cts +25 -0
  11. package/dist/avatar.d.ts +25 -0
  12. package/dist/avatar.js +125 -0
  13. package/dist/badge.cjs +611 -0
  14. package/dist/badge.d.cts +23 -0
  15. package/dist/badge.d.ts +23 -0
  16. package/dist/badge.js +589 -0
  17. package/dist/bank.cjs +272 -0
  18. package/dist/bank.d.cts +76 -0
  19. package/dist/bank.d.ts +76 -0
  20. package/dist/bank.js +258 -0
  21. package/dist/button.cjs +689 -0
  22. package/dist/button.d.cts +52 -0
  23. package/dist/button.d.ts +52 -0
  24. package/dist/button.js +664 -0
  25. package/dist/checkbox.cjs +265 -0
  26. package/dist/checkbox.d.cts +31 -0
  27. package/dist/checkbox.d.ts +31 -0
  28. package/dist/checkbox.js +241 -0
  29. package/dist/close-button.cjs +73 -0
  30. package/dist/close-button.d.cts +9 -0
  31. package/dist/close-button.d.ts +9 -0
  32. package/dist/close-button.js +51 -0
  33. package/dist/collapsible.cjs +702 -0
  34. package/dist/collapsible.d.cts +23 -0
  35. package/dist/collapsible.d.ts +23 -0
  36. package/dist/collapsible.js +679 -0
  37. package/dist/color-mode.cjs +96 -0
  38. package/dist/color-mode.d.cts +25 -0
  39. package/dist/color-mode.d.ts +25 -0
  40. package/dist/color-mode.js +72 -0
  41. package/dist/dialog.cjs +279 -0
  42. package/dist/dialog.d.cts +66 -0
  43. package/dist/dialog.d.ts +66 -0
  44. package/dist/dialog.js +246 -0
  45. package/dist/drawer.cjs +207 -0
  46. package/dist/drawer.d.cts +36 -0
  47. package/dist/drawer.d.ts +36 -0
  48. package/dist/drawer.js +175 -0
  49. package/dist/empty-state.cjs +93 -0
  50. package/dist/empty-state.d.cts +13 -0
  51. package/dist/empty-state.d.ts +13 -0
  52. package/dist/empty-state.js +71 -0
  53. package/dist/expiration-selector.cjs +138 -0
  54. package/dist/expiration-selector.d.cts +16 -0
  55. package/dist/expiration-selector.d.ts +16 -0
  56. package/dist/expiration-selector.js +116 -0
  57. package/dist/field.cjs +183 -0
  58. package/dist/field.d.cts +24 -0
  59. package/dist/field.d.ts +24 -0
  60. package/dist/field.js +160 -0
  61. package/dist/greeks-display.cjs +114 -0
  62. package/dist/greeks-display.d.cts +14 -0
  63. package/dist/greeks-display.d.ts +14 -0
  64. package/dist/greeks-display.js +92 -0
  65. package/dist/heading.cjs +46 -0
  66. package/dist/heading.d.cts +10 -0
  67. package/dist/heading.d.ts +10 -0
  68. package/dist/heading.js +40 -0
  69. package/dist/icon-button.cjs +491 -0
  70. package/dist/icon-button.d.cts +33 -0
  71. package/dist/icon-button.d.ts +33 -0
  72. package/dist/icon-button.js +470 -0
  73. package/dist/image.cjs +572 -0
  74. package/dist/image.d.cts +57 -0
  75. package/dist/image.d.ts +57 -0
  76. package/dist/image.js +551 -0
  77. package/dist/index.cjs +7316 -0
  78. package/dist/index.d.cts +58 -0
  79. package/dist/index.d.ts +58 -0
  80. package/dist/index.js +7137 -0
  81. package/dist/input-group.cjs +155 -0
  82. package/dist/input-group.d.cts +17 -0
  83. package/dist/input-group.d.ts +17 -0
  84. package/dist/input-group.js +133 -0
  85. package/dist/input.cjs +65 -0
  86. package/dist/input.d.cts +11 -0
  87. package/dist/input.d.ts +11 -0
  88. package/dist/input.js +59 -0
  89. package/dist/link.cjs +630 -0
  90. package/dist/link.d.cts +37 -0
  91. package/dist/link.d.ts +37 -0
  92. package/dist/link.js +606 -0
  93. package/dist/menu.cjs +305 -0
  94. package/dist/menu.d.cts +84 -0
  95. package/dist/menu.d.ts +84 -0
  96. package/dist/menu.js +269 -0
  97. package/dist/option-chain.cjs +221 -0
  98. package/dist/option-chain.d.cts +37 -0
  99. package/dist/option-chain.d.ts +37 -0
  100. package/dist/option-chain.js +199 -0
  101. package/dist/option-position.cjs +164 -0
  102. package/dist/option-position.d.cts +29 -0
  103. package/dist/option-position.d.ts +29 -0
  104. package/dist/option-position.js +142 -0
  105. package/dist/pin-input.cjs +182 -0
  106. package/dist/pin-input.d.cts +25 -0
  107. package/dist/pin-input.d.ts +25 -0
  108. package/dist/pin-input.js +160 -0
  109. package/dist/pnl-diagram.cjs +453 -0
  110. package/dist/pnl-diagram.d.cts +11 -0
  111. package/dist/pnl-diagram.d.ts +11 -0
  112. package/dist/pnl-diagram.js +431 -0
  113. package/dist/popover.cjs +327 -0
  114. package/dist/popover.d.cts +73 -0
  115. package/dist/popover.d.ts +73 -0
  116. package/dist/popover.js +294 -0
  117. package/dist/progress-circle.cjs +152 -0
  118. package/dist/progress-circle.d.cts +47 -0
  119. package/dist/progress-circle.d.ts +47 -0
  120. package/dist/progress-circle.js +128 -0
  121. package/dist/progress.cjs +117 -0
  122. package/dist/progress.d.cts +28 -0
  123. package/dist/progress.d.ts +28 -0
  124. package/dist/progress.js +94 -0
  125. package/dist/provider.cjs +62 -0
  126. package/dist/provider.d.cts +7 -0
  127. package/dist/provider.d.ts +7 -0
  128. package/dist/provider.js +40 -0
  129. package/dist/radio.cjs +177 -0
  130. package/dist/radio.d.cts +53 -0
  131. package/dist/radio.d.ts +53 -0
  132. package/dist/radio.js +153 -0
  133. package/dist/rating.cjs +80 -0
  134. package/dist/rating.d.cts +14 -0
  135. package/dist/rating.d.ts +14 -0
  136. package/dist/rating.js +58 -0
  137. package/dist/select.cjs +791 -0
  138. package/dist/select.d.cts +130 -0
  139. package/dist/select.d.ts +130 -0
  140. package/dist/select.js +757 -0
  141. package/dist/separator.cjs +57 -0
  142. package/dist/separator.d.cts +13 -0
  143. package/dist/separator.d.ts +13 -0
  144. package/dist/separator.js +51 -0
  145. package/dist/skeleton.cjs +370 -0
  146. package/dist/skeleton.d.cts +60 -0
  147. package/dist/skeleton.d.ts +60 -0
  148. package/dist/skeleton.js +346 -0
  149. package/dist/slider.cjs +138 -0
  150. package/dist/slider.d.cts +24 -0
  151. package/dist/slider.d.ts +24 -0
  152. package/dist/slider.js +115 -0
  153. package/dist/strategy-builder.cjs +373 -0
  154. package/dist/strategy-builder.d.cts +26 -0
  155. package/dist/strategy-builder.d.ts +26 -0
  156. package/dist/strategy-builder.js +351 -0
  157. package/dist/switch.cjs +163 -0
  158. package/dist/switch.d.cts +27 -0
  159. package/dist/switch.d.ts +27 -0
  160. package/dist/switch.js +140 -0
  161. package/dist/table.cjs +1044 -0
  162. package/dist/table.d.cts +107 -0
  163. package/dist/table.d.ts +107 -0
  164. package/dist/table.js +1013 -0
  165. package/dist/tabs.cjs +240 -0
  166. package/dist/tabs.d.cts +78 -0
  167. package/dist/tabs.d.ts +78 -0
  168. package/dist/tabs.js +213 -0
  169. package/dist/tag.cjs +651 -0
  170. package/dist/tag.d.cts +21 -0
  171. package/dist/tag.d.ts +21 -0
  172. package/dist/tag.js +628 -0
  173. package/dist/textarea.cjs +65 -0
  174. package/dist/textarea.d.cts +11 -0
  175. package/dist/textarea.d.ts +11 -0
  176. package/dist/textarea.js +59 -0
  177. package/dist/toaster.cjs +99 -0
  178. package/dist/toaster.d.cts +29 -0
  179. package/dist/toaster.d.ts +29 -0
  180. package/dist/toaster.js +96 -0
  181. package/dist/tooltip.cjs +171 -0
  182. package/dist/tooltip.d.cts +39 -0
  183. package/dist/tooltip.d.ts +39 -0
  184. package/dist/tooltip.js +148 -0
  185. package/dist/utils.cjs +11 -0
  186. package/dist/utils.d.cts +5 -0
  187. package/dist/utils.d.ts +5 -0
  188. package/dist/utils.js +9 -0
  189. package/package.json +284 -85
  190. package/src/accordion.tsx +285 -0
  191. package/src/alert.tsx +221 -0
  192. package/src/avatar.tsx +174 -0
  193. package/src/badge.tsx +158 -0
  194. package/src/bank.tsx +325 -0
  195. package/src/button.tsx +411 -0
  196. package/src/checkbox.tsx +307 -0
  197. package/src/close-button.tsx +51 -0
  198. package/src/collapsible.tsx +126 -0
  199. package/src/color-mode.tsx +125 -0
  200. package/src/dialog.tsx +356 -0
  201. package/src/drawer.tsx +186 -0
  202. package/src/empty-state.tsx +97 -0
  203. package/src/expiration-selector.tsx +163 -0
  204. package/src/field.tsx +202 -0
  205. package/src/greeks-display.tsx +138 -0
  206. package/src/heading.tsx +55 -0
  207. package/src/icon-button.tsx +192 -0
  208. package/src/image.tsx +280 -0
  209. package/src/index.ts +268 -0
  210. package/src/input-group.tsx +159 -0
  211. package/src/input.tsx +60 -0
  212. package/src/link.tsx +326 -0
  213. package/src/menu.tsx +471 -0
  214. package/src/option-chain.tsx +261 -0
  215. package/src/option-position.tsx +200 -0
  216. package/src/pin-input.tsx +187 -0
  217. package/src/pnl-diagram.tsx +458 -0
  218. package/src/popover.tsx +400 -0
  219. package/src/progress-circle.tsx +180 -0
  220. package/src/progress.tsx +109 -0
  221. package/src/provider.tsx +12 -0
  222. package/src/radio.tsx +175 -0
  223. package/src/rating.tsx +79 -0
  224. package/src/select.tsx +696 -0
  225. package/src/separator.tsx +59 -0
  226. package/src/skeleton.tsx +302 -0
  227. package/src/slider.tsx +152 -0
  228. package/src/strategy-builder.tsx +466 -0
  229. package/src/switch.tsx +158 -0
  230. package/src/table.tsx +621 -0
  231. package/src/tabs.tsx +354 -0
  232. package/src/tag.tsx +159 -0
  233. package/src/textarea.tsx +60 -0
  234. package/src/toaster.tsx +117 -0
  235. package/src/tokens.css +438 -0
  236. package/src/tooltip.tsx +184 -0
  237. package/src/utils/cn.ts +7 -0
  238. package/src/utils.ts +6 -0
  239. package/tokens.css +438 -0
  240. package/README.md +0 -109
package/src/badge.tsx ADDED
@@ -0,0 +1,158 @@
1
+ import { cva } from 'class-variance-authority';
2
+ import type { VariantProps } from 'class-variance-authority';
3
+ import React from 'react';
4
+
5
+ import { cn } from './utils';
6
+
7
+ import { Skeleton } from './skeleton';
8
+ import { Tooltip } from './tooltip';
9
+
10
+ // Inline truncation tooltip (replaces explorer's TruncatedTextTooltip)
11
+ function TruncatedTextTooltip({ label, children }: { readonly label: React.ReactNode; readonly children: React.ReactNode }) {
12
+ return (
13
+ <Tooltip content={ label } positioning={{ placement: 'top' }}>
14
+ { children }
15
+ </Tooltip>
16
+ );
17
+ }
18
+
19
+ type ColorPalette =
20
+ 'gray' | 'green' | 'red' | 'purple' | 'orange' | 'blue' | 'yellow' |
21
+ 'teal' | 'cyan' | 'pink' | 'purple_alt' | 'blue_alt' |
22
+ 'bright_gray' | 'bright_green' | 'bright_red' | 'bright_blue' |
23
+ 'bright_yellow' | 'bright_teal' | 'bright_cyan' | 'bright_orange' |
24
+ 'bright_purple' | 'bright_pink';
25
+
26
+ const badgeVariants = cva(
27
+ 'inline-flex items-center rounded-sm gap-1 font-medium w-fit max-w-full whitespace-nowrap select-text',
28
+ {
29
+ variants: {
30
+ variant: {
31
+ subtle: '',
32
+ solid: '',
33
+ },
34
+ size: {
35
+ sm: 'text-xs p-1 h-[18px] min-h-[18px]',
36
+ md: 'text-sm px-1 py-0.5 min-h-6',
37
+ lg: 'text-sm px-2 py-1 min-h-7 font-semibold',
38
+ },
39
+ },
40
+ defaultVariants: {
41
+ variant: 'subtle',
42
+ size: 'md',
43
+ },
44
+ },
45
+ );
46
+
47
+ const COLOR_PALETTE_CLASSES: Record<ColorPalette, string> = {
48
+ gray: 'bg-badge-gray-bg text-badge-gray-fg',
49
+ green: 'bg-badge-green-bg text-badge-green-fg',
50
+ red: 'bg-badge-red-bg text-badge-red-fg',
51
+ purple: 'bg-badge-purple-bg text-badge-purple-fg',
52
+ orange: 'bg-badge-orange-bg text-badge-orange-fg',
53
+ blue: 'bg-badge-blue-bg text-badge-blue-fg',
54
+ yellow: 'bg-badge-yellow-bg text-badge-yellow-fg',
55
+ teal: 'bg-badge-teal-bg text-badge-teal-fg',
56
+ cyan: 'bg-badge-cyan-bg text-badge-cyan-fg',
57
+ pink: 'bg-badge-pink-bg text-badge-pink-fg',
58
+ purple_alt: 'bg-badge-purple-alt-bg text-badge-purple-alt-fg',
59
+ blue_alt: 'bg-badge-blue-alt-bg text-badge-blue-alt-fg',
60
+ bright_gray: 'bg-badge-bright-gray-bg text-badge-bright-gray-fg',
61
+ bright_green: 'bg-badge-bright-green-bg text-badge-bright-green-fg',
62
+ bright_red: 'bg-badge-bright-red-bg text-badge-bright-red-fg',
63
+ bright_blue: 'bg-badge-bright-blue-bg text-badge-bright-blue-fg',
64
+ bright_yellow: 'bg-badge-bright-yellow-bg text-badge-bright-yellow-fg',
65
+ bright_teal: 'bg-badge-bright-teal-bg text-badge-bright-teal-fg',
66
+ bright_cyan: 'bg-badge-bright-cyan-bg text-badge-bright-cyan-fg',
67
+ bright_orange: 'bg-badge-bright-orange-bg text-badge-bright-orange-fg',
68
+ bright_purple: 'bg-badge-bright-purple-bg text-badge-bright-purple-fg',
69
+ bright_pink: 'bg-badge-bright-pink-bg text-badge-bright-pink-fg',
70
+ };
71
+
72
+ export interface BadgeProps
73
+ extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'>,
74
+ VariantProps<typeof badgeVariants> {
75
+ readonly loading?: boolean;
76
+ readonly startElement?: React.ReactNode;
77
+ readonly endElement?: React.ReactNode;
78
+ readonly truncated?: boolean;
79
+ readonly colorPalette?: ColorPalette;
80
+ // Legacy Chakra style-prop shims
81
+ readonly flexShrink?: number;
82
+ readonly gap?: number | string;
83
+ readonly ml?: number | string | Record<string, number>;
84
+ readonly mr?: number | string;
85
+ }
86
+
87
+ export const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
88
+ function Badge(props, ref) {
89
+ const {
90
+ loading,
91
+ startElement,
92
+ children,
93
+ truncated = false,
94
+ endElement,
95
+ variant,
96
+ size,
97
+ colorPalette = 'gray',
98
+ className,
99
+ flexShrink: _flexShrink,
100
+ gap: _gap,
101
+ ml: _ml,
102
+ mr: _mr,
103
+ style: styleProp,
104
+ ...rest
105
+ } = props;
106
+
107
+ const shimStyle: React.CSSProperties = { ...styleProp };
108
+ if (_flexShrink !== undefined) shimStyle.flexShrink = _flexShrink;
109
+ if (_gap !== undefined) shimStyle.gap = typeof _gap === 'number' ? `${ _gap * 4 }px` : _gap;
110
+ if (_ml !== undefined) {
111
+ if (typeof _ml === 'object') {
112
+ const obj = _ml as Record<string, number>;
113
+ shimStyle.marginLeft = `${ (obj.base ?? obj.lg ?? 0) * 4 }px`;
114
+ } else {
115
+ shimStyle.marginLeft = typeof _ml === 'number' ? `${ _ml * 4 }px` : _ml;
116
+ }
117
+ }
118
+ if (_mr !== undefined) shimStyle.marginRight = typeof _mr === 'number' ? `${ _mr * 4 }px` : _mr;
119
+ const badgeStyle = Object.keys(shimStyle).length > 0 ? shimStyle : undefined;
120
+
121
+ const child = children ? (
122
+ <span className="overflow-hidden text-ellipsis">{ children }</span>
123
+ ) : null;
124
+
125
+ const childrenElement = truncated ? (
126
+ <TruncatedTextTooltip label={ children }>
127
+ { child }
128
+ </TruncatedTextTooltip>
129
+ ) : child;
130
+
131
+ const badgeElement = (
132
+ <span
133
+ ref={ ref as React.Ref<HTMLSpanElement> }
134
+ className={ cn(
135
+ badgeVariants({ variant, size }),
136
+ COLOR_PALETTE_CLASSES[colorPalette],
137
+ className,
138
+ ) }
139
+ style={ badgeStyle }
140
+ { ...rest }
141
+ >
142
+ { startElement }
143
+ { childrenElement }
144
+ { endElement }
145
+ </span>
146
+ );
147
+
148
+ if (loading) {
149
+ return (
150
+ <Skeleton loading={ loading } asChild>
151
+ { badgeElement }
152
+ </Skeleton>
153
+ );
154
+ }
155
+
156
+ return badgeElement;
157
+ },
158
+ );
package/src/bank.tsx ADDED
@@ -0,0 +1,325 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import type { GetProps } from '@hanzogui/core'
5
+ import { View, Text, styled } from '@hanzogui/core'
6
+
7
+ // ── Bank Theme Tokens ─────────────────────────────────────────────
8
+ export const bankColors = {
9
+ bg: '#000000',
10
+ card: '#111111',
11
+ cardBorder: '#222222',
12
+ input: '#1A1A1A',
13
+ inputBorder: '#333333',
14
+ inputFocus: '#555555',
15
+ inputPlaceholder: '#666666',
16
+ text: '#FFFFFF',
17
+ textMuted: '#888888',
18
+ textLabel: '#CCCCCC',
19
+ accent: '#FFFFFF',
20
+ accentPress: '#E0E0E0',
21
+ accentHover: '#F0F0F0',
22
+ error: '#FF4444',
23
+ errorBg: '#1C0A0A',
24
+ errorBorder: '#441111',
25
+ success: '#44FF44',
26
+ successBg: '#0A1C0A',
27
+ successBorder: '#114411',
28
+ divider: '#222222',
29
+ disabled: '#444444',
30
+ } as const
31
+
32
+ // ── BankCard ──────────────────────────────────────────────────────
33
+ export const BankCard = styled(View, {
34
+ name: 'BankCard',
35
+ backgroundColor: bankColors.card,
36
+ borderRadius: 24,
37
+ borderWidth: 1,
38
+ borderColor: bankColors.cardBorder,
39
+ padding: 32,
40
+ gap: 32,
41
+ width: '100%',
42
+ maxWidth: 512,
43
+
44
+ variants: {
45
+ size: {
46
+ sm: { padding: 24, gap: 24, maxWidth: 448 },
47
+ md: { padding: 32, gap: 32, maxWidth: 512 },
48
+ lg: { padding: 40, gap: 40, maxWidth: 640 },
49
+ },
50
+ } as const,
51
+
52
+ defaultVariants: {
53
+ size: 'md',
54
+ },
55
+ })
56
+
57
+ export type BankCardProps = GetProps<typeof BankCard>
58
+
59
+ // ── BankInput ─────────────────────────────────────────────────────
60
+ export const BankInput = styled(Text, {
61
+ name: 'BankInput',
62
+ render: 'input',
63
+ backgroundColor: bankColors.input,
64
+ color: bankColors.text,
65
+ borderWidth: 1,
66
+ borderColor: bankColors.inputBorder,
67
+ borderRadius: 12,
68
+ paddingHorizontal: 16,
69
+ paddingVertical: 14,
70
+ fontSize: 16,
71
+ lineHeight: 24,
72
+ outlineStyle: 'none',
73
+ width: '100%',
74
+
75
+ hoverStyle: {
76
+ borderColor: bankColors.inputFocus,
77
+ },
78
+
79
+ focusStyle: {
80
+ borderColor: bankColors.inputFocus,
81
+ },
82
+
83
+ variants: {
84
+ invalid: {
85
+ true: {
86
+ borderColor: bankColors.error,
87
+ },
88
+ },
89
+ size: {
90
+ sm: { paddingVertical: 10, fontSize: 14 },
91
+ md: { paddingVertical: 14, fontSize: 16 },
92
+ lg: { paddingVertical: 18, fontSize: 18 },
93
+ },
94
+ } as const,
95
+
96
+ defaultVariants: {
97
+ size: 'md',
98
+ },
99
+ })
100
+
101
+ export type BankInputProps = GetProps<typeof BankInput> & {
102
+ placeholderTextColor?: string
103
+ }
104
+
105
+ // ── BankButton ────────────────────────────────────────────────────
106
+ export const BankButton = styled(View, {
107
+ name: 'BankButton',
108
+ render: 'button',
109
+ backgroundColor: bankColors.accent,
110
+ borderRadius: 16,
111
+ height: 56,
112
+ alignItems: 'center',
113
+ justifyContent: 'center',
114
+ cursor: 'pointer',
115
+ width: '100%',
116
+ userSelect: 'none',
117
+ borderWidth: 0,
118
+
119
+ pressStyle: {
120
+ backgroundColor: bankColors.accentPress,
121
+ scale: 0.98,
122
+ },
123
+
124
+ hoverStyle: {
125
+ backgroundColor: bankColors.accentHover,
126
+ },
127
+
128
+ variants: {
129
+ variant: {
130
+ primary: {
131
+ backgroundColor: bankColors.accent,
132
+ },
133
+ secondary: {
134
+ backgroundColor: bankColors.cardBorder,
135
+ },
136
+ ghost: {
137
+ backgroundColor: 'transparent',
138
+ borderWidth: 1,
139
+ borderColor: bankColors.cardBorder,
140
+ },
141
+ },
142
+ disabled: {
143
+ true: {
144
+ opacity: 0.3,
145
+ cursor: 'not-allowed',
146
+ pointerEvents: 'none',
147
+ },
148
+ },
149
+ } as const,
150
+
151
+ defaultVariants: {
152
+ variant: 'primary',
153
+ },
154
+ })
155
+
156
+ export const BankButtonText = styled(Text, {
157
+ name: 'BankButtonText',
158
+ color: '#000000',
159
+ fontSize: 16,
160
+ fontWeight: '700',
161
+ textAlign: 'center',
162
+
163
+ variants: {
164
+ variant: {
165
+ primary: { color: '#000000' },
166
+ secondary: { color: bankColors.text },
167
+ ghost: { color: bankColors.text },
168
+ },
169
+ } as const,
170
+ })
171
+
172
+ export type BankButtonProps = GetProps<typeof BankButton>
173
+
174
+ // ── BankHeading ───────────────────────────────────────────────────
175
+ export const BankHeading = styled(Text, {
176
+ name: 'BankHeading',
177
+ color: bankColors.text,
178
+ fontWeight: '700',
179
+
180
+ variants: {
181
+ size: {
182
+ xs: { fontSize: 18, lineHeight: 24 },
183
+ sm: { fontSize: 24, lineHeight: 32 },
184
+ md: { fontSize: 30, lineHeight: 38 },
185
+ lg: { fontSize: 36, lineHeight: 44 },
186
+ xl: { fontSize: 48, lineHeight: 56 },
187
+ },
188
+ } as const,
189
+
190
+ defaultVariants: {
191
+ size: 'lg',
192
+ },
193
+ })
194
+
195
+ export type BankHeadingProps = GetProps<typeof BankHeading>
196
+
197
+ // ── BankText ──────────────────────────────────────────────────────
198
+ export const BankText = styled(Text, {
199
+ name: 'BankText',
200
+ color: bankColors.textMuted,
201
+ fontSize: 16,
202
+ lineHeight: 24,
203
+
204
+ variants: {
205
+ variant: {
206
+ default: { color: bankColors.textMuted },
207
+ label: { color: bankColors.textLabel, fontSize: 14, fontWeight: '500' },
208
+ error: { color: bankColors.error, fontSize: 13 },
209
+ success: { color: bankColors.success, fontSize: 13 },
210
+ link: { color: bankColors.text, fontWeight: '600', cursor: 'pointer' },
211
+ muted: { color: bankColors.disabled },
212
+ },
213
+ } as const,
214
+
215
+ defaultVariants: {
216
+ variant: 'default',
217
+ },
218
+ })
219
+
220
+ export type BankTextProps = GetProps<typeof BankText>
221
+
222
+ // ── BankField ─────────────────────────────────────────────────────
223
+ // Compound component: label + input + error
224
+ export function BankField({
225
+ label,
226
+ error,
227
+ children,
228
+ }: {
229
+ label?: string
230
+ error?: string
231
+ children: React.ReactNode
232
+ }) {
233
+ return (
234
+ <View gap={8} width="100%">
235
+ {label && <BankText variant="label">{label}</BankText>}
236
+ {children}
237
+ {error && <BankText variant="error">{error}</BankText>}
238
+ </View>
239
+ )
240
+ }
241
+
242
+ // ── BankAlert ─────────────────────────────────────────────────────
243
+ export const BankAlert = styled(View, {
244
+ name: 'BankAlert',
245
+ borderRadius: 12,
246
+ padding: 16,
247
+ borderWidth: 1,
248
+ gap: 4,
249
+
250
+ variants: {
251
+ status: {
252
+ error: {
253
+ backgroundColor: bankColors.errorBg,
254
+ borderColor: bankColors.errorBorder,
255
+ },
256
+ success: {
257
+ backgroundColor: bankColors.successBg,
258
+ borderColor: bankColors.successBorder,
259
+ },
260
+ },
261
+ } as const,
262
+ })
263
+
264
+ export const BankAlertText = styled(Text, {
265
+ name: 'BankAlertText',
266
+ fontSize: 14,
267
+
268
+ variants: {
269
+ status: {
270
+ error: { color: bankColors.error },
271
+ success: { color: bankColors.success },
272
+ },
273
+ } as const,
274
+ })
275
+
276
+ export type BankAlertProps = GetProps<typeof BankAlert>
277
+
278
+ // ── BankPinInput ──────────────────────────────────────────────────
279
+ export const BankPinBox = styled(Text, {
280
+ name: 'BankPinBox',
281
+ render: 'input',
282
+ backgroundColor: bankColors.input,
283
+ color: bankColors.text,
284
+ borderWidth: 1,
285
+ borderColor: bankColors.inputBorder,
286
+ borderRadius: 12,
287
+ width: 48,
288
+ height: 48,
289
+ textAlign: 'center',
290
+ fontSize: 20,
291
+ fontWeight: '600',
292
+ outlineStyle: 'none',
293
+
294
+ focusStyle: {
295
+ borderColor: bankColors.inputFocus,
296
+ },
297
+
298
+ variants: {
299
+ invalid: {
300
+ true: { borderColor: bankColors.error },
301
+ },
302
+ } as const,
303
+ })
304
+
305
+ export type BankPinBoxProps = GetProps<typeof BankPinBox>
306
+
307
+ // ── BankDivider ───────────────────────────────────────────────────
308
+ export const BankDivider = styled(View, {
309
+ name: 'BankDivider',
310
+ height: 1,
311
+ width: '100%',
312
+ backgroundColor: bankColors.divider,
313
+ })
314
+
315
+ // ── BankPage (full-screen dark background) ────────────────────────
316
+ export const BankPage = styled(View, {
317
+ name: 'BankPage',
318
+ backgroundColor: bankColors.bg,
319
+ minHeight: '100vh',
320
+ alignItems: 'center',
321
+ justifyContent: 'center',
322
+ padding: 16,
323
+ })
324
+
325
+ export type BankPageProps = GetProps<typeof BankPage>