@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.
Files changed (84) hide show
  1. package/dist/alert.cjs +68 -46
  2. package/dist/alert.js +69 -46
  3. package/dist/avatar.cjs +49 -47
  4. package/dist/avatar.js +52 -49
  5. package/dist/badge.cjs +82 -49
  6. package/dist/badge.js +83 -50
  7. package/dist/checkbox.cjs +42 -75
  8. package/dist/checkbox.js +43 -76
  9. package/dist/chrome.cjs +3 -7
  10. package/dist/chrome.js +3 -7
  11. package/dist/close-button.cjs +3 -7
  12. package/dist/close-button.js +3 -7
  13. package/dist/dialog.cjs +3 -7
  14. package/dist/dialog.js +3 -7
  15. package/dist/drawer.cjs +3 -7
  16. package/dist/drawer.js +3 -7
  17. package/dist/empty-state.cjs +13 -13
  18. package/dist/empty-state.js +13 -13
  19. package/dist/expiration-selector.cjs +58 -63
  20. package/dist/expiration-selector.js +58 -63
  21. package/dist/greeks-display.cjs +48 -39
  22. package/dist/greeks-display.js +48 -39
  23. package/dist/index.cjs +1053 -888
  24. package/dist/index.js +1054 -889
  25. package/dist/input-group.cjs +36 -19
  26. package/dist/input-group.js +37 -19
  27. package/dist/option-chain.cjs +89 -67
  28. package/dist/option-chain.js +89 -67
  29. package/dist/option-position.cjs +88 -85
  30. package/dist/option-position.js +88 -85
  31. package/dist/pin-input.cjs +30 -29
  32. package/dist/pin-input.js +30 -29
  33. package/dist/pnl-diagram.cjs +20 -20
  34. package/dist/pnl-diagram.js +20 -20
  35. package/dist/popover.cjs +3 -7
  36. package/dist/popover.js +3 -7
  37. package/dist/progress-circle.cjs +40 -22
  38. package/dist/progress-circle.d.cts +5 -5
  39. package/dist/progress-circle.d.ts +5 -5
  40. package/dist/progress-circle.js +41 -22
  41. package/dist/progress.cjs +15 -22
  42. package/dist/progress.d.cts +6 -6
  43. package/dist/progress.d.ts +6 -6
  44. package/dist/progress.js +15 -22
  45. package/dist/radio.cjs +35 -68
  46. package/dist/radio.d.cts +18 -18
  47. package/dist/radio.d.ts +18 -18
  48. package/dist/radio.js +36 -69
  49. package/dist/rating.cjs +15 -17
  50. package/dist/rating.js +15 -17
  51. package/dist/slider.cjs +33 -50
  52. package/dist/slider.js +34 -51
  53. package/dist/strategy-builder.cjs +194 -115
  54. package/dist/strategy-builder.js +194 -115
  55. package/dist/switch.cjs +48 -55
  56. package/dist/switch.js +49 -56
  57. package/dist/tag.cjs +115 -69
  58. package/dist/tag.js +116 -69
  59. package/dist/tooltip.cjs +28 -17
  60. package/dist/tooltip.js +30 -18
  61. package/package.json +1 -1
  62. package/src/alert.tsx +78 -45
  63. package/src/avatar.tsx +54 -38
  64. package/src/badge.tsx +65 -44
  65. package/src/checkbox.tsx +70 -89
  66. package/src/close-button.tsx +3 -8
  67. package/src/empty-state.tsx +21 -17
  68. package/src/expiration-selector.tsx +84 -66
  69. package/src/greeks-display.tsx +59 -51
  70. package/src/input-group.tsx +38 -24
  71. package/src/option-chain.tsx +154 -104
  72. package/src/option-position.tsx +143 -114
  73. package/src/pin-input.tsx +37 -29
  74. package/src/pnl-diagram.tsx +36 -28
  75. package/src/progress-circle.tsx +52 -28
  76. package/src/progress.tsx +17 -21
  77. package/src/radio.tsx +56 -76
  78. package/src/rating.tsx +22 -20
  79. package/src/slider.tsx +43 -45
  80. package/src/strategy-builder.tsx +260 -162
  81. package/src/switch.tsx +63 -64
  82. package/src/tag.tsx +89 -51
  83. package/src/tooltip.tsx +21 -13
  84. package/tokens.css +18 -0
