@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
package/dist/tag.js CHANGED
@@ -1,15 +1,13 @@
1
1
  "use client";
2
+ import { styled, View, TooltipGroup, Tooltip as Tooltip$1, Text, XStack } from '@hanzo/gui';
2
3
  import * as React4 from 'react';
4
+ import { Children, createElement } from 'react';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
6
  import { clsx } from 'clsx';
4
7
  import { twMerge } from 'tailwind-merge';
5
- import { styled, View, TooltipGroup, Tooltip as Tooltip$1 } from '@hanzo/gui';
6
- import { jsx, jsxs } from 'react/jsx-runtime';
7
8
  import { useClickAway } from '@uidotdev/usehooks';
8
9
 
9
10
  // src/tag.tsx
10
- function cn(...inputs) {
11
- return twMerge(clsx(inputs));
12
- }
13
11
  var CLOSE_ICON_PATH = "M9.44 8.035a.791.791 0 0 0 1.12 0l3.802-3.803a.791.791 0 0 1 1.119 0l.287.287a.79.79 0 0 1 0 1.119L11.965 9.44a.79.79 0 0 0 0 1.118l3.803 3.803a.791.791 0 0 1 0 1.119l-.287.287a.791.791 0 0 1-1.119 0l-3.803-3.803a.79.79 0 0 0-1.118 0l-3.803 3.803a.79.79 0 0 1-1.119 0l-.287-.287a.791.791 0 0 1 0-1.119l3.803-3.803a.791.791 0 0 0 0-1.118L4.232 5.638a.791.791 0 0 1 0-1.119l.287-.287a.791.791 0 0 1 1.119 0L9.44 8.035Z";
14
12
  var CloseButtonFrame = styled(View, {
15
13
  name: "LuxCloseButton",
@@ -40,23 +38,19 @@ var CloseButtonFrame = styled(View, {
40
38
  }
41
39
  }
42
40
  });
43
- var CLOSE_BUTTON_CLASSES = [
44
- "text-[var(--closeButton-fg,currentColor)]",
45
- "hover:text-[var(--hover-color,currentColor)]",
46
- "disabled:opacity-40"
47
- ].join(" ");
48
41
  var CloseButton = React4.forwardRef(function CloseButton2(props, ref) {
49
42
  const { variant: _variant, size: _size, className, children, ...rest } = props;
50
43
  return /* @__PURE__ */ jsx(
51
44
  CloseButtonFrame,
52
45
  {
53
46
  ref,
54
- className: [CLOSE_BUTTON_CLASSES, className].filter(Boolean).join(" "),
47
+ className,
55
48
  ...rest,
56
49
  children: children ?? /* @__PURE__ */ jsx(
57
50
  "svg",
58
51
  {
59
- className: "size-5",
52
+ width: 20,
53
+ height: 20,
60
54
  viewBox: "0 0 20 20",
61
55
  fill: "none",
62
56
  "aria-hidden": "true",
@@ -72,6 +66,9 @@ var CloseButton = React4.forwardRef(function CloseButton2(props, ref) {
72
66
  }
73
67
  );
74
68
  });
69
+ function cn(...inputs) {
70
+ return twMerge(clsx(inputs));
71
+ }
75
72
  var SHIM_PROPS = [
76
73
  "w",
77
74
  "h",
@@ -255,6 +252,14 @@ React4.forwardRef(
255
252
  )) });
256
253
  }
257
254
  );
255
+ var ink = (children, Wrap = Text, props = {}) => {
256
+ let hasText = false;
257
+ Children.forEach(children, (child) => {
258
+ if (typeof child === "string" || typeof child === "number") hasText = true;
259
+ });
260
+ if (!hasText) return children;
261
+ return Children.map(children, (child) => typeof child === "string" || typeof child === "number" ? createElement(Wrap, props, child) : child);
262
+ };
258
263
  var TOUCH_PX = 1024;
