@luxfi/ui 7.4.11 → 7.4.13
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/alert.cjs +68 -46
- package/dist/alert.js +69 -46
- package/dist/avatar.cjs +49 -47
- package/dist/avatar.js +52 -49
- package/dist/badge.cjs +82 -49
- package/dist/badge.js +83 -50
- package/dist/checkbox.cjs +42 -75
- package/dist/checkbox.js +43 -76
- package/dist/chrome.cjs +3 -7
- package/dist/chrome.js +3 -7
- package/dist/close-button.cjs +3 -7
- package/dist/close-button.js +3 -7
- package/dist/dialog.cjs +3 -7
- package/dist/dialog.js +3 -7
- package/dist/drawer.cjs +3 -7
- package/dist/drawer.js +3 -7
- package/dist/empty-state.cjs +13 -13
- package/dist/empty-state.js +13 -13
- package/dist/expiration-selector.cjs +58 -63
- package/dist/expiration-selector.js +58 -63
- package/dist/greeks-display.cjs +48 -39
- package/dist/greeks-display.js +48 -39
- package/dist/index.cjs +1053 -888
- package/dist/index.js +1054 -889
- package/dist/input-group.cjs +36 -19
- package/dist/input-group.js +37 -19
- package/dist/option-chain.cjs +89 -67
- package/dist/option-chain.js +89 -67
- package/dist/option-position.cjs +88 -85
- package/dist/option-position.js +88 -85
- package/dist/pin-input.cjs +30 -29
- package/dist/pin-input.js +30 -29
- package/dist/pnl-diagram.cjs +20 -20
- package/dist/pnl-diagram.js +20 -20
- package/dist/popover.cjs +3 -7
- package/dist/popover.js +3 -7
- package/dist/progress-circle.cjs +40 -22
- package/dist/progress-circle.d.cts +5 -5
- package/dist/progress-circle.d.ts +5 -5
- package/dist/progress-circle.js +41 -22
- package/dist/progress.cjs +15 -22
- package/dist/progress.d.cts +6 -6
- package/dist/progress.d.ts +6 -6
- package/dist/progress.js +15 -22
- package/dist/radio.cjs +35 -68
- package/dist/radio.d.cts +18 -18
- package/dist/radio.d.ts +18 -18
- package/dist/radio.js +36 -69
- package/dist/rating.cjs +15 -17
- package/dist/rating.js +15 -17
- package/dist/slider.cjs +33 -50
- package/dist/slider.js +34 -51
- package/dist/strategy-builder.cjs +194 -115
- package/dist/strategy-builder.js +194 -115
- package/dist/switch.cjs +48 -55
- package/dist/switch.js +49 -56
- package/dist/tag.cjs +115 -69
- package/dist/tag.js +116 -69
- package/dist/tooltip.cjs +28 -17
- package/dist/tooltip.js +30 -18
- package/package.json +1 -1
- package/src/alert.tsx +78 -45
- package/src/avatar.tsx +54 -38
- package/src/badge.tsx +65 -44
- package/src/checkbox.tsx +70 -89
- package/src/close-button.tsx +3 -8
- package/src/empty-state.tsx +21 -17
- package/src/expiration-selector.tsx +84 -66
- package/src/greeks-display.tsx +59 -51
- package/src/input-group.tsx +38 -24
- package/src/option-chain.tsx +154 -104
- package/src/option-position.tsx +143 -114
- package/src/pin-input.tsx +37 -29
- package/src/pnl-diagram.tsx +36 -28
- package/src/progress-circle.tsx +52 -28
- package/src/progress.tsx +17 -21
- package/src/radio.tsx +56 -76
- package/src/rating.tsx +22 -20
- package/src/slider.tsx +43 -45
- package/src/strategy-builder.tsx +260 -162
- package/src/switch.tsx +63 -64
- package/src/tag.tsx +89 -51
- package/src/tooltip.tsx +21 -13
- package/tokens.css +18 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { Text, XStack, YStack } from '@hanzo/gui';
|
|
3
4
|
import * as React from 'react';
|
|
4
5
|
|
|
5
|
-
import { cn } from './utils';
|
|
6
|
-
|
|
7
6
|
// ---------------------------------------------------------------------------
|
|
8
7
|
// Types
|
|
9
8
|
// ---------------------------------------------------------------------------
|
|
@@ -48,31 +47,62 @@ interface ExpirationPillProps {
|
|
|
48
47
|
readonly onClick: () => void;
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
// Resting and selected are the same two states every selectable pill in this
|
|
51
|
+
// package uses (tabs, menu rows): a solid fill when selected, a bordered card
|
|
52
|
+
// otherwise. Stacks carry no `color` of their own (only Text does — same
|
|
53
|
+
// reason they carry no `fontSize`), so ink is computed per-state below and
|
|
54
|
+
// set directly on each Text rather than left to cascade from the button.
|
|
55
|
+
const SHAPE = {
|
|
56
|
+
selected: {
|
|
57
|
+
borderColor: 'transparent',
|
|
58
|
+
backgroundColor: 'var(--color-selected-control-bg)',
|
|
59
|
+
},
|
|
60
|
+
resting: {
|
|
61
|
+
borderColor: 'var(--color-border-divider)',
|
|
62
|
+
backgroundColor: 'var(--card)',
|
|
63
|
+
hoverStyle: { borderColor: 'var(--color-hover)' },
|
|
64
|
+
},
|
|
65
|
+
} as const;
|
|
66
|
+
|
|
51
67
|
function ExpirationPill({ exp, isSelected, onClick }: ExpirationPillProps) {
|
|
68
|
+
const shape = isSelected ? SHAPE.selected : SHAPE.resting;
|
|
69
|
+
const dateColor = isSelected ? 'var(--color-selected-control-text)' : 'var(--color-text-secondary)';
|
|
70
|
+
|
|
71
|
+
// Near-expiry is a notice, and a notice in Lux is the loudest neutral — it
|
|
72
|
+
// only shows while resting; a selected pill's own fill already carries the
|
|
73
|
+
// emphasis.
|
|
74
|
+
const dteColor = exp.dte <= 7 && !isSelected
|
|
75
|
+
? 'var(--color-status-warn)'
|
|
76
|
+
: isSelected ? 'var(--color-selected-control-text)' : 'var(--muted-foreground)';
|
|
77
|
+
|
|
52
78
|
return (
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
<YStack
|
|
80
|
+
unstyled
|
|
81
|
+
render={ <button type="button"/> }
|
|
82
|
+
onClick={ onClick }
|
|
83
|
+
alignItems="center"
|
|
84
|
+
gap={ 2 }
|
|
85
|
+
borderRadius={ 6 }
|
|
86
|
+
paddingHorizontal={ 12 }
|
|
87
|
+
paddingVertical={ 6 }
|
|
88
|
+
flexShrink={ 0 }
|
|
89
|
+
borderWidth={ 1 }
|
|
90
|
+
borderStyle="solid"
|
|
91
|
+
cursor="pointer"
|
|
92
|
+
{ ...(shape as object) }
|
|
63
93
|
>
|
|
64
|
-
<
|
|
65
|
-
{formatExpDate(exp.date)}
|
|
66
|
-
</
|
|
67
|
-
<
|
|
68
|
-
'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{exp.dte}d
|
|
74
|
-
</
|
|
75
|
-
</
|
|
94
|
+
<Text fontSize={ 12 } fontWeight="500" style={ { whiteSpace: 'nowrap' } as never } color={ dateColor as never }>
|
|
95
|
+
{ formatExpDate(exp.date) }
|
|
96
|
+
</Text>
|
|
97
|
+
<Text
|
|
98
|
+
fontVariant={ ['tabular-nums'] as never }
|
|
99
|
+
style={ { fontFamily: 'monospace' } as never }
|
|
100
|
+
fontSize={ 10 }
|
|
101
|
+
color={ dteColor as never }
|
|
102
|
+
>
|
|
103
|
+
{ exp.dte }d
|
|
104
|
+
</Text>
|
|
105
|
+
</YStack>
|
|
76
106
|
);
|
|
77
107
|
}
|
|
78
108
|
|
|
@@ -111,54 +141,42 @@ export const ExpirationSelector = React.forwardRef<HTMLDivElement, ExpirationSel
|
|
|
111
141
|
})).filter((g) => g.items.length > 0);
|
|
112
142
|
|
|
113
143
|
return (
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{group.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/>
|
|
144
|
+
<YStack ref={ ref as never } gap={ 8 } className={ className } { ...(rest as object) }>
|
|
145
|
+
{ grouped.map((group) => (
|
|
146
|
+
<YStack key={ group.type } gap={ 4 }>
|
|
147
|
+
<Text
|
|
148
|
+
fontSize={ 10 }
|
|
149
|
+
fontWeight="600"
|
|
150
|
+
textTransform="uppercase"
|
|
151
|
+
letterSpacing={ 0.5 }
|
|
152
|
+
paddingHorizontal={ 4 }
|
|
153
|
+
color={ 'var(--color-text-secondary)' as never }
|
|
154
|
+
>
|
|
155
|
+
{ group.label }
|
|
156
|
+
</Text>
|
|
157
|
+
<XStack gap={ 6 } overflowX="auto" overflowY="hidden" className="lux-no-scrollbar">
|
|
158
|
+
{ group.items.map((exp) => (
|
|
159
|
+
<div key={ exp.date } data-selected={ exp.date === selected || undefined }>
|
|
160
|
+
<ExpirationPill exp={ exp } isSelected={ exp.date === selected } onClick={ () => onSelect(exp.date) }/>
|
|
132
161
|
</div>
|
|
133
|
-
))}
|
|
134
|
-
</
|
|
135
|
-
</
|
|
136
|
-
))}
|
|
137
|
-
</
|
|
162
|
+
)) }
|
|
163
|
+
</XStack>
|
|
164
|
+
</YStack>
|
|
165
|
+
)) }
|
|
166
|
+
</YStack>
|
|
138
167
|
);
|
|
139
168
|
}
|
|
140
169
|
|
|
141
170
|
return (
|
|
142
|
-
<
|
|
143
|
-
ref={
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
<div
|
|
148
|
-
ref={scrollRef}
|
|
149
|
-
className="flex gap-1.5 overflow-x-auto no-scrollbar"
|
|
150
|
-
>
|
|
151
|
-
{expirations.map((exp) => (
|
|
152
|
-
<div key={exp.date} data-selected={exp.date === selected || undefined}>
|
|
153
|
-
<ExpirationPill
|
|
154
|
-
exp={exp}
|
|
155
|
-
isSelected={exp.date === selected}
|
|
156
|
-
onClick={() => onSelect(exp.date)}
|
|
157
|
-
/>
|
|
171
|
+
<XStack ref={ ref as never } alignItems="center" gap={ 4 } className={ className } { ...(rest as object) }>
|
|
172
|
+
<XStack ref={ scrollRef as never } gap={ 6 } overflowX="auto" overflowY="hidden" className="lux-no-scrollbar">
|
|
173
|
+
{ expirations.map((exp) => (
|
|
174
|
+
<div key={ exp.date } data-selected={ exp.date === selected || undefined }>
|
|
175
|
+
<ExpirationPill exp={ exp } isSelected={ exp.date === selected } onClick={ () => onSelect(exp.date) }/>
|
|
158
176
|
</div>
|
|
159
|
-
))}
|
|
160
|
-
</
|
|
161
|
-
</
|
|
177
|
+
)) }
|
|
178
|
+
</XStack>
|
|
179
|
+
</XStack>
|
|
162
180
|
);
|
|
163
181
|
},
|
|
164
182
|
);
|
package/src/greeks-display.tsx
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { Text, View, XStack } from '@hanzo/gui';
|
|
3
4
|
import * as React from 'react';
|
|
4
5
|
|
|
5
|
-
import { cn } from './utils';
|
|
6
|
-
|
|
7
6
|
// ---------------------------------------------------------------------------
|
|
8
7
|
// Types
|
|
9
8
|
// ---------------------------------------------------------------------------
|
|
@@ -36,12 +35,12 @@ interface GreekDef {
|
|
|
36
35
|
// on one achromatic ramp (tokens.css --chart-*, plus --foreground for the sixth),
|
|
37
36
|
// so the panel obeys the brand atom and reskins with the host.
|
|
38
37
|
const GREEKS: GreekDef[] = [
|
|
39
|
-
{ key: 'delta', label: 'Delta', symbol: '
|
|
40
|
-
{ key: 'gamma', label: 'Gamma', symbol: '
|
|
41
|
-
{ key: 'theta', label: 'Theta', symbol: '
|
|
42
|
-
{ key: 'vega', label: 'Vega', symbol: '
|
|
43
|
-
{ key: 'rho', label: 'Rho', symbol: '
|
|
44
|
-
{ key: 'iv', label: 'IV', symbol: '
|
|
38
|
+
{ key: 'delta', label: 'Delta', symbol: 'Δ', color: 'var(--foreground)', barColor: 'var(--foreground)', decimals: 4, maxMagnitude: 1 },
|
|
39
|
+
{ key: 'gamma', label: 'Gamma', symbol: 'Γ', color: 'var(--chart-1)', barColor: 'var(--chart-1)', decimals: 4, maxMagnitude: 0.1 },
|
|
40
|
+
{ key: 'theta', label: 'Theta', symbol: 'Θ', color: 'var(--chart-4)', barColor: 'var(--chart-4)', decimals: 4, maxMagnitude: 1 },
|
|
41
|
+
{ key: 'vega', label: 'Vega', symbol: 'ν', color: 'var(--chart-2)', barColor: 'var(--chart-2)', decimals: 4, maxMagnitude: 1 },
|
|
42
|
+
{ key: 'rho', label: 'Rho', symbol: 'ρ', color: 'var(--chart-3)', barColor: 'var(--chart-3)', decimals: 4, maxMagnitude: 1 },
|
|
43
|
+
{ key: 'iv', label: 'IV', symbol: 'σ', color: 'var(--chart-5)', barColor: 'var(--chart-5)', decimals: 1, maxMagnitude: 100 },
|
|
45
44
|
];
|
|
46
45
|
|
|
47
46
|
// ---------------------------------------------------------------------------
|
|
@@ -61,35 +60,45 @@ function GreekItem({ def, value, compact }: GreekItemProps) {
|
|
|
61
60
|
: value.toFixed(def.decimals);
|
|
62
61
|
|
|
63
62
|
return (
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
63
|
+
<XStack alignItems="center" gap={ 6 } minWidth={ compact ? 0 : 100 }>
|
|
64
|
+
<Text fontSize={ 10 } fontWeight="600" flexShrink={ 0 } color={ def.color as never }>
|
|
65
|
+
{ def.symbol }
|
|
66
|
+
</Text>
|
|
67
|
+
{ !compact && (
|
|
68
|
+
<Text fontSize={ 10 } flexShrink={ 0 } width={ 34 } color={ 'var(--color-text-secondary)' as never }>
|
|
69
|
+
{ def.label }
|
|
70
|
+
</Text>
|
|
71
|
+
) }
|
|
72
|
+
<Text
|
|
73
|
+
fontSize={ 12 }
|
|
74
|
+
flexShrink={ 0 }
|
|
75
|
+
style={ { fontFamily: 'monospace' } as never }
|
|
76
|
+
fontVariant={ ['tabular-nums'] as never }
|
|
77
|
+
color={ (value < 0 ? 'var(--color-status-bad)' : 'var(--color-text-primary)') as never }
|
|
78
|
+
>
|
|
79
|
+
{ displayValue }
|
|
80
|
+
</Text>
|
|
81
|
+
{ !compact && (
|
|
82
|
+
<View
|
|
83
|
+
flex={ 1 }
|
|
84
|
+
height={ 4 }
|
|
85
|
+
borderRadius={ 9999 }
|
|
86
|
+
minWidth={ 24 }
|
|
87
|
+
maxWidth={ 48 }
|
|
88
|
+
overflow="hidden"
|
|
89
|
+
backgroundColor={ 'var(--color-progress-track)' as never }
|
|
90
|
+
>
|
|
91
|
+
<View
|
|
92
|
+
height="100%"
|
|
93
|
+
borderRadius={ 9999 }
|
|
94
|
+
transition="quick"
|
|
95
|
+
width={ `${ magnitude * 100 }%` as never }
|
|
96
|
+
opacity={ 0.7 }
|
|
97
|
+
backgroundColor={ def.barColor as never }
|
|
89
98
|
/>
|
|
90
|
-
</
|
|
91
|
-
)}
|
|
92
|
-
</
|
|
99
|
+
</View>
|
|
100
|
+
) }
|
|
101
|
+
</XStack>
|
|
93
102
|
);
|
|
94
103
|
}
|
|
95
104
|
|
|
@@ -118,24 +127,23 @@ export const GreeksDisplay = React.forwardRef<HTMLDivElement, GreeksDisplayProps
|
|
|
118
127
|
const activeGreeks = GREEKS.filter((g) => values[g.key] !== undefined);
|
|
119
128
|
|
|
120
129
|
return (
|
|
121
|
-
<
|
|
122
|
-
ref={ref}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)}
|
|
128
|
-
{...rest}
|
|
130
|
+
<XStack
|
|
131
|
+
ref={ ref as never }
|
|
132
|
+
flexWrap="wrap"
|
|
133
|
+
alignItems="center"
|
|
134
|
+
gap={ compact ? 12 : 16 }
|
|
135
|
+
className={ className }
|
|
136
|
+
{ ...(rest as object) }
|
|
129
137
|
>
|
|
130
|
-
{activeGreeks.map((g) => (
|
|
138
|
+
{ activeGreeks.map((g) => (
|
|
131
139
|
<GreekItem
|
|
132
|
-
key={g.key}
|
|
133
|
-
def={g}
|
|
134
|
-
value={values[g.key] as number}
|
|
135
|
-
compact={compact}
|
|
140
|
+
key={ g.key }
|
|
141
|
+
def={ g }
|
|
142
|
+
value={ values[g.key] as number }
|
|
143
|
+
compact={ compact }
|
|
136
144
|
/>
|
|
137
|
-
))}
|
|
138
|
-
</
|
|
145
|
+
)) }
|
|
146
|
+
</XStack>
|
|
139
147
|
);
|
|
140
148
|
},
|
|
141
149
|
);
|
package/src/input-group.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { XStack } from '@hanzo/gui';
|
|
1
2
|
import { debounce } from 'es-toolkit';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { ink } from './ink';
|
|
5
6
|
|
|
6
7
|
import type { InputProps } from './input';
|
|
7
8
|
|
|
@@ -110,22 +111,30 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
|
|
110
111
|
const { className: endClassName, ...endRest } = endElementProps ?? {};
|
|
111
112
|
|
|
112
113
|
return (
|
|
113
|
-
<
|
|
114
|
-
ref={ combinedRef }
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
<XStack
|
|
115
|
+
ref={ combinedRef as never }
|
|
116
|
+
position="relative"
|
|
117
|
+
width="100%"
|
|
118
|
+
alignItems="center"
|
|
119
|
+
className={ className }
|
|
120
|
+
{ ...(rest as object) }
|
|
117
121
|
>
|
|
118
122
|
{ startElement && (
|
|
119
|
-
<
|
|
120
|
-
ref={ startElementRef }
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{
|
|
123
|
+
<XStack
|
|
124
|
+
ref={ startElementRef as never }
|
|
125
|
+
position="absolute"
|
|
126
|
+
top={ 0 }
|
|
127
|
+
bottom={ 0 }
|
|
128
|
+
left={ 0 }
|
|
129
|
+
zIndex={ 1 }
|
|
130
|
+
alignItems="center"
|
|
131
|
+
pointerEvents="none"
|
|
132
|
+
style={{ color: 'var(--color-icon-secondary)' }}
|
|
133
|
+
className={ startClassName }
|
|
134
|
+
{ ...(startRest as object) }
|
|
126
135
|
>
|
|
127
|
-
{ startElement }
|
|
128
|
-
</
|
|
136
|
+
{ ink(startElement) }
|
|
137
|
+
</XStack>
|
|
129
138
|
) }
|
|
130
139
|
{ React.Children.map(children, (child: React.ReactElement<InputProps>) => {
|
|
131
140
|
if (!React.isValidElement(child)) {
|
|
@@ -149,18 +158,23 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
|
|
|
149
158
|
});
|
|
150
159
|
}) }
|
|
151
160
|
{ endElement && (
|
|
152
|
-
<
|
|
153
|
-
ref={ endElementRef }
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
{
|
|
161
|
+
<XStack
|
|
162
|
+
ref={ endElementRef as never }
|
|
163
|
+
position="absolute"
|
|
164
|
+
top={ 0 }
|
|
165
|
+
bottom={ 0 }
|
|
166
|
+
right={ 0 }
|
|
167
|
+
zIndex={ 1 }
|
|
168
|
+
alignItems="center"
|
|
169
|
+
pointerEvents="none"
|
|
170
|
+
style={{ color: 'var(--color-icon-secondary)' }}
|
|
171
|
+
className={ endClassName }
|
|
172
|
+
{ ...(endRest as object) }
|
|
159
173
|
>
|
|
160
|
-
{ endElement }
|
|
161
|
-
</
|
|
174
|
+
{ ink(endElement) }
|
|
175
|
+
</XStack>
|
|
162
176
|
) }
|
|
163
|
-
</
|
|
177
|
+
</XStack>
|
|
164
178
|
);
|
|
165
179
|
},
|
|
166
180
|
);
|