@@ -1,9 +1,8 @@
1
1
  'use client';
2
2
 
3
+ import { Text, View, 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
  // ---------------------------------------------------------------------------
@@ -163,6 +162,26 @@ const STRATEGY_PRESETS: StrategyPreset[] = [
163
162
  },
164
163
  ];
165
164
 
165
+ // ---------------------------------------------------------------------------
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.
171
+ // ---------------------------------------------------------------------------
172
+
173
+ const MONO = 'monospace';
174
+
175
+ const CONTROL_BOX = {
176
+ backgroundColor: 'var(--color-input-bg)',
177
+ borderWidth: 1,
178
+ borderColor: 'var(--color-input-border)',
179
+ outlineWidth: 0,
180
+ focusStyle: { borderColor: 'var(--color-input-border-focus)' },
181
+ } as const;
182
+
183
+ const CONTROL_INK = { color: 'var(--color-input-fg)' };
184
+
166
185
  // ---------------------------------------------------------------------------
167
186
  // LegRow
168
187
  // ---------------------------------------------------------------------------
@@ -183,100 +202,153 @@ function LegRow({ leg, index, strikes, expirations, removable, onChange, onRemov
183
202
  };
184
203
 
185
204
  return (
186
- <div className="flex items-center gap-2 rounded-md bg-zinc-800/50 px-2 py-1.5">
187
- <span className="text-[10px] font-mono text-zinc-500 w-4 shrink-0">
188
- {index + 1}
189
- </span>
205
+ <XStack
206
+ alignItems="center"
207
+ gap={ 8 }
208
+ borderRadius={ 6 }
209
+ backgroundColor={ 'var(--color-tag-subtle-bg)' as never }
210
+ paddingHorizontal={ 8 }
211
+ paddingVertical={ 6 }
212
+ >
213
+ <Text fontSize={ 10 } style={ { fontFamily: MONO } as never } flexShrink={ 0 } width={ 16 } color={ 'var(--color-text-secondary)' as never }>
214
+ { index + 1 }
215
+ </Text>
190
216
 
191
217
  {/* Action */}
192
- <button
193
- type="button"
194
- className={cn(
195
- 'px-2 py-0.5 rounded text-xs font-semibold transition-colors',
196
- leg.action === 'buy'
197
- ? 'bg-emerald-900/60 text-emerald-400'
198
- : 'bg-red-900/60 text-red-400',
199
- )}
200
- onClick={() => update({ action: leg.action === 'buy' ? 'sell' : 'buy' })}
218
+ <XStack
219
+ unstyled
220
+ render={ <button type="button"/> }
221
+ onClick={ () => update({ action: leg.action === 'buy' ? 'sell' : 'buy' }) }
222
+ paddingHorizontal={ 8 }
223
+ paddingVertical={ 2 }
224
+ borderRadius={ 4 }
225
+ borderWidth={ 0 }
226
+ cursor="pointer"
227
+ transition="quick"
228
+ backgroundColor={ (leg.action === 'buy'
229
+ ? 'color-mix(in srgb, var(--color-status-good) 20%, transparent)'
230
+ : 'color-mix(in srgb, var(--color-status-bad) 20%, transparent)') as never }
201
231
  >
202
- {leg.action === 'buy' ? 'BUY' : 'SELL'}
203
- </button>
204
-
205
- {/* Type */}
206
- <button
207
- type="button"
208
- className={cn(
209
- 'px-2 py-0.5 rounded text-xs font-medium transition-colors',
210
- // Call vs put is a rank difference, not a hue difference.
211
- leg.type === 'call'
212
- ? 'bg-[var(--secondary)] text-[var(--foreground)]'
213
- : 'bg-[var(--muted)] text-[var(--muted-foreground)]',
214
- )}
215
- onClick={() => update({ type: leg.type === 'call' ? 'put' : 'call' })}
232
+ <Text fontSize={ 12 } fontWeight="600" color={ (leg.action === 'buy' ? 'var(--color-status-good)' : 'var(--color-status-bad)') as never }>
233
+ { leg.action === 'buy' ? 'BUY' : 'SELL' }
234
+ </Text>
235
+ </XStack>
236
+
237
+ {/* Type — call vs put is a rank difference, not a hue difference. */}
238
+ <XStack
239
+ unstyled
240
+ render={ <button type="button"/> }
241
+ onClick={ () => update({ type: leg.type === 'call' ? 'put' : 'call' }) }
242
+ paddingHorizontal={ 8 }
243
+ paddingVertical={ 2 }
244
+ borderRadius={ 4 }
245
+ borderWidth={ 0 }
246
+ cursor="pointer"
247
+ transition="quick"
248
+ backgroundColor={ (leg.type === 'call' ? 'var(--secondary)' : 'var(--muted)') as never }
216
249
  >
217
- {leg.type === 'call' ? 'CALL' : 'PUT'}
218
- </button>
219
-
220
- {/* Strike */}
221
- <select
222
- value={leg.strike}
223
- onChange={(e) => update({ strike: Number(e.target.value) })}
224
- className="bg-zinc-900 border border-zinc-700 rounded px-1.5 py-0.5 text-xs font-mono text-zinc-200 outline-none focus:border-zinc-500 min-w-[72px]"
250
+ <Text fontSize={ 12 } fontWeight="500" color={ (leg.type === 'call' ? 'var(--foreground)' : 'var(--muted-foreground)') as never }>
251
+ { leg.type === 'call' ? 'CALL' : 'PUT' }
252
+ </Text>
253
+ </XStack>
254
+
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. */}
259
+ <View
260
+ unstyled
261
+ render={ <select value={ leg.strike } onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => update({ strike: Number(e.target.value) }) }/> as never }
262
+ { ...CONTROL_BOX }
263
+ borderRadius={ 4 }
264
+ paddingHorizontal={ 6 }
265
+ paddingVertical={ 2 }
266
+ minWidth={ 72 }
267
+ style={ { ...CONTROL_INK, fontFamily: MONO, fontSize: 12 } as never }
225
268
  >
