@luxfi/ui 7.4.5 → 7.4.7

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 (159) hide show
  1. package/dist/accordion.d.cts +74 -0
  2. package/dist/accordion.d.ts +74 -0
  3. package/dist/alert.cjs +3 -7
  4. package/dist/alert.d.cts +30 -0
  5. package/dist/alert.d.ts +30 -0
  6. package/dist/alert.js +3 -7
  7. package/dist/auth.cjs +481 -0
  8. package/dist/auth.d.cts +80 -0
  9. package/dist/auth.d.ts +80 -0
  10. package/dist/auth.js +456 -0
  11. package/dist/avatar.d.cts +25 -0
  12. package/dist/avatar.d.ts +25 -0
  13. package/dist/badge.cjs +4 -8
  14. package/dist/badge.d.cts +19 -0
  15. package/dist/badge.d.ts +19 -0
  16. package/dist/badge.js +4 -8
  17. package/dist/bank.d.cts +83 -0
  18. package/dist/bank.d.ts +83 -0
  19. package/dist/button.cjs +3 -7
  20. package/dist/button.d.cts +55 -0
  21. package/dist/button.d.ts +55 -0
  22. package/dist/button.js +3 -7
  23. package/dist/checkbox.d.cts +32 -0
  24. package/dist/checkbox.d.ts +32 -0
  25. package/dist/chrome.d.cts +93 -0
  26. package/dist/chrome.d.ts +93 -0
  27. package/dist/close-button.d.cts +9 -0
  28. package/dist/close-button.d.ts +9 -0
  29. package/dist/collapsible.cjs +3 -7
  30. package/dist/collapsible.d.cts +23 -0
  31. package/dist/collapsible.d.ts +23 -0
  32. package/dist/collapsible.js +3 -7
  33. package/dist/color-mode.d.cts +25 -0
  34. package/dist/color-mode.d.ts +25 -0
  35. package/dist/dialog.d.cts +118 -0
  36. package/dist/dialog.d.ts +118 -0
  37. package/dist/drawer.d.cts +36 -0
  38. package/dist/drawer.d.ts +36 -0
  39. package/dist/empty-state.d.cts +13 -0
  40. package/dist/empty-state.d.ts +13 -0
  41. package/dist/expiration-selector.d.cts +16 -0
  42. package/dist/expiration-selector.d.ts +16 -0
  43. package/dist/field.d.cts +24 -0
  44. package/dist/field.d.ts +24 -0
  45. package/dist/greeks-display.d.cts +14 -0
  46. package/dist/greeks-display.d.ts +14 -0
  47. package/dist/gui.d.cts +2 -0
  48. package/dist/gui.d.ts +2 -0
  49. package/dist/heading.d.cts +10 -0
  50. package/dist/heading.d.ts +10 -0
  51. package/dist/iam.d.cts +65 -0
  52. package/dist/iam.d.ts +65 -0
  53. package/dist/icon-button.cjs +3 -7
  54. package/dist/icon-button.d.cts +33 -0
  55. package/dist/icon-button.d.ts +33 -0
  56. package/dist/icon-button.js +3 -7
  57. package/dist/icons.cjs +0 -1
  58. package/dist/icons.d.cts +1 -0
  59. package/dist/icons.d.ts +1 -0
  60. package/dist/icons.js +0 -1
  61. package/dist/identity.d.cts +64 -0
  62. package/dist/identity.d.ts +64 -0
  63. package/dist/image.cjs +3 -7
  64. package/dist/image.d.cts +57 -0
  65. package/dist/image.d.ts +57 -0
  66. package/dist/image.js +3 -7
  67. package/dist/index.cjs +9 -8
  68. package/dist/index.d.cts +64 -0
  69. package/dist/index.d.ts +64 -0
  70. package/dist/index.js +9 -9
  71. package/dist/input-group.d.cts +17 -0
  72. package/dist/input-group.d.ts +17 -0
  73. package/dist/input.d.cts +17 -0
  74. package/dist/input.d.ts +17 -0
  75. package/dist/link.cjs +3 -7
  76. package/dist/link.d.cts +37 -0
  77. package/dist/link.d.ts +37 -0
  78. package/dist/link.js +3 -7
  79. package/dist/lux.config.d.cts +433 -0
  80. package/dist/lux.config.d.ts +433 -0
  81. package/dist/menu.d.cts +84 -0
  82. package/dist/menu.d.ts +84 -0
  83. package/dist/next.cjs +11 -1
  84. package/dist/next.d.cts +32 -0
  85. package/dist/next.d.ts +32 -0
  86. package/dist/next.js +11 -1
  87. package/dist/option-chain.d.cts +37 -0
  88. package/dist/option-chain.d.ts +37 -0
  89. package/dist/option-position.d.cts +29 -0
  90. package/dist/option-position.d.ts +29 -0
  91. package/dist/pin-input.d.cts +25 -0
  92. package/dist/pin-input.d.ts +25 -0
  93. package/dist/pnl-diagram.d.cts +11 -0
  94. package/dist/pnl-diagram.d.ts +11 -0
  95. package/dist/popover.d.cts +73 -0
  96. package/dist/popover.d.ts +73 -0
  97. package/dist/progress-circle.d.cts +47 -0
  98. package/dist/progress-circle.d.ts +47 -0
  99. package/dist/progress.d.cts +28 -0
  100. package/dist/progress.d.ts +28 -0
  101. package/dist/provider.d.cts +25 -0
  102. package/dist/provider.d.ts +25 -0
  103. package/dist/radio.d.cts +53 -0
  104. package/dist/radio.d.ts +53 -0
  105. package/dist/rating.d.cts +14 -0
  106. package/dist/rating.d.ts +14 -0
  107. package/dist/select.cjs +3 -7
  108. package/dist/select.d.cts +130 -0
  109. package/dist/select.d.ts +130 -0
  110. package/dist/select.js +3 -7
  111. package/dist/separator.d.cts +13 -0
  112. package/dist/separator.d.ts +13 -0
  113. package/dist/skeleton.cjs +8 -7
  114. package/dist/skeleton.d.cts +76 -0
  115. package/dist/skeleton.d.ts +76 -0
  116. package/dist/skeleton.js +8 -8
  117. package/dist/slider.d.cts +24 -0
  118. package/dist/slider.d.ts +24 -0
  119. package/dist/strategy-builder.d.cts +26 -0
  120. package/dist/strategy-builder.d.ts +26 -0
  121. package/dist/switch.d.cts +27 -0
  122. package/dist/switch.d.ts +27 -0
  123. package/dist/table.cjs +3 -7
  124. package/dist/table.d.cts +107 -0
  125. package/dist/table.d.ts +107 -0
  126. package/dist/table.js +3 -7
  127. package/dist/tabs.d.cts +78 -0
  128. package/dist/tabs.d.ts +78 -0
  129. package/dist/tag.cjs +4 -8
  130. package/dist/tag.d.cts +21 -0
  131. package/dist/tag.d.ts +21 -0
  132. package/dist/tag.js +4 -8
  133. package/dist/textarea.d.cts +13 -0
  134. package/dist/textarea.d.ts +13 -0
  135. package/dist/toaster.d.cts +29 -0
  136. package/dist/toaster.d.ts +29 -0
  137. package/dist/tooltip.cjs +1 -1
  138. package/dist/tooltip.d.cts +38 -0
  139. package/dist/tooltip.d.ts +38 -0
  140. package/dist/tooltip.js +1 -1
  141. package/dist/use-narrow.d.cts +12 -0
  142. package/dist/use-narrow.d.ts +12 -0
  143. package/dist/utils.d.cts +5 -0
  144. package/dist/utils.d.ts +5 -0
  145. package/dist/vite.cjs +4 -3
  146. package/dist/vite.d.cts +29 -0
  147. package/dist/vite.d.ts +29 -0
  148. package/dist/vite.js +4 -3
  149. package/dist/white-label.d.cts +59 -0
  150. package/dist/white-label.d.ts +59 -0
  151. package/package.json +12 -2
  152. package/src/auth.tsx +198 -0
  153. package/src/engine.ts +24 -3
  154. package/src/index.ts +1 -1
  155. package/src/next.ts +10 -0
  156. package/src/skeleton.tsx +36 -7
  157. package/src/tooltip.tsx +13 -5
  158. package/src/vite.ts +4 -9
  159. package/tokens.css +828 -317
