@hanzo/ui 8.31.0 → 8.32.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.
@@ -0,0 +1,49 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.SignInPanel = SignInPanel;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const react_2 = require("@hanzo/i18n/react");
8
+ const react_3 = require("@hanzo/iam/react");
9
+ const react_simple_icons_1 = require("@icons-pack/react-simple-icons");
10
+ const button_1 = require("../backends/gui/button.cjs");
11
+ const field_1 = require("../backends/gui/field.cjs");
12
+ const input_1 = require("../backends/gui/input.cjs");
13
+ const layout_1 = require("../backends/gui/layout.cjs");
14
+ const handoff_1 = require("./handoff.cjs");
15
+ const NAME = { google: 'Google', github: 'GitHub' };
16
+ function SignInPanel({ title, line, providers = ['google', 'github'], signin = handoff_1.SIGNIN, signup = true, termsHref = 'https://hanzo.ai/terms', privacyHref = 'https://hanzo.ai/privacy', authorize = (u) => u, track, }) {
17
+ const { t } = (0, react_2.useI18n)();
18
+ const { sdk } = (0, react_3.useIam)();
19
+ const [email, setEmail] = (0, react_1.useState)('');
20
+ const [busy, setBusy] = (0, react_1.useState)(null);
21
+ const [wrong, setWrong] = (0, react_1.useState)(null);
22
+ /** Mint this site's own request, then leave for where `way` goes. */
23
+ async function leave(method, way, hint) {
24
+ setWrong(null);
25
+ setBusy(method);
26
+ track?.('signin_started', { method });
27
+ try {
28
+ const request = await sdk.getSigninUrl(hint ? { additionalParams: { login_hint: hint } } : undefined);
29
+ window.location.assign(authorize((0, handoff_1.handoff)(request, way, signin)));
30
+ }
31
+ catch (err) {
32
+ setWrong(err instanceof Error && err.message ? err.message : 'Signing in could not start. Try again.');
33
+ setBusy(null);
34
+ }
35
+ }
36
+ function withEmail(e) {
37
+ e.preventDefault();
38
+ const typed = (0, handoff_1.address)(email);
39
+ if (!typed) {
40
+ setWrong('Enter your email address.');
41
+ return;
42
+ }
43
+ void leave('email', { kind: 'email', email: typed }, typed);
44
+ }
45
+ return ((0, jsx_runtime_1.jsxs)(layout_1.YStack, { width: "100%", maxW: 400, items: "center", gap: "$4", children: [title ? ((0, jsx_runtime_1.jsx)(layout_1.Heading, { render: "h1", size: "$8", fontWeight: "500", color: "$ink", m: 0, text: "center", children: title })) : null, line ? ((0, jsx_runtime_1.jsx)(layout_1.Paragraph, { size: "$3", color: "$quiet", m: 0, text: "center", maxW: 360, children: line })) : null, (0, jsx_runtime_1.jsx)(layout_1.YStack, { width: "100%", gap: "$2.5", mt: title || line ? '$2' : 0, children: providers.map((p) => ((0, jsx_runtime_1.jsxs)(button_1.Button, { type: "button", variant: "secondary", size: "lg", rounded: "$10", width: "100%", disabled: busy !== null, onClick: () => void leave(p, { kind: 'provider', provider: p }), children: [p === 'google' ? (0, jsx_runtime_1.jsx)(react_simple_icons_1.SiGoogle, { size: 16 }) : (0, jsx_runtime_1.jsx)(react_simple_icons_1.SiGithub, { size: 16 }), t('Continue with {provider}', { provider: NAME[p] })] }, p))) }), providers.length ? ((0, jsx_runtime_1.jsx)(layout_1.YStack, { width: "100%", children: (0, jsx_runtime_1.jsx)(field_1.FieldSeparator, { children: t('or') }) })) : null, (0, jsx_runtime_1.jsxs)(layout_1.YStack, { render: (0, jsx_runtime_1.jsx)("form", { onSubmit: withEmail, noValidate: true }), width: "100%", gap: "$3", children: [(0, jsx_runtime_1.jsx)(field_1.Field, { gap: "$2", children: (0, jsx_runtime_1.jsx)(input_1.Input, { id: "hanzo-signin-email", type: "email", name: "email", autoComplete: "username", "aria-label": t('Email'), value: email, onChangeText: setEmail, placeholder: "you@company.com" }) }), wrong ? (0, jsx_runtime_1.jsx)(field_1.FieldError, { children: t(wrong) }) : null, (0, jsx_runtime_1.jsx)(button_1.Button, { type: "submit", size: "lg", rounded: "$10", width: "100%", bg: "$ink", color: "$background", borderColor: "$ink", hoverStyle: { opacity: 0.92 }, disabled: busy !== null, children: t('Continue with email') })] }), signup ? ((0, jsx_runtime_1.jsxs)(layout_1.Paragraph, { size: "$2", color: "$quiet", m: 0, children: [`${t('New to Hanzo?')} `, (0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", variant: "link", size: "sm", px: 0, height: "auto", disabled: busy !== null, onClick: () => void leave('signup', { kind: 'signup' }), children: t('Create account') })] })) : null, (0, jsx_runtime_1.jsx)(layout_1.Paragraph, { size: "$1", color: "$quiet", m: 0, text: "center", maxW: 400, children: t("By continuing, you agree to Hanzo's {terms} and {privacy}.", {
46
+ terms: ((0, jsx_runtime_1.jsx)(layout_1.Anchor, { href: termsHref, color: "$ink", textDecorationLine: "underline", children: t('Terms') })),
47
+ privacy: ((0, jsx_runtime_1.jsx)(layout_1.Anchor, { href: privacyHref, color: "$ink", textDecorationLine: "underline", children: t('Privacy Policy') })),
48
+ }) })] }));
49
+ }
@@ -0,0 +1,38 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type ProviderKind } from './handoff.js';
3
+ /**
4
+ * The sign-in a Hanzo site draws on its own front page (hanzo.app, hanzo.bot,
5
+ * hanzo.team), shared so every site asks the same way and leaves the same way.
6
+ *
7
+ * It looks like a sign-in and is a door: no credential is typed here, and no
8
+ * session is made on this origin. Each press mints this site's own authorize
9
+ * request (`getSigninUrl`, which keeps the PKCE verifier and state here) and
10
+ * leaves with it (./handoff.ts): Google or GitHub straight to the provider, in one
11
+ * press; an email to hanzo.ai/login with the address filled in; a new account to
12
+ * hanzo.ai/signup. The session that answers is hanzo.ai's, so a person signed in
13
+ * on any Hanzo site is not asked again.
14
+ *
15
+ * Drawn from @hanzo/ui components in the theme's tokens; the host mounts its
16
+ * GuiProvider and imports no stylesheet. Framework-free: a Next export and a Vite
17
+ * app draw it alike.
18
+ */
19
+ export interface SignInPanelProps {
20
+ /** The headline: `Sign in to Hanzo Team`. Omit to draw the panel alone under the host's own. */
21
+ title?: ReactNode;
22
+ /** One line under the headline. */
23
+ line?: ReactNode;
24
+ /** The providers offered, in order. Default Google, then GitHub. */
25
+ providers?: ProviderKind[];
26
+ /** The origin people sign in on. Default https://hanzo.ai. */
27
+ signin?: string;
28
+ /** Offer "Create account". Default true. */
29
+ signup?: boolean;
30
+ termsHref?: string;
31
+ privacyHref?: string;
32
+ /** Decorates an address the browser is about to leave for (the visitor rides along). */
33
+ authorize?: (url: string) => string;
34
+ /** A press the stream should hear: `signin_started{method}`. */
35
+ track?: (name: string, props?: Record<string, unknown>) => void;
36
+ }
37
+ export declare function SignInPanel({ title, line, providers, signin, signup, termsHref, privacyHref, authorize, track, }: SignInPanelProps): import("react").JSX.Element;
38
+ //# sourceMappingURL=SignInPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignInPanel.d.ts","sourceRoot":"","sources":["../../src/auth/SignInPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAQhE,OAAO,EAA4B,KAAK,YAAY,EAAY,MAAM,WAAW,CAAA;AAEjF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gGAAgG;IAChG,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,mCAAmC;IACnC,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,oEAAoE;IACpE,SAAS,CAAC,EAAE,YAAY,EAAE,CAAA;IAC1B,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wFAAwF;IACxF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,gEAAgE;IAChE,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CAChE;AAID,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,IAAI,EACJ,SAAgC,EAChC,MAAe,EACf,MAAa,EACb,SAAoC,EACpC,WAAwC,EACxC,SAAoB,EACpB,KAAK,GACN,EAAE,gBAAgB,+BAkGlB"}
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { useI18n } from '@hanzo/i18n/react';
5
+ import { useIam } from '@hanzo/iam/react';
6
+ import { SiGithub, SiGoogle } from '@icons-pack/react-simple-icons';
7
+ import { Button } from '../backends/gui/button.js';
8
+ import { Field, FieldError, FieldSeparator } from '../backends/gui/field.js';
9
+ import { Input } from '../backends/gui/input.js';
10
+ import { Anchor, Heading, Paragraph, YStack } from '../backends/gui/layout.js';
11
+ import { address, handoff, SIGNIN } from './handoff.js';
12
+ const NAME = { google: 'Google', github: 'GitHub' };
13
+ export function SignInPanel({ title, line, providers = ['google', 'github'], signin = SIGNIN, signup = true, termsHref = 'https://hanzo.ai/terms', privacyHref = 'https://hanzo.ai/privacy', authorize = (u) => u, track, }) {
14
+ const { t } = useI18n();
15
+ const { sdk } = useIam();
16
+ const [email, setEmail] = useState('');
17
+ const [busy, setBusy] = useState(null);
18
+ const [wrong, setWrong] = useState(null);
19
+ /** Mint this site's own request, then leave for where `way` goes. */
20
+ async function leave(method, way, hint) {
21
+ setWrong(null);
22
+ setBusy(method);
23
+ track?.('signin_started', { method });
24
+ try {
25
+ const request = await sdk.getSigninUrl(hint ? { additionalParams: { login_hint: hint } } : undefined);
26
+ window.location.assign(authorize(handoff(request, way, signin)));
27
+ }
28
+ catch (err) {
29
+ setWrong(err instanceof Error && err.message ? err.message : 'Signing in could not start. Try again.');
30
+ setBusy(null);
31
+ }
32
+ }
33
+ function withEmail(e) {
34
+ e.preventDefault();
35
+ const typed = address(email);
36
+ if (!typed) {
37
+ setWrong('Enter your email address.');
38
+ return;
39
+ }
40
+ void leave('email', { kind: 'email', email: typed }, typed);
41
+ }
42
+ return (_jsxs(YStack, { width: "100%", maxW: 400, items: "center", gap: "$4", children: [title ? (_jsx(Heading, { render: "h1", size: "$8", fontWeight: "500", color: "$ink", m: 0, text: "center", children: title })) : null, line ? (_jsx(Paragraph, { size: "$3", color: "$quiet", m: 0, text: "center", maxW: 360, children: line })) : null, _jsx(YStack, { width: "100%", gap: "$2.5", mt: title || line ? '$2' : 0, children: providers.map((p) => (_jsxs(Button, { type: "button", variant: "secondary", size: "lg", rounded: "$10", width: "100%", disabled: busy !== null, onClick: () => void leave(p, { kind: 'provider', provider: p }), children: [p === 'google' ? _jsx(SiGoogle, { size: 16 }) : _jsx(SiGithub, { size: 16 }), t('Continue with {provider}', { provider: NAME[p] })] }, p))) }), providers.length ? (_jsx(YStack, { width: "100%", children: _jsx(FieldSeparator, { children: t('or') }) })) : null, _jsxs(YStack, { render: _jsx("form", { onSubmit: withEmail, noValidate: true }), width: "100%", gap: "$3", children: [_jsx(Field, { gap: "$2", children: _jsx(Input, { id: "hanzo-signin-email", type: "email", name: "email", autoComplete: "username", "aria-label": t('Email'), value: email, onChangeText: setEmail, placeholder: "you@company.com" }) }), wrong ? _jsx(FieldError, { children: t(wrong) }) : null, _jsx(Button, { type: "submit", size: "lg", rounded: "$10", width: "100%", bg: "$ink", color: "$background", borderColor: "$ink", hoverStyle: { opacity: 0.92 }, disabled: busy !== null, children: t('Continue with email') })] }), signup ? (_jsxs(Paragraph, { size: "$2", color: "$quiet", m: 0, children: [`${t('New to Hanzo?')} `, _jsx(Button, { type: "button", variant: "link", size: "sm", px: 0, height: "auto", disabled: busy !== null, onClick: () => void leave('signup', { kind: 'signup' }), children: t('Create account') })] })) : null, _jsx(Paragraph, { size: "$1", color: "$quiet", m: 0, text: "center", maxW: 400, children: t("By continuing, you agree to Hanzo's {terms} and {privacy}.", {
43
+ terms: (_jsx(Anchor, { href: termsHref, color: "$ink", textDecorationLine: "underline", children: t('Terms') })),
44
+ privacy: (_jsx(Anchor, { href: privacyHref, color: "$ink", textDecorationLine: "underline", children: t('Privacy Policy') })),
45
+ }) })] }));
46
+ }
47
+ //# sourceMappingURL=SignInPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignInPanel.js","sourceRoot":"","sources":["../../src/auth/SignInPanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /**
3
+ * Where a Hanzo site sends somebody to sign in: hanzo.ai, never its own page.
4
+ *
5
+ * One IAM, and one origin every Hanzo site signs in on, so the session that
6
+ * answers every site lives on hanzo.ai. Each site is still its own OAuth client:
7
+ * it mints its own authorize request (its client, its callback, a fresh state and
8
+ * a PKCE challenge whose verifier stays in its own storage) with `getSigninUrl`,
9
+ * and hands hanzo.ai only the query. hanzo.ai answers it and IAM returns the code
10
+ * to the site's callback, where the site redeems it.
11
+ *
12
+ * a provider straight to IAM's authorize ON hanzo.ai with `provider`, which
13
+ * sends the browser to Google or GitHub at once (one press) and
14
+ * takes the provider's return on hanzo.ai, so the session lands
15
+ * there. Not the issuer's authorize: a provider hop that starts
16
+ * on hanzo.id returns to hanzo.id and leaves hanzo.ai signed out.
17
+ * an email hanzo.ai/login with `login_hint`, where the password or the
18
+ * code is typed.
19
+ * a new account hanzo.ai/signup.
20
+ *
21
+ * Pure, so every address is tested without a browser.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.SIGNIN = void 0;
25
+ exports.handoff = handoff;
26
+ exports.address = address;
27
+ /** The one origin Hanzo signs people in on. */
28
+ exports.SIGNIN = 'https://hanzo.ai';
29
+ /**
30
+ * The address a press leaves for, from the site's own authorize request
31
+ * (`request`, as `getSigninUrl` answered it). Only its query travels.
32
+ */
33
+ function handoff(request, way, signin = exports.SIGNIN) {
34
+ const q = new URL(request).searchParams;
35
+ const at = signin.replace(/\/+$/, '');
36
+ switch (way.kind) {
37
+ case 'provider':
38
+ q.set('provider', way.provider);
39
+ return `${at}/v1/iam/oauth/authorize?${q}`;
40
+ case 'email':
41
+ q.set('login_hint', way.email);
42
+ return `${at}/login?${q}`;
43
+ case 'another':
44
+ q.set('prompt', 'select_account');
45
+ return `${at}/login?${q}`;
46
+ case 'signup':
47
+ return `${at}/signup?${q}`;
48
+ case 'login':
49
+ return `${at}/login?${q}`;
50
+ }
51
+ }
52
+ /** The address typed, trimmed, when it reads as an email; null otherwise. */
53
+ function address(typed) {
54
+ const s = typed.trim();
55
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s) ? s : null;
56
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Where a Hanzo site sends somebody to sign in: hanzo.ai, never its own page.
3
+ *
4
+ * One IAM, and one origin every Hanzo site signs in on, so the session that
5
+ * answers every site lives on hanzo.ai. Each site is still its own OAuth client:
6
+ * it mints its own authorize request (its client, its callback, a fresh state and
7
+ * a PKCE challenge whose verifier stays in its own storage) with `getSigninUrl`,
8
+ * and hands hanzo.ai only the query. hanzo.ai answers it and IAM returns the code
9
+ * to the site's callback, where the site redeems it.
10
+ *
11
+ * a provider straight to IAM's authorize ON hanzo.ai with `provider`, which
12
+ * sends the browser to Google or GitHub at once (one press) and
13
+ * takes the provider's return on hanzo.ai, so the session lands
14
+ * there. Not the issuer's authorize: a provider hop that starts
15
+ * on hanzo.id returns to hanzo.id and leaves hanzo.ai signed out.
16
+ * an email hanzo.ai/login with `login_hint`, where the password or the
17
+ * code is typed.
18
+ * a new account hanzo.ai/signup.
19
+ *
20
+ * Pure, so every address is tested without a browser.
21
+ */
22
+ /** The one origin Hanzo signs people in on. */
23
+ export declare const SIGNIN = "https://hanzo.ai";
24
+ /** The providers the shared panel draws. IAM names them by these words. */
25
+ export type ProviderKind = 'google' | 'github';
26
+ /**
27
+ * Where a press goes. A provider is named the way IAM names it: a kind (`google`)
28
+ * or a provider record's name (`provider-google`); either starts the same hop.
29
+ */
30
+ export type Way = {
31
+ kind: 'provider';
32
+ provider: string;
33
+ } | {
34
+ kind: 'email';
35
+ email: string;
36
+ } | {
37
+ kind: 'login';
38
+ } | {
39
+ kind: 'signup';
40
+ } | {
41
+ kind: 'another';
42
+ };
43
+ /**
44
+ * The address a press leaves for, from the site's own authorize request
45
+ * (`request`, as `getSigninUrl` answered it). Only its query travels.
46
+ */
47
+ export declare function handoff(request: string, way: Way, signin?: string): string;
48
+ /** The address typed, trimmed, when it reads as an email; null otherwise. */
49
+ export declare function address(typed: string): string | null;
50
+ //# sourceMappingURL=handoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/auth/handoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,MAAM,qBAAqB,CAAA;AAExC,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE9C;;;GAGG;AACH,MAAM,MAAM,GAAG,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAE1J;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAE,MAAe,GAAG,MAAM,CAkBlF;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGpD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Where a Hanzo site sends somebody to sign in: hanzo.ai, never its own page.
3
+ *
4
+ * One IAM, and one origin every Hanzo site signs in on, so the session that
5
+ * answers every site lives on hanzo.ai. Each site is still its own OAuth client:
6
+ * it mints its own authorize request (its client, its callback, a fresh state and
7
+ * a PKCE challenge whose verifier stays in its own storage) with `getSigninUrl`,
8
+ * and hands hanzo.ai only the query. hanzo.ai answers it and IAM returns the code
9
+ * to the site's callback, where the site redeems it.
10
+ *
11
+ * a provider straight to IAM's authorize ON hanzo.ai with `provider`, which
12
+ * sends the browser to Google or GitHub at once (one press) and
13
+ * takes the provider's return on hanzo.ai, so the session lands
14
+ * there. Not the issuer's authorize: a provider hop that starts
15
+ * on hanzo.id returns to hanzo.id and leaves hanzo.ai signed out.
16
+ * an email hanzo.ai/login with `login_hint`, where the password or the
17
+ * code is typed.
18
+ * a new account hanzo.ai/signup.
19
+ *
20
+ * Pure, so every address is tested without a browser.
21
+ */
22
+ /** The one origin Hanzo signs people in on. */
23
+ export const SIGNIN = 'https://hanzo.ai';
24
+ /**
25
+ * The address a press leaves for, from the site's own authorize request
26
+ * (`request`, as `getSigninUrl` answered it). Only its query travels.
27
+ */
28
+ export function handoff(request, way, signin = SIGNIN) {
29
+ const q = new URL(request).searchParams;
30
+ const at = signin.replace(/\/+$/, '');
31
+ switch (way.kind) {
32
+ case 'provider':
33
+ q.set('provider', way.provider);
34
+ return `${at}/v1/iam/oauth/authorize?${q}`;
35
+ case 'email':
36
+ q.set('login_hint', way.email);
37
+ return `${at}/login?${q}`;
38
+ case 'another':
39
+ q.set('prompt', 'select_account');
40
+ return `${at}/login?${q}`;
41
+ case 'signup':
42
+ return `${at}/signup?${q}`;
43
+ case 'login':
44
+ return `${at}/login?${q}`;
45
+ }
46
+ }
47
+ /** The address typed, trimmed, when it reads as an email; null otherwise. */
48
+ export function address(typed) {
49
+ const s = typed.trim();
50
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s) ? s : null;
51
+ }
52
+ //# sourceMappingURL=handoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/auth/handoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,+CAA+C;AAC/C,MAAM,CAAC,MAAM,MAAM,GAAG,kBAAkB,CAAA;AAWxC;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,GAAQ,EAAE,MAAM,GAAW,MAAM;IACxE,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,YAAY,CAAA;IACvC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACrC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;YAC/B,OAAO,GAAG,EAAE,2BAA2B,CAAC,EAAE,CAAA;QAC5C,KAAK,OAAO;YACV,CAAC,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;YAC9B,OAAO,GAAG,EAAE,UAAU,CAAC,EAAE,CAAA;QAC3B,KAAK,SAAS;YACZ,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAA;YACjC,OAAO,GAAG,EAAE,UAAU,CAAC,EAAE,CAAA;QAC3B,KAAK,QAAQ;YACX,OAAO,GAAG,EAAE,WAAW,CAAC,EAAE,CAAA;QAC5B,KAAK,OAAO;YACV,OAAO,GAAG,EAAE,UAAU,CAAC,EAAE,CAAA;IAC7B,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IACtB,OAAO,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACxD,CAAC"}
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.refresher = exports.live = exports.bearer = exports.useSignOut = exports.signOut = exports.SignIn = void 0;
3
+ exports.refresher = exports.live = exports.bearer = exports.useSignOut = exports.signOut = exports.SIGNIN = exports.handoff = exports.address = exports.SignInPanel = exports.SignIn = void 0;
4
4
  /**
5
5
  * Signing in, signing out, and the session, for every Hanzo site: IAM answers
6
6
  * (/v1/iam), the site draws.
7
7
  */