226
- {strikes.map((s) => (
227
- <option key={s} value={s}>
228
- {s.toFixed(2)}
269
+ { strikes.map((s) => (
270
+ <option key={ s } value={ s }>
271
+ { s.toFixed(2) }
229
272
  </option>
230
- ))}
231
- </select>
273
+ )) }
274
+ </View>
232
275
 
233
276
  {/* Expiration */}
234
- <select
235
- value={leg.expiration}
236
- onChange={(e) => update({ expiration: e.target.value })}
237
- className="bg-zinc-900 border border-zinc-700 rounded px-1.5 py-0.5 text-xs text-zinc-200 outline-none focus:border-zinc-500 min-w-[80px]"
277
+ <View
278
+ unstyled
279
+ render={ <select value={ leg.expiration } onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => update({ expiration: e.target.value }) }/> as never }
280
+ { ...CONTROL_BOX }
281
+ borderRadius={ 4 }
282
+ paddingHorizontal={ 6 }
283
+ paddingVertical={ 2 }
284
+ minWidth={ 80 }
285
+ style={ { ...CONTROL_INK, fontSize: 12 } as never }
238
286
  >
239
- {expirations.map((exp) => (
240
- <option key={exp} value={exp}>
241
- {exp}
287
+ { expirations.map((exp) => (
288
+ <option key={ exp } value={ exp }>
289
+ { exp }
242
290
  </option>
243
- ))}
244
- </select>
291
+ )) }
292
+ </View>
245
293
 
246
294
  {/* Quantity */}
247
- <input
248
- type="number"
249
- min={1}
250
- max={999}
251
- value={leg.quantity}
252
- onChange={(e) => update({ quantity: Math.max(1, parseInt(e.target.value, 10) || 1) })}
253
- className="bg-zinc-900 border border-zinc-700 rounded px-1.5 py-0.5 text-xs font-mono text-zinc-200 outline-none focus:border-zinc-500 w-[48px] text-center"
295
+ <View
296
+ unstyled
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 }
307
+ borderRadius={ 4 }
308
+ paddingHorizontal={ 6 }
309
+ paddingVertical={ 2 }
310
+ width={ 48 }
311
+ style={ { ...CONTROL_INK, fontFamily: MONO, fontSize: 12, textAlign: 'center' } as never }
254
312
  />
