@luxfi/ui 7.3.1 → 7.4.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 (59) hide show
  1. package/dist/alert.cjs +2 -2
  2. package/dist/alert.js +1 -1
  3. package/dist/badge.cjs +6 -6
  4. package/dist/badge.js +1 -1
  5. package/dist/bank.cjs +13 -13
  6. package/dist/bank.d.cts +30 -23
  7. package/dist/bank.d.ts +30 -23
  8. package/dist/bank.js +1 -1
  9. package/dist/button.cjs +3 -3
  10. package/dist/button.js +1 -1
  11. package/dist/close-button.cjs +2 -2
  12. package/dist/close-button.js +1 -1
  13. package/dist/dialog.cjs +13 -14
  14. package/dist/dialog.d.cts +58 -5
  15. package/dist/dialog.d.ts +58 -5
  16. package/dist/dialog.js +1 -2
  17. package/dist/drawer.cjs +2 -2
  18. package/dist/drawer.js +1 -1
  19. package/dist/icon-button.cjs +2 -2
  20. package/dist/icon-button.js +1 -1
  21. package/dist/index.cjs +127 -59
  22. package/dist/index.d.cts +6 -2
  23. package/dist/index.d.ts +6 -2
  24. package/dist/index.js +85 -22
  25. package/dist/input.cjs +10 -2
  26. package/dist/input.d.cts +8 -0
  27. package/dist/input.d.ts +8 -0
  28. package/dist/input.js +10 -2
  29. package/dist/lux.config.cjs +56 -0
  30. package/dist/lux.config.d.cts +415 -0
  31. package/dist/lux.config.d.ts +415 -0
  32. package/dist/lux.config.js +48 -0
  33. package/dist/popover.cjs +8 -9
  34. package/dist/popover.js +1 -2
  35. package/dist/provider.cjs +62 -12
  36. package/dist/provider.d.cts +3 -2
  37. package/dist/provider.d.ts +3 -2
  38. package/dist/provider.js +62 -12
  39. package/dist/tag.cjs +7 -8
  40. package/dist/tag.js +1 -2
  41. package/dist/textarea.cjs +10 -2
  42. package/dist/textarea.d.cts +2 -0
  43. package/dist/textarea.d.ts +2 -0
  44. package/dist/textarea.js +10 -2
  45. package/dist/tooltip.cjs +6 -6
  46. package/dist/tooltip.js +1 -1
  47. package/package.json +24 -12
  48. package/src/bank.tsx +2 -2
  49. package/src/button.tsx +1 -1
  50. package/src/close-button.tsx +1 -1
  51. package/src/dialog.tsx +1 -1
  52. package/src/icon-button.tsx +1 -1
  53. package/src/index.ts +6 -0
  54. package/src/input.tsx +17 -1
  55. package/src/lux.config.ts +81 -0
  56. package/src/popover.tsx +1 -1
  57. package/src/provider.tsx +51 -15
  58. package/src/textarea.tsx +11 -1
  59. package/src/tooltip.tsx +2 -2
package/dist/provider.js CHANGED
@@ -1,25 +1,75 @@
1
1
  "use client";