8
8
  var SignIn_1 = require("./SignIn.cjs");
9
9
  Object.defineProperty(exports, "SignIn", { enumerable: true, get: function () { return SignIn_1.SignIn; } });
10
+ var SignInPanel_1 = require("./SignInPanel.cjs");
11
+ Object.defineProperty(exports, "SignInPanel", { enumerable: true, get: function () { return SignInPanel_1.SignInPanel; } });
12
+ var handoff_1 = require("./handoff.cjs");
13
+ Object.defineProperty(exports, "address", { enumerable: true, get: function () { return handoff_1.address; } });
14
+ Object.defineProperty(exports, "handoff", { enumerable: true, get: function () { return handoff_1.handoff; } });
15
+ Object.defineProperty(exports, "SIGNIN", { enumerable: true, get: function () { return handoff_1.SIGNIN; } });
10
16
  var signout_1 = require("./signout.cjs");
11
17
  Object.defineProperty(exports, "signOut", { enumerable: true, get: function () { return signout_1.signOut; } });
12
18
  Object.defineProperty(exports, "useSignOut", { enumerable: true, get: function () { return signout_1.useSignOut; } });
@@ -3,6 +3,8 @@
3
3
  * (/v1/iam), the site draws.
4
4
  */
5
5
  export { SignIn, type Mode, type Provider, type SignInProps } from './SignIn.js';