255
313
 
256
314
  {/* Premium (read-only if provided) */}
257
- {leg.premium !== undefined && (
258
- <span className={cn(
259
- 'font-mono tabular-nums text-xs ml-auto',
260
- leg.premium >= 0 ? 'text-emerald-400' : 'text-red-400',
261
- )}>
262
- {leg.premium >= 0 ? '+' : ''}{leg.premium.toFixed(2)}
263
- </span>
264
- )}
265
-
266
- {/* Remove */}
267
- {removable && (
268
- <button
269
- type="button"
270
- onClick={() => onRemove(index)}
271
- className="ml-auto p-0.5 text-zinc-500 hover:text-red-400 transition-colors"
272
- aria-label="Remove leg"
315
+ { leg.premium !== undefined && (
316
+ <Text
317
+ fontSize={ 12 }
318
+ style={ { fontFamily: MONO } as never }
319
+ fontVariant={ ['tabular-nums'] as never }
320
+ marginLeft="auto"
321
+ color={ (leg.premium >= 0 ? 'var(--color-status-good)' : 'var(--color-status-bad)') as never }
322
+ >
323
+ { leg.premium >= 0 ? '+' : '' }{ leg.premium.toFixed(2) }
324
+ </Text>
325
+ ) }
326
+
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. */ }
333
+ { removable && (
334
+ <XStack
335
+ unstyled
336
+ render={ <button type="button" aria-label="Remove leg"/> }
337
+ onClick={ () => onRemove(index) }
338
+ marginLeft="auto"
339
+ padding={ 2 }
340
+ borderWidth={ 0 }
341
+ cursor="pointer"
342
+ transition="quick"
343
+ style={ { color: 'var(--color-text-secondary)' } as never }
344
+ hoverStyle={ { opacity: 0.7 } as never }
273
345
  >
274
- <svg className="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none">
275
- <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
346
+ <svg width={ 14 } height={ 14 } viewBox="0 0 24 24" fill="none">
347
+ <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
276
348
  </svg>
277
- </button>
278
- )}
279
- </div>
349
+ </XStack>
350
+ ) }
351
+ </XStack>
280
352
  );
281
353
  }
282
354
 
@@ -360,108 +432,134 @@ export const StrategyBuilder = React.forwardRef<HTMLDivElement, StrategyBuilderP
360
432
  }, [onSubmit, strategyType, legs, netPremium]);
361
433
 
362
434
  const currentPreset = STRATEGY_PRESETS.find((p) => p.value === strategyType);
435
+ const netColor = netPremium > 0 ? 'var(--color-status-good)' : netPremium < 0 ? 'var(--color-status-bad)' : 'var(--color-text-secondary)';
363
436
 
