@haatlabs-core/ui 0.12.3 → 0.12.5

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.
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
+ import { resendLabel, useResendWait } from './resend-wait.js';
3
4
  import { SIGN_IN_CODE_DIGITS, SIGN_IN_CODE_MINUTES } from '@haatlabs-core/auth-contracts';
4
5
  import { useEffect, useState } from 'react';
5
6
  const KEY = ['email-sign-in'];
@@ -23,6 +24,7 @@ export function EmailSignInPanel({ client }) {
23
24
  if (suggested)
24
25
  setEmail((typed) => typed || suggested);
25
26
  }, [suggested]);
27
+ const wait = useResendWait();
26
28
  const send = useMutation({
27
29
  mutationFn: (to) => client.requestEmailSignInCode({ email: to }),
28
30
  // Never asked again by itself: each ask counts against the address's allowance.
@@ -30,6 +32,7 @@ export function EmailSignInPanel({ client }) {
30
32
  onSuccess: (_result, to) => {
31
33
  setSentTo(to);
32
34
  setCode('');
35
+ wait.start();
33
36
  },
34
37
  });
35
38
  const confirm = useMutation({
@@ -54,10 +57,10 @@ export function EmailSignInPanel({ client }) {
54
57
  }
55
58
  const { dashboardUrl } = current.data;
56
59
  const dashboard = (_jsx("a", { href: dashboardUrl, target: "_blank", rel: "noreferrer", children: dashboardUrl }));
57
- return (_jsxs("section", { className: "panel", children: [_jsx("h2", { children: "Sign in outside Shopify" }), current.data.email ? (_jsxs("p", { children: ["Sign in at ", dashboard, " as ", _jsx("strong", { children: current.data.email }), " to work on this store without opening Shopify admin. There is no password: a code is emailed to that address each time."] })) : !current.data.canCreate ? (_jsxs("p", { className: "muted", children: ["Only the owner of this store's Shopify account can create an email sign-in for the dashboard at ", dashboard, ". Ask them to open the app here."] })) : sentTo === null ? (_jsxs(_Fragment, { children: [_jsxs("p", { className: "muted", children: ["Choose the email to sign in with at ", dashboard, ", to work on this store without opening Shopify admin. Anyone who can read that inbox will be able to sign in, and it cannot be changed from here later."] }), _jsxs("form", { onSubmit: onEmail, className: "fields stacked", children: [_jsxs("label", { children: ["Email", _jsx("input", { type: "email", name: "email", autoComplete: "email", required: true, value: email, onChange: (event) => setEmail(event.target.value) })] }), _jsx("button", { type: "submit", className: "primary", disabled: send.isPending, children: "Send a code" }), send.error && _jsx("p", { role: "alert", children: send.error.message })] })] })) : (_jsxs("form", { onSubmit: onCode, className: "fields stacked", children: [_jsxs("p", { children: ["We sent an ", CODE_LENGTH, "-digit code to ", _jsx("strong", { children: sentTo }), ". Enter it to show the address is yours. It works once, for ", SIGN_IN_CODE_MINUTES, " minutes."] }), _jsxs("label", { children: ["Code", _jsx("input", { inputMode: "numeric", autoComplete: "one-time-code", pattern: `[0-9]{${CODE_LENGTH}}`, maxLength: CODE_LENGTH, required: true, autoFocus: true, value: code, onChange: (event) => setCode(event.target.value.replace(/\D/g, '')) })] }), _jsx("button", { type: "submit", className: "primary", disabled: confirm.isPending, children: "Confirm email" }), confirm.error && _jsx("p", { role: "alert", children: confirm.error.message }), send.error && _jsx("p", { role: "alert", children: send.error.message }), _jsxs("p", { className: "row", children: [_jsx("button", { type: "button", className: "quiet", disabled: send.isPending, onClick: () => {
60
+ return (_jsxs("section", { className: "panel", children: [_jsx("h2", { children: "Sign in outside Shopify" }), current.data.email ? (_jsxs("p", { children: ["Sign in at ", dashboard, " as ", _jsx("strong", { children: current.data.email }), " to work on this store without opening Shopify admin. There is no password: a code is emailed to that address each time."] })) : !current.data.canCreate ? (_jsxs("p", { className: "muted", children: ["Only the owner of this store's Shopify account can create an email sign-in for the dashboard at ", dashboard, ". Ask them to open the app here."] })) : sentTo === null ? (_jsxs(_Fragment, { children: [_jsxs("p", { className: "muted", children: ["Choose the email to sign in with at ", dashboard, ", to work on this store without opening Shopify admin. Anyone who can read that inbox will be able to sign in, and it cannot be changed from here later."] }), _jsxs("form", { onSubmit: onEmail, className: "fields stacked", children: [_jsxs("label", { children: ["Email", _jsx("input", { type: "email", name: "email", autoComplete: "email", required: true, value: email, onChange: (event) => setEmail(event.target.value) })] }), _jsx("button", { type: "submit", className: "primary", disabled: send.isPending, children: "Send a code" }), send.error && _jsx("p", { role: "alert", children: send.error.message })] })] })) : (_jsxs("form", { onSubmit: onCode, className: "fields stacked", children: [_jsxs("p", { children: ["We sent an ", CODE_LENGTH, "-digit code to ", _jsx("strong", { children: sentTo }), ". Enter it to show the address is yours. It works once, for ", SIGN_IN_CODE_MINUTES, " minutes."] }), _jsxs("label", { children: ["Code", _jsx("input", { inputMode: "numeric", autoComplete: "one-time-code", pattern: `[0-9]{${CODE_LENGTH}}`, maxLength: CODE_LENGTH, required: true, autoFocus: true, value: code, onChange: (event) => setCode(event.target.value.replace(/\D/g, '')) })] }), _jsx("button", { type: "submit", className: "primary", disabled: confirm.isPending, children: "Confirm email" }), confirm.error && _jsx("p", { role: "alert", children: confirm.error.message }), send.error && _jsx("p", { role: "alert", children: send.error.message }), _jsxs("p", { className: "row", children: [_jsx("button", { type: "button", className: "quiet", disabled: send.isPending || wait.left > 0, onClick: () => {
58
61
  confirm.reset();
59
62
  send.mutate(sentTo);
60
- }, children: "Send a new code" }), _jsx("button", { type: "button", className: "quiet", onClick: () => {
63
+ }, children: resendLabel(wait.left) }), _jsx("button", { type: "button", className: "quiet", onClick: () => {
61
64
  confirm.reset();
62
65
  send.reset();
63
66
  setSentTo(null);
@@ -1 +1 @@
1
- {"version":3,"file":"EmailSignInPanel.js","sourceRoot":"","sources":["../../src/client/EmailSignInPanel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EmailSignInPanel.js","sourceRoot":"","sources":["../../src/client/EmailSignInPanel.tsx"],"names":[],"mappings":"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"}
@@ -16,8 +16,16 @@ export interface SignInClient {
16
16
  * separate registration. `aside` is the app's own panel beside the form: its logo and what
17
17
  * it does.
18
18
  */
19
- export declare function LoginPage({ client, aside, meKey, }: {
19
+ export declare function LoginPage({ client, aside, meKey, accent, glow, legal, }: {
20
20
  client: SignInClient;
21
21
  aside: ReactNode;
22
22
  meKey?: QueryKey;
23
+ /** The app's colour: the button, links and focus ring. */
24
+ accent?: string;
25
+ /** The panel's glow; the accent when not given. */
26
+ glow?: string;
27
+ legal?: {
28
+ terms: string;
29
+ privacy: string;
30
+ };
23
31
  }): ReactElement;
@@ -1,7 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMutation, useQueryClient } from '@tanstack/react-query';
3
+ import { resendLabel, useResendWait } from './resend-wait.js';
3
4
  import { SIGN_IN_CODE_DIGITS, SIGN_IN_CODE_MINUTES } from '@haatlabs-core/auth-contracts';
4
5
  import { useState } from 'react';
6
+ import { SIGN_IN_CSS } from './sign-in-styles.js';
5
7
  import { ApiError } from './transport.js';
6
8
  const CODE_LENGTH = SIGN_IN_CODE_DIGITS;
7
9
  /**
@@ -10,12 +12,13 @@ const CODE_LENGTH = SIGN_IN_CODE_DIGITS;
10
12
  * separate registration. `aside` is the app's own panel beside the form: its logo and what
11
13
  * it does.
12
14
  */
13
- export function LoginPage({ client, aside, meKey = ['me'], }) {
15
+ export function LoginPage({ client, aside, meKey = ['me'], accent = '#2447d6', glow, legal = { terms: 'https://haatlabs.shop/terms/', privacy: 'https://haatlabs.shop/privacy/' }, }) {
14
16
  const queryClient = useQueryClient();
15
17
  const [email, setEmail] = useState('');
16
18
  const [code, setCode] = useState('');
17
19
  /** The email a code was sent to; null while the email is still being typed. */
18
20
  const [sentTo, setSentTo] = useState(null);
21
+ const wait = useResendWait();
19
22
  const send = useMutation({
20
23
  mutationFn: (to) => client.requestSignInCode({ email: to }),
21
24
  meta: { skipSessionReset: true },
@@ -25,6 +28,7 @@ export function LoginPage({ client, aside, meKey = ['me'], }) {
25
28
  onSuccess: (_result, to) => {
26
29
  setSentTo(to);
27
30
  setCode('');
31
+ wait.start();
28
32
  },
29
33
  });
30
34
  const signIn = useMutation({
@@ -41,17 +45,17 @@ export function LoginPage({ client, aside, meKey = ['me'], }) {
41
45
  event.preventDefault();
42
46
  signIn.mutate();
43
47
  };
44
- return (_jsxs("div", { className: "auth", children: [aside, _jsxs("main", { children: [_jsx("h1", { children: "Sign in" }), sentTo === null ? (_jsxs("form", { onSubmit: onEmail, children: [_jsxs("label", { children: ["Email", _jsx("input", { type: "email", autoComplete: "email", required: true, value: email, onChange: (e) => setEmail(e.target.value) })] }), _jsx("button", { type: "submit", disabled: send.isPending, children: "Send me a code" }), send.error && _jsx("p", { role: "alert", children: send.error.message }), send.error instanceof ApiError && send.error.code === 'RATE_LIMITED' && (_jsx("button", { type: "button", className: "link", disabled: email.trim() === '', onClick: () => {
45
- send.reset();
46
- setSentTo(email.trim());
47
- setCode('');
48
- }, children: "I already have a code" }))] })) : (_jsxs("form", { onSubmit: onCode, children: [_jsxs("p", { children: ["We sent an ", CODE_LENGTH, "-digit code to ", _jsx("strong", { children: sentTo }), ". It works once, for", ' ', SIGN_IN_CODE_MINUTES, " minutes."] }), _jsxs("label", { children: ["Code", _jsx("input", { inputMode: "numeric", autoComplete: "one-time-code", pattern: `[0-9]{${CODE_LENGTH}}`, maxLength: CODE_LENGTH, required: true, autoFocus: true, value: code, onChange: (e) => setCode(e.target.value.replace(/\D/g, '')) })] }), _jsx("button", { type: "submit", disabled: signIn.isPending, children: "Sign in" }), signIn.error && _jsx("p", { role: "alert", children: signIn.error.message }), send.error && _jsx("p", { role: "alert", children: send.error.message }), _jsxs("p", { className: "row", children: [_jsx("button", { type: "button", className: "link", disabled: send.isPending, onClick: () => {
49
- signIn.reset();
50
- send.mutate(sentTo);
51
- }, children: "Send a new code" }), _jsx("button", { type: "button", className: "link", onClick: () => {
52
- signIn.reset();
53
- send.reset();
54
- setSentTo(null);
55
- }, children: "Use another email" })] })] }))] })] }));
48
+ return (_jsxs("div", { className: "auth hl-auth", style: { '--auth-accent': accent, '--auth-glow': glow ?? accent }, children: [_jsx("style", { children: SIGN_IN_CSS }), aside, _jsx("main", { className: "hl-auth__main", children: _jsxs("div", { className: "hl-auth__card", children: [_jsx("h1", { children: "Sign in" }), _jsx("p", { className: "hl-auth__sub", children: "We\u2019ll email you a code. No password, and no separate sign-up." }), sentTo === null ? (_jsxs("form", { onSubmit: onEmail, children: [_jsxs("label", { children: ["Email", _jsx("input", { type: "email", autoComplete: "email", required: true, value: email, onChange: (e) => setEmail(e.target.value) })] }), _jsx("button", { type: "submit", disabled: send.isPending, children: "Send me a code" }), send.error && _jsx("p", { role: "alert", children: send.error.message }), send.error instanceof ApiError && send.error.code === 'RATE_LIMITED' && (_jsx("button", { type: "button", className: "link", disabled: email.trim() === '', onClick: () => {
49
+ send.reset();
50
+ setSentTo(email.trim());
51
+ setCode('');
52
+ }, children: "I already have a code" }))] })) : (_jsxs("form", { onSubmit: onCode, children: [_jsxs("p", { children: ["We sent an ", CODE_LENGTH, "-digit code to ", _jsx("strong", { children: sentTo }), ". It works once, for", ' ', SIGN_IN_CODE_MINUTES, " minutes."] }), _jsxs("label", { children: ["Code", _jsx("input", { inputMode: "numeric", autoComplete: "one-time-code", pattern: `[0-9]{${CODE_LENGTH}}`, maxLength: CODE_LENGTH, required: true, autoFocus: true, value: code, onChange: (e) => setCode(e.target.value.replace(/\D/g, '')) })] }), _jsx("button", { type: "submit", disabled: signIn.isPending, children: "Sign in" }), signIn.error && _jsx("p", { role: "alert", children: signIn.error.message }), send.error && _jsx("p", { role: "alert", children: send.error.message }), _jsxs("p", { className: "row", children: [_jsx("button", { type: "button", className: "link", disabled: send.isPending || wait.left > 0, onClick: () => {
53
+ signIn.reset();
54
+ send.mutate(sentTo);
55
+ }, children: resendLabel(wait.left) }), _jsx("button", { type: "button", className: "link", onClick: () => {
56
+ signIn.reset();
57
+ send.reset();
58
+ setSentTo(null);
59
+ }, children: "Use another email" })] })] })), _jsxs("p", { className: "hl-auth__fine", children: ["By continuing you agree to the ", _jsx("a", { href: legal.terms, children: "Terms" }), " and", ' ', _jsx("a", { href: legal.privacy, children: "Privacy policy" }), "."] })] }) })] }));
56
60
  }
57
61
  //# sourceMappingURL=LoginPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoginPage.js","sourceRoot":"","sources":["../../src/client/LoginPage.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LoginPage.js","sourceRoot":"","sources":["../../src/client/LoginPage.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ /**
3
+ * An app's panel beside the sign-in form: its logo, what it does as a check list, a small
4
+ * drawn preview (sample data, hidden from screen readers), trust chips and its small print.
5
+ */
6
+ export declare function SignInAside({ name, logo, kind, title, points, preview, chips, note, }: {
7
+ name: string;
8
+ logo: ReactNode;
9
+ kind?: string;
10
+ title: string;
11
+ points: string[];
12
+ preview?: {
13
+ title: string;
14
+ rows: [string, string][];
15
+ };
16
+ chips?: string[];
17
+ note?: ReactNode;
18
+ }): ReactElement;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const CHIPS = ['No password', 'Free plan to start', 'Hosted in India'];
3
+ /**
4
+ * An app's panel beside the sign-in form: its logo, what it does as a check list, a small
5
+ * drawn preview (sample data, hidden from screen readers), trust chips and its small print.
6
+ */
7
+ export function SignInAside({ name, logo, kind = 'Shopify app', title, points, preview, chips = CHIPS, note, }) {
8
+ return (_jsxs("section", { className: "hl-auth__panel", "aria-label": `About ${name}`, children: [_jsx("div", { children: logo }), _jsxs("div", { children: [_jsx("span", { className: "hl-auth__kind", children: kind }), _jsx("h2", { children: title }), _jsx("ul", { className: "hl-auth__points", children: points.map((point) => (_jsx("li", { children: point }, point))) }), preview ? (_jsxs("div", { className: "hl-auth__preview", "aria-hidden": "true", children: [_jsx("p", { children: preview.title }), _jsx("dl", { children: preview.rows.map(([label, value]) => (_jsxs("div", { children: [_jsx("dt", { children: label }), _jsx("dd", { children: value })] }, label))) }), _jsx("small", { children: "Sample data" })] })) : null, chips.length > 0 ? (_jsx("div", { className: "hl-auth__chips", children: chips.map((chip) => (_jsx("span", { children: chip }, chip))) })) : null] }), note ? _jsx("p", { className: "hl-auth__note", children: note }) : null] }));
9
+ }
10
+ //# sourceMappingURL=SignInAside.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignInAside.js","sourceRoot":"","sources":["../../src/client/SignInAside.tsx"],"names":[],"mappings":";AAEA,MAAM,KAAK,GAAG,CAAC,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,CAAC,CAAC;AAEvE;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAI,EACJ,IAAI,GAAG,aAAa,EACpB,KAAK,EACL,MAAM,EACN,OAAO,EACP,KAAK,GAAG,KAAK,EACb,IAAI,GAUL;IACC,OAAO,CACL,mBAAS,SAAS,EAAC,gBAAgB,gBAAa,SAAS,IAAI,EAAE,aAC7D,wBAAM,IAAI,GAAO,EACjB,0BACE,eAAM,SAAS,EAAC,eAAe,YAAE,IAAI,GAAQ,EAC7C,uBAAK,KAAK,GAAM,EAChB,aAAI,SAAS,EAAC,iBAAiB,YAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,uBAAiB,KAAK,IAAb,KAAK,CAAc,CAC7B,CAAC,GACC,EACJ,OAAO,CAAC,CAAC,CAAC,CACT,eAAK,SAAS,EAAC,kBAAkB,iBAAa,MAAM,aAClD,sBAAI,OAAO,CAAC,KAAK,GAAK,EACtB,uBACG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CACpC,0BACE,uBAAK,KAAK,GAAM,EAChB,uBAAK,KAAK,GAAM,KAFR,KAAK,CAGT,CACP,CAAC,GACC,EACL,0CAA0B,IACtB,CACP,CAAC,CAAC,CAAC,IAAI,EACP,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAClB,cAAK,SAAS,EAAC,gBAAgB,YAC5B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,yBAAkB,IAAI,IAAX,IAAI,CAAe,CAC/B,CAAC,GACE,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,EACL,IAAI,CAAC,CAAC,CAAC,YAAG,SAAS,EAAC,eAAe,YAAE,IAAI,GAAK,CAAC,CAAC,CAAC,IAAI,IAC9C,CACX,CAAC;AACJ,CAAC"}
@@ -2,6 +2,8 @@ export { EmailSignInPanel } from './EmailSignInPanel.js';
2
2
  export type { EmailSignInClient } from './EmailSignInPanel.js';
3
3
  export { LoginPage } from './LoginPage.js';
4
4
  export type { SignInClient } from './LoginPage.js';
5
+ export { SignInAside } from './SignInAside.js';
6
+ export { SIGN_IN_CSS } from './sign-in-styles.js';
5
7
  export { createQueryClient, isUnauthorized, shouldRetry } from './query-client.js';
6
8
  export { ApiError, OkSchema, cookieCredentials, createTransport, readCookie } from './transport.js';
7
9
  export type { CredentialStrategy, Method, Transport } from './transport.js';
@@ -1,5 +1,7 @@
1
1
  export { EmailSignInPanel } from './EmailSignInPanel.js';
2
2
  export { LoginPage } from './LoginPage.js';
3
+ export { SignInAside } from './SignInAside.js';
4
+ export { SIGN_IN_CSS } from './sign-in-styles.js';
3
5
  export { createQueryClient, isUnauthorized, shouldRetry } from './query-client.js';
4
6
  export { ApiError, OkSchema, cookieCredentials, createTransport, readCookie } from './transport.js';
5
7
  export { UsagePage } from './UsagePage.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEpG,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEpG,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** Seconds before "Send a new code" works again: each code is an email, and emails are counted. */
2
+ export declare const RESEND_WAIT_SECONDS = 60;
3
+ /** The wait after a code was sent: seconds left (0 when a new one may be asked for) and a restart. */
4
+ export declare function useResendWait(): {
5
+ left: number;
6
+ start: () => void;
7
+ };
8
+ /** "Send a new code", or "Send a new code in 0:45" while waiting. */
9
+ export declare const resendLabel: (left: number) => string;
@@ -0,0 +1,27 @@
1
+ import { useEffect, useState } from 'react';
2
+ /** Seconds before "Send a new code" works again: each code is an email, and emails are counted. */
3
+ export const RESEND_WAIT_SECONDS = 60;
4
+ /** The wait after a code was sent: seconds left (0 when a new one may be asked for) and a restart. */
5
+ export function useResendWait() {
6
+ const [until, setUntil] = useState(0);
7
+ const [now, setNow] = useState(() => Date.now());
8
+ useEffect(() => {
9
+ if (until <= now)
10
+ return undefined;
11
+ const timer = setInterval(() => setNow(Date.now()), 1000);
12
+ return () => clearInterval(timer);
13
+ }, [until, now]);
14
+ return {
15
+ left: Math.max(0, Math.ceil((until - now) / 1000)),
16
+ start: () => {
17
+ const at = Date.now();
18
+ setNow(at);
19
+ setUntil(at + RESEND_WAIT_SECONDS * 1000);
20
+ },
21
+ };
22
+ }
23
+ /** "Send a new code", or "Send a new code in 0:45" while waiting. */
24
+ export const resendLabel = (left) => left > 0
25
+ ? `Send a new code in ${Math.floor(left / 60)}:${String(left % 60).padStart(2, '0')}`
26
+ : 'Send a new code';
27
+ //# sourceMappingURL=resend-wait.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resend-wait.js","sourceRoot":"","sources":["../../src/client/resend-wait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,mGAAmG;AACnG,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,sGAAsG;AACtG,MAAM,UAAU,aAAa;IAC3B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,IAAI,GAAG;YAAE,OAAO,SAAS,CAAC;QACnC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAC1D,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IACjB,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QAClD,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACtB,MAAM,CAAC,EAAE,CAAC,CAAC;YACX,QAAQ,CAAC,EAAE,GAAG,mBAAmB,GAAG,IAAI,CAAC,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE,CAClD,IAAI,GAAG,CAAC;IACN,CAAC,CAAC,sBAAsB,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;IACrF,CAAC,CAAC,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The sign-in page's look, shared by every app so they cannot drift apart. It is rendered as
3
+ * a <style> element by LoginPage; everything is scoped under `.hl-auth`. An app sets its
4
+ * colour with LoginPage's `accent` (and optional `glow`).
5
+ */
6
+ export declare const SIGN_IN_CSS = "\n.hl-auth { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); margin: 0; }\n.hl-auth__panel { position: relative; overflow: hidden; background: #0d1020; color: #fff; padding: 44px 48px; display: flex; flex-direction: column; justify-content: space-between; gap: 36px; }\n.hl-auth__panel::before { content: ''; position: absolute; top: -30%; right: -40%; width: 620px; height: 620px; border-radius: 50%; background: radial-gradient(closest-side, color-mix(in srgb, var(--auth-glow) 45%, transparent), transparent); pointer-events: none; }\n.hl-auth__panel > * { position: relative; }\n.hl-auth__kind { display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: #c7d0ff; background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.12); padding: 4px 10px; border-radius: 999px; }\n.hl-auth__panel h2 { font-size: 34px; line-height: 1.12; letter-spacing: -.02em; margin: 14px 0 0; max-width: 460px; color: #fff; }\n.hl-auth__points { list-style: none; padding: 0; margin: 22px 0 0; display: flex; flex-direction: column; gap: 12px; max-width: 460px; color: #d9ddf2; font-size: 15.5px; line-height: 1.5; }\n.hl-auth__points li { display: grid; grid-template-columns: 22px 1fr; gap: 10px; margin: 0; }\n.hl-auth__points li::before { content: '\u2713'; width: 22px; height: 22px; border-radius: 50%; background: color-mix(in srgb, var(--auth-glow) 30%, transparent); color: #fff; font-size: 12px; font-weight: 800; display: grid; place-items: center; margin-top: 1px; }\n.hl-auth__preview { margin-top: 26px; max-width: 420px; border: 1px solid rgba(255,255,255,.12); border-radius: 14px; background: rgba(255,255,255,.04); padding: 14px 16px; }\n.hl-auth__preview p { margin: 0 0 6px; font: 600 12px ui-monospace, SFMono-Regular, Menlo, monospace; color: #9aa3c7; }\n.hl-auth__preview dl { margin: 0; }\n.hl-auth__preview dl > div { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-top: 1px solid rgba(255,255,255,.08); font-size: 14px; }\n.hl-auth__preview dt { color: #9aa3c7; }\n.hl-auth__preview dd { margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-align: right; }\n.hl-auth__preview small { display: block; text-align: right; color: #7d86ab; font-size: 11px; margin-top: 6px; }\n.hl-auth__chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }\n.hl-auth__chips span { font-size: 12.5px; color: #d9ddf2; border: 1px solid rgba(255,255,255,.14); border-radius: 999px; padding: 5px 11px; }\n.hl-auth__note { color: #8e96b8; font-size: 13px; max-width: 460px; margin: 0; }\n.hl-auth__main { background: #f5f6fa; display: grid; place-items: center; padding: 48px 24px; margin: 0; max-width: none; }\n.hl-auth__card { width: 100%; max-width: 420px; background: #fff; border: 1px solid #e6e8f0; border-radius: 18px; box-shadow: 0 20px 50px rgba(20,24,60,.08); padding: 36px; color: #15171c; }\n.hl-auth__card h1 { margin: 0; font-size: 30px; letter-spacing: -.02em; }\n.hl-auth__sub { margin: 8px 0 26px; color: #5a6075; font-size: 15px; }\n.hl-auth__card form { display: flex; flex-direction: column; gap: 16px; background: transparent; border: 0; padding: 0; margin: 0; }\n.hl-auth__card form > p { margin: 0; color: #30343f; font-size: 15px; }\n.hl-auth__card label { display: flex; flex-direction: column; gap: 8px; font-size: 14px; font-weight: 600; color: #30343f; }\n.hl-auth__card input { height: 50px; border: 1.5px solid #d7dbe7; border-radius: 12px; padding: 0 14px; font: inherit; font-size: 16px; background: #fff; color: #15171c; }\n.hl-auth__card input:focus { outline: none; border-color: var(--auth-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--auth-accent) 18%, transparent); }\n.hl-auth__card button[type='submit'] { width: 100%; height: 50px; border: 0; border-radius: 12px; background: var(--auth-accent); color: #fff; font: inherit; font-size: 16px; font-weight: 700; cursor: pointer; }\n.hl-auth__card button[type='submit']:disabled { opacity: .6; cursor: default; }\n.hl-auth__card button:focus-visible, .hl-auth__card a:focus-visible { outline: 3px solid var(--auth-accent); outline-offset: 2px; }\n.hl-auth__card button.link { border: 0; background: transparent; padding: 0; color: var(--auth-accent); font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; min-height: 44px; }\n.hl-auth__card .row { display: flex; flex-wrap: wrap; gap: 4px 20px; }\n.hl-auth__card [role='alert'] { margin: 0; color: #b42318; font-size: 14px; }\n.hl-auth__fine { margin: 18px 0 0; color: #6b7186; font-size: 13px; line-height: 1.5; }\n.hl-auth__fine a { color: var(--auth-accent); font-weight: 600; }\n@media (max-width: 860px) {\n .hl-auth { grid-template-columns: minmax(0, 1fr); }\n .hl-auth__panel { padding: 32px 24px; gap: 24px; }\n .hl-auth__panel h2 { font-size: 26px; }\n .hl-auth__preview, .hl-auth__note { display: none; }\n .hl-auth__card { padding: 24px; }\n}\n";
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The sign-in page's look, shared by every app so they cannot drift apart. It is rendered as
3
+ * a <style> element by LoginPage; everything is scoped under `.hl-auth`. An app sets its
4
+ * colour with LoginPage's `accent` (and optional `glow`).
5
+ */
6
+ export const SIGN_IN_CSS = `
7
+ .hl-auth { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); margin: 0; }
8
+ .hl-auth__panel { position: relative; overflow: hidden; background: #0d1020; color: #fff; padding: 44px 48px; display: flex; flex-direction: column; justify-content: space-between; gap: 36px; }
9
+ .hl-auth__panel::before { content: ''; position: absolute; top: -30%; right: -40%; width: 620px; height: 620px; border-radius: 50%; background: radial-gradient(closest-side, color-mix(in srgb, var(--auth-glow) 45%, transparent), transparent); pointer-events: none; }
10
+ .hl-auth__panel > * { position: relative; }
11
+ .hl-auth__kind { display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: #c7d0ff; background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.12); padding: 4px 10px; border-radius: 999px; }
12
+ .hl-auth__panel h2 { font-size: 34px; line-height: 1.12; letter-spacing: -.02em; margin: 14px 0 0; max-width: 460px; color: #fff; }
13
+ .hl-auth__points { list-style: none; padding: 0; margin: 22px 0 0; display: flex; flex-direction: column; gap: 12px; max-width: 460px; color: #d9ddf2; font-size: 15.5px; line-height: 1.5; }
14
+ .hl-auth__points li { display: grid; grid-template-columns: 22px 1fr; gap: 10px; margin: 0; }
15
+ .hl-auth__points li::before { content: '✓'; width: 22px; height: 22px; border-radius: 50%; background: color-mix(in srgb, var(--auth-glow) 30%, transparent); color: #fff; font-size: 12px; font-weight: 800; display: grid; place-items: center; margin-top: 1px; }
16
+ .hl-auth__preview { margin-top: 26px; max-width: 420px; border: 1px solid rgba(255,255,255,.12); border-radius: 14px; background: rgba(255,255,255,.04); padding: 14px 16px; }
17
+ .hl-auth__preview p { margin: 0 0 6px; font: 600 12px ui-monospace, SFMono-Regular, Menlo, monospace; color: #9aa3c7; }
18
+ .hl-auth__preview dl { margin: 0; }
19
+ .hl-auth__preview dl > div { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-top: 1px solid rgba(255,255,255,.08); font-size: 14px; }
20
+ .hl-auth__preview dt { color: #9aa3c7; }
21
+ .hl-auth__preview dd { margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-align: right; }
22
+ .hl-auth__preview small { display: block; text-align: right; color: #7d86ab; font-size: 11px; margin-top: 6px; }
23
+ .hl-auth__chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
24
+ .hl-auth__chips span { font-size: 12.5px; color: #d9ddf2; border: 1px solid rgba(255,255,255,.14); border-radius: 999px; padding: 5px 11px; }
25
+ .hl-auth__note { color: #8e96b8; font-size: 13px; max-width: 460px; margin: 0; }
26
+ .hl-auth__main { background: #f5f6fa; display: grid; place-items: center; padding: 48px 24px; margin: 0; max-width: none; }
27
+ .hl-auth__card { width: 100%; max-width: 420px; background: #fff; border: 1px solid #e6e8f0; border-radius: 18px; box-shadow: 0 20px 50px rgba(20,24,60,.08); padding: 36px; color: #15171c; }
28
+ .hl-auth__card h1 { margin: 0; font-size: 30px; letter-spacing: -.02em; }
29
+ .hl-auth__sub { margin: 8px 0 26px; color: #5a6075; font-size: 15px; }
30
+ .hl-auth__card form { display: flex; flex-direction: column; gap: 16px; background: transparent; border: 0; padding: 0; margin: 0; }
31
+ .hl-auth__card form > p { margin: 0; color: #30343f; font-size: 15px; }
32
+ .hl-auth__card label { display: flex; flex-direction: column; gap: 8px; font-size: 14px; font-weight: 600; color: #30343f; }
33
+ .hl-auth__card input { height: 50px; border: 1.5px solid #d7dbe7; border-radius: 12px; padding: 0 14px; font: inherit; font-size: 16px; background: #fff; color: #15171c; }
34
+ .hl-auth__card input:focus { outline: none; border-color: var(--auth-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--auth-accent) 18%, transparent); }
35
+ .hl-auth__card button[type='submit'] { width: 100%; height: 50px; border: 0; border-radius: 12px; background: var(--auth-accent); color: #fff; font: inherit; font-size: 16px; font-weight: 700; cursor: pointer; }
36
+ .hl-auth__card button[type='submit']:disabled { opacity: .6; cursor: default; }
37
+ .hl-auth__card button:focus-visible, .hl-auth__card a:focus-visible { outline: 3px solid var(--auth-accent); outline-offset: 2px; }
38
+ .hl-auth__card button.link { border: 0; background: transparent; padding: 0; color: var(--auth-accent); font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; min-height: 44px; }
39
+ .hl-auth__card .row { display: flex; flex-wrap: wrap; gap: 4px 20px; }
40
+ .hl-auth__card [role='alert'] { margin: 0; color: #b42318; font-size: 14px; }
41
+ .hl-auth__fine { margin: 18px 0 0; color: #6b7186; font-size: 13px; line-height: 1.5; }
42
+ .hl-auth__fine a { color: var(--auth-accent); font-weight: 600; }
43
+ @media (max-width: 860px) {
44
+ .hl-auth { grid-template-columns: minmax(0, 1fr); }
45
+ .hl-auth__panel { padding: 32px 24px; gap: 24px; }
46
+ .hl-auth__panel h2 { font-size: 26px; }
47
+ .hl-auth__preview, .hl-auth__note { display: none; }
48
+ .hl-auth__card { padding: 24px; }
49
+ }
50
+ `;
51
+ //# sourceMappingURL=sign-in-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-in-styles.js","sourceRoot":"","sources":["../../src/client/sign-in-styles.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haatlabs-core/ui",
3
- "version": "0.12.3",
3
+ "version": "0.12.5",
4
4
  "description": "React components for an app's dashboard, styled by the app.",
5
5
  "keywords": [
6
6
  "haatlabs",
@@ -67,11 +67,11 @@
67
67
  "react-router-dom": "^7.18.4",
68
68
  "@tanstack/react-query": "^5.104.1",
69
69
  "zod": "^4.6.5",
70
- "@haatlabs-core/tsconfig": "0.12.3",
71
- "@haatlabs-core/vitest-config": "0.12.3"
70
+ "@haatlabs-core/vitest-config": "0.12.5",
71
+ "@haatlabs-core/tsconfig": "0.12.5"
72
72
  },
73
73
  "dependencies": {
74
- "@haatlabs-core/auth-contracts": "0.12.3"
74
+ "@haatlabs-core/auth-contracts": "0.12.5"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "rm -rf dist && tsc -p tsconfig.build.json",