6
+ export { SignInPanel, type SignInPanelProps } from './SignInPanel.js';
7
+ export { address, handoff, SIGNIN, type ProviderKind, type Way } from './handoff.js';
6
8
  export { signOut, useSignOut, type SignOutOptions } from './signout.js';
7
9
  export { bearer, live, refresher } from './session.js';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AAC7E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,GAAG,EAAE,MAAM,WAAW,CAAA;AACjF,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA"}
@@ -3,6 +3,8 @@
3
3
  * (/v1/iam), the site draws.
4
4
  */
5
5
  export { SignIn } from './SignIn.js';
6
+ export { SignInPanel } from './SignInPanel.js';
7
+ export { address, handoff, SIGNIN } from './handoff.js';
6
8
  export { signOut, useSignOut } from './signout.js';
7
9
  export { bearer, live, refresher } from './session.js';
8
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAA8C,MAAM,UAAU,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAuB,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAA8C,MAAM,UAAU,CAAA;AAC7E,OAAO,EAAE,WAAW,EAAyB,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAA+B,MAAM,WAAW,CAAA;AACjF,OAAO,EAAE,OAAO,EAAE,UAAU,EAAuB,MAAM,WAAW,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA"}
package/dist/gallery.html CHANGED
@@ -1,4 +1,4 @@
1
- <!doctype html><html lang="en" class="t_dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>@hanzo/ui 8.31.0</title><style>/* @hanzo/ui — generated by scripts/gen-css.mjs. Do not edit. */
1
+ <!doctype html><html lang="en" class="t_dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>@hanzo/ui 8.32.0</title><style>/* @hanzo/ui — generated by scripts/gen-css.mjs. Do not edit. */
2
2
  :root { --hanzo-ui-styles: 1; }
3
3
  /* Hanzo Design System — the entry point. Import THIS one file.
4
4
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/ui",
3
- "version": "8.31.0",
3
+ "version": "8.32.0",
4
4
  "type": "module",
5
5
  "description": "Hanzo UI — the one canonical Hanzo component library, on @hanzo/gui + @hanzo/design. ONE substrate: every component renders through @hanzo/gui primitives, so the same import works on web, native (expo) and desktop (Tauri). Self-contained (theme.css), presentational, host-agnostic, clean-room.",
6
6
  "exports": {