259
264
  function useBelow(px) {
260
265
  const [below, setBelow] = React4.useState(false);
@@ -359,14 +364,21 @@ var Tooltip = React4.forwardRef(
359
364
  {
360
365
  ref,
361
366
  unstyled: true,
362
- className: cn(
363
- "z-[9999] overflow-hidden rounded-lg px-3 py-2 text-sm",
364
- "animate-in fade-in-0 zoom-in-95",
365
- isPopover && "bg-[var(--color-popover-bg)] text-[var(--color-text-primary)]",
366
- isPopover && "shadow-[var(--shadow-popover)] border border-[var(--color-border-divider)] max-w-sm",
367
- !isPopover && "bg-[var(--color-tooltip-bg)] text-[var(--color-tooltip-fg)] max-w-xs",
368
- contentProps?.className
369
- ),
367
+ zIndex: 9999,
368
+ overflow: "hidden",
369
+ borderRadius: 8,
370
+ paddingHorizontal: 12,
371
+ paddingVertical: 8,
372
+ maxWidth: isPopover ? 384 : 320,
373
+ backgroundColor: isPopover ? "var(--color-popover-bg)" : "var(--color-tooltip-bg)",
374
+ transition: "quick",
375
+ enterStyle: { opacity: 0, scale: 0.95 },
376
+ exitStyle: { opacity: 0, scale: 0.95 },
377
+ ...isPopover ? {
378
+ borderWidth: 1,
379
+ borderColor: "var(--color-border-divider)",
380
+ shadowColor: "var(--shadow-popover)"
381
+ } : {},
370
382
  onClick: interactive ? handleContentClick : void 0,
371
383
  ...selected ? { "data-selected": true } : {},
372
384
  ...contentProps,
@@ -375,12 +387,13 @@ var Tooltip = React4.forwardRef(
375
387
  Tooltip$1.Arrow,
376
388
  {
377
389
  unstyled: true,
378
- className: cn(
379
- isPopover ? "fill-[var(--color-popover-bg)]" : "fill-[var(--color-tooltip-bg)]"
380
- )
390
+ backgroundColor: isPopover ? "var(--color-popover-bg)" : "var(--color-tooltip-bg)"
381
391
  }
382
392
  ),
383
- content
393
+ ink(content, void 0, {
394
+ fontSize: 14,
395
+ color: isPopover ? "var(--color-text-primary)" : "var(--color-tooltip-fg)"
396
+ })
384
397
  ]
385
398
  }
386
399
  )
@@ -393,25 +406,24 @@ var nbsp = String.fromCharCode(160);
393
406
  function TruncatedTextTooltip({ label, children }) {
394
407
  return /* @__PURE__ */ jsx(Tooltip, { content: label, positioning: { placement: "top" }, children });
395
408
  }
396
- var TAG_BASE = "inline-flex items-center align-top max-w-full select-text rounded-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500";
397
- var TAG_VARIANT_CLASSES = {
398
- subtle: "bg-[var(--color-tag-subtle-bg)] text-[var(--color-tag-subtle-fg)]",
399
- clickable: "cursor-pointer bg-[var(--color-tag-clickable-bg)] text-[var(--color-tag-clickable-fg)] hover:opacity-76",
400
- filter: "bg-[var(--color-tag-filter-bg)]",
401
- select: "cursor-pointer bg-[var(--color-tag-select-bg)] text-[var(--color-tag-select-fg)] hover:text-[var(--color-hover)] hover:opacity-76"
409
+ var TAG_VARIANT = {
410
+ subtle: { backgroundColor: "var(--color-tag-subtle-bg)" },
411
+ clickable: { backgroundColor: "var(--color-tag-clickable-bg)", cursor: "pointer", hoverStyle: { opacity: 0.76 } },
412
+ filter: { backgroundColor: "var(--color-tag-filter-bg)" },
413
+ select: { backgroundColor: "var(--color-tag-select-bg)", cursor: "pointer", hoverStyle: { opacity: 0.76 } }
414
+ };
415
+ var TAG_VARIANT_FG = {
416
+ subtle: "var(--color-tag-subtle-fg)",
417
+ clickable: "var(--color-tag-clickable-fg)",
418
+ filter: void 0,
419
+ select: "var(--color-tag-select-fg)"
402
420
  };
403
- var TAG_SIZE_CLASSES = {
404
- sm: "px-1 py-0.5 min-h-5 gap-1 text-xs",
405
- md: "px-1 py-0.5 min-h-6 gap-1 text-sm",
406
- lg: "px-1.5 py-1.5 min-h-8 min-w-8 gap-1 text-sm"
421
+ var TAG_SIZE = {
422
+ sm: { paddingHorizontal: 4, paddingVertical: 2, minHeight: 20, gap: 4 },
423
+ md: { paddingHorizontal: 4, paddingVertical: 2, minHeight: 24, gap: 4 },
424
+ lg: { paddingHorizontal: 6, paddingVertical: 6, minHeight: 32, minWidth: 32, gap: 4 }
407
425
  };
408
- var TAG_SELECTED_CLASSES = [
409
- "bg-[var(--color-tag-select-selected-bg)]",
410
- "text-[var(--color-tag-select-selected-fg)]",
411
- "hover:text-[var(--color-tag-select-selected-fg)]",
412
- "hover:opacity-76"
413
- ].join(" ");
414
- var TAG_DISABLED_CLASSES = "opacity-40 pointer-events-none cursor-not-allowed";
426
+ var TAG_SIZE_FONT = { sm: 12, md: 14, lg: 14 };
415
427
  var Tag = React4.forwardRef(
416
428
  function Tag2(props, ref) {
417
429
  const {
@@ -431,46 +443,81 @@ var Tag = React4.forwardRef(
431
443
  className,
432
444
  ...rest
433
445
  } = props;
434
- const labelElement = label ? /* @__PURE__ */ jsxs("span", { className: "text-[var(--color-text-secondary)]", children: [
446
+ const resolvedVariant = variant ?? "subtle";
447
+ const resolvedSize = size ?? "md";
448
+ const isSelected = Boolean(selected) && !loading;
449
+ const backgroundColor = isSelected ? "var(--color-tag-select-selected-bg)" : TAG_VARIANT[resolvedVariant].backgroundColor;
450
+ const color = isSelected ? "var(--color-tag-select-selected-fg)" : TAG_VARIANT_FG[resolvedVariant];
451
+ const hoverStyle = isSelected ? { opacity: 0.76 } : TAG_VARIANT[resolvedVariant].hoverStyle;
452
+ const textHoverColor = !isSelected && resolvedVariant === "select" ? "var(--color-hover)" : void 0;
453
+ const labelElement = label ? /* @__PURE__ */ jsxs(Text, { fontSize: TAG_SIZE_FONT[resolvedSize], fontWeight: "500", color: "var(--color-text-secondary)", children: [
435
454
  label,
436
455
  ":",
437
456
  nbsp
438
457
  ] }) : null;
439
- const labelSpan = /* @__PURE__ */ jsxs("span", { className: "line-clamp-1 whitespace-nowrap text-ellipsis font-medium inline", children: [
440
- labelElement,
441
- children
442
- ] });
458
+ const labelSpan = (
459
+ // `ellipsis` is Text's own built-in single-line-truncation variant —
460
+ // the same rule Tailwind's `line-clamp-1`/`text-ellipsis` drew, through
461
+ // the component's variants rather than three separate style props.
462
+ /* @__PURE__ */ jsxs(
463
+ Text,
464
+ {
465
+ ellipsis: true,
466
+ fontWeight: "500",
467
+ fontSize: TAG_SIZE_FONT[resolvedSize],
468
+ color,
469
+ hoverStyle: textHoverColor ? { color: textHoverColor } : void 0,
470
+ children: [
471
+ labelElement,
472
+ children
473
+ ]
474
+ }
475
+ )
476
+ );
443
477
  const contentElement = truncated ? /* @__PURE__ */ jsx(TruncatedTextTooltip, { label: children, children: labelSpan }) : labelSpan;
444
478
  return /* @__PURE__ */ jsx(Skeleton, { loading, asChild: true, children: /* @__PURE__ */ jsxs(
445
- "span",
479
+ XStack,
446
480
  {
447
481
  ref,
448
- className: cn(
449
- TAG_BASE,
450
- TAG_VARIANT_CLASSES[variant ?? "subtle"],
451
- TAG_SIZE_CLASSES[size ?? "md"],
452
- selected && !loading && TAG_SELECTED_CLASSES,
453
- disabled && TAG_DISABLED_CLASSES,
454
- className
455
- ),
456
- ...selected && !loading && { "data-selected": true },
482
+ render: /* @__PURE__ */ jsx("span", {}),
483
+ display: "inline-flex",
484
+ alignItems: "center",
485
+ verticalAlign: "top",
486
+ maxWidth: "100%",
487
+ userSelect: "text",
488
+ ...TAG_SIZE[resolvedSize],
489
+ backgroundColor,
490
+ hoverStyle,
491
+ focusVisibleStyle: {
492
+ outlineWidth: 2,
493
+ outlineOffset: 2,
494
+ outlineColor: "var(--color-gray-500)",
495
+ outlineStyle: "solid"
496
+ },
497
+ cursor: disabled ? "not-allowed" : TAG_VARIANT[resolvedVariant].cursor,
498
+ ...disabled ? { opacity: 0.4, pointerEvents: "none" } : {},
499
+ ...isSelected && { "data-selected": true },
457
500
  ...disabled && { "data-disabled": true },
501
+ className,
458
502
  ...rest,
459
503
  children: [
460
- startElement && /* @__PURE__ */ jsx("span", { className: "shrink-0 inline-flex items-center justify-center empty:hidden", children: startElement }),
504
+ startElement && /* @__PURE__ */ jsx(XStack, { flexShrink: 0, alignItems: "center", justifyContent: "center", children: startElement }),
461
505
  contentElement,
462
- endElement && /* @__PURE__ */ jsx(
463
- "span",
464
- {
465
- ...endElementProps,
466
- className: cn(
467
- "shrink-0 inline-flex items-center justify-center",
468
- endElementProps?.className
469
- ),
470
- children: endElement
471
- }
472
- ),
473
- closable && /* @__PURE__ */ jsx("span", { className: "shrink-0 inline-flex items-center justify-center", children: /* @__PURE__ */ jsx(CloseButton, { onClick: onClose }) })
506
+ endElement && (() => {
507
+ const { className: endClassName, ...endElementRest } = endElementProps ?? {};
508
+ return /* @__PURE__ */ jsx(
509
+ XStack,
510
+ {
511
+ ...endElementRest,
512
+ flexShrink: 0,
513
+ alignItems: "center",
514
+ justifyContent: "center",
515
+ className: endClassName,
516
+ children: endElement
517
+ }
518
+ );
519
+ })(),
520
+ closable && /* @__PURE__ */ jsx(XStack, { flexShrink: 0, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx(CloseButton, { onClick: onClose }) })
474
521
  ]
475
522
  }
476
523
  ) });
package/dist/tooltip.cjs CHANGED
@@ -4,8 +4,6 @@
4
4
  var gui = require('@hanzo/gui');
5
5
  var usehooks = require('@uidotdev/usehooks');
6
6
  var React2 = require('react');
7
- var clsx = require('clsx');
8
- var tailwindMerge = require('tailwind-merge');
9
7
  var jsxRuntime = require('react/jsx-runtime');
10
8
 
11
9
  function _interopNamespace(e) {
@@ -29,6 +27,14 @@ function _interopNamespace(e) {
29
27
  var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
30
28
 
31
29
  // src/tooltip.tsx
30
+ var ink = (children, Wrap = gui.Text, props = {}) => {
31
+ let hasText = false;
32
+ React2.Children.forEach(children, (child) => {
33
+ if (typeof child === "string" || typeof child === "number") hasText = true;
34
+ });
35
+ if (!hasText) return children;
36
+ return React2.Children.map(children, (child) => typeof child === "string" || typeof child === "number" ? React2.createElement(Wrap, props, child) : child);
37
+ };
32
38
  var TOUCH_PX = 1024;
33
39
  function useBelow(px) {
34
40
  const [below, setBelow] = React2__namespace.useState(false);
@@ -42,9 +48,6 @@ function useBelow(px) {
42
48
  return below;
43
49
  }
44
50
  var useIsTouch = () => useBelow(TOUCH_PX);
45
- function cn(...inputs) {
46
- return tailwindMerge.twMerge(clsx.clsx(inputs));
47
- }
48
51
  function mapPlacement(p) {
49
52
  if (!p) return void 0;
50
53
  return p;
@@ -136,14 +139,21 @@ var Tooltip = React2__namespace.forwardRef(
136
139
  {
137
140
  ref,
138
141
  unstyled: true,
139
- className: cn(
140
- "z-[9999] overflow-hidden rounded-lg px-3 py-2 text-sm",
141
- "animate-in fade-in-0 zoom-in-95",
142
- isPopover && "bg-[var(--color-popover-bg)] text-[var(--color-text-primary)]",
143
- isPopover && "shadow-[var(--shadow-popover)] border border-[var(--color-border-divider)] max-w-sm",
144
- !isPopover && "bg-[var(--color-tooltip-bg)] text-[var(--color-tooltip-fg)] max-w-xs",
145
- contentProps?.className
146
- ),
142
+ zIndex: 9999,
143
+ overflow: "hidden",
144
+ borderRadius: 8,
145
+ paddingHorizontal: 12,
146
+ paddingVertical: 8,
147
+ maxWidth: isPopover ? 384 : 320,
148
+ backgroundColor: isPopover ? "var(--color-popover-bg)" : "var(--color-tooltip-bg)",
149
+ transition: "quick",
150
+ enterStyle: { opacity: 0, scale: 0.95 },
151
+ exitStyle: { opacity: 0, scale: 0.95 },
152
+ ...isPopover ? {
153
+ borderWidth: 1,
154
+ borderColor: "var(--color-border-divider)",
155
+ shadowColor: "var(--shadow-popover)"
156
+ } : {},
147
157
  onClick: interactive ? handleContentClick : void 0,
148
158
  ...selected ? { "data-selected": true } : {},
149
159
  ...contentProps,
@@ -152,12 +162,13 @@ var Tooltip = React2__namespace.forwardRef(
152
162
  gui.Tooltip.Arrow,
153
163
  {
154
164
  unstyled: true,
155
- className: cn(
156
- isPopover ? "fill-[var(--color-popover-bg)]" : "fill-[var(--color-tooltip-bg)]"
157
- )
165
+ backgroundColor: isPopover ? "var(--color-popover-bg)" : "var(--color-tooltip-bg)"
158
166
  }
159
167
  ),
160
- content
168
+ ink(content, void 0, {
169
+ fontSize: 14,
170
+ color: isPopover ? "var(--color-text-primary)" : "var(--color-tooltip-fg)"
171
+ })
161
172
  ]
162
173
  }
163
174
  )
package/dist/tooltip.js CHANGED
@@ -1,12 +1,19 @@
1
1
  "use client";
2
- import { TooltipGroup, Tooltip as Tooltip$1 } from '@hanzo/gui';
2
+ import { TooltipGroup, Tooltip as Tooltip$1, Text } from '@hanzo/gui';
3
3
  import { useClickAway } from '@uidotdev/usehooks';
4
4
  import * as React2 from 'react';
5
- import { clsx } from 'clsx';
6
- import { twMerge } from 'tailwind-merge';
5
+ import { Children, createElement } from 'react';
7
6
  import { jsx, jsxs } from 'react/jsx-runtime';
8
7
 
9
8
  // src/tooltip.tsx
9
+ var ink = (children, Wrap = Text, props = {}) => {
10
+ let hasText = false;
11
+ Children.forEach(children, (child) => {
12
+ if (typeof child === "string" || typeof child === "number") hasText = true;
13
+ });
14
+ if (!hasText) return children;
15
+ return Children.map(children, (child) => typeof child === "string" || typeof child === "number" ? createElement(Wrap, props, child) : child);
16
+ };
10
17
  var TOUCH_PX = 1024;
11
18
  function useBelow(px) {
12
19
  const [below, setBelow] = React2.useState(false);
@@ -20,9 +27,6 @@ function useBelow(px) {
20
27
  return below;
21
28
  }
22
29
  var useIsTouch = () => useBelow(TOUCH_PX);
23
- function cn(...inputs) {
24
- return twMerge(clsx(inputs));
25
- }
26
30
  function mapPlacement(p) {
27
31
  if (!p) return void 0;
28
32
  return p;
@@ -114,14 +118,21 @@ var Tooltip = React2.forwardRef(
114
118
  {
115
119
  ref,
116
120
  unstyled: true,
117
- className: cn(
118
- "z-[9999] overflow-hidden rounded-lg px-3 py-2 text-sm",
119
- "animate-in fade-in-0 zoom-in-95",
120
- isPopover && "bg-[var(--color-popover-bg)] text-[var(--color-text-primary)]",
121
- isPopover && "shadow-[var(--shadow-popover)] border border-[var(--color-border-divider)] max-w-sm",
122
- !isPopover && "bg-[var(--color-tooltip-bg)] text-[var(--color-tooltip-fg)] max-w-xs",
123
- contentProps?.className
124
- ),
121
+ zIndex: 9999,
122
+ overflow: "hidden",
123
+ borderRadius: 8,
124
+ paddingHorizontal: 12,
125
+ paddingVertical: 8,
126
+ maxWidth: isPopover ? 384 : 320,
127
+ backgroundColor: isPopover ? "var(--color-popover-bg)" : "var(--color-tooltip-bg)",
128
+ transition: "quick",
129
+ enterStyle: { opacity: 0, scale: 0.95 },
130
+ exitStyle: { opacity: 0, scale: 0.95 },
131
+ ...isPopover ? {
132
+ borderWidth: 1,
133
+ borderColor: "var(--color-border-divider)",
134
+ shadowColor: "var(--shadow-popover)"
135
+ } : {},
125
136
  onClick: interactive ? handleContentClick : void 0,
126
137
  ...selected ? { "data-selected": true } : {},
127
138
  ...contentProps,
@@ -130,12 +141,13 @@ var Tooltip = React2.forwardRef(
130
141
  Tooltip$1.Arrow,
131
142
  {
132
143
  unstyled: true,
133
- className: cn(
134
- isPopover ? "fill-[var(--color-popover-bg)]" : "fill-[var(--color-tooltip-bg)]"
135
- )
144
+ backgroundColor: isPopover ? "var(--color-popover-bg)" : "var(--color-tooltip-bg)"
136
145
  }
137
146
  ),
138
- content
147
+ ink(content, void 0, {
148
+ fontSize: 14,
149
+ color: isPopover ? "var(--color-text-primary)" : "var(--color-tooltip-fg)"
150
+ })
139
151
  ]
140
152
  }
141
153
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxfi/ui",
3
- "version": "7.4.11",
3
+ "version": "7.4.13",
4
4
  "description": "Cross-platform UI components on @hanzo/gui. Native mobile + web.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/alert.tsx CHANGED
@@ -1,15 +1,15 @@
1
+ import { Text, View, XStack, YStack } from '@hanzo/gui';
1
2
  import * as React from 'react';
2
3
 
3
- import { cn } from './utils';
4
-
5
4
  // Inline info icon (filled circle with i)
6
- const IndicatorIcon = ({ className }: { readonly className?: string }) => (
7
- <svg className={ className } viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
5
+ const IndicatorIcon = () => (
6
+ <svg width={ 20 } height={ 20 } viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
8
7
  <path fillRule="evenodd" clipRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm.75-11.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM9.25 10a.75.75 0 011.5 0v3a.75.75 0 01-1.5 0v-3z"/>
9
8
  </svg>
10
9
  );
11
10
 
12
11
  import { CloseButton } from './close-button';
12
+ import { ink } from './ink';
13
13
  import { Skeleton } from './skeleton';
14
14
 
15
15
  /* ------------------------------------------------------------------ */
@@ -19,27 +19,38 @@ import { Skeleton } from './skeleton';
19
19
  type AlertStatus = 'info' | 'warning' | 'warning_table' | 'success' | 'error';
20
20
 
21
21
  /* ------------------------------------------------------------------ */
22
- /* Class maps (replaced CVA) */
22
+ /* Style maps (replaced CVA) */
23
23
  /* ------------------------------------------------------------------ */
24
24
 
25
- const ALERT_BASE = 'w-full flex items-start relative rounded text-[var(--color-alert-fg)]';
26
-
27
- const STATUS_CLASSES: Record<AlertStatus, string> = {
28
- info: 'bg-[var(--color-alert-bg-info)]',
29
- warning: 'bg-[var(--color-alert-bg-warning)]',
30
- warning_table: 'bg-[var(--color-alert-bg-warning-table)]',
31
- success: 'bg-[var(--color-alert-bg-success)]',
32
- error: 'bg-[var(--color-alert-bg-error)]',
25
+ /** The frame every alert shares, regardless of status or size. */
26
+ const ALERT_BASE = {
27
+ width: '100%',
28
+ position: 'relative',
29
+ alignItems: 'flex-start',
30
+ borderRadius: 4,
31
+ gap: 8,
32
+ paddingVertical: 8,
33
+ } as const;
34
+
35
+ /** Foreground is constant across every status — only the background moves. */
36
+ const ALERT_FG = 'var(--color-alert-fg)' as never;
37
+
38
+ const STATUS_BG: Record<AlertStatus, string> = {
39
+ info: 'var(--color-alert-bg-info)',
40
+ warning: 'var(--color-alert-bg-warning)',
41
+ warning_table: 'var(--color-alert-bg-warning-table)',
42
+ success: 'var(--color-alert-bg-success)',
43
+ error: 'var(--color-alert-bg-error)',
33
44
  };
34
45
 
35
- const SIZE_CLASSES: Record<string, string> = {
36
- sm: 'gap-2 px-2 py-2 text-xs',
37
- md: 'gap-2 px-3 py-2 text-base',
46
+ const SIZE: Record<'sm' | 'md', { paddingHorizontal: number; fontSize: number }> = {
47
+ sm: { paddingHorizontal: 8, fontSize: 12 },
48
+ md: { paddingHorizontal: 12, fontSize: 16 },
38
49
  };
39
50
 
40
- const INDICATOR_SIZE_CLASSES: Record<string, string> = {
41
- sm: 'w-5 h-5 my-0',
42
- md: 'w-5 h-5 my-[2px]',
51
+ const INDICATOR_SIZE: Record<'sm' | 'md', { marginVertical: number }> = {
52
+ sm: { marginVertical: 0 },
53
+ md: { marginVertical: 2 },
43
54
  };
44
55
 
45
56
  /* ------------------------------------------------------------------ */
@@ -107,10 +118,9 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
107
118
  const [ isOpen, setIsOpen ] = React.useState(true);
108
119
 
109
120
  const resolvedSize = size ?? 'md';
121
+ const fontSize = SIZE[resolvedSize].fontSize;
110
122
 
111
- const defaultIcon = (
112
- <IndicatorIcon className="w-5 h-5"/>
113
- );
123
+ const defaultIcon = <IndicatorIcon/>;
114
124
 
115
125
  const iconElement = (() => {
116
126
  if (startElement !== undefined) {
@@ -122,12 +132,23 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
122
132
  }
123
133
 
124
134
  return (
125
- <span className={ cn(
126
- 'inline-flex items-center justify-center shrink-0 text-[var(--color-alert-fg)] [&>svg]:w-full [&>svg]:h-full',
127
- INDICATOR_SIZE_CLASSES[resolvedSize],
128
- ) }>
135
+ <XStack
136
+ alignItems="center"
137
+ justifyContent="center"
138
+ flexShrink={ 0 }
139
+ width={ 20 }
140
+ height={ 20 }
141
+ { ...INDICATOR_SIZE[resolvedSize] }
142
+ // The default icon and a caller's custom `icon` both use
143
+ // `fill="currentColor"`; `.lux-icon` (tokens.css) is the existing
144
+ // descendant-selector rule that sizes an arbitrary child svg to the
145
+ // box (20px default) instead of its own intrinsic size — no prop
146
+ // reaches a child element, so this is shared, not reinvented here.
147
+ className="lux-icon"
148
+ style={{ color: ALERT_FG }}
149
+ >
129
150
  { icon || defaultIcon }
130
- </span>
151
+ </XStack>
131
152
  );
132
153
  })();
133
154
 
@@ -156,37 +177,49 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
156
177
  ...(descColumnGap !== undefined ? { columnGap: typeof descColumnGap === 'number' ? `${ descColumnGap * 4 }px` : descColumnGap } : {}),
157
178
  };
158
179
 
180
+ // Row when inline (text sits beside the title), column otherwise.
181
+ const ContentFrame = inline ? XStack : YStack;
182
+
159
183
  return (
160
184
  <Skeleton loading={ loading }>
161
- <div
162
- ref={ ref }
163
- className={ cn(ALERT_BASE, STATUS_CLASSES[status], SIZE_CLASSES[resolvedSize], className) }
185
+ <XStack
186
+ ref={ ref as never }
187
+ { ...ALERT_BASE }
188
+ paddingHorizontal={ SIZE[resolvedSize].paddingHorizontal }
189
+ backgroundColor={ STATUS_BG[status] as never }
190
+ className={ className }
164
191
  style={ alertStyle }
165
- { ...alertRest }
192
+ { ...(alertRest as object) }
166
193
  >
167
194
  { iconElement }
168
195
  { children ? (
169
- <div className={ cn('flex flex-1', inline ? 'inline-flex flex-row items-center' : 'flex flex-col') }>
170
- { title && <div className="font-semibold">{ title }</div> }
171
- <div
172
- className={ cn('inline-flex flex-wrap', descClassName) }
196
+ <ContentFrame flex={ 1 } alignItems={ inline ? 'center' : undefined }>
197
+ { title && (
198
+ <Text fontWeight="600" fontSize={ fontSize } color={ ALERT_FG }>
199
+ { title }
200
+ </Text>
201
+ ) }
202
+ <XStack
203
+ flexWrap="wrap"
204
+ className={ descClassName }
173
205
  style={ Object.keys(descStyle).length > 0 ? descStyle : undefined }
174
- { ...descRest }
206
+ { ...(descRest as object) }
175
207
  >
176
- { children }
177
- </div>
178
- </div>
208
+ { ink(children, undefined, { fontSize, color: ALERT_FG }) }
209
+ </XStack>
210
+ </ContentFrame>
179
211
  ) : (
180
- <div className="font-semibold flex-1">{ title }</div>
212
+ <Text flex={ 1 } fontWeight="600" fontSize={ fontSize } color={ ALERT_FG }>
213
+ { title }
214
+ </Text>
181
215
  ) }
182
216
  { endElement }
183
217
  { closable && (
184
- <CloseButton
185
- className="relative self-start"
186
- onClick={ handleClose }
187
- />
218
+ <View position="relative" alignSelf="flex-start">
219
+ <CloseButton onClick={ handleClose }/>
220
+ </View>
188
221
  ) }
189
- </div>
222
+ </XStack>
190
223
  </Skeleton>
191
224
  );
192
225
  },