364
437
  return (
365
- <div
366
- ref={ref}
367
- className={cn(
368
- 'flex flex-col gap-3 rounded-lg border border-zinc-800 bg-zinc-900/50 p-3',
369
- className,
370
- )}
371
- {...rest}
438
+ <YStack
439
+ ref={ ref as never }
440
+ gap={ 12 }
441
+ borderRadius={ 8 }
442
+ borderWidth={ 1 }
443
+ borderColor={ 'var(--color-border-divider)' as never }
444
+ backgroundColor={ 'var(--card)' as never }
445
+ padding={ 12 }
446
+ className={ className }
447
+ { ...(rest as object) }
372
448
  >
373
449
  {/* Header */}
374
- <div className="flex items-center justify-between gap-3">
375
- <div className="flex items-center gap-2">
376
- <span className="text-xs font-semibold uppercase tracking-wider text-zinc-500">
450
+ <XStack alignItems="center" justifyContent="space-between" gap={ 12 }>
451
+ <XStack alignItems="center" gap={ 8 }>
452
+ <Text fontSize={ 12 } fontWeight="600" textTransform="uppercase" letterSpacing={ 0.6 } color={ 'var(--color-text-secondary)' as never }>
377
453
  Strategy
378
- </span>
379
- <span className="text-sm font-medium text-zinc-200">
380
- {underlying}
381
- </span>
382
- </div>
383
- <span className="text-[10px] text-zinc-500">
384
- Spot: <span className="font-mono tabular-nums text-zinc-300">{spotPrice.toFixed(2)}</span>
385
- </span>
386
- </div>
454
+ </Text>
455
+ <Text fontSize={ 14 } fontWeight="500" color={ 'var(--color-text-primary)' as never }>
456
+ { underlying }
457
+ </Text>
458
+ </XStack>
459
+ <Text fontSize={ 10 } color={ 'var(--color-text-secondary)' as never }>
460
+ Spot: <Text style={ { fontFamily: MONO } as never } fontVariant={ ['tabular-nums'] as never } color={ 'var(--color-text-primary)' as never }>{ spotPrice.toFixed(2) }</Text>
461
+ </Text>
462
+ </XStack>
387
463
 
388
464
  {/* Strategy selector */}
389
- <div className="flex items-center gap-2">
390
- <select
391
- value={strategyType}
392
- onChange={handleStrategyChange}
393
- className="flex-1 bg-zinc-900 border border-zinc-700 rounded-md px-2.5 py-1.5 text-sm text-zinc-200 outline-none focus:border-zinc-500"
465
+ <XStack alignItems="center" gap={ 8 }>
466
+ <View
467
+ unstyled
468
+ render={ <select value={ strategyType } onChange={ handleStrategyChange }/> as never }
469
+ flex={ 1 }
470
+ { ...CONTROL_BOX }
471
+ borderRadius={ 6 }
472
+ paddingHorizontal={ 10 }
473
+ paddingVertical={ 6 }
474
+ style={ { ...CONTROL_INK, fontSize: 14 } as never }
394
475
  >
395
- {STRATEGY_PRESETS.map((preset) => (
396
- <option key={preset.value} value={preset.value}>
397
- {preset.label}
476
+ { STRATEGY_PRESETS.map((preset) => (
477
+ <option key={ preset.value } value={ preset.value }>
478
+ { preset.label }
398
479
  </option>
399
- ))}
400
- </select>
401
- </div>
480
+ )) }
481
+ </View>
482
+ </XStack>
402
483
 
403
- {currentPreset && (
404
- <p className="text-[11px] text-zinc-500 -mt-1">
405
- {currentPreset.description}
406
- </p>
407
- )}
484
+ { currentPreset && (
485
+ <Text fontSize={ 11 } marginTop={ -4 } color={ 'var(--color-text-secondary)' as never }>
486
+ { currentPreset.description }
487
+ </Text>
488
+ ) }
408
489
 
409
490
  {/* Legs */}
410
- <div className="flex flex-col gap-1.5">
411
- {legs.map((leg, i) => (
491
+ <YStack gap={ 6 }>
492
+ { legs.map((leg, i) => (
412
493
  <LegRow
413
- key={i}
414
- leg={leg}
415
- index={i}
416
- strikes={strikes}
417
- expirations={expirations}
418
- removable={strategyType === 'custom' && legs.length > 1}
419
- onChange={handleLegChange}
420
- onRemove={handleLegRemove}
494
+ key={ i }
495
+ leg={ leg }
496
+ index={ i }
497
+ strikes={ strikes }
498
+ expirations={ expirations }
499
+ removable={ strategyType === 'custom' && legs.length > 1 }
500
+ onChange={ handleLegChange }
501
+ onRemove={ handleLegRemove }
421
502
  />
422
- ))}
423
- </div>
424
-
425
- {/* Add leg button (custom only) */}
426
- {strategyType === 'custom' && legs.length < 4 && (
427
- <button
428
- type="button"
429
- onClick={handleAddLeg}
430
- className="flex items-center justify-center gap-1 rounded-md border border-dashed border-zinc-700 py-1 text-xs text-zinc-500 hover:text-zinc-300 hover:border-zinc-500 transition-colors"
503
+ )) }
504
+ </YStack>
505
+
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. */}
509
+ { strategyType === 'custom' && legs.length < 4 && (
510
+ <XStack
511
+ unstyled
512
+ render={ <button type="button"/> }
513
+ onClick={ handleAddLeg }
514
+ alignItems="center"
515
+ justifyContent="center"
516
+ gap={ 4 }
517
+ borderRadius={ 6 }
518
+ borderWidth={ 1 }
519
+ paddingVertical={ 4 }
520
+ cursor="pointer"
521
+ transition="quick"
522
+ borderColor={ 'var(--color-border-divider)' as never }
523
+ hoverStyle={ { borderColor: 'var(--color-hover)' } as never }
524
+ style={ { color: 'var(--color-text-secondary)', borderStyle: 'dashed' } as never }
431
525
  >
432
- <svg className="h-3 w-3" viewBox="0 0 24 24" fill="none">
433
- <path d="M12 5v14M5 12h14" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
526
+ <svg width={ 12 } height={ 12 } viewBox="0 0 24 24" fill="none">
527
+ <path d="M12 5v14M5 12h14" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
434
528
  </svg>
435
- Add Leg
436
- </button>
437
- )}
529
+ <Text fontSize={ 12 } color={ 'var(--color-text-secondary)' as never }>Add Leg</Text>
530
+ </XStack>
531
+ ) }
438
532
 