2
- import { createGui } from '@hanzogui/core';
2
+ import { createGui, GuiProvider } from '@hanzo/gui';
3
3
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
4
  export { QueryClient, useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
5
5
  import React from 'react';
6
+ import { defaultConfig } from '@hanzogui/config/v5';
6
7
  import { jsx } from 'react/jsx-runtime';
7
8
 
8
- var _guiInitialized = false;
9
- function ensureGui() {
10
- if (_guiInitialized) return;
11
- if (typeof window === "undefined") return;
12
- createGui({ settings: { autocompleteSpecificTokens: "except-special" } });
13
- _guiInitialized = true;
14
- }
9
+ var LUX_BRAND = {
10
+ lux: "#7000FF",
11
+ zoo: "#6C5EFB",
12
+ hanzo: "#EA580C",
13
+ pars: "#1C3879"
14
+ };
15
+ var PARS_GOLD = "#C8A45C";
16
+ var TRUE_BLACK = "#000000";
17
+ var darkBase = {
18
+ ...defaultConfig.themes.dark,
19
+ background: TRUE_BLACK,
20
+ backgroundHover: "#0A0A0A",
21
+ backgroundPress: "#141414",
22
+ backgroundFocus: "#0A0A0A"
23
+ };
24
+ var brandTheme = (accent, extra = {}) => ({
25
+ ...darkBase,
26
+ accentBackground: accent,
27
+ accentColor: "#FFFFFF",
28
+ borderColorHover: accent,
29
+ colorHover: accent,
30
+ ...extra
31
+ });
32
+ var luxThemes = {
33
+ dark: darkBase,
34
+ dark_lux: brandTheme(LUX_BRAND.lux),
35
+ dark_zoo: brandTheme(LUX_BRAND.zoo),
36
+ dark_hanzo: brandTheme(LUX_BRAND.hanzo),
37
+ dark_pars: brandTheme(LUX_BRAND.pars, { accentColor: PARS_GOLD })
38
+ };
39
+ var config = createGui({
40
+ ...defaultConfig,
41
+ settings: {
42
+ ...defaultConfig.settings,
43
+ onlyAllowShorthands: false
44
+ },
45
+ themes: {
46
+ ...defaultConfig.themes,
47
+ ...luxThemes
48
+ }
49
+ });
50
+ var lux_config_default = config;
15
51
  var defaultQueryClient = new QueryClient({
16
52
  defaultOptions: { queries: { refetchOnWindowFocus: false, retry: 1, staleTime: 3e4 } }
17
53
  });
18
- var AppProvider = ({ children, queryClient }) => {
19
- React.useEffect(() => {
20
- ensureGui();
54
+ var FONT_BODY_RESET_ID = "lux-ui-font-body-reset";
55
+ var FONT_BODY_RESET_CSS = "body .font_body{line-height:1.5}";
56
+ var useFontBodyReset = () => {
57
+ React.useInsertionEffect(() => {
58
+ if (typeof document === "undefined") return;
59
+ if (document.getElementById(FONT_BODY_RESET_ID)) return;
60
+ const style = document.createElement("style");
61
+ style.id = FONT_BODY_RESET_ID;
62
+ style.textContent = FONT_BODY_RESET_CSS;
63
+ document.head.appendChild(style);
21
64
  }, []);
22
- return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children });
65
+ };
66
+ var AppProvider = ({
67
+ children,
68
+ queryClient,
69
+ defaultTheme = "dark_lux"
70
+ }) => {
71
+ useFontBodyReset();
72
+ return /* @__PURE__ */ jsx(GuiProvider, { config: lux_config_default, defaultTheme, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children }) });
23
73
  };
24
74
 
25
75
  export { AppProvider };
package/dist/tag.cjs CHANGED
@@ -4,9 +4,8 @@
4
4
  var React3 = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
- var core = require('@hanzogui/core');
7
+ var gui = require('@hanzo/gui');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
- var tooltip = require('@hanzogui/tooltip');
10
9
  var usehooks = require('@uidotdev/usehooks');
11
10
 
12
11
  function _interopNamespace(e) {
@@ -34,7 +33,7 @@ function cn(...inputs) {
34
33
  return tailwindMerge.twMerge(clsx.clsx(inputs));
35
34
  }
36
35
  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";
37
- var CloseButtonFrame = core.styled(core.View, {
36
+ var CloseButtonFrame = gui.styled(gui.View, {
38
37
  name: "LuxCloseButton",
39
38
  render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-label": "Close" }),
40
39
  role: "button",
@@ -363,8 +362,8 @@ var Tooltip = React3__namespace.forwardRef(
363
362
  const isPopover = variant === "popover";
364
363
  const placement = mapPlacement(positioning?.placement) ?? "top";
365
364
  const offset = positioning?.offset?.mainAxis ?? 4;
366
- return /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipGroup, { delay: openDelay, children: /* @__PURE__ */ jsxRuntime.jsxs(
367
- tooltip.Tooltip,
365
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.TooltipGroup, { delay: openDelay, children: /* @__PURE__ */ jsxRuntime.jsxs(
366
+ gui.Tooltip,
368
367
  {
369
368
  open,
370
369
  onOpenChange: handleOpenChange,
@@ -374,7 +373,7 @@ var Tooltip = React3__namespace.forwardRef(
374
373
  unstyled: true,
375
374
  children: [
376
375
  /* @__PURE__ */ jsxRuntime.jsx(
377
- tooltip.Tooltip.Trigger,
376
+ gui.Tooltip.Trigger,
378
377
  {
379
378
  ref: open ? triggerRef : void 0,
380
379
  asChild: true,
@@ -384,7 +383,7 @@ var Tooltip = React3__namespace.forwardRef(
384
383
  }
385
384
  ),
386
385
  /* @__PURE__ */ jsxRuntime.jsxs(
387
- tooltip.Tooltip.Content,
386
+ gui.Tooltip.Content,
388
387
  {
389
388
  ref,
390
389
  unstyled: true,
@@ -401,7 +400,7 @@ var Tooltip = React3__namespace.forwardRef(
401
400
  ...contentProps,
402
401
  children: [
403
402
  showArrow && /* @__PURE__ */ jsxRuntime.jsx(
404
- tooltip.Tooltip.Arrow,
403
+ gui.Tooltip.Arrow,
405
404
  {
406
405
  unstyled: true,
407
406
  className: cn(
package/dist/tag.js CHANGED
@@ -2,9 +2,8 @@
2
2
  import * as React3 from 'react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
- import { styled, View } from '@hanzogui/core';
5
+ import { styled, View, TooltipGroup, Tooltip as Tooltip$1 } from '@hanzo/gui';
6
6
  import { jsx, jsxs } from 'react/jsx-runtime';
7
- import { TooltipGroup, Tooltip as Tooltip$1 } from '@hanzogui/tooltip';
8
7
  import { useClickAway } from '@uidotdev/usehooks';
9
8
 
10
9
  // src/tag.tsx
package/dist/textarea.cjs CHANGED
@@ -38,13 +38,21 @@ var TEXTAREA_VARIANT_CLASSES = {
38
38
  unstyled: "border-0 bg-transparent p-0"
39
39
  };
40
40
  var Textarea = React__default.default.forwardRef(
41
- ({ size = "md", variant = "outline", className, ...rest }, ref) => {
41
+ ({ size = "md", variant = "outline", className, onChange, onChangeText, ...rest }, ref) => {
42
+ const handleChange = React__default.default.useCallback(
43
+ (event) => {
44
+ onChange?.(event);
45
+ onChangeText?.(event.target.value);
46
+ },
47
+ [onChange, onChangeText]
48
+ );
42
49
  return /* @__PURE__ */ jsxRuntime.jsx(
43
50
  "textarea",
44
51
  {
45
52
  ref,
46
53
  className: cn(TEXTAREA_BASE, TEXTAREA_SIZE_CLASSES[size], TEXTAREA_VARIANT_CLASSES[variant], className),
47
- ...rest
54
+ ...rest,
55
+ onChange: handleChange
48
56
  }
49
57
  );
50
58
  }
@@ -5,6 +5,8 @@ type TextareaVariant = 'outline' | 'filled' | 'unstyled';
5
5
  interface TextareaProps extends Omit<React__default.ComponentPropsWithRef<'textarea'>, 'size'> {
6
6
  readonly size?: TextareaSize;
7
7
  readonly variant?: TextareaVariant;
8
+ /** Tamagui / React-Native convention — bridged to native `onChange` (see Input). */
9
+ readonly onChangeText?: (text: string) => void;
8
10
  }
9
11
  declare const Textarea: React__default.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & React__default.RefAttributes<HTMLTextAreaElement>>;
10
12
 
@@ -5,6 +5,8 @@ type TextareaVariant = 'outline' | 'filled' | 'unstyled';
5
5
  interface TextareaProps extends Omit<React__default.ComponentPropsWithRef<'textarea'>, 'size'> {
6
6
  readonly size?: TextareaSize;
7
7
  readonly variant?: TextareaVariant;
8
+ /** Tamagui / React-Native convention — bridged to native `onChange` (see Input). */
9
+ readonly onChangeText?: (text: string) => void;
8
10
  }
9
11
  declare const Textarea: React__default.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & React__default.RefAttributes<HTMLTextAreaElement>>;
10
12
 
package/dist/textarea.js CHANGED
@@ -32,13 +32,21 @@ var TEXTAREA_VARIANT_CLASSES = {
32
32
  unstyled: "border-0 bg-transparent p-0"
33
33
  };
34
34
  var Textarea = React.forwardRef(
35
- ({ size = "md", variant = "outline", className, ...rest }, ref) => {
35
+ ({ size = "md", variant = "outline", className, onChange, onChangeText, ...rest }, ref) => {
36
+ const handleChange = React.useCallback(
37
+ (event) => {
38
+ onChange?.(event);
39
+ onChangeText?.(event.target.value);
40
+ },
41
+ [onChange, onChangeText]
42
+ );
36
43
  return /* @__PURE__ */ jsx(
37
44
  "textarea",
38
45
  {
39
46
  ref,
40
47
  className: cn(TEXTAREA_BASE, TEXTAREA_SIZE_CLASSES[size], TEXTAREA_VARIANT_CLASSES[variant], className),
41
- ...rest
48
+ ...rest,
49
+ onChange: handleChange
42
50
  }
43
51
  );
44
52
  }
package/dist/tooltip.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var tooltip = require('@hanzogui/tooltip');
4
+ var gui = require('@hanzo/gui');
5
5
  var usehooks = require('@uidotdev/usehooks');
6
6
  var React = require('react');
7
7
  var clsx = require('clsx');
@@ -113,8 +113,8 @@ var Tooltip = React__namespace.forwardRef(
113
113
  const isPopover = variant === "popover";
114
114
  const placement = mapPlacement(positioning?.placement) ?? "top";
115
115
  const offset = positioning?.offset?.mainAxis ?? 4;
116
- return /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipGroup, { delay: openDelay, children: /* @__PURE__ */ jsxRuntime.jsxs(
117
- tooltip.Tooltip,
116
+ return /* @__PURE__ */ jsxRuntime.jsx(gui.TooltipGroup, { delay: openDelay, children: /* @__PURE__ */ jsxRuntime.jsxs(
117
+ gui.Tooltip,
118
118
  {
119
119
  open,
120
120
  onOpenChange: handleOpenChange,
@@ -124,7 +124,7 @@ var Tooltip = React__namespace.forwardRef(
124
124
  unstyled: true,
125
125
  children: [
126
126
  /* @__PURE__ */ jsxRuntime.jsx(
127
- tooltip.Tooltip.Trigger,
127
+ gui.Tooltip.Trigger,
128
128
  {
129
129
  ref: open ? triggerRef : void 0,
130
130
  asChild: true,
@@ -134,7 +134,7 @@ var Tooltip = React__namespace.forwardRef(
134
134
  }
135
135
  ),
136
136
  /* @__PURE__ */ jsxRuntime.jsxs(
137
- tooltip.Tooltip.Content,
137
+ gui.Tooltip.Content,
138
138
  {
139
139
  ref,
140
140
  unstyled: true,
@@ -151,7 +151,7 @@ var Tooltip = React__namespace.forwardRef(
151
151
  ...contentProps,
152
152
  children: [
153
153
  showArrow && /* @__PURE__ */ jsxRuntime.jsx(
154
- tooltip.Tooltip.Arrow,
154
+ gui.Tooltip.Arrow,
155
155
  {
156
156
  unstyled: true,
157
157
  className: cn(
package/dist/tooltip.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { TooltipGroup, Tooltip as Tooltip$1 } from '@hanzogui/tooltip';
2
+ import { TooltipGroup, Tooltip as Tooltip$1 } from '@hanzo/gui';
3
3
  import { useClickAway } from '@uidotdev/usehooks';
4
4
  import * as React from 'react';
5
5
  import { clsx } from 'clsx';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@luxfi/ui",
3
- "version": "7.3.1",
4
- "description": "Radix + Tailwind UI primitives for Lux apps. Drop-in replacements for Chakra compound components.",
3
+ "version": "7.4.0",
4
+ "description": "Cross-platform DeFi UI components built on @hanzo/gui (Tamagui). Native mobile + web.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -253,11 +253,6 @@
253
253
  "dev": "tsup --watch"
254
254
  },
255
255
  "dependencies": {
256
- "@hanzogui/core": "^3.0.6",
257
- "@hanzogui/dialog": "^3.0.2",
258
- "@hanzogui/popover": "^3.0.2",
259
- "@hanzogui/text": "^3.0.2",
260
- "@hanzogui/tooltip": "^3.0.2",
261
256
  "@radix-ui/react-accordion": "^1.2.12",
262
257
  "@radix-ui/react-avatar": "^1.1.10",
263
258
  "@radix-ui/react-checkbox": "^1.3.3",
@@ -277,17 +272,34 @@
277
272
  "react-icons": "^5.4.0",
278
273
  "sonner": "^2.0.0",
279
274
  "tailwind-merge": "^3.0.0",
280
- "@tanstack/react-query": "^5.76.0"
275
+ "@tanstack/react-query": "^5.76.0",
276
+ "@hanzo/gui": "^7.3.0",
277
+ "@hanzogui/config": "^7.3.0",
278
+ "@hanzogui/core": "^7.3.0",
279
+ "@hanzogui/web": "^7.3.0"
281
280
  },
282
281
  "peerDependencies": {
283
- "@hanzogui/core": "^3.0.6",
284
- "react": ">=18",
285
- "react-dom": "^18.0.0 || ^19.0.0"
282
+ "react": ">=19",
283
+ "react-dom": ">=19",
284
+ "@hanzo/gui": "^7.3.0",
285
+ "@hanzogui/config": "^7.3.0",
286
+ "@hanzogui/themes": "^7.3.0",
287
+ "@hanzogui/colors": "^7.3.0",
288
+ "@hanzogui/lucide-icons-2": "^7.3.0"
289
+ },
290
+ "peerDependenciesMeta": {
291
+ "@hanzogui/themes": { "optional": true },
292
+ "@hanzogui/colors": { "optional": true },
293
+ "@hanzogui/lucide-icons-2": { "optional": true }
286
294
  },
287
295
  "devDependencies": {
288
- "@hanzogui/core": "^3.0.6",
296
+ "@hanzogui/config": "7.3.0",
297
+ "@hanzogui/themes": "7.3.0",
298
+ "@hanzogui/colors": "7.3.0",
289
299
  "@types/react": "^19.0.0",
290
300
  "@types/react-dom": "^19.0.0",
301
+ "react": "^19.0.0",
302
+ "react-dom": "^19.0.0",
291
303
  "tsup": "^8.5.0",
292
304
  "typescript": "^5.9.3"
293
305
  }
package/src/bank.tsx CHANGED
@@ -1,8 +1,8 @@
1
1
  'use client'
2
2
 
3
3
  import React from 'react'
4
- import type { GetProps } from '@hanzogui/core'
5
- import { View, Text, styled } from '@hanzogui/core'
4
+ import type { GetProps } from '@hanzo/gui'
5
+ import { View, Text, styled } from '@hanzo/gui'
6
6
 
7
7
  // ── Bank Theme Tokens ─────────────────────────────────────────────
8
8
  export const bankColors = {
package/src/button.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { styled, View } from '@hanzogui/core';
1
+ import { styled, View } from '@hanzo/gui';
2
2
  import * as React from 'react';
3
3
 
4
4
  import { Skeleton } from './skeleton';
@@ -1,4 +1,4 @@
1
- import { styled, View } from '@hanzogui/core';
1
+ import { styled, View } from '@hanzo/gui';
2
2
  import * as React from 'react';
3
3
 
4
4
  // eslint-disable-next-line max-len
package/src/dialog.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { Dialog as GuiDialog } from '@hanzogui/dialog';
1
+ import { Dialog as GuiDialog } from '@hanzo/gui';
2
2
  import * as React from 'react';
3
3
 
4
4
  import { cn } from './utils';
@@ -1,4 +1,4 @@
1
- import { styled, View } from '@hanzogui/core';
1
+ import { styled, View } from '@hanzo/gui';
2
2
  import * as React from 'react';
3
3
 
4
4
  import { Skeleton } from './skeleton';
package/src/index.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  export { AppProvider } from './provider';
2
2
  export { cn } from './utils';
3
3
 
4
+ // Lux gui config — the createGui() result (fed to GuiProvider) + the brand
5
+ // child-theme rows. Exposed so app bundlers (Vite/Next SSR extraction) and
6
+ // escape-hatch consumers can reach the resolved config and brand palette.
7
+ export { default as guiConfig, config, luxThemes, LUX_BRAND, PARS_GOLD } from './lux.config';
8
+ export type { Conf, LuxBrand } from './lux.config';
9
+
4
10
  export {
5
11
  AccordionRoot,
6
12
  AccordionItem,
package/src/input.tsx CHANGED
@@ -34,15 +34,31 @@ type InputVariant = 'outline' | 'filled' | 'unstyled';
34
34
  export interface InputProps extends Omit<React.ComponentPropsWithRef<'input'>, 'size'> {
35
35
  readonly size?: InputSize;
36
36
  readonly variant?: InputVariant;
37
+ /**
38
+ * Tamagui / React-Native convention: called with the text value on every
39
+ * change. Bridged to the native `onChange`, so callers using EITHER the web
40
+ * `onChange(e)` API OR the `onChangeText(text)` API get updates. Without this
41
+ * bridge, RN/Tamagui-style code (e.g. seed-phrase / PIN entry ported from a
42
+ * gui-based surface) passes `onChangeText` and the field silently no-ops.
43
+ */
44
+ readonly onChangeText?: (text: string) => void;
37
45
  }
38
46
 
39
47
  export const Input = React.forwardRef<HTMLInputElement, InputProps>(
40
- ({ size = 'md', variant = 'outline', className, ...rest }, ref) => {
48
+ ({ size = 'md', variant = 'outline', className, onChange, onChangeText, ...rest }, ref) => {
49
+ const handleChange = React.useCallback(
50
+ (event: React.ChangeEvent<HTMLInputElement>): void => {
51
+ onChange?.(event);
52
+ onChangeText?.(event.target.value);
53
+ },
54
+ [ onChange, onChangeText ],
55
+ );
41
56
  return (
42
57
  <input
43
58
  ref={ ref }
44
59
  className={ cn(INPUT_BASE, INPUT_SIZE_CLASSES[size], INPUT_VARIANT_CLASSES[variant], className) }
45
60
  { ...rest }
61
+ onChange={ handleChange }
46
62
  />
47
63
  );
48
64
  },
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { createGui } from '@hanzo/gui';
4
+ import { defaultConfig } from '@hanzogui/config/v5';
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Branding = VALUE, not place.
8
+ // The ONE spot brand hex is allowed to live (project rule: never hardcode hex
9
+ // in components). Accents sourced from the work-board brand palette.
10
+ // ---------------------------------------------------------------------------
11
+ export const LUX_BRAND = {
12
+ lux: '#7000FF',
13
+ zoo: '#6C5EFB',
14
+ hanzo: '#EA580C',
15
+ pars: '#1C3879',
16
+ } as const;
17
+
18
+ export const PARS_GOLD = '#C8A45C';
19
+
20
+ export type LuxBrand = keyof typeof LUX_BRAND;
21
+
22
+ // Shared true-black neutral base: take @hanzogui's resolved dark theme and
23
+ // force a pure-black canvas so every Lux surface sits on the same ground.
24
+ const TRUE_BLACK = '#000000';
25
+
26
+ const darkBase = {
27
+ ...defaultConfig.themes.dark,
28
+ background: TRUE_BLACK,
29
+ backgroundHover: '#0A0A0A',
30
+ backgroundPress: '#141414',
31
+ backgroundFocus: '#0A0A0A',
32
+ } as typeof defaultConfig.themes.dark;
33
+
34
+ // A brand child-theme row = the true-black base with the brand accent woven
35
+ // into the accent-carrying keys. `<Theme name="lux">` under a dark parent
36
+ // resolves to `dark_lux`.
37
+ const brandTheme = (
38
+ accent: string,
39
+ extra: Record<string, string> = {},
40
+ ): typeof darkBase =>
41
+ ({
42
+ ...darkBase,
43
+ accentBackground: accent,
44
+ accentColor: '#FFFFFF',
45
+ borderColorHover: accent,
46
+ colorHover: accent,
47
+ ...extra,
48
+ }) as typeof darkBase;
49
+
50
+ export const luxThemes = {
51
+ dark: darkBase,
52
+ dark_lux: brandTheme(LUX_BRAND.lux),
53
+ dark_zoo: brandTheme(LUX_BRAND.zoo),
54
+ dark_hanzo: brandTheme(LUX_BRAND.hanzo),
55
+ dark_pars: brandTheme(LUX_BRAND.pars, { accentColor: PARS_GOLD }),
56
+ };
57
+
58
+ // One engine, tokens-not-forks: reuse @hanzogui's v5 defaultConfig
59
+ // (tokens / fonts / media / shorthands) and only add the Lux child-theme rows
60
+ // over it. The lone settings override — `onlyAllowShorthands: false` — keeps the
61
+ // harvested exchange primitives (which author with longhand style props like
62
+ // `borderRadius` / `paddingHorizontal`) valid; v5 defaults to shorthands-only.
63
+ export const config = createGui({
64
+ ...defaultConfig,
65
+ settings: {
66
+ ...defaultConfig.settings,
67
+ onlyAllowShorthands: false,
68
+ },
69
+ themes: {
70
+ ...defaultConfig.themes,
71
+ ...luxThemes,
72
+ },
73
+ });
74
+
75
+ export type Conf = typeof config;
76
+
77
+ declare module '@hanzo/gui' {
78
+ interface GuiCustomConfig extends Conf {}
79
+ }
80
+
81
+ export default config;
package/src/popover.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { Popover as GuiPopover } from '@hanzogui/popover';
1
+ import { Popover as GuiPopover } from '@hanzo/gui';
2
2
  import * as React from 'react';
3
3
 
4
4
  import { cn } from './utils';
package/src/provider.tsx CHANGED
@@ -1,33 +1,69 @@
1
1
  'use client';
2
2
 
3
- import { createGui } from '@hanzogui/core';
4
- import { QueryClient, QueryClientProvider, useQueryClient, useQuery, useMutation, useInfiniteQuery } from '@tanstack/react-query';
3
+ import { GuiProvider } from '@hanzo/gui';
4
+ import {
5
+ QueryClient,
6
+ QueryClientProvider,
7
+ useQueryClient,
8
+ useQuery,
9
+ useMutation,
10
+ useInfiniteQuery,
11
+ } from '@tanstack/react-query';
5
12
  import React from 'react';
6
13
 
7
- // Initialize @hanzogui once — lazy, not at module load (would crash Node/SSR).
8
- let _guiInitialized = false;
9
- function ensureGui() {
10
- if (_guiInitialized) return;
11
- if (typeof window === 'undefined') return;
12
- createGui({ settings: { autocompleteSpecificTokens: 'except-special' } });
13
- _guiInitialized = true;
14
- }
14
+ import config from './lux.config';
15
15
 
16
16
  const defaultQueryClient = new QueryClient({
17
17
  defaultOptions: { queries: { refetchOnWindowFocus: false, retry: 1, staleTime: 30_000 } },
18
18
  });
19
19
 
20
+ // --- Tailwind-Preflight baseline reset -------------------------------------
21
+ // @hanzo/gui's GuiProvider scopes its subtree in a Tamagui `font_body` context
22
+ // whose shared CSS rule pins an ABSOLUTE line-height (23px). That cascades into
23
+ // consumer text authored at an arbitrary size with no line-height utility of its
24
+ // own (e.g. `text-[11px]` labels), making each line too tall and reflowing dense
25
+ // layouts. Restore Tailwind Preflight's `line-height: 1.5` baseline at
26
+ // `body .font_body` specificity — proportional, so any element carrying its own
27
+ // text-* / leading utility is unaffected. Shipping it from AppProvider means
28
+ // every Lux surface inherits the fix with no per-app CSS pin. Web-only (there is
29
+ // no `document` on native), injected once via useInsertionEffect (React's
30
+ // primitive for style insertion — runs before the browser paints, so no reflow
31
+ // flash), idempotent by element id.
32
+ const FONT_BODY_RESET_ID = 'lux-ui-font-body-reset';
33
+ const FONT_BODY_RESET_CSS = 'body .font_body{line-height:1.5}';
34
+
35
+ const useFontBodyReset = (): void => {
36
+ React.useInsertionEffect(() => {
37
+ if (typeof document === 'undefined') return;
38
+ if (document.getElementById(FONT_BODY_RESET_ID)) return;
39
+ const style = document.createElement('style');
40
+ style.id = FONT_BODY_RESET_ID;
41
+ style.textContent = FONT_BODY_RESET_CSS;
42
+ document.head.appendChild(style);
43
+ }, []);
44
+ };
45
+
20
46
  interface AppProviderProps {
21
47
  children: React.ReactNode;
22
48
  queryClient?: QueryClient;
49
+ /** Lux brand child-theme row: dark_lux | dark_zoo | dark_hanzo | dark_pars */
50
+ defaultTheme?: string;
23
51
  }
24
52
 
25
- export const AppProvider = ({ children, queryClient }: AppProviderProps) => {
26
- React.useEffect(() => { ensureGui(); }, []);
53
+ // AppProvider wraps GuiProvider (the @hanzogui engine, fed the Lux config) +
54
+ // tanstack QueryClientProvider. One provider for every Lux surface.
55
+ export const AppProvider = ({
56
+ children,
57
+ queryClient,
58
+ defaultTheme = 'dark_lux',
59
+ }: AppProviderProps): React.ReactElement => {
60
+ useFontBodyReset();
27
61
  return (
28
- <QueryClientProvider client={ queryClient ?? defaultQueryClient }>
29
- { children }
30
- </QueryClientProvider>
62
+ <GuiProvider config={config} defaultTheme={defaultTheme as never}>
63
+ <QueryClientProvider client={queryClient ?? defaultQueryClient}>
64
+ {children}
65
+ </QueryClientProvider>
66
+ </GuiProvider>
31
67
  );
32
68
  };
33
69
 
package/src/textarea.tsx CHANGED
@@ -34,15 +34,25 @@ type TextareaVariant = 'outline' | 'filled' | 'unstyled';
34
34
  export interface TextareaProps extends Omit<React.ComponentPropsWithRef<'textarea'>, 'size'> {
35
35
  readonly size?: TextareaSize;
36
36
  readonly variant?: TextareaVariant;
37
+ /** Tamagui / React-Native convention — bridged to native `onChange` (see Input). */
38
+ readonly onChangeText?: (text: string) => void;
37
39
  }
38
40
 
39
41
  export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
40
- ({ size = 'md', variant = 'outline', className, ...rest }, ref) => {
42
+ ({ size = 'md', variant = 'outline', className, onChange, onChangeText, ...rest }, ref) => {
43
+ const handleChange = React.useCallback(
44
+ (event: React.ChangeEvent<HTMLTextAreaElement>): void => {
45
+ onChange?.(event);
46
+ onChangeText?.(event.target.value);
47
+ },
48
+ [ onChange, onChangeText ],
49
+ );
41
50
  return (
42
51
  <textarea
43
52
  ref={ ref }
44
53
  className={ cn(TEXTAREA_BASE, TEXTAREA_SIZE_CLASSES[size], TEXTAREA_VARIANT_CLASSES[variant], className) }
45
54
  { ...rest }
55
+ onChange={ handleChange }
46
56
  />
47
57
  );
48
58
  },
package/src/tooltip.tsx CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Tooltip as GuiTooltip,
3
3
  TooltipGroup as GuiTooltipGroup,
4
- } from '@hanzogui/tooltip';
4
+ } from '@hanzo/gui';
5
5
  import { useClickAway } from '@uidotdev/usehooks';
6
6
  import * as React from 'react';
7
7
 
@@ -30,7 +30,7 @@ function useIsMobile(): boolean {
30
30
  /** Map placement string to @hanzogui Popper placement prop. */
31
31
  function mapPlacement(p: string | undefined): string | undefined {
32
32
  if (!p) return undefined;
33
- // @hanzogui/popper uses same placement strings as floating-ui
33
+ // @hanzo/gui uses same placement strings as floating-ui
34
34
  return p;
35
35
  }
36
36