package/dist/auth.js ADDED
@@ -0,0 +1,456 @@
1
+ "use client";
2
+ import { configureIam, handleCallback, logout, startLogin } from '@hanzo/iam/browser';
3
+ import * as React2 from 'react';
4
+ import React2__default from 'react';
5
+ import '@hanzo/gui';
6
+ import { QueryClient } from '@tanstack/react-query';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+
9
+ // src/white-label.ts
10
+ var LUX_BRAND = {
11
+ lux: "#7000FF",
12
+ zoo: "#6C5EFB",
13
+ hanzo: "#EA580C",
14
+ pars: "#1C3879"};
15
+ var PARS_GOLD = "#C8A45C";
16
+ var ORGS = {
17
+ lux: {
18
+ org: "lux",
19
+ name: "Lux",
20
+ domain: "lux.network",
21
+ iamDomain: "lux.id",
22
+ accent: LUX_BRAND.lux,
23
+ accentForeground: "#FFFFFF"
24
+ },
25
+ zoo: {
26
+ org: "zoo",
27
+ name: "Zoo",
28
+ domain: "zoo.ngo",
29
+ // Zoo's issuer is `zoolabs.id` — the one row where it is not `<org>.id`,
30
+ // and the one every hand-rolled branding map gets wrong. `id.zoo.network`
31
+ // ANSWERS, which is why it keeps being copied around, but it is an alias:
32
+ // its own discovery document advertises
33
+ // issuer https://zoolabs.id
34
+ // authorization_endpoint https://zoolabs.id/v1/iam/oauth/authorize
35
+ // jwks_uri https://zoolabs.id/v1/iam/.well-known/jwks
36
+ // so a client configured on the alias validates `iss` against a string the
37
+ // IdP never emits and rejects every token it is given — the exact shape of
38
+ // the lux.id outage. `zoo.id` is not an IdP at all (no discovery document).
39
+ iamDomain: "zoolabs.id",
40
+ accent: LUX_BRAND.zoo,
41
+ accentForeground: "#FFFFFF"
42
+ },
43
+ bootnode: {
44
+ org: "bootnode",
45
+ name: "Bootnode",
46
+ domain: "bootno.de",
47
+ iamDomain: "id.bootno.de",
48
+ accent: LUX_BRAND.lux,
49
+ accentForeground: "#FFFFFF"
50
+ },
51
+ hanzo: {
52
+ org: "hanzo",
53
+ name: "Hanzo",
54
+ domain: "hanzo.ai",
55
+ iamDomain: "hanzo.id",
56
+ accent: LUX_BRAND.hanzo,
57
+ accentForeground: "#FFFFFF"
58
+ },
59
+ pars: {
60
+ org: "pars",
61
+ name: "Pars",
62
+ domain: "pars.id",
63
+ iamDomain: "pars.id",
64
+ accent: LUX_BRAND.pars,
65
+ accentForeground: PARS_GOLD
66
+ }
67
+ };
68
+ var DOMAIN_ORG = [
69
+ ["lux.network", "lux"],
70
+ ["lux.cloud", "lux"],
71
+ ["lux.id", "lux"],
72
+ ["lux.finance", "lux"],
73
+ ["lux.market", "lux"],
74
+ ["lux.exchange", "lux"],
75
+ ["zoo.ngo", "zoo"],
76
+ ["zoo.network", "zoo"],
77
+ ["zoo.cloud", "zoo"],
78
+ ["zoolabs.id", "zoo"],
79
+ ["hanzo.ai", "hanzo"],
80
+ ["hanzo.cloud", "hanzo"],
81
+ ["hanzo.id", "hanzo"],
82
+ ["pars.id", "pars", "app"],
83
+ ["pars.network", "pars", "app"],
84
+ ["parsdao.org", "pars", "app"],
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, pinned) {
105
+ if (pinned) return pinned;
106
+ const sub = host === domain ? "" : host.slice(0, -(domain.length + 1));
107
+ const leftmost = sub.split(".")[0] ?? "";
108
+ if (leftmost && leftmost !== "www") return leftmost;
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
+
132
+ // src/iam.ts
133
+ var IamError = class extends Error {
134
+ constructor(message, status, unauthenticated) {
135
+ super(message);
136
+ this.name = "IamError";
137
+ this.status = status;
138
+ this.unauthenticated = unauthenticated;
139
+ }
140
+ };
141
+ var SIGNED_OUT = /please sign in|authentication required|unauthorized/i;
142
+ function isSignedOut(status, msg) {
143
+ return status === 401 || SIGNED_OUT.test(msg);
144
+ }
145
+ function iamBase(host) {
146
+ const wl = typeof host === "object" && host !== null ? host : resolveWhiteLabel(host);
147
+ return `${wl.issuer}/v1/iam`;
148
+ }
149
+ async function read(call, verb, params) {
150
+ const url = new URL(`${call.base}/${verb}`);
151
+ for (const [k, v] of Object.entries(params)) url.searchParams.set(k, String(v));
152
+ let res;
153
+ try {
154
+ res = await fetch(url.toString(), {
155
+ method: "GET",
156
+ // The bearer is the whole credential. IAM does not allow credentialed
157
+ // CORS, so sending cookies would only get the response blocked.
158
+ headers: call.token ? { Authorization: `Bearer ${call.token}` } : {},
159
+ signal: call.signal
160
+ });
161
+ } catch (e) {
162
+ throw new IamError(e instanceof Error ? e.message : "IAM unreachable", 0, false);
163
+ }
164
+ const body = await res.json().catch(() => ({}));
165
+ const msg = typeof body.msg === "string" ? body.msg : "";
166
+ if (!res.ok || body.status === "error") {
167
+ throw new IamError(msg || `IAM ${verb} failed (${res.status})`, res.status, isSignedOut(res.status, msg));
168
+ }
169
+ return body.data;
170
+ }
171
+ var IAM_PAGE_SIZE = 20;
172
+ var iam = {
173
+ /** The signed-in principal, or null when there is no session. */
174
+ async account(call) {
175
+ try {
176
+ const data = await read(call, "get-account", {});
177
+ return data && data.name ? data : null;
178
+ } catch (e) {
179
+ if (e instanceof IamError && e.unauthenticated) return null;
180
+ throw e;
181
+ }
182
+ },
183
+ /**
184
+ * One page of the orgs the principal can see. IAM scopes the read to the
185
+ * caller's authority, so a normal member gets their own org and a super
186
+ * admin gets the tenant list — the page never has to decide.
187
+ */
188
+ async organizations(call, page = 0, query = "", pageSize = IAM_PAGE_SIZE) {
189
+ const params = {
190
+ owner: "admin",
191
+ // IAM orgs live under the reserved `admin` owner
192
+ p: page + 1,
193
+ // the backend page is 1-based
194
+ pageSize,
195
+ sortField: "name",
196
+ sortOrder: "ascending"
197
+ };
198
+ const q = query.trim();
199
+ if (q) {
200
+ params.field = "name";
201
+ params.value = q;
202
+ }
203
+ return await read(call, "get-organizations", params) ?? [];
204
+ },
205
+ /** One organization by name. */
206
+ async organization(call, name) {
207
+ return await read(call, "get-organization", { id: `admin/${name}` }) ?? null;
208
+ },
209
+ /** Members of an organization. */
210
+ async users(call, org) {
211
+ return await read(call, "get-users", { owner: org }) ?? [];
212
+ },
213
+ /** The organization's projects — IAM keys this read by `organization`. */
214
+ async projects(call, org) {
215
+ return await read(call, "get-organization-projects", { organization: org }) ?? [];
216
+ }
217
+ };
218
+ new QueryClient({
219
+ defaultOptions: { queries: { refetchOnWindowFocus: false, retry: 1, staleTime: 3e4 } }
220
+ });
221
+ var WhiteLabelContext = React2__default.createContext(resolveWhiteLabel(""));
222
+ var useWhiteLabel = () => React2__default.useContext(WhiteLabelContext);
223
+ var IAM_TOKEN_KEY = "hanzo_iam_access_token";
224
+ function storedToken() {
225
+ if (typeof window === "undefined") return null;
226
+ for (const store of [window.sessionStorage, window.localStorage]) {
227
+ try {
228
+ const t = store.getItem(IAM_TOKEN_KEY);
229
+ if (t) return t;
230
+ } catch {
231
+ }
232
+ }
233
+ return null;
234
+ }
235
+ function clearStoredTokens() {
236
+ if (typeof window === "undefined") return;
237
+ for (const store of [window.sessionStorage, window.localStorage]) {
238
+ try {
239
+ for (const k of ["access_token", "refresh_token", "id_token", "expires_at"]) {
240
+ store.removeItem(`hanzo_iam_${k}`);
241
+ }
242
+ } catch {
243
+ }
244
+ }
245
+ }
246
+ var defaultAuth = {};
247
+ var scopeKey = (host, kind) => `lux-ui:${kind}:${host}`;
248
+ function readScope(host, kind) {
249
+ if (typeof window === "undefined") return null;
250
+ try {
251
+ return window.localStorage.getItem(scopeKey(host, kind));
252
+ } catch {
253
+ return null;
254
+ }
255
+ }
256
+ function writeScope(host, kind, value) {
257
+ if (typeof window === "undefined") return;
258
+ try {
259
+ window.localStorage.setItem(scopeKey(host, kind), value);
260
+ } catch {
261
+ }
262
+ }
263
+ var IdentityContext = React2.createContext(null);
264
+ var IdentityProvider = ({
265
+ children,
266
+ auth = defaultAuth,
267
+ loginPath = "/login"
268
+ }) => {
269
+ const whiteLabel = useWhiteLabel();
270
+ const base = React2.useMemo(() => iamBase(whiteLabel), [whiteLabel]);
271
+ const [status, setStatus] = React2.useState("loading");
272
+ const [account, setAccount] = React2.useState(null);
273
+ const [orgs, setOrgs] = React2.useState([]);
274
+ const [projects, setProjects] = React2.useState([]);
275
+ const [error, setError] = React2.useState(null);
276
+ const [orgName, setOrgName] = React2.useState(null);
277
+ const [projectName, setProjectName] = React2.useState(null);
278
+ const [epoch, setEpoch] = React2.useState(0);
279
+ React2.useEffect(() => {
280
+ const ac = new AbortController();
281
+ let live = true;
282
+ void (async () => {
283
+ const token = await (auth.token ?? storedToken)();
284
+ if (!live) return;
285
+ if (!token) {
286
+ setStatus("anonymous");
287
+ setAccount(null);
288
+ setOrgs([]);
289
+ return;
290
+ }
291
+ const call = { base, token, signal: ac.signal };
292
+ try {
293
+ const me = await iam.account(call);
294
+ if (!live) return;
295
+ if (!me) {
296
+ setStatus("anonymous");
297
+ setAccount(null);
298
+ setOrgs([]);
299
+ return;
300
+ }
301
+ setAccount(me);
302
+ const rows = await iam.organizations(call).catch((e) => {
303
+ if (e instanceof IamError && !e.unauthenticated) return [{ owner: "admin", name: me.owner }];
304
+ throw e;
305
+ });
306
+ if (!live) return;
307
+ setOrgs(rows);
308
+ setStatus("ready");
309
+ setError(null);
310
+ } catch (e) {
311
+ if (!live || ac.signal.aborted) return;
312
+ if (e instanceof IamError && e.unauthenticated) {
313
+ setStatus("anonymous");
314
+ setAccount(null);
315
+ setOrgs([]);
316
+ return;
317
+ }
318
+ setStatus("error");
319
+ setError(e instanceof Error ? e.message : "Could not reach IAM.");
320
+ }
321
+ })();
322
+ return () => {
323
+ live = false;
324
+ ac.abort();
325
+ };
326
+ }, [base, auth, epoch]);
327
+ const org = React2.useMemo(() => {
328
+ if (orgs.length === 0) return null;
329
+ const saved = orgName ?? readScope(whiteLabel.host, "org");
330
+ return orgs.find((o) => o.name === saved) ?? orgs.find((o) => o.name === account?.owner) ?? orgs[0];
331
+ }, [orgs, orgName, account, whiteLabel.host]);
332
+ React2.useEffect(() => {
333
+ if (!org) {
334
+ setProjects([]);
335
+ return;
336
+ }
337
+ const ac = new AbortController();
338
+ let live = true;
339
+ void (async () => {
340
+ const token = await (auth.token ?? storedToken)();
341
+ if (!live || !token) return;
342
+ const rows = await iam.projects({ base, token, signal: ac.signal }, org.name).catch(() => []);
343
+ if (live) setProjects(rows);
344
+ })();
345
+ return () => {
346
+ live = false;
347
+ ac.abort();
348
+ };
349
+ }, [base, auth, org, epoch]);
350
+ const project = React2.useMemo(() => {
351
+ if (projects.length === 0) return null;
352
+ const saved = projectName ?? readScope(whiteLabel.host, "project");
353
+ return projects.find((p) => p.name === saved) ?? projects.find((p) => p.isDefault) ?? projects[0];
354
+ }, [projects, projectName, whiteLabel.host]);
355
+ const value = React2.useMemo(() => ({
356
+ status,
357
+ account,
358
+ orgs,
359
+ org,
360
+ projects,
361
+ project,
362
+ error,
363
+ whiteLabel,
364
+ setOrg: (name) => {
365
+ writeScope(whiteLabel.host, "org", name);
366
+ setOrgName(name);
367
+ setProjectName(null);
368
+ },
369
+ setProject: (name) => {
370
+ writeScope(whiteLabel.host, "project", name);
371
+ setProjectName(name);
372
+ },
373
+ signIn: () => {
374
+ if (auth.signIn) return auth.signIn();
375
+ if (typeof window !== "undefined") window.location.assign(loginPath);
376
+ },
377
+ signOut: () => {
378
+ if (auth.signOut) return auth.signOut();
379
+ clearStoredTokens();
380
+ if (typeof window !== "undefined") window.location.assign(loginPath);
381
+ },
382
+ reload: () => setEpoch((n) => n + 1)
383
+ }), [status, account, orgs, org, projects, project, error, whiteLabel, auth, loginPath]);
384
+ return /* @__PURE__ */ jsx(IdentityContext.Provider, { value, children });
385
+ };
386
+ var CALLBACK_PATH = "/auth/callback";
387
+ function configureAuth(wl) {
388
+ if (typeof window === "undefined") return;
389
+ configureIam({
390
+ issuer: wl.issuer,
391
+ clientId: wl.clientId,
392
+ // The SDK already defaults to `${origin}${CALLBACK_PATH}`; naming it here
393
+ // makes the fleet-wide invariant one readable, testable line instead of a
394
+ // default nobody can see.
395
+ redirect: `${window.location.origin}${CALLBACK_PATH}`
396
+ });
397
+ }
398
+ function useAuth(defaultRedirect = "/") {
399
+ const whiteLabel = useWhiteLabel();
400
+ configureAuth(whiteLabel);
401
+ return React2.useMemo(() => ({
402
+ signIn: (redirect = defaultRedirect) => void startLogin({ redirect }),
403
+ signOut: () => void logout(),
404
+ complete: () => handleCallback(),
405
+ whiteLabel
406
+ }), [whiteLabel, defaultRedirect]);
407
+ }
408
+ var AuthProvider = ({ children, redirect = "/", onSignOut }) => {
409
+ const auth = useAuth(redirect);
410
+ const identityAuth = React2.useMemo(() => ({
411
+ signIn: () => auth.signIn(redirect),
412
+ signOut: () => {
413
+ onSignOut?.();
414
+ auth.signOut();
415
+ }
416
+ }), [auth, redirect, onSignOut]);
417
+ return /* @__PURE__ */ jsx(IdentityProvider, { auth: identityAuth, children });
418
+ };
419
+ var AuthCallback = ({
420
+ onSignedIn,
421
+ navigate,
422
+ fallback = "/",
423
+ retryPath = "/login"
424
+ }) => {
425
+ const auth = useAuth();
426
+ const [error, setError] = React2.useState(null);
427
+ React2.useEffect(() => {
428
+ let live = true;
429
+ void (async () => {
430
+ try {
431
+ const result = await auth.complete();
432
+ if (!live) return;
433
+ try {
434
+ await onSignedIn?.(result);
435
+ } catch {
436
+ }
437
+ if (!live) return;
438
+ const to = result.redirect || fallback;
439
+ if (navigate) navigate(to);
440
+ else window.location.replace(to);
441
+ } catch (e) {
442
+ if (live) setError(e instanceof Error ? e.message : "Authentication failed");
443
+ }
444
+ })();
445
+ return () => {
446
+ live = false;
447
+ };
448
+ }, []);
449
+ return /* @__PURE__ */ jsx("div", { className: "flex min-h-[50vh] items-center justify-center px-4", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-sm text-center", children: error ? /* @__PURE__ */ jsxs(Fragment, { children: [
450
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-lg font-semibold text-[var(--color-text-error)]", children: "Sign-in failed" }),
451
+ /* @__PURE__ */ jsx("p", { className: "mb-6 text-sm text-[var(--color-text-secondary)]", children: error }),
452
+ /* @__PURE__ */ jsx("a", { href: retryPath, className: "text-sm underline underline-offset-4", children: "Try again" })
453
+ ] }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--color-text-secondary)]", children: "Completing sign in\u2026" }) }) });
454
+ };
455
+
456
+ export { AuthCallback, AuthProvider, CALLBACK_PATH, configureAuth, useAuth };
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+
3
+ type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
4
+ type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
5
+ type AvatarVariant = 'solid' | 'subtle' | 'outline';
6
+ interface AvatarProps extends React.ComponentPropsWithoutRef<'span'> {
7
+ name?: string;
8
+ src?: string;
9
+ srcSet?: string;
10
+ loading?: ImageProps['loading'];
11
+ icon?: React.ReactElement;
12
+ fallback?: React.ReactNode;
13
+ size?: AvatarSize;
14
+ variant?: AvatarVariant;
15
+ borderless?: boolean;
16
+ }
17
+ declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
18
+ interface AvatarGroupProps extends React.ComponentPropsWithoutRef<'div'> {
19
+ size?: AvatarSize;
20
+ variant?: AvatarVariant;
21
+ borderless?: boolean;
22
+ }
23
+ declare const AvatarGroup: React.ForwardRefExoticComponent<AvatarGroupProps & React.RefAttributes<HTMLDivElement>>;
24
+
25
+ export { Avatar, AvatarGroup, type AvatarProps };
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+
3
+ type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
4
+ type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
5
+ type AvatarVariant = 'solid' | 'subtle' | 'outline';
6
+ interface AvatarProps extends React.ComponentPropsWithoutRef<'span'> {
7
+ name?: string;
8
+ src?: string;
9
+ srcSet?: string;
10
+ loading?: ImageProps['loading'];
11
+ icon?: React.ReactElement;
12
+ fallback?: React.ReactNode;
13
+ size?: AvatarSize;
14
+ variant?: AvatarVariant;
15
+ borderless?: boolean;
16
+ }
17
+ declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
18
+ interface AvatarGroupProps extends React.ComponentPropsWithoutRef<'div'> {
19
+ size?: AvatarSize;
20
+ variant?: AvatarVariant;
21
+ borderless?: boolean;
22
+ }
23
+ declare const AvatarGroup: React.ForwardRefExoticComponent<AvatarGroupProps & React.RefAttributes<HTMLDivElement>>;
24
+
25
+ export { Avatar, AvatarGroup, type AvatarProps };
package/dist/badge.cjs CHANGED
@@ -146,11 +146,7 @@ function stripShims(props) {
146
146
  for (const k of SHIM_PROPS) delete out[k];
147
147
  return out;
148
148
  }
149
- var SKELETON_CLASSES = [
150
- "animate-skeleton-shimmer rounded-sm",
151
- "bg-[linear-gradient(90deg,var(--color-skeleton-start)_0%,var(--color-skeleton-end)_50%,var(--color-skeleton-start)_100%)]",
152
- "bg-[length:200%_100%]"
153
- ].join(" ");
149
+ var SKELETON_CLASSES = "lux-skeleton rounded-sm";
154
150
  var HIDE_BELOW_MAP = { lg: "lg:hidden", md: "md:hidden", sm: "sm:hidden" };
155
151
  var Skeleton = React3__namespace.forwardRef(
156
152
  function Skeleton2(props, ref) {
@@ -170,7 +166,7 @@ var Skeleton = React3__namespace.forwardRef(
170
166
  {
171
167
  ref,
172
168
  "data-loading": true,
173
- className: cn(SKELETON_CLASSES, "text-transparent [&_*]:invisible", cls),
169
+ className: cn(SKELETON_CLASSES, "[&_*]:invisible", cls),
174
170
  style: mergedStyle,
175
171
  ...htmlRest,
176
172
  children
@@ -182,7 +178,7 @@ var Skeleton = React3__namespace.forwardRef(
182
178
  {
183
179
  ref,
184
180
  "data-loading": true,
185
- className: cn(SKELETON_CLASSES, children ? "text-transparent [&_*]:invisible" : "min-h-5", cls),
181
+ className: cn(SKELETON_CLASSES, children ? "[&_*]:invisible" : "min-h-5", cls),
186
182
  style: mergedStyle,
187
183
  ...htmlRest,
188
184
  children
@@ -313,7 +309,7 @@ var Tooltip = React3__namespace.forwardRef(
313
309
  {
314
310
  ref: triggerRef,
315
311
  asChild: true,
316
- ...isMobile ? { onPress: handleTriggerClick } : {},
312
+ ...isMobile ? { onClick: handleTriggerClick } : {},
317
313
  ...triggerProps,
318
314
  children
319
315
  }
@@ -0,0 +1,19 @@
1
+ import React__default from 'react';
2
+
3
+ type ColorPalette = 'gray' | 'green' | 'red' | 'purple' | 'orange' | 'blue' | 'yellow' | 'teal' | 'cyan' | 'pink' | 'purple_alt' | 'blue_alt' | 'bright_gray' | 'bright_green' | 'bright_red' | 'bright_blue' | 'bright_yellow' | 'bright_teal' | 'bright_cyan' | 'bright_orange' | 'bright_purple' | 'bright_pink';
4
+ interface BadgeProps extends Omit<React__default.HTMLAttributes<HTMLSpanElement>, 'color'> {
5
+ readonly loading?: boolean;
6
+ readonly startElement?: React__default.ReactNode;
7
+ readonly endElement?: React__default.ReactNode;
8
+ readonly truncated?: boolean;
9
+ readonly colorPalette?: ColorPalette;
10
+ readonly variant?: 'subtle' | 'solid';
11
+ readonly size?: 'sm' | 'md' | 'lg';
12
+ readonly flexShrink?: number;
13
+ readonly gap?: number | string;
14
+ readonly ml?: number | string | Record<string, number>;
15
+ readonly mr?: number | string;
16
+ }
17
+ declare const Badge: React__default.ForwardRefExoticComponent<BadgeProps & React__default.RefAttributes<HTMLDivElement>>;
18
+
19
+ export { Badge, type BadgeProps };
@@ -0,0 +1,19 @@
1
+ import React__default from 'react';
2
+
3
+ type ColorPalette = 'gray' | 'green' | 'red' | 'purple' | 'orange' | 'blue' | 'yellow' | 'teal' | 'cyan' | 'pink' | 'purple_alt' | 'blue_alt' | 'bright_gray' | 'bright_green' | 'bright_red' | 'bright_blue' | 'bright_yellow' | 'bright_teal' | 'bright_cyan' | 'bright_orange' | 'bright_purple' | 'bright_pink';
4
+ interface BadgeProps extends Omit<React__default.HTMLAttributes<HTMLSpanElement>, 'color'> {
5
+ readonly loading?: boolean;
6
+ readonly startElement?: React__default.ReactNode;
7
+ readonly endElement?: React__default.ReactNode;
8
+ readonly truncated?: boolean;
9
+ readonly colorPalette?: ColorPalette;
10
+ readonly variant?: 'subtle' | 'solid';
11
+ readonly size?: 'sm' | 'md' | 'lg';
12
+ readonly flexShrink?: number;
13
+ readonly gap?: number | string;
14
+ readonly ml?: number | string | Record<string, number>;
15
+ readonly mr?: number | string;
16
+ }
17
+ declare const Badge: React__default.ForwardRefExoticComponent<BadgeProps & React__default.RefAttributes<HTMLDivElement>>;
18
+
19
+ export { Badge, type BadgeProps };
package/dist/badge.js CHANGED
@@ -125,11 +125,7 @@ function stripShims(props) {
125
125
  for (const k of SHIM_PROPS) delete out[k];
126
126
  return out;
127
127
  }
128
- var SKELETON_CLASSES = [
129
- "animate-skeleton-shimmer rounded-sm",
130
- "bg-[linear-gradient(90deg,var(--color-skeleton-start)_0%,var(--color-skeleton-end)_50%,var(--color-skeleton-start)_100%)]",
131
- "bg-[length:200%_100%]"
132
- ].join(" ");
128
+ var SKELETON_CLASSES = "lux-skeleton rounded-sm";
133
129
  var HIDE_BELOW_MAP = { lg: "lg:hidden", md: "md:hidden", sm: "sm:hidden" };
134
130
  var Skeleton = React3.forwardRef(
135
131
  function Skeleton2(props, ref) {
@@ -149,7 +145,7 @@ var Skeleton = React3.forwardRef(
149
145
  {
150
146
  ref,
151
147
  "data-loading": true,
152
- className: cn(SKELETON_CLASSES, "text-transparent [&_*]:invisible", cls),
148
+ className: cn(SKELETON_CLASSES, "[&_*]:invisible", cls),
153
149
  style: mergedStyle,
154
150
  ...htmlRest,
155
151
  children
@@ -161,7 +157,7 @@ var Skeleton = React3.forwardRef(
161
157
  {
162
158
  ref,
163
159
  "data-loading": true,
164
- className: cn(SKELETON_CLASSES, children ? "text-transparent [&_*]:invisible" : "min-h-5", cls),
160
+ className: cn(SKELETON_CLASSES, children ? "[&_*]:invisible" : "min-h-5", cls),
165
161
  style: mergedStyle,
166
162
  ...htmlRest,
167
163
  children
@@ -292,7 +288,7 @@ var Tooltip = React3.forwardRef(
292
288
  {
293
289
  ref: triggerRef,
294
290
  asChild: true,
295
- ...isMobile ? { onPress: handleTriggerClick } : {},
291
+ ...isMobile ? { onClick: handleTriggerClick } : {},
296
292
  ...triggerProps,
297
293
  children
298
294
  }