439
533
  {/* Net premium + submit */}
440
- <div className="flex items-center justify-between pt-1 border-t border-zinc-800">
441
- <div className="flex items-center gap-2">
442
- <span className="text-xs text-zinc-500">Net:</span>
443
- <span className={cn(
444
- 'font-mono tabular-nums text-sm font-semibold',
445
- netPremium > 0 ? 'text-emerald-400' : netPremium < 0 ? 'text-red-400' : 'text-zinc-400',
446
- )}>
447
- {netPremium > 0 ? 'Credit ' : netPremium < 0 ? 'Debit ' : ''}
448
- {netPremium !== 0 ? `$${Math.abs(netPremium).toFixed(2)}` : '-'}
449
- </span>
450
- </div>
451
- <button
452
- type="button"
453
- onClick={handleSubmit}
454
- disabled={legs.length === 0}
455
- className={cn(
456
- 'px-4 py-1.5 rounded-md text-xs font-semibold transition-colors',
457
- 'bg-blue-600 text-white hover:bg-blue-500',
458
- 'disabled:opacity-40 disabled:cursor-not-allowed',
459
- )}
534
+ <XStack alignItems="center" justifyContent="space-between" paddingTop={ 4 } borderTopWidth={ 1 } borderColor={ 'var(--color-border-divider)' as never }>
535
+ <XStack alignItems="center" gap={ 8 }>
536
+ <Text fontSize={ 12 } color={ 'var(--color-text-secondary)' as never }>Net:</Text>
537
+ <Text fontSize={ 14 } fontWeight="600" style={ { fontFamily: MONO } as never } fontVariant={ ['tabular-nums'] as never } color={ netColor as never }>
538
+ { netPremium > 0 ? 'Credit ' : netPremium < 0 ? 'Debit ' : '' }
539
+ { netPremium !== 0 ? `$${ Math.abs(netPremium).toFixed(2) }` : '-' }
540
+ </Text>
541
+ </XStack>
542
+ <XStack
543
+ unstyled
544
+ render={ <button type="button"/> }
545
+ onClick={ handleSubmit }
546
+ disabled={ legs.length === 0 }
547
+ paddingHorizontal={ 16 }
548
+ paddingVertical={ 6 }
549
+ borderRadius={ 6 }
550
+ borderWidth={ 0 }
551
+ cursor="pointer"
552
+ transition="quick"
553
+ backgroundColor={ 'var(--color-button-solid-bg)' as never }
554
+ hoverStyle={ { backgroundColor: 'var(--color-hover)' } as never }
555
+ disabledStyle={ { opacity: 0.4, cursor: 'not-allowed' } as never }
460
556
  >
461
- Review Order
462
- </button>
463
- </div>
464
- </div>
557
+ <Text fontSize={ 12 } fontWeight="600" color={ 'var(--color-button-solid-text)' as never }>
558
+ Review Order
559
+ </Text>
560
+ </XStack>
561
+ </XStack>
562
+ </YStack>
465
563
  );
466
564
  },
467
565
  );