@luxfi/ui 7.4.12 → 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/avatar.cjs +0 -1
- package/dist/avatar.js +0 -1
- package/dist/index.cjs +320 -208
- package/dist/index.js +320 -208
- package/dist/input-group.cjs +36 -19
- package/dist/input-group.js +37 -19
- package/dist/pin-input.cjs +30 -29
- package/dist/pin-input.js +30 -29
- 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/radio.cjs +0 -1
- package/dist/radio.js +0 -1
- package/dist/rating.cjs +15 -17
- package/dist/rating.js +15 -17
- package/dist/slider.cjs +0 -1
- package/dist/slider.js +0 -1
- package/dist/strategy-builder.cjs +194 -115
- package/dist/strategy-builder.js +194 -115
- package/dist/tag.cjs +18 -15
- package/dist/tag.js +18 -15
- package/package.json +1 -1
- package/src/avatar.tsx +1 -2
- package/src/expiration-selector.tsx +6 -6
- package/src/input-group.tsx +2 -2
- package/src/option-position.tsx +9 -2
- package/src/progress-circle.tsx +52 -28
- package/src/radio.tsx +0 -1
- package/src/rating.tsx +22 -20
- package/src/slider.tsx +0 -1
- package/src/strategy-builder.tsx +51 -42
package/src/progress-circle.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { View } from '@hanzo/gui';
|
|
1
2
|
import * as React from 'react';
|
|
2
3
|
|
|
4
|
+
import { ink } from './ink';
|
|
3
5
|
import { cn } from './utils';
|
|
4
6
|
|
|
5
7
|
// ---------------------------------------------------------------------------
|
|
@@ -7,11 +9,11 @@ import { cn } from './utils';
|
|
|
7
9
|
// ---------------------------------------------------------------------------
|
|
8
10
|
|
|
9
11
|
const SIZE_MAP = {
|
|
10
|
-
xs: { size: 24, thickness: 4,
|
|
11
|
-
sm: { size: 32, thickness: 5,
|
|
12
|
-
md: { size: 40, thickness: 6,
|
|
13
|
-
lg: { size: 48, thickness: 7,
|
|
14
|
-
xl: { size: 64, thickness: 8,
|
|
12
|
+
xs: { size: 24, thickness: 4, fontSize: 10 },
|
|
13
|
+
sm: { size: 32, thickness: 5, fontSize: 10 },
|
|
14
|
+
md: { size: 40, thickness: 6, fontSize: 12 },
|
|
15
|
+
lg: { size: 48, thickness: 7, fontSize: 14 },
|
|
16
|
+
xl: { size: 64, thickness: 8, fontSize: 14 },
|
|
15
17
|
} as const;
|
|
16
18
|
|
|
17
19
|
type Size = keyof typeof SIZE_MAP;
|
|
@@ -63,17 +65,23 @@ export const ProgressCircleRoot = React.forwardRef<
|
|
|
63
65
|
|
|
64
66
|
return (
|
|
65
67
|
<Ctx.Provider value={ ctx }>
|
|
66
|
-
<
|
|
67
|
-
ref={ ref }
|
|
68
|
+
<View
|
|
69
|
+
ref={ ref as never }
|
|
68
70
|
role="progressbar"
|
|
69
71
|
aria-valuenow={ value ?? undefined }
|
|
70
72
|
aria-valuemin={ 0 }
|
|
71
73
|
aria-valuemax={ 100 }
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
position="relative"
|
|
75
|
+
// `inline-flex` and `fontSize` are not in a Stack's style base — a
|
|
76
|
+
// Stack has no text props at all, and its `display` enum is narrower
|
|
77
|
+
// than CSS's (no `inline-*` variants) — so both travel as plain style
|
|
78
|
+
// here rather than gui props.
|
|
79
|
+
style={{ display: 'inline-flex', fontSize: 14 }}
|
|
80
|
+
className={ className }
|
|
81
|
+
{ ...(rest as object) }
|
|
74
82
|
>
|
|
75
|
-
{ children }
|
|
76
|
-
</
|
|
83
|
+
{ ink(children) }
|
|
84
|
+
</View>
|
|
77
85
|
</Ctx.Provider>
|
|
78
86
|
);
|
|
79
87
|
});
|
|
@@ -108,10 +116,7 @@ export const ProgressCircleRing = React.forwardRef<
|
|
|
108
116
|
width={ size }
|
|
109
117
|
height={ size }
|
|
110
118
|
viewBox={ `0 0 ${ size } ${ size }` }
|
|
111
|
-
className={ cn(
|
|
112
|
-
value === null && 'animate-spin',
|
|
113
|
-
className,
|
|
114
|
-
) }
|
|
119
|
+
className={ value === null ? cn('lux-spin', className) : className }
|
|
115
120
|
{ ...rest }
|
|
116
121
|
>
|
|
117
122
|
{ /* Track */ }
|
|
@@ -122,7 +127,7 @@ export const ProgressCircleRing = React.forwardRef<
|
|
|
122
127
|
fill="transparent"
|
|
123
128
|
strokeWidth={ thickness }
|
|
124
129
|
stroke={ trackColor ?? 'currentColor' }
|
|
125
|
-
|
|
130
|
+
opacity={ !trackColor ? 0.2 : undefined }
|
|
126
131
|
/>
|
|
127
132
|
{ /* Range */ }
|
|
128
133
|
<circle
|
|
@@ -160,21 +165,40 @@ export const ProgressCircleValueText = React.forwardRef<
|
|
|
160
165
|
const { className, children, ...rest } = props;
|
|
161
166
|
const { value, size: sizeKey } = React.useContext(Ctx);
|
|
162
167
|
|
|
163
|
-
const {
|
|
168
|
+
const { fontSize } = SIZE_MAP[sizeKey];
|
|
164
169
|
|
|
165
170
|
return (
|
|
166
|
-
<
|
|
167
|
-
ref={ ref }
|
|
171
|
+
<View
|
|
172
|
+
ref={ ref as never }
|
|
168
173
|
aria-live="polite"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
position="absolute"
|
|
175
|
+
top={ 0 }
|
|
176
|
+
left={ 0 }
|
|
177
|
+
right={ 0 }
|
|
178
|
+
bottom={ 0 }
|
|
179
|
+
display="flex"
|
|
180
|
+
alignItems="center"
|
|
181
|
+
justifyContent="center"
|
|
182
|
+
// A Stack has no text props (fontSize/fontWeight/letterSpacing/lineHeight
|
|
183
|
+
// /fontVariantNumeric) — a View cannot style text any more than a native
|
|
184
|
+
// <View> can, only the <Text> inside it. `ink()` below hosts the string
|
|
185
|
+
// in a real Text, but callers may also pass their own element, so this
|
|
186
|
+
// stays a style object rather than gui text props: it composes either
|
|
187
|
+
// way, exactly like the Tailwind classes it replaces did through
|
|
188
|
+
// inheritance. Tailwind's `leading-none` (line-height: 1, unitless) and
|
|
189
|
+
// `tracking-tight` (-0.025em) are both relative to font size, so they are
|
|
190
|
+
// computed per size tier here instead of copied as one constant.
|
|
191
|
+
style={{
|
|
192
|
+
fontWeight: 500,
|
|
193
|
+
fontSize,
|
|
194
|
+
lineHeight: `${ fontSize }px`,
|
|
195
|
+
letterSpacing: fontSize * -0.025,
|
|
196
|
+
fontVariantNumeric: 'tabular-nums',
|
|
197
|
+
}}
|
|
198
|
+
className={ className }
|
|
199
|
+
{ ...(rest as object) }
|
|
176
200
|
>
|
|
177
|
-
{ children ?? `${ Math.round(value ?? 0) }%` }
|
|
178
|
-
</
|
|
201
|
+
{ ink(children ?? `${ Math.round(value ?? 0) }%`) }
|
|
202
|
+
</View>
|
|
179
203
|
);
|
|
180
204
|
});
|
package/src/radio.tsx
CHANGED
|
@@ -64,7 +64,6 @@ const RadioGroupBase = React.forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
|
64
64
|
from its headless core, real Pressables on native. */ }
|
|
65
65
|
<GuiRadioGroup
|
|
66
66
|
ref={ ref as never }
|
|
67
|
-
unstyled
|
|
68
67
|
name={ name }
|
|
69
68
|
required={ required }
|
|
70
69
|
disabled={ disabled || readOnly }
|
package/src/rating.tsx
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import { Text, View, XStack } from '@hanzo/gui';
|
|
1
2
|
import * as React from 'react';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<svg className={ className } viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
4
|
+
// Inline star icons — fixed at the one size Rating ever draws them (20px, the
|
|
5
|
+
// star buttons' own width/height), so there is nothing left to parameterize.
|
|
6
|
+
const StarFilledIcon = () => (
|
|
7
|
+
<svg width={ 20 } height={ 20 } viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
8
8
|
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
|
|
9
9
|
</svg>
|
|
10
10
|
);
|
|
11
|
-
const StarOutlineIcon = (
|
|
12
|
-
<svg
|
|
11
|
+
const StarOutlineIcon = () => (
|
|
12
|
+
<svg width={ 20 } height={ 20 } viewBox="0 0 20 20" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
13
13
|
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" strokeWidth="1.5"/>
|
|
14
14
|
</svg>
|
|
15
15
|
);
|
|
@@ -48,32 +48,34 @@ export const Rating = React.forwardRef<HTMLDivElement, RatingProps>(
|
|
|
48
48
|
}, []);
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
|
-
<
|
|
52
|
-
<
|
|
51
|
+
<XStack ref={ ref as never } display="inline-flex" alignItems="center" gap={ 4 } className={ className } { ...(rest as object) }>
|
|
52
|
+
<XStack display="inline-flex" alignItems="center" onMouseLeave={ handleMouseLeave }>
|
|
53
53
|
{ Array.from({ length: count }).map((_, index) => {
|
|
54
54
|
const filled = index < highlightedIndex;
|
|
55
55
|
const starIndex = index + 1;
|
|
56
56
|
|
|
57
57
|
return (
|
|
58
|
-
<
|
|
58
|
+
<View
|
|
59
59
|
key={ index }
|
|
60
|
-
type="button"
|
|
60
|
+
render={ <button type="button"/> }
|
|
61
61
|
tabIndex={ readOnly ? -1 : 0 }
|
|
62
62
|
aria-label={ `Rate ${ starIndex } of ${ count }` }
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
display="inline-flex"
|
|
64
|
+
alignItems="center"
|
|
65
|
+
justifyContent="center"
|
|
66
|
+
width={ 20 }
|
|
67
|
+
height={ 20 }
|
|
68
|
+
cursor={ readOnly ? 'default' : 'pointer' }
|
|
67
69
|
onClick={ handleClick(starIndex) }
|
|
68
70
|
onMouseEnter={ handleMouseEnter(index) }
|
|
69
71
|
>
|
|
70
|
-
{ filled ? <StarFilledIcon
|
|
71
|
-
</
|
|
72
|
+
{ filled ? <StarFilledIcon/> : <StarOutlineIcon/> }
|
|
73
|
+
</View>
|
|
72
74
|
);
|
|
73
75
|
}) }
|
|
74
|
-
</
|
|
75
|
-
{ label && <
|
|
76
|
-
</
|
|
76
|
+
</XStack>
|
|
77
|
+
{ label && <Text fontSize={ 14 }>{ label }</Text> }
|
|
78
|
+
</XStack>
|
|
77
79
|
);
|
|
78
80
|
},
|
|
79
81
|
);
|
package/src/slider.tsx
CHANGED
package/src/strategy-builder.tsx
CHANGED
|
@@ -163,20 +163,25 @@ const STRATEGY_PRESETS: StrategyPreset[] = [
|
|
|
163
163
|
];
|
|
164
164
|
|
|
165
165
|
// ---------------------------------------------------------------------------
|
|
166
|
-
// Shared control shape — same tokens input.tsx's
|
|
166
|
+
// Shared native-control shape — same tokens input.tsx's own control uses.
|
|
167
|
+
// `<select>`/`<input>` render no gui Text of their own, so every text-facing
|
|
168
|
+
// property (colour, size, family) rides the `style` escape hatch here rather
|
|
169
|
+
// than a typed prop: View's typed props are the same regardless of what tag
|
|
170
|
+
// `render` points at, and none of them cover text — only Text has those.
|
|
167
171
|
// ---------------------------------------------------------------------------
|
|
168
172
|
|
|
169
|
-
const MONO =
|
|
173
|
+
const MONO = 'monospace';
|
|
170
174
|
|
|
171
|
-
const
|
|
175
|
+
const CONTROL_BOX = {
|
|
172
176
|
backgroundColor: 'var(--color-input-bg)',
|
|
173
177
|
borderWidth: 1,
|
|
174
178
|
borderColor: 'var(--color-input-border)',
|
|
175
|
-
color: 'var(--color-input-fg)',
|
|
176
179
|
outlineWidth: 0,
|
|
177
180
|
focusStyle: { borderColor: 'var(--color-input-border-focus)' },
|
|
178
181
|
} as const;
|
|
179
182
|
|
|
183
|
+
const CONTROL_INK = { color: 'var(--color-input-fg)' };
|
|
184
|
+
|
|
180
185
|
// ---------------------------------------------------------------------------
|
|
181
186
|
// LegRow
|
|
182
187
|
// ---------------------------------------------------------------------------
|
|
@@ -205,7 +210,7 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
|
|
|
205
210
|
paddingHorizontal={ 8 }
|
|
206
211
|
paddingVertical={ 6 }
|
|
207
212
|
>
|
|
208
|
-
<Text fontSize={ 10 } style={ MONO } flexShrink={ 0 } width={ 16 } color={ 'var(--color-text-secondary)' as never }>
|
|
213
|
+
<Text fontSize={ 10 } style={ { fontFamily: MONO } as never } flexShrink={ 0 } width={ 16 } color={ 'var(--color-text-secondary)' as never }>
|
|
209
214
|
{ index + 1 }
|
|
210
215
|
</Text>
|
|
211
216
|
|
|
@@ -247,19 +252,19 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
|
|
|
247
252
|
</Text>
|
|
248
253
|
</XStack>
|
|
249
254
|
|
|
250
|
-
{/* Strike
|
|
255
|
+
{/* Strike. `value`/`onChange` are native <select> attributes, not gui
|
|
256
|
+
style props — View's prop set is fixed regardless of what `render`
|
|
257
|
+
points at, so anything the host tag itself needs (not a style) lives
|
|
258
|
+
on the `render` element, same as `type="button"` does for buttons. */}
|
|
251
259
|
<View
|
|
252
260
|
unstyled
|
|
253
|
-
render={ <select/> }
|
|
254
|
-
|
|
255
|
-
onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => update({ strike: Number(e.target.value) }) }
|
|
256
|
-
{ ...CONTROL }
|
|
257
|
-
style={ MONO }
|
|
258
|
-
fontSize={ 12 }
|
|
261
|
+
render={ <select value={ leg.strike } onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => update({ strike: Number(e.target.value) }) }/> as never }
|
|
262
|
+
{ ...CONTROL_BOX }
|
|
259
263
|
borderRadius={ 4 }
|
|
260
264
|
paddingHorizontal={ 6 }
|
|
261
265
|
paddingVertical={ 2 }
|
|
262
266
|
minWidth={ 72 }
|
|
267
|
+
style={ { ...CONTROL_INK, fontFamily: MONO, fontSize: 12 } as never }
|
|
263
268
|
>
|
|
264
269
|
{ strikes.map((s) => (
|
|
265
270
|
<option key={ s } value={ s }>
|
|
@@ -271,15 +276,13 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
|
|
|
271
276
|
{/* Expiration */}
|
|
272
277
|
<View
|
|
273
278
|
unstyled
|
|
274
|
-
render={ <select/> }
|
|
275
|
-
|
|
276
|
-
onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => update({ expiration: e.target.value }) }
|
|
277
|
-
{ ...CONTROL }
|
|
278
|
-
fontSize={ 12 }
|
|
279
|
+
render={ <select value={ leg.expiration } onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => update({ expiration: e.target.value }) }/> as never }
|
|
280
|
+
{ ...CONTROL_BOX }
|
|
279
281
|
borderRadius={ 4 }
|
|
280
282
|
paddingHorizontal={ 6 }
|
|
281
283
|
paddingVertical={ 2 }
|
|
282
284
|
minWidth={ 80 }
|
|
285
|
+
style={ { ...CONTROL_INK, fontSize: 12 } as never }
|
|
283
286
|
>
|
|
284
287
|
{ expirations.map((exp) => (
|
|
285
288
|
<option key={ exp } value={ exp }>
|
|
@@ -291,26 +294,28 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
|
|
|
291
294
|
{/* Quantity */}
|
|
292
295
|
<View
|
|
293
296
|
unstyled
|
|
294
|
-
render={
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
297
|
+
render={ (
|
|
298
|
+
<input
|
|
299
|
+
type="number"
|
|
300
|
+
min={ 1 }
|
|
301
|
+
max={ 999 }
|
|
302
|
+
value={ leg.quantity }
|
|
303
|
+
onChange={ (e: React.ChangeEvent<HTMLInputElement>) => update({ quantity: Math.max(1, parseInt(e.target.value, 10) || 1) }) }
|
|
304
|
+
/>
|
|
305
|
+
) as never }
|
|
306
|
+
{ ...CONTROL_BOX }
|
|
302
307
|
borderRadius={ 4 }
|
|
303
308
|
paddingHorizontal={ 6 }
|
|
304
309
|
paddingVertical={ 2 }
|
|
305
310
|
width={ 48 }
|
|
306
|
-
textAlign
|
|
311
|
+
style={ { ...CONTROL_INK, fontFamily: MONO, fontSize: 12, textAlign: 'center' } as never }
|
|
307
312
|
/>
|
|
308
313
|
|
|
309
314
|
{/* Premium (read-only if provided) */}
|
|
310
315
|
{ leg.premium !== undefined && (
|
|
311
316
|
<Text
|
|
312
317
|
fontSize={ 12 }
|
|
313
|
-
style={ MONO }
|
|
318
|
+
style={ { fontFamily: MONO } as never }
|
|
314
319
|
fontVariant={ ['tabular-nums'] as never }
|
|
315
320
|
marginLeft="auto"
|
|
316
321
|
color={ (leg.premium >= 0 ? 'var(--color-status-good)' : 'var(--color-status-bad)') as never }
|
|
@@ -319,7 +324,12 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
|
|
|
319
324
|
</Text>
|
|
320
325
|
) }
|
|
321
326
|
|
|
322
|
-
{/* Remove
|
|
327
|
+
{/* Remove. The icon's `currentColor` needs a real ancestor CSS colour —
|
|
328
|
+
not a gui prop (Stacks have none) — so it rides `style`. The
|
|
329
|
+
hover→red retint from the original Tailwind isn't reachable without
|
|
330
|
+
either a new named class (out of scope) or component-local hover
|
|
331
|
+
state, so resting colour is kept and a same-family opacity shift
|
|
332
|
+
substitutes for hover feedback. */ }
|
|
323
333
|
{ removable && (
|
|
324
334
|
<XStack
|
|
325
335
|
unstyled
|
|
@@ -330,8 +340,8 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
|
|
|
330
340
|
borderWidth={ 0 }
|
|
331
341
|
cursor="pointer"
|
|
332
342
|
transition="quick"
|
|
333
|
-
|
|
334
|
-
hoverStyle={ {
|
|
343
|
+
style={ { color: 'var(--color-text-secondary)' } as never }
|
|
344
|
+
hoverStyle={ { opacity: 0.7 } as never }
|
|
335
345
|
>
|
|
336
346
|
<svg width={ 14 } height={ 14 } viewBox="0 0 24 24" fill="none">
|
|
337
347
|
<path d="M18 6L6 18M6 6l12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
|
|
@@ -447,7 +457,7 @@ export const StrategyBuilder = React.forwardRef<HTMLDivElement, StrategyBuilderP
|
|
|
447
457
|
</Text>
|
|
448
458
|
</XStack>
|
|
449
459
|
<Text fontSize={ 10 } color={ 'var(--color-text-secondary)' as never }>
|
|
450
|
-
Spot: <Text style={ MONO } fontVariant={ ['tabular-nums'] as never } color={ 'var(--color-text-primary)' as never }>{ spotPrice.toFixed(2) }</Text>
|
|
460
|
+
Spot: <Text style={ { fontFamily: MONO } as never } fontVariant={ ['tabular-nums'] as never } color={ 'var(--color-text-primary)' as never }>{ spotPrice.toFixed(2) }</Text>
|
|
451
461
|
</Text>
|
|
452
462
|
</XStack>
|
|
453
463
|
|
|
@@ -455,15 +465,13 @@ export const StrategyBuilder = React.forwardRef<HTMLDivElement, StrategyBuilderP
|
|
|
455
465
|
<XStack alignItems="center" gap={ 8 }>
|
|
456
466
|
<View
|
|
457
467
|
unstyled
|
|
458
|
-
render={ <select/> }
|
|
459
|
-
value={ strategyType }
|
|
460
|
-
onChange={ handleStrategyChange }
|
|
468
|
+
render={ <select value={ strategyType } onChange={ handleStrategyChange }/> as never }
|
|
461
469
|
flex={ 1 }
|
|
462
|
-
{ ...
|
|
463
|
-
fontSize={ 14 }
|
|
470
|
+
{ ...CONTROL_BOX }
|
|
464
471
|
borderRadius={ 6 }
|
|
465
472
|
paddingHorizontal={ 10 }
|
|
466
473
|
paddingVertical={ 6 }
|
|
474
|
+
style={ { ...CONTROL_INK, fontSize: 14 } as never }
|
|
467
475
|
>
|
|
468
476
|
{ STRATEGY_PRESETS.map((preset) => (
|
|
469
477
|
<option key={ preset.value } value={ preset.value }>
|
|
@@ -495,7 +503,9 @@ export const StrategyBuilder = React.forwardRef<HTMLDivElement, StrategyBuilderP
|
|
|
495
503
|
)) }
|
|
496
504
|
</YStack>
|
|
497
505
|
|
|
498
|
-
{/* Add leg button (custom only)
|
|
506
|
+
{/* Add leg button (custom only). Resting ink rides `style` so the
|
|
507
|
+
icon's `currentColor` and the label both resolve it; hover keeps
|
|
508
|
+
the border re-tint (a valid Stack prop) as the interactive cue. */}
|
|
499
509
|
{ strategyType === 'custom' && legs.length < 4 && (
|
|
500
510
|
<XStack
|
|
501
511
|
unstyled
|
|
@@ -509,15 +519,14 @@ export const StrategyBuilder = React.forwardRef<HTMLDivElement, StrategyBuilderP
|
|
|
509
519
|
paddingVertical={ 4 }
|
|
510
520
|
cursor="pointer"
|
|
511
521
|
transition="quick"
|
|
512
|
-
style={ { borderStyle: 'dashed' } as never }
|
|
513
522
|
borderColor={ 'var(--color-border-divider)' as never }
|
|
514
|
-
|
|
515
|
-
|
|
523
|
+
hoverStyle={ { borderColor: 'var(--color-hover)' } as never }
|
|
524
|
+
style={ { color: 'var(--color-text-secondary)', borderStyle: 'dashed' } as never }
|
|
516
525
|
>
|
|
517
526
|
<svg width={ 12 } height={ 12 } viewBox="0 0 24 24" fill="none">
|
|
518
527
|
<path d="M12 5v14M5 12h14" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
|
|
519
528
|
</svg>
|
|
520
|
-
<Text
|
|
529
|
+
<Text fontSize={ 12 } color={ 'var(--color-text-secondary)' as never }>Add Leg</Text>
|
|
521
530
|
</XStack>
|
|
522
531
|
) }
|
|
523
532
|
|
|
@@ -525,7 +534,7 @@ export const StrategyBuilder = React.forwardRef<HTMLDivElement, StrategyBuilderP
|
|
|
525
534
|
<XStack alignItems="center" justifyContent="space-between" paddingTop={ 4 } borderTopWidth={ 1 } borderColor={ 'var(--color-border-divider)' as never }>
|
|
526
535
|
<XStack alignItems="center" gap={ 8 }>
|
|
527
536
|
<Text fontSize={ 12 } color={ 'var(--color-text-secondary)' as never }>Net:</Text>
|
|
528
|
-
<Text fontSize={ 14 } fontWeight="600" style={ MONO } fontVariant={ ['tabular-nums'] as never } color={ netColor as never }>
|
|
537
|
+
<Text fontSize={ 14 } fontWeight="600" style={ { fontFamily: MONO } as never } fontVariant={ ['tabular-nums'] as never } color={ netColor as never }>
|
|
529
538
|
{ netPremium > 0 ? 'Credit ' : netPremium < 0 ? 'Debit ' : '' }
|
|
530
539
|
{ netPremium !== 0 ? `$${ Math.abs(netPremium).toFixed(2) }` : '-' }
|
|
531
540
|
</Text>
|