@luxfi/ui 7.4.0 → 7.4.2

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 (130) hide show
  1. package/dist/avatar.cjs +7 -6
  2. package/dist/avatar.js +7 -5
  3. package/dist/badge.cjs +30 -32
  4. package/dist/badge.js +30 -32
  5. package/dist/bank.d.cts +3 -3
  6. package/dist/bank.d.ts +3 -3
  7. package/dist/checkbox.cjs +4 -4
  8. package/dist/checkbox.d.cts +3 -2
  9. package/dist/checkbox.d.ts +3 -2
  10. package/dist/checkbox.js +5 -4
  11. package/dist/chrome.cjs +950 -0
  12. package/dist/chrome.d.cts +93 -0
  13. package/dist/chrome.d.ts +93 -0
  14. package/dist/chrome.js +921 -0
  15. package/dist/drawer.cjs +86 -20
  16. package/dist/drawer.js +85 -19
  17. package/dist/expiration-selector.cjs +3 -2
  18. package/dist/expiration-selector.js +3 -2
  19. package/dist/greeks-display.cjs +6 -6
  20. package/dist/greeks-display.js +6 -6
  21. package/dist/gui.cjs +13 -0
  22. package/dist/gui.d.cts +2 -0
  23. package/dist/gui.d.ts +2 -0
  24. package/dist/gui.js +2 -0
  25. package/dist/heading.cjs +4 -2
  26. package/dist/heading.js +4 -2
  27. package/dist/iam.cjs +206 -0
  28. package/dist/iam.d.cts +65 -0
  29. package/dist/iam.d.ts +65 -0
  30. package/dist/iam.js +201 -0
  31. package/dist/icons.cjs +13 -0
  32. package/dist/icons.d.cts +1 -0
  33. package/dist/icons.d.ts +1 -0
  34. package/dist/icons.js +2 -0
  35. package/dist/identity.cjs +420 -0
  36. package/dist/identity.d.cts +64 -0
  37. package/dist/identity.d.ts +64 -0
  38. package/dist/identity.js +398 -0
  39. package/dist/index.cjs +1597 -833
  40. package/dist/index.d.cts +7 -3
  41. package/dist/index.d.ts +7 -3
  42. package/dist/index.js +1574 -828
  43. package/dist/input.cjs +3 -1
  44. package/dist/input.d.cts +3 -5
  45. package/dist/input.d.ts +3 -5
  46. package/dist/input.js +3 -1
  47. package/dist/lux.config.cjs +23 -2
  48. package/dist/lux.config.d.cts +28 -10
  49. package/dist/lux.config.d.ts +28 -10
  50. package/dist/lux.config.js +23 -2
  51. package/dist/menu.cjs +4 -4
  52. package/dist/menu.js +4 -4
  53. package/dist/next.cjs +99 -0
  54. package/dist/next.d.cts +29 -0
  55. package/dist/next.d.ts +29 -0
  56. package/dist/next.js +96 -0
  57. package/dist/option-chain.cjs +1 -1
  58. package/dist/option-chain.js +1 -1
  59. package/dist/option-position.cjs +2 -1
  60. package/dist/option-position.js +2 -1
  61. package/dist/pnl-diagram.cjs +8 -6
  62. package/dist/pnl-diagram.js +8 -6
  63. package/dist/progress.cjs +7 -6
  64. package/dist/progress.js +7 -5
  65. package/dist/provider.cjs +136 -4
  66. package/dist/provider.d.cts +15 -3
  67. package/dist/provider.d.ts +15 -3
  68. package/dist/provider.js +136 -5
  69. package/dist/radio.cjs +9 -7
  70. package/dist/radio.js +10 -7
  71. package/dist/separator.cjs +3 -1
  72. package/dist/separator.js +3 -1
  73. package/dist/slider.cjs +28 -16
  74. package/dist/slider.js +28 -15
  75. package/dist/strategy-builder.cjs +2 -1
  76. package/dist/strategy-builder.js +2 -1
  77. package/dist/switch.cjs +11 -12
  78. package/dist/switch.js +12 -12
  79. package/dist/tag.cjs +31 -33
  80. package/dist/tag.js +30 -32
  81. package/dist/textarea.cjs +3 -1
  82. package/dist/textarea.js +3 -1
  83. package/dist/tooltip.cjs +25 -27
  84. package/dist/tooltip.js +24 -26
  85. package/dist/use-narrow.cjs +46 -0
  86. package/dist/use-narrow.d.cts +12 -0
  87. package/dist/use-narrow.d.ts +12 -0
  88. package/dist/use-narrow.js +20 -0
  89. package/dist/vite.cjs +40 -0
  90. package/dist/vite.d.cts +29 -0
  91. package/dist/vite.d.ts +29 -0
  92. package/dist/vite.js +38 -0
  93. package/dist/white-label.cjs +132 -0
  94. package/dist/white-label.d.cts +59 -0
  95. package/dist/white-label.d.ts +59 -0
  96. package/dist/white-label.js +124 -0
  97. package/package.json +85 -19
  98. package/src/avatar.tsx +22 -16
  99. package/src/checkbox.tsx +15 -10
  100. package/src/chrome.tsx +459 -0
  101. package/src/drawer.tsx +83 -10
  102. package/src/expiration-selector.tsx +3 -2
  103. package/src/greeks-display.tsx +9 -6
  104. package/src/gui.ts +17 -0
  105. package/src/heading.tsx +12 -8
  106. package/src/iam.ts +170 -0
  107. package/src/icons.ts +18 -0
  108. package/src/identity.tsx +318 -0
  109. package/src/index.ts +44 -1
  110. package/src/input.tsx +13 -9
  111. package/src/lux.config.ts +16 -15
  112. package/src/menu.tsx +4 -4
  113. package/src/next.ts +142 -0
  114. package/src/option-chain.tsx +1 -1
  115. package/src/option-position.tsx +2 -1
  116. package/src/pnl-diagram.tsx +11 -6
  117. package/src/progress.tsx +15 -8
  118. package/src/provider.tsx +48 -7
  119. package/src/radio.tsx +15 -11
  120. package/src/separator.tsx +8 -3
  121. package/src/slider.tsx +35 -19
  122. package/src/strategy-builder.tsx +3 -2
  123. package/src/switch.tsx +17 -16
  124. package/src/textarea.tsx +8 -4
  125. package/src/tooltip.tsx +2 -21
  126. package/src/use-narrow.ts +40 -0
  127. package/src/vite.ts +78 -0
  128. package/src/white-label.ts +240 -0
  129. package/tokens.css +544 -319
  130. package/src/tokens.css +0 -438
@@ -37,7 +37,8 @@ var OptionPositionCard = React.forwardRef(
37
37
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
38
38
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs("span", { className: cn(
39
39
  "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs font-semibold",
40
- isCall ? "bg-blue-900/40 text-blue-400" : "bg-orange-900/40 text-orange-400"
40
+ // Call vs put is a rank difference, not a hue difference.
41
+ isCall ? "bg-[var(--secondary)] text-[var(--foreground)]" : "bg-[var(--muted)] text-[var(--muted-foreground)]"
41
42
  ), children: [
42
43
  position.underlying,
43
44
  /* @__PURE__ */ jsx("span", { className: "font-mono tabular-nums", children: position.strike }),
@@ -54,7 +54,9 @@ function buildPath(points, vb, width, height) {
54
54
  });
55
55
  return parts.join(" ");
56
56
  }
57
- var LEG_COLORS = ["#6366f1", "#f59e0b", "#ec4899", "#06b6d4"];
57
+ var LEG_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)"];
58
+ var BREAKEVEN_COLOR = "var(--chart-1)";
59
+ var BREAKEVEN_RING = "var(--background)";
58
60
  var PnlDiagram = React__namespace.forwardRef(
59
61
  function PnlDiagram2(props, ref) {
60
62
  const {
@@ -296,13 +298,13 @@ var PnlDiagram = React__namespace.forwardRef(
296
298
  }
297
299
  ),
298
300
  breakevens.map((be, i) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
299
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: scaleX(be), cy: zeroY, r: "3", fill: "#fbbf24", stroke: "#18181b", strokeWidth: "1" }),
301
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: scaleX(be), cy: zeroY, r: "3", fill: BREAKEVEN_COLOR, stroke: BREAKEVEN_RING, strokeWidth: "1" }),
300
302
  /* @__PURE__ */ jsxRuntime.jsx(
301
303
  "text",
302
304
  {
303
305
  x: scaleX(be),
304
306
  y: PADDING.top + chartH + 14,
305
- fill: "#fbbf24",
307
+ fill: BREAKEVEN_COLOR,
306
308
  fontSize: "8",
307
309
  fontFamily: "monospace",
308
310
  textAnchor: "middle",
@@ -343,7 +345,7 @@ var PnlDiagram = React__namespace.forwardRef(
343
345
  cy: scaleY(hoverPnl),
344
346
  r: "3",
345
347
  fill: hoverPnl >= 0 ? "#22c55e" : "#ef4444",
346
- stroke: "#18181b",
348
+ stroke: BREAKEVEN_RING,
347
349
  strokeWidth: "1"
348
350
  }
349
351
  ),
@@ -355,7 +357,7 @@ var PnlDiagram = React__namespace.forwardRef(
355
357
  width: "90",
356
358
  height: "28",
357
359
  rx: "3",
358
- fill: "#18181b",
360
+ fill: BREAKEVEN_RING,
359
361
  stroke: "#3f3f46",
360
362
  strokeWidth: "1"
361
363
  }
@@ -437,7 +439,7 @@ var PnlDiagram = React__namespace.forwardRef(
437
439
  ] })
438
440
  ] }, i)),
439
441
  breakevens.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
440
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-1.5 rounded-full bg-amber-400" }),
442
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-1.5 rounded-full", style: { background: BREAKEVEN_COLOR } }),
441
443
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-zinc-500", children: [
442
444
  "BE: ",
443
445
  breakevens.map((b) => b.toFixed(1)).join(", ")
@@ -32,7 +32,9 @@ function buildPath(points, vb, width, height) {
32
32
  });
33
33
  return parts.join(" ");
34
34
  }
35
- var LEG_COLORS = ["#6366f1", "#f59e0b", "#ec4899", "#06b6d4"];
35
+ var LEG_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)"];
36
+ var BREAKEVEN_COLOR = "var(--chart-1)";
37
+ var BREAKEVEN_RING = "var(--background)";
36
38
  var PnlDiagram = React.forwardRef(
37
39
  function PnlDiagram2(props, ref) {
38
40
  const {
@@ -274,13 +276,13 @@ var PnlDiagram = React.forwardRef(
274
276
  }
275
277
  ),
276
278
  breakevens.map((be, i) => /* @__PURE__ */ jsxs("g", { children: [
277
- /* @__PURE__ */ jsx("circle", { cx: scaleX(be), cy: zeroY, r: "3", fill: "#fbbf24", stroke: "#18181b", strokeWidth: "1" }),
279
+ /* @__PURE__ */ jsx("circle", { cx: scaleX(be), cy: zeroY, r: "3", fill: BREAKEVEN_COLOR, stroke: BREAKEVEN_RING, strokeWidth: "1" }),
278
280
  /* @__PURE__ */ jsx(
279
281
  "text",
280
282
  {
281
283
  x: scaleX(be),
282
284
  y: PADDING.top + chartH + 14,
283
- fill: "#fbbf24",
285
+ fill: BREAKEVEN_COLOR,
284
286
  fontSize: "8",
285
287
  fontFamily: "monospace",
286
288
  textAnchor: "middle",
@@ -321,7 +323,7 @@ var PnlDiagram = React.forwardRef(
321
323
  cy: scaleY(hoverPnl),
322
324
  r: "3",
323
325
  fill: hoverPnl >= 0 ? "#22c55e" : "#ef4444",
324
- stroke: "#18181b",
326
+ stroke: BREAKEVEN_RING,
325
327
  strokeWidth: "1"
326
328
  }
327
329
  ),
@@ -333,7 +335,7 @@ var PnlDiagram = React.forwardRef(
333
335
  width: "90",
334
336
  height: "28",
335
337
  rx: "3",
336
- fill: "#18181b",
338
+ fill: BREAKEVEN_RING,
337
339
  stroke: "#3f3f46",
338
340
  strokeWidth: "1"
339
341
  }
@@ -415,7 +417,7 @@ var PnlDiagram = React.forwardRef(
415
417
  ] })
416
418
  ] }, i)),
417
419
  breakevens.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
418
- /* @__PURE__ */ jsx("div", { className: "h-1.5 w-1.5 rounded-full bg-amber-400" }),
420
+ /* @__PURE__ */ jsx("div", { className: "h-1.5 w-1.5 rounded-full", style: { background: BREAKEVEN_COLOR } }),
419
421
  /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-zinc-500", children: [
420
422
  "BE: ",
421
423
  breakevens.map((b) => b.toFixed(1)).join(", ")
package/dist/progress.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var RadixProgress = require('@radix-ui/react-progress');
4
+ var gui = require('@hanzo/gui');
5
5
  var React = require('react');
6
6
  var clsx = require('clsx');
7
7
  var tailwindMerge = require('tailwind-merge');
@@ -25,7 +25,6 @@ function _interopNamespace(e) {
25
25
  return Object.freeze(n);
26
26
  }
27
27
 
28
- var RadixProgress__namespace = /*#__PURE__*/_interopNamespace(RadixProgress);
29
28
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
30
29
 
31
30
  // src/progress.tsx
@@ -83,10 +82,11 @@ var Progress = React__namespace.forwardRef(
83
82
  style: rootStyle,
84
83
  ...rest,
85
84
  children: /* @__PURE__ */ jsxRuntime.jsx(
86
- RadixProgress__namespace.Root,
85
+ gui.Progress,
87
86
  {
88
87
  value: percent,
89
88
  max: 100,
89
+ unstyled: true,
90
90
  className: cn(
91
91
  "w-full overflow-hidden rounded-full",
92
92
  "bg-[var(--color-progress-track)]",
@@ -95,14 +95,15 @@ var Progress = React__namespace.forwardRef(
95
95
  ),
96
96
  style: trackStyle,
97
97
  children: /* @__PURE__ */ jsxRuntime.jsx(
98
- RadixProgress__namespace.Indicator,
98
+ gui.Progress.Indicator,
99
99
  {
100
+ unstyled: true,
101
+ transition: "slow",
100
102
  className: cn(
101
- "h-full rounded-full transition-transform duration-500 ease-out",
103
+ "h-full rounded-full",
102
104
  !color && "bg-[var(--color-progress-indicator)]"
103
105
  ),
104
106
  style: {
105
- width: `${percent}%`,
106
107
  ...color && { backgroundColor: `var(--color-${color.replace(".", "-")}, ${color})` }
107
108
  }
108
109
  }
package/dist/progress.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import * as RadixProgress from '@radix-ui/react-progress';
2
+ import { Progress as Progress$1 } from '@hanzo/gui';
3
3
  import * as React from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
@@ -60,10 +60,11 @@ var Progress = React.forwardRef(
60
60
  style: rootStyle,
61
61
  ...rest,
62
62
  children: /* @__PURE__ */ jsx(
63
- RadixProgress.Root,
63
+ Progress$1,
64
64
  {
65
65
  value: percent,
66
66
  max: 100,
67
+ unstyled: true,
67
68
  className: cn(
68
69
  "w-full overflow-hidden rounded-full",
69
70
  "bg-[var(--color-progress-track)]",
@@ -72,14 +73,15 @@ var Progress = React.forwardRef(
72
73
  ),
73
74
  style: trackStyle,
74
75
  children: /* @__PURE__ */ jsx(
75
- RadixProgress.Indicator,
76
+ Progress$1.Indicator,
76
77
  {
78
+ unstyled: true,
79
+ transition: "slow",
77
80
  className: cn(
78
- "h-full rounded-full transition-transform duration-500 ease-out",
81
+ "h-full rounded-full",
79
82
  !color && "bg-[var(--color-progress-indicator)]"
80
83
  ),
81
84
  style: {
82
- width: `${percent}%`,
83
85
  ...color && { backgroundColor: `var(--color-${color.replace(".", "-")}, ${color})` }
84
86
  }
85
87
  }
package/dist/provider.cjs CHANGED
@@ -5,19 +5,134 @@ var gui = require('@hanzo/gui');
5
5
  var reactQuery = require('@tanstack/react-query');
6
6
  var React = require('react');
7
7
  var v5 = require('@hanzogui/config/v5');
8
+ var v5Css = require('@hanzogui/config/v5-css');
8
9
  var jsxRuntime = require('react/jsx-runtime');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
12
 
12
13
  var React__default = /*#__PURE__*/_interopDefault(React);
13
14
 
15
+ // src/white-label.ts
14
16
  var LUX_BRAND = {
15
17
  lux: "#7000FF",
16
18
  zoo: "#6C5EFB",
17
19
  hanzo: "#EA580C",
18
- pars: "#1C3879"
20
+ pars: "#1C3879",
21
+ // bootno.de is its own white label with its own IdP (id.bootno.de) — accent
22
+ // taken from the bootnode console's own brand default, not invented here.
23
+ bootnode: "#3B82F6"
19
24
  };
20
25
  var PARS_GOLD = "#C8A45C";
26
+ var ORGS = {
27
+ lux: {
28
+ org: "lux",
29
+ name: "Lux",
30
+ domain: "lux.network",
31
+ iamDomain: "lux.id",
32
+ accent: LUX_BRAND.lux,
33
+ accentForeground: "#FFFFFF"
34
+ },
35
+ zoo: {
36
+ org: "zoo",
37
+ name: "Zoo",
38
+ domain: "zoo.ngo",
39
+ // Zoo's IdP is `id.zoo.network`, not a `zoo.id` apex — the one row in this
40
+ // table where the issuer is not `<org>.id`, and the one every hand-rolled
41
+ // per-app branding map got wrong.
42
+ iamDomain: "id.zoo.network",
43
+ accent: LUX_BRAND.zoo,
44
+ accentForeground: "#FFFFFF"
45
+ },
46
+ bootnode: {
47
+ org: "bootnode",
48
+ name: "Bootnode",
49
+ domain: "bootno.de",
50
+ iamDomain: "id.bootno.de",
51
+ accent: LUX_BRAND.lux,
52
+ accentForeground: "#FFFFFF"
53
+ },
54
+ hanzo: {
55
+ org: "hanzo",
56
+ name: "Hanzo",
57
+ domain: "hanzo.ai",
58
+ iamDomain: "hanzo.id",
59
+ accent: LUX_BRAND.hanzo,
60
+ accentForeground: "#FFFFFF"
61
+ },
62
+ pars: {
63
+ org: "pars",
64
+ name: "Pars",
65
+ domain: "pars.id",
66
+ iamDomain: "pars.id",
67
+ accent: LUX_BRAND.pars,
68
+ accentForeground: PARS_GOLD
69
+ }
70
+ };
71
+ var DOMAIN_ORG = [
72
+ ["lux.network", "lux"],
73
+ ["lux.cloud", "lux"],
74
+ ["lux.id", "lux"],
75
+ ["lux.finance", "lux"],
76
+ ["zoo.ngo", "zoo"],
77
+ ["zoo.network", "zoo"],
78
+ ["zoo.cloud", "zoo"],
79
+ ["zoo.id", "zoo"],
80
+ ["hanzo.ai", "hanzo"],
81
+ ["hanzo.cloud", "hanzo"],
82
+ ["hanzo.id", "hanzo"],
83
+ ["pars.id", "pars"],
84
+ ["parsdao.org", "pars"],
85
+ ["bootno.de", "bootnode", "platform"]
86
+ ];
87
+ var DEFAULT_ORG = "lux";
88
+ function normalizeHost(host) {
89
+ const noPort = host.trim().toLowerCase().split(":")[0] ?? "";
90
+ return noPort.replace(/\.$/, "");
91
+ }
92
+ function isUnder(host, domain) {
93
+ return host === domain || host.endsWith(`.${domain}`);
94
+ }
95
+ function matchDomain(host) {
96
+ let best;
97
+ for (const entry of DOMAIN_ORG) {
98
+ if (isUnder(host, entry[0]) && (!best || entry[0].length > best[0].length)) {
99
+ best = entry;
100
+ }
101
+ }
102
+ return best;
103
+ }
104
+ function appSlug(host, domain, apexApp) {
105
+ const sub = host === domain ? "" : host.slice(0, -(domain.length + 1));
106
+ const leftmost = sub.split(".")[0] ?? "";
107
+ if (leftmost && leftmost !== "www") return leftmost;
108
+ if (apexApp) return apexApp;
109
+ const label = domain.split(".")[0] ?? "";
110
+ const tld = domain.split(".").slice(1).join(".");
111
+ return tld.split(".")[0] || label;
112
+ }
113
+ function isLocal(host) {
114
+ return host === "localhost" || host.endsWith(".localhost") || host === "127.0.0.1" || host === "0.0.0.0" || host === "[::1]" || host.endsWith(".local");
115
+ }
116
+ function resolveWhiteLabel(host) {
117
+ const h = normalizeHost(host ?? "");
118
+ const match = h ? matchDomain(h) : void 0;
119
+ const org = match ? match[1] : DEFAULT_ORG;
120
+ const identity = ORGS[org];
121
+ const app = match ? appSlug(h, match[0], match[2]) : h && isLocal(h) ? "local" : "app";
122
+ return {
123
+ ...identity,
124
+ host: h,
125
+ app,
126
+ theme: `dark_${org}`,
127
+ issuer: `https://${identity.iamDomain}`,
128
+ clientId: `${org}-${app}`
129
+ };
130
+ }
131
+ function currentHost() {
132
+ return typeof window === "undefined" ? "" : window.location.host;
133
+ }
134
+
135
+ // src/lux.config.ts
21
136
  var TRUE_BLACK = "#000000";
22
137
  var darkBase = {
23
138
  ...v5.defaultConfig.themes.dark,
@@ -39,10 +154,12 @@ var luxThemes = {
39
154
  dark_lux: brandTheme(LUX_BRAND.lux),
40
155
  dark_zoo: brandTheme(LUX_BRAND.zoo),
41
156
  dark_hanzo: brandTheme(LUX_BRAND.hanzo),
42
- dark_pars: brandTheme(LUX_BRAND.pars, { accentColor: PARS_GOLD })
157
+ dark_pars: brandTheme(LUX_BRAND.pars, { accentColor: PARS_GOLD }),
158
+ dark_bootnode: brandTheme(LUX_BRAND.bootnode)
43
159
  };
44
160
  var config = gui.createGui({
45
161
  ...v5.defaultConfig,
162
+ animations: v5Css.animations,
46
163
  settings: {
47
164
  ...v5.defaultConfig.settings,
48
165
  onlyAllowShorthands: false
@@ -68,13 +185,27 @@ var useFontBodyReset = () => {
68
185
  document.head.appendChild(style);
69
186
  }, []);
70
187
  };
188
+ var WhiteLabelContext = React__default.default.createContext(resolveWhiteLabel(""));
189
+ var useWhiteLabel = () => React__default.default.useContext(WhiteLabelContext);
190
+ var useHostWhiteLabel = (host) => {
191
+ const [resolvedHost, setResolvedHost] = React__default.default.useState(host ?? "");
192
+ React__default.default.useEffect(() => {
193
+ if (host !== void 0) return;
194
+ const browserHost = currentHost();
195
+ if (browserHost) setResolvedHost(browserHost);
196
+ }, [host]);
197
+ return React__default.default.useMemo(() => resolveWhiteLabel(resolvedHost), [resolvedHost]);
198
+ };
71
199
  var AppProvider = ({
72
200
  children,
73
201
  queryClient,
74
- defaultTheme = "dark_lux"
202
+ host,
203
+ defaultTheme
75
204
  }) => {
76
205
  useFontBodyReset();
77
- return /* @__PURE__ */ jsxRuntime.jsx(gui.GuiProvider, { config: lux_config_default, defaultTheme, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient ?? defaultQueryClient, children }) });
206
+ const whiteLabel = useHostWhiteLabel(host);
207
+ const theme = defaultTheme ?? whiteLabel.theme;
208
+ return /* @__PURE__ */ jsxRuntime.jsx(WhiteLabelContext.Provider, { value: whiteLabel, children: /* @__PURE__ */ jsxRuntime.jsx(gui.GuiProvider, { config: lux_config_default, defaultTheme: theme, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient ?? defaultQueryClient, children }) }) });
78
209
  };
79
210
 
80
211
  Object.defineProperty(exports, "QueryClient", {
@@ -98,3 +229,4 @@ Object.defineProperty(exports, "useQueryClient", {
98
229
  get: function () { return reactQuery.useQueryClient; }
99
230
  });
100
231
  exports.AppProvider = AppProvider;
232
+ exports.useWhiteLabel = useWhiteLabel;
@@ -1,13 +1,25 @@
1
1
  import { QueryClient } from '@tanstack/react-query';
2
2
  export { QueryClient, useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
3
  import React__default from 'react';
4
+ import { WhiteLabel } from './white-label.cjs';
4
5
 
6
+ /** The white-label identity for the host this page is being served under. */
7
+ declare const useWhiteLabel: () => WhiteLabel;
5
8
  interface AppProviderProps {
6
9
  children: React__default.ReactNode;
7
10
  queryClient?: QueryClient;
8
- /** Lux brand child-theme row: dark_lux | dark_zoo | dark_hanzo | dark_pars */
11
+ /**
12
+ * Host header value, for server rendering. Omit in the browser and the host
13
+ * is read from `location`. Never bake a brand into a deployment — pass the
14
+ * request's host and the same image serves every org.
15
+ */
16
+ host?: string;
17
+ /**
18
+ * Escape hatch: pin the gui child-theme row (`dark_lux` | `dark_zoo` |
19
+ * `dark_hanzo` | `dark_pars`). Leave unset so the theme follows the host.
20
+ */
9
21
  defaultTheme?: string;
10
22
  }
11
- declare const AppProvider: ({ children, queryClient, defaultTheme, }: AppProviderProps) => React__default.ReactElement;
23
+ declare const AppProvider: ({ children, queryClient, host, defaultTheme, }: AppProviderProps) => React__default.ReactElement;
12
24
 
13
- export { AppProvider };
25
+ export { AppProvider, useWhiteLabel };
@@ -1,13 +1,25 @@
1
1
  import { QueryClient } from '@tanstack/react-query';
2
2
  export { QueryClient, useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
3
  import React__default from 'react';
4
+ import { WhiteLabel } from './white-label.js';
4
5
 
6
+ /** The white-label identity for the host this page is being served under. */
7
+ declare const useWhiteLabel: () => WhiteLabel;
5
8
  interface AppProviderProps {
6
9
  children: React__default.ReactNode;
7
10
  queryClient?: QueryClient;
8
- /** Lux brand child-theme row: dark_lux | dark_zoo | dark_hanzo | dark_pars */
11
+ /**
12
+ * Host header value, for server rendering. Omit in the browser and the host
13
+ * is read from `location`. Never bake a brand into a deployment — pass the
14
+ * request's host and the same image serves every org.
15
+ */
16
+ host?: string;
17
+ /**
18
+ * Escape hatch: pin the gui child-theme row (`dark_lux` | `dark_zoo` |
19
+ * `dark_hanzo` | `dark_pars`). Leave unset so the theme follows the host.
20
+ */
9
21
  defaultTheme?: string;
10
22
  }
11
- declare const AppProvider: ({ children, queryClient, defaultTheme, }: AppProviderProps) => React__default.ReactElement;
23
+ declare const AppProvider: ({ children, queryClient, host, defaultTheme, }: AppProviderProps) => React__default.ReactElement;
12
24
 
13
- export { AppProvider };
25
+ export { AppProvider, useWhiteLabel };
package/dist/provider.js CHANGED
@@ -4,15 +4,130 @@ 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
6
  import { defaultConfig } from '@hanzogui/config/v5';
7
+ import { animations } from '@hanzogui/config/v5-css';
7
8
  import { jsx } from 'react/jsx-runtime';
8
9
 
10
+ // src/white-label.ts
9
11
  var LUX_BRAND = {
10
12
  lux: "#7000FF",
11
13
  zoo: "#6C5EFB",
12
14
  hanzo: "#EA580C",
13
- pars: "#1C3879"
15
+ pars: "#1C3879",
16
+ // bootno.de is its own white label with its own IdP (id.bootno.de) — accent
17
+ // taken from the bootnode console's own brand default, not invented here.
18
+ bootnode: "#3B82F6"
14
19
  };
15
20
  var PARS_GOLD = "#C8A45C";
21
+ var ORGS = {
22
+ lux: {
23
+ org: "lux",
24
+ name: "Lux",
25
+ domain: "lux.network",
26
+ iamDomain: "lux.id",
27
+ accent: LUX_BRAND.lux,
28
+ accentForeground: "#FFFFFF"
29
+ },
30
+ zoo: {
31
+ org: "zoo",
32
+ name: "Zoo",
33
+ domain: "zoo.ngo",
34
+ // Zoo's IdP is `id.zoo.network`, not a `zoo.id` apex — the one row in this
35
+ // table where the issuer is not `<org>.id`, and the one every hand-rolled
36
+ // per-app branding map got wrong.
37
+ iamDomain: "id.zoo.network",
38
+ accent: LUX_BRAND.zoo,
39
+ accentForeground: "#FFFFFF"
40
+ },
41
+ bootnode: {
42
+ org: "bootnode",
43
+ name: "Bootnode",
44
+ domain: "bootno.de",
45
+ iamDomain: "id.bootno.de",
46
+ accent: LUX_BRAND.lux,
47
+ accentForeground: "#FFFFFF"
48
+ },
49
+ hanzo: {
50
+ org: "hanzo",
51
+ name: "Hanzo",
52
+ domain: "hanzo.ai",
53
+ iamDomain: "hanzo.id",
54
+ accent: LUX_BRAND.hanzo,
55
+ accentForeground: "#FFFFFF"
56
+ },
57
+ pars: {
58
+ org: "pars",
59
+ name: "Pars",
60
+ domain: "pars.id",
61
+ iamDomain: "pars.id",
62
+ accent: LUX_BRAND.pars,
63
+ accentForeground: PARS_GOLD
64
+ }
65
+ };
66
+ var DOMAIN_ORG = [
67
+ ["lux.network", "lux"],
68
+ ["lux.cloud", "lux"],
69
+ ["lux.id", "lux"],
70
+ ["lux.finance", "lux"],
71
+ ["zoo.ngo", "zoo"],
72
+ ["zoo.network", "zoo"],
73
+ ["zoo.cloud", "zoo"],
74
+ ["zoo.id", "zoo"],
75
+ ["hanzo.ai", "hanzo"],
76
+ ["hanzo.cloud", "hanzo"],
77
+ ["hanzo.id", "hanzo"],
78
+ ["pars.id", "pars"],
79
+ ["parsdao.org", "pars"],
80
+ ["bootno.de", "bootnode", "platform"]
81
+ ];
82
+ var DEFAULT_ORG = "lux";
83
+ function normalizeHost(host) {
84
+ const noPort = host.trim().toLowerCase().split(":")[0] ?? "";
85
+ return noPort.replace(/\.$/, "");
86
+ }
87
+ function isUnder(host, domain) {
88
+ return host === domain || host.endsWith(`.${domain}`);
89
+ }
90
+ function matchDomain(host) {
91
+ let best;
92
+ for (const entry of DOMAIN_ORG) {
93
+ if (isUnder(host, entry[0]) && (!best || entry[0].length > best[0].length)) {
94
+ best = entry;
95
+ }
96
+ }
97
+ return best;
98
+ }
99
+ function appSlug(host, domain, apexApp) {
100
+ const sub = host === domain ? "" : host.slice(0, -(domain.length + 1));
101
+ const leftmost = sub.split(".")[0] ?? "";
102
+ if (leftmost && leftmost !== "www") return leftmost;
103
+ if (apexApp) return apexApp;
104
+ const label = domain.split(".")[0] ?? "";
105
+ const tld = domain.split(".").slice(1).join(".");
106
+ return tld.split(".")[0] || label;
107
+ }
108
+ function isLocal(host) {
109
+ return host === "localhost" || host.endsWith(".localhost") || host === "127.0.0.1" || host === "0.0.0.0" || host === "[::1]" || host.endsWith(".local");
110
+ }
111
+ function resolveWhiteLabel(host) {
112
+ const h = normalizeHost(host ?? "");
113
+ const match = h ? matchDomain(h) : void 0;
114
+ const org = match ? match[1] : DEFAULT_ORG;
115
+ const identity = ORGS[org];
116
+ const app = match ? appSlug(h, match[0], match[2]) : h && isLocal(h) ? "local" : "app";
117
+ return {
118
+ ...identity,
119
+ host: h,
120
+ app,
121
+ theme: `dark_${org}`,
122
+ issuer: `https://${identity.iamDomain}`,
123
+ clientId: `${org}-${app}`
124
+ };
125
+ }
126
+ function currentHost() {
127
+ return typeof window === "undefined" ? "" : window.location.host;
128
+ }
129
+
130
+ // src/lux.config.ts
16
131
  var TRUE_BLACK = "#000000";
17
132
  var darkBase = {
18
133
  ...defaultConfig.themes.dark,
@@ -34,10 +149,12 @@ var luxThemes = {
34
149
  dark_lux: brandTheme(LUX_BRAND.lux),
35
150
  dark_zoo: brandTheme(LUX_BRAND.zoo),
36
151
  dark_hanzo: brandTheme(LUX_BRAND.hanzo),
37
- dark_pars: brandTheme(LUX_BRAND.pars, { accentColor: PARS_GOLD })
152
+ dark_pars: brandTheme(LUX_BRAND.pars, { accentColor: PARS_GOLD }),
153
+ dark_bootnode: brandTheme(LUX_BRAND.bootnode)
38
154
  };
39
155
  var config = createGui({
40
156
  ...defaultConfig,
157
+ animations,
41
158
  settings: {
42
159
  ...defaultConfig.settings,
43
160
  onlyAllowShorthands: false
@@ -63,13 +180,27 @@ var useFontBodyReset = () => {
63
180
  document.head.appendChild(style);
64
181
  }, []);
65
182
  };
183
+ var WhiteLabelContext = React.createContext(resolveWhiteLabel(""));
184
+ var useWhiteLabel = () => React.useContext(WhiteLabelContext);
185
+ var useHostWhiteLabel = (host) => {
186
+ const [resolvedHost, setResolvedHost] = React.useState(host ?? "");
187
+ React.useEffect(() => {
188
+ if (host !== void 0) return;
189
+ const browserHost = currentHost();
190
+ if (browserHost) setResolvedHost(browserHost);
191
+ }, [host]);
192
+ return React.useMemo(() => resolveWhiteLabel(resolvedHost), [resolvedHost]);
193
+ };
66
194
  var AppProvider = ({
67
195
  children,
68
196
  queryClient,
69
- defaultTheme = "dark_lux"
197
+ host,
198
+ defaultTheme
70
199
  }) => {
71
200
  useFontBodyReset();
72
- return /* @__PURE__ */ jsx(GuiProvider, { config: lux_config_default, defaultTheme, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children }) });
201
+ const whiteLabel = useHostWhiteLabel(host);
202
+ const theme = defaultTheme ?? whiteLabel.theme;
203
+ return /* @__PURE__ */ jsx(WhiteLabelContext.Provider, { value: whiteLabel, children: /* @__PURE__ */ jsx(GuiProvider, { config: lux_config_default, defaultTheme: theme, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children }) }) });
73
204
  };
74
205
 
75
- export { AppProvider };
206
+ export { AppProvider, useWhiteLabel };