@clicoh/orion-library 1.2.0-beta.16 → 1.2.0-beta.18

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 (31) hide show
  1. package/dist/components/04-templates/LoginTemplate/LoginForm.d.ts +66 -3
  2. package/dist/components/04-templates/LoginTemplate/LoginForm.d.ts.map +1 -1
  3. package/dist/components/04-templates/LoginTemplate/LoginForm.jsx +80 -16
  4. package/dist/components/04-templates/LoginTemplate/LoginForm.jsx.map +1 -1
  5. package/dist/components/04-templates/LoginTemplate/LoginTemplate.d.ts +22 -4
  6. package/dist/components/04-templates/LoginTemplate/LoginTemplate.d.ts.map +1 -1
  7. package/dist/components/04-templates/LoginTemplate/LoginTemplate.jsx +26 -7
  8. package/dist/components/04-templates/LoginTemplate/LoginTemplate.jsx.map +1 -1
  9. package/dist/components/04-templates/LoginTemplate/index.d.ts +1 -0
  10. package/dist/components/04-templates/LoginTemplate/index.d.ts.map +1 -1
  11. package/expresivo/ExpEnterIcon/ExpEnterIcon.d.ts +32 -0
  12. package/expresivo/ExpEnterIcon/ExpEnterIcon.d.ts.map +1 -0
  13. package/expresivo/ExpEnterIcon/ExpEnterIcon.jsx +32 -0
  14. package/expresivo/ExpEnterIcon/ExpEnterIcon.jsx.map +1 -0
  15. package/expresivo/ExpEnterIcon/index.d.ts +3 -0
  16. package/expresivo/ExpEnterIcon/index.d.ts.map +1 -0
  17. package/expresivo/ExpEnterIcon/index.js +2 -0
  18. package/expresivo/ExpEnterIcon/index.js.map +1 -0
  19. package/expresivo/ExpPeek/ExpPeek.d.ts +56 -0
  20. package/expresivo/ExpPeek/ExpPeek.d.ts.map +1 -0
  21. package/expresivo/ExpPeek/ExpPeek.jsx +131 -0
  22. package/expresivo/ExpPeek/ExpPeek.jsx.map +1 -0
  23. package/expresivo/ExpPeek/index.d.ts +3 -0
  24. package/expresivo/ExpPeek/index.d.ts.map +1 -0
  25. package/expresivo/ExpPeek/index.js +2 -0
  26. package/expresivo/ExpPeek/index.js.map +1 -0
  27. package/expresivo/index.d.ts +2 -0
  28. package/expresivo/index.d.ts.map +1 -1
  29. package/expresivo/index.js +2 -0
  30. package/expresivo/index.js.map +1 -1
  31. package/package.json +1 -1
@@ -1,5 +1,21 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { type SetupMfaAccessibilityLabels } from './SetupMfa';
3
+ /** Copy of the form. Each one falls back to the original Spanish text. */
4
+ export type LoginFormLabels = {
5
+ username?: string;
6
+ password?: string;
7
+ code?: string;
8
+ submit?: string;
9
+ back?: string;
10
+ };
11
+ /** What `renderSubmit` receives to draw its own submit button. */
12
+ export type LoginFormSubmitState = {
13
+ /** `true` while `login` runs. */
14
+ pending: boolean;
15
+ /** `labels.submit`, or its default. */
16
+ label: string;
17
+ };
18
+ export type LoginFormErrorStyle = 'text' | 'message';
3
19
  type LoginFormProps = {
4
20
  login: (formData: FormData) => Promise<string | undefined>;
5
21
  callback?: () => void;
@@ -12,21 +28,68 @@ type LoginFormProps = {
12
28
  getOtpDigitAriaLabel?: (digit: number) => string;
13
29
  loadingLabel?: string;
14
30
  setupMfaAccessibilityLabels?: SetupMfaAccessibilityLabels;
31
+ title?: ReactNode;
32
+ description?: ReactNode;
33
+ labels?: LoginFormLabels;
34
+ forgotPassword?: ReactNode;
35
+ footer?: ReactNode;
36
+ renderSubmit?: (state: LoginFormSubmitState) => ReactNode;
37
+ errorStyle?: LoginFormErrorStyle;
38
+ toastErrors?: boolean;
39
+ showSpinner?: boolean;
15
40
  };
16
41
  /**
17
- * LoginForm component for rendering a login form with email and password inputs.
42
+ * LoginForm component for rendering a login form with email and password
43
+ * inputs, the verification code step and the MFA setup wizard.
44
+ *
45
+ * Every prop after `setupMfaAccessibilityLabels` is optional and keeps the
46
+ * original look when left out.
18
47
  *
19
48
  * @component
20
49
  * @example
21
50
  * // Example usage of LoginForm component
22
51
  * <LoginForm login={yourLoginFunction} callback={yourCallbackFunction} />
23
52
  *
53
+ * @example
54
+ * // Own copy, a recovery link, the error above the button and a custom submit
55
+ * <LoginForm
56
+ * login={yourLoginFunction}
57
+ * title="Welcome back"
58
+ * description="Sign in with your account."
59
+ * labels={{ username: 'Email', password: 'Password', submit: 'Sign in' }}
60
+ * forgotPassword={<a href="/recover">Forgot your password?</a>}
61
+ * footer={<Paragraph size="body-2">No access? Ask your admin.</Paragraph>}
62
+ * errorStyle="message"
63
+ * toastErrors={false}
64
+ * showSpinner={false}
65
+ * renderSubmit={({ pending, label }) => (
66
+ * <Button type="submit" disabled={pending} className="w-full">{label}</Button>
67
+ * )}
68
+ * />
69
+ *
24
70
  * @param {Object} props - The properties of the LoginForm component.
25
- * @param {Function} props.login - The function to handle the login process.
71
+ * @param {Function} props.login - The function to handle the login process. Resolves with a QR image to start the MFA setup, or with nothing when done; rejects with the message to show.
26
72
  * @param {Function} [props.callback] - Optional callback function to be called after a successful login.
73
+ * @param {boolean} [props.needCode=false] - Shows the verification code step instead of the credentials.
74
+ * @param {number} [props.lengthCode=6] - Digits of the verification code.
75
+ * @param {Function} [props.setupMfa] - Receives the two codes of the MFA setup wizard.
76
+ * @param {string} [props.showPasswordAriaLabel] - Accessible name of the button that shows the password.
77
+ * @param {string} [props.hidePasswordAriaLabel] - Accessible name of the button that hides the password.
78
+ * @param {Function} [props.getOtpDigitAriaLabel] - Accessible name of each code digit.
79
+ * @param {string} [props.loadingLabel] - Accessible name of the spinner.
80
+ * @param {SetupMfaAccessibilityLabels} [props.setupMfaAccessibilityLabels] - Accessible names of the MFA setup wizard.
81
+ * @param {ReactNode} [props.title='Bienvenido!'] - Heading above the form.
82
+ * @param {ReactNode} [props.description] - Text under the heading.
83
+ * @param {LoginFormLabels} [props.labels] - Field, code and button copy.
84
+ * @param {ReactNode} [props.forgotPassword] - Content above the submit button on the credentials step, such as a password recovery link.
85
+ * @param {ReactNode} [props.footer] - Content under the form, on the credentials and code steps.
86
+ * @param {Function} [props.renderSubmit] - Draws the submit button instead of the default one. It must render a `type="submit"` button.
87
+ * @param {'text' | 'message'} [props.errorStyle='text'] - `text` shows the error as red text under the buttons; `message` as an error `InlineMessage` above the submit button.
88
+ * @param {boolean} [props.toastErrors=true] - Also shows each error in a toast.
89
+ * @param {boolean} [props.showSpinner=true] - Shows a spinner under the form while `login` runs. Turn it off when `renderSubmit` already shows the wait.
27
90
  *
28
91
  * @returns {ReactNode} The rendered LoginForm component.
29
92
  */
30
- export declare function LoginForm({ login, callback, needCode, lengthCode, setupMfa, showPasswordAriaLabel, hidePasswordAriaLabel, getOtpDigitAriaLabel, loadingLabel, setupMfaAccessibilityLabels, }: LoginFormProps): ReactNode;
93
+ export declare function LoginForm({ login, callback, needCode, lengthCode, setupMfa, showPasswordAriaLabel, hidePasswordAriaLabel, getOtpDigitAriaLabel, loadingLabel, setupMfaAccessibilityLabels, title, description, labels, forgotPassword, footer, renderSubmit, errorStyle, toastErrors, showSpinner, }: LoginFormProps): ReactNode;
31
94
  export {};
32
95
  //# sourceMappingURL=LoginForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginForm.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAoB,SAAS,EAAuB,MAAM,OAAO,CAAC;AAWzE,OAAO,EAAY,KAAK,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAExE,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;CAC3D,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,UAAc,EACd,QAAQ,EACR,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,2BAA2B,GAC5B,EAAE,cAAc,GAAG,SAAS,CAwI5B"}
1
+ {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginForm.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAoB,SAAS,EAAuB,MAAM,OAAO,CAAC;AAYzE,OAAO,EAAY,KAAK,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAExE,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG;IACjC,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAAC;AAErD,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACzE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,SAAS,CAAC;IAC1D,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAUF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,UAAc,EACd,QAAQ,EACR,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,2BAA2B,EAC3B,KAAqB,EACrB,WAAW,EACX,MAAM,EACN,cAAc,EACd,MAAM,EACN,YAAY,EACZ,UAAmB,EACnB,WAAkB,EAClB,WAAkB,GACnB,EAAE,cAAc,GAAG,SAAS,CAkK5B"}
@@ -3,33 +3,81 @@ import clsx from 'clsx';
3
3
  import { useEffect, useState } from 'react';
4
4
  import { FiArrowRight } from 'react-icons/fi';
5
5
  import { Button, Heading, Input, OtpInput, Paragraph, showToast, Spinner, } from '../../01-atoms';
6
+ import { InlineMessage } from '../../02-molecules';
6
7
  import { SetupMfa } from './SetupMfa';
8
+ const DEFAULT_LABELS = {
9
+ username: 'Usuario',
10
+ password: 'Contraseña',
11
+ code: 'Codigo de Verificación',
12
+ submit: 'Iniciar sesión',
13
+ back: 'Volver',
14
+ };
7
15
  /**
8
- * LoginForm component for rendering a login form with email and password inputs.
16
+ * LoginForm component for rendering a login form with email and password
17
+ * inputs, the verification code step and the MFA setup wizard.
18
+ *
19
+ * Every prop after `setupMfaAccessibilityLabels` is optional and keeps the
20
+ * original look when left out.
9
21
  *
10
22
  * @component
11
23
  * @example
12
24
  * // Example usage of LoginForm component
13
25
  * <LoginForm login={yourLoginFunction} callback={yourCallbackFunction} />
14
26
  *
27
+ * @example
28
+ * // Own copy, a recovery link, the error above the button and a custom submit
29
+ * <LoginForm
30
+ * login={yourLoginFunction}
31
+ * title="Welcome back"
32
+ * description="Sign in with your account."
33
+ * labels={{ username: 'Email', password: 'Password', submit: 'Sign in' }}
34
+ * forgotPassword={<a href="/recover">Forgot your password?</a>}
35
+ * footer={<Paragraph size="body-2">No access? Ask your admin.</Paragraph>}
36
+ * errorStyle="message"
37
+ * toastErrors={false}
38
+ * showSpinner={false}
39
+ * renderSubmit={({ pending, label }) => (
40
+ * <Button type="submit" disabled={pending} className="w-full">{label}</Button>
41
+ * )}
42
+ * />
43
+ *
15
44
  * @param {Object} props - The properties of the LoginForm component.
16
- * @param {Function} props.login - The function to handle the login process.
45
+ * @param {Function} props.login - The function to handle the login process. Resolves with a QR image to start the MFA setup, or with nothing when done; rejects with the message to show.
17
46
  * @param {Function} [props.callback] - Optional callback function to be called after a successful login.
47
+ * @param {boolean} [props.needCode=false] - Shows the verification code step instead of the credentials.
48
+ * @param {number} [props.lengthCode=6] - Digits of the verification code.
49
+ * @param {Function} [props.setupMfa] - Receives the two codes of the MFA setup wizard.
50
+ * @param {string} [props.showPasswordAriaLabel] - Accessible name of the button that shows the password.
51
+ * @param {string} [props.hidePasswordAriaLabel] - Accessible name of the button that hides the password.
52
+ * @param {Function} [props.getOtpDigitAriaLabel] - Accessible name of each code digit.
53
+ * @param {string} [props.loadingLabel] - Accessible name of the spinner.
54
+ * @param {SetupMfaAccessibilityLabels} [props.setupMfaAccessibilityLabels] - Accessible names of the MFA setup wizard.
55
+ * @param {ReactNode} [props.title='Bienvenido!'] - Heading above the form.
56
+ * @param {ReactNode} [props.description] - Text under the heading.
57
+ * @param {LoginFormLabels} [props.labels] - Field, code and button copy.
58
+ * @param {ReactNode} [props.forgotPassword] - Content above the submit button on the credentials step, such as a password recovery link.
59
+ * @param {ReactNode} [props.footer] - Content under the form, on the credentials and code steps.
60
+ * @param {Function} [props.renderSubmit] - Draws the submit button instead of the default one. It must render a `type="submit"` button.
61
+ * @param {'text' | 'message'} [props.errorStyle='text'] - `text` shows the error as red text under the buttons; `message` as an error `InlineMessage` above the submit button.
62
+ * @param {boolean} [props.toastErrors=true] - Also shows each error in a toast.
63
+ * @param {boolean} [props.showSpinner=true] - Shows a spinner under the form while `login` runs. Turn it off when `renderSubmit` already shows the wait.
18
64
  *
19
65
  * @returns {ReactNode} The rendered LoginForm component.
20
66
  */
21
- export function LoginForm({ login, callback, needCode = false, lengthCode = 6, setupMfa, showPasswordAriaLabel, hidePasswordAriaLabel, getOtpDigitAriaLabel, loadingLabel, setupMfaAccessibilityLabels, }) {
67
+ export function LoginForm({ login, callback, needCode = false, lengthCode = 6, setupMfa, showPasswordAriaLabel, hidePasswordAriaLabel, getOtpDigitAriaLabel, loadingLabel, setupMfaAccessibilityLabels, title = 'Bienvenido!', description, labels, forgotPassword, footer, renderSubmit, errorStyle = 'text', toastErrors = true, showSpinner = true, }) {
22
68
  const [errorMessage, setErrorMessage] = useState();
23
69
  const [otpCode, setOtpCode] = useState('');
24
70
  const [isPending, setIsPending] = useState(false);
25
71
  const [qr, setQr] = useState();
26
72
  const [showLogin, setShowLogin] = useState(!needCode);
73
+ const copy = { ...DEFAULT_LABELS, ...labels };
27
74
  useEffect(() => {
28
75
  setShowLogin(!needCode);
29
76
  }, [needCode]);
30
77
  const handlerSubmit = (event) => {
31
78
  event.preventDefault();
32
79
  setIsPending(true);
80
+ setErrorMessage(undefined);
33
81
  const formData = new FormData(event.currentTarget);
34
82
  if (needCode && otpCode) {
35
83
  formData.append('otpCode', otpCode);
@@ -41,7 +89,8 @@ export function LoginForm({ login, callback, needCode = false, lengthCode = 6, s
41
89
  .catch((error) => {
42
90
  const message = error instanceof Error ? error.message : String(error);
43
91
  setErrorMessage(message);
44
- showToast(message, 'error');
92
+ if (toastErrors)
93
+ showToast(message, 'error');
45
94
  })
46
95
  .finally(() => {
47
96
  setIsPending(false);
@@ -55,19 +104,30 @@ export function LoginForm({ login, callback, needCode = false, lengthCode = 6, s
55
104
  const handleSetupMfa = (firstCode, secondCode) => {
56
105
  return setupMfa?.(firstCode, secondCode);
57
106
  };
107
+ const submit = renderSubmit?.({
108
+ pending: isPending,
109
+ label: copy.submit,
110
+ }) ?? (<Button type="submit" iconR={<FiArrowRight />} aria-disabled={isPending} disabled={isPending} className="w-full">
111
+ {copy.submit}
112
+ </Button>);
58
113
  return (<>
59
114
  {!qr && (<>
60
- <Heading level="h4">Bienvenido!</Heading>
115
+ <div className="flex flex-col items-center gap-2 text-center">
116
+ <Heading level="h4">{title}</Heading>
117
+ {!!description && (<Paragraph className="text-gray-1 dark:text-gray-2 text-pretty">
118
+ {description}
119
+ </Paragraph>)}
120
+ </div>
61
121
  <form onSubmit={handlerSubmit} aria-busy={isPending} className="flex w-72 flex-col items-center gap-4">
62
122
  {!!showLogin && (<>
63
- <Input label="Usuario" input={{
123
+ <Input label={copy.username} input={{
64
124
  type: 'email',
65
125
  name: 'username',
66
126
  required: true,
67
127
  autoComplete: 'email',
68
128
  disabled: isPending,
69
129
  }}/>
70
- <Input label="Contraseña" showPasswordAriaLabel={showPasswordAriaLabel} hidePasswordAriaLabel={hidePasswordAriaLabel} input={{
130
+ <Input label={copy.password} showPasswordAriaLabel={showPasswordAriaLabel} hidePasswordAriaLabel={hidePasswordAriaLabel} input={{
71
131
  type: 'password',
72
132
  name: 'password',
73
133
  required: true,
@@ -76,21 +136,25 @@ export function LoginForm({ login, callback, needCode = false, lengthCode = 6, s
76
136
  }}/>
77
137
  </>)}
78
138
 
79
- {!showLogin && (<OtpInput label="Codigo de Verificación" length={lengthCode} handleSubmit={(otp) => setOtpCode(otp)} getDigitAriaLabel={getOtpDigitAriaLabel}/>)}
139
+ {!showLogin && (<OtpInput label={copy.code} length={lengthCode} handleSubmit={(otp) => setOtpCode(otp)} getDigitAriaLabel={getOtpDigitAriaLabel}/>)}
140
+
141
+ {errorStyle === 'message' && !!errorMessage && (<InlineMessage modifier="error" className="w-full">
142
+ {errorMessage}
143
+ </InlineMessage>)}
144
+ {!!showLogin && forgotPassword}
80
145
 
81
- <Button type="submit" iconR={<FiArrowRight />} aria-disabled={isPending} disabled={isPending} className="w-full">
82
- Iniciar sesión
83
- </Button>
146
+ {submit}
84
147
  {!showLogin && (<Button className="w-56" type="button" onClick={onCancel}>
85
- Volver
148
+ {copy.back}
86
149
  </Button>)}
87
- {!!errorMessage && (<Paragraph role="alert" className="text-error dark:text-error-1 text-center" size="chips">
150
+ {errorStyle === 'text' && !!errorMessage && (<Paragraph role="alert" className="text-error dark:text-error-1 text-center" size="chips">
88
151
  {errorMessage}
89
152
  </Paragraph>)}
90
- <div className={clsx('self-center', !isPending && 'invisible opacity-0')}>
91
- <Spinner label={loadingLabel}/>
92
- </div>
153
+ {showSpinner && (<div className={clsx('self-center', !isPending && 'invisible opacity-0')}>
154
+ <Spinner label={loadingLabel}/>
155
+ </div>)}
93
156
  </form>
157
+ {footer}
94
158
  </>)}
95
159
  {!!qr && (<SetupMfa lengthCode={lengthCode} onCancel={onCancel} qrImage={qr} setupMfa={handleSetupMfa} accessibilityLabels={setupMfaAccessibilityLabels}/>)}
96
160
  </>);
@@ -1 +1 @@
1
- {"version":3,"file":"LoginForm.jsx","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginForm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LoginForm.jsx","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginForm.tsx"],"names":[],"mappings":"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"}
@@ -1,27 +1,45 @@
1
- import type { ReactNode } from 'react';
1
+ import type { CSSProperties, ReactNode } from 'react';
2
2
  import { StaticImageData } from 'next/dist/shared/lib/get-img-props';
3
3
  type LoginTemplateProps = {
4
4
  children: ReactNode;
5
5
  loginImg?: StaticImageData;
6
6
  logoAriaLabel?: string;
7
7
  logo?: ReactNode;
8
+ aside?: ReactNode;
9
+ imagePosition?: CSSProperties['objectPosition'];
8
10
  };
9
11
  /**
10
- * LoginTemplate component for rendering the login page layout.
12
+ * LoginTemplate component for rendering the login page layout: an image on
13
+ * the left and the content on the right. On small screens only the content
14
+ * shows.
11
15
  *
12
16
  * @component
13
17
  * @example
14
18
  * // Example usage of LoginTemplate component
15
19
  * <LoginTemplate>
16
- * <LoginForm handlerLogin={yourHandlerLoginFunction} />
20
+ * <LoginForm login={yourLoginFunction} />
21
+ * </LoginTemplate>
22
+ *
23
+ * @example
24
+ * // A tagline over the image, keeping the left part of the image in view
25
+ * <LoginTemplate
26
+ * loginImg={productImage}
27
+ * imagePosition="30% 50%"
28
+ * aside={<Heading level="h4">Your tagline</Heading>}
29
+ * >
30
+ * <LoginForm login={yourLoginFunction} />
17
31
  * </LoginTemplate>
18
32
  *
19
33
  * @param {Object} props - The properties of the LoginTemplate component.
20
34
  * @param {ReactNode} props.children - The content to be rendered inside the login template.
35
+ * @param {StaticImageData} [props.loginImg] - Image on the left. Defaults to the clicOH one.
36
+ * @param {string} [props.logoAriaLabel] - Accessible name of the default clicOH logo.
21
37
  * @param {ReactNode} [props.logo=<Logo />] - Brand mark above the content. Replaces the clicOH logo, so `logoAriaLabel` no longer applies.
38
+ * @param {ReactNode} [props.aside] - Content over the bottom of the image, on a dark gradient so white text reads. White by default; hidden with the image on small screens.
39
+ * @param {string} [props.imagePosition] - CSS `object-position` of the image: the part that stays in view when it is cropped. Defaults to the center.
22
40
  *
23
41
  * @returns {ReactNode} The rendered LoginTemplate component.
24
42
  */
25
- export declare function LoginTemplate(props: LoginTemplateProps): ReactNode;
43
+ export declare function LoginTemplate({ children, loginImg, logoAriaLabel, logo, aside, imagePosition, }: LoginTemplateProps): ReactNode;
26
44
  export {};
27
45
  //# sourceMappingURL=LoginTemplate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoginTemplate.d.ts","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginTemplate.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAyBlE"}
1
+ {"version":3,"file":"LoginTemplate.d.ts","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginTemplate.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAItD,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;CACjD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,IAAI,EACJ,KAAK,EACL,aAAa,GACd,EAAE,kBAAkB,GAAG,SAAS,CA6BhC"}
@@ -3,30 +3,49 @@ import LoginImg from '../../../../assets/images/login-clicoh.jpg';
3
3
  import { Logo } from '../../01-atoms';
4
4
  import { dataUrl } from './dataUrl';
5
5
  /**
6
- * LoginTemplate component for rendering the login page layout.
6
+ * LoginTemplate component for rendering the login page layout: an image on
7
+ * the left and the content on the right. On small screens only the content
8
+ * shows.
7
9
  *
8
10
  * @component
9
11
  * @example
10
12
  * // Example usage of LoginTemplate component
11
13
  * <LoginTemplate>
12
- * <LoginForm handlerLogin={yourHandlerLoginFunction} />
14
+ * <LoginForm login={yourLoginFunction} />
15
+ * </LoginTemplate>
16
+ *
17
+ * @example
18
+ * // A tagline over the image, keeping the left part of the image in view
19
+ * <LoginTemplate
20
+ * loginImg={productImage}
21
+ * imagePosition="30% 50%"
22
+ * aside={<Heading level="h4">Your tagline</Heading>}
23
+ * >
24
+ * <LoginForm login={yourLoginFunction} />
13
25
  * </LoginTemplate>
14
26
  *
15
27
  * @param {Object} props - The properties of the LoginTemplate component.
16
28
  * @param {ReactNode} props.children - The content to be rendered inside the login template.
29
+ * @param {StaticImageData} [props.loginImg] - Image on the left. Defaults to the clicOH one.
30
+ * @param {string} [props.logoAriaLabel] - Accessible name of the default clicOH logo.
17
31
  * @param {ReactNode} [props.logo=<Logo />] - Brand mark above the content. Replaces the clicOH logo, so `logoAriaLabel` no longer applies.
32
+ * @param {ReactNode} [props.aside] - Content over the bottom of the image, on a dark gradient so white text reads. White by default; hidden with the image on small screens.
33
+ * @param {string} [props.imagePosition] - CSS `object-position` of the image: the part that stays in view when it is cropped. Defaults to the center.
18
34
  *
19
35
  * @returns {ReactNode} The rendered LoginTemplate component.
20
36
  */
21
- export function LoginTemplate(props) {
37
+ export function LoginTemplate({ children, loginImg, logoAriaLabel, logo, aside, imagePosition, }) {
22
38
  return (<div className="flex">
23
- <div className="relative min-h-svh flex-1 bg-black">
24
- <Image src={props.loginImg || LoginImg} alt="" aria-hidden="true" sizes="(max-width: 2247px) 100vw, 2247px" fill={true} className="object-cover" placeholder="blur" blurDataURL={dataUrl}/>
39
+ <div className="relative min-h-svh flex-1 overflow-hidden bg-black">
40
+ <Image src={loginImg || LoginImg} alt="" aria-hidden="true" sizes="(max-width: 2247px) 100vw, 2247px" fill={true} className="object-cover" style={imagePosition ? { objectPosition: imagePosition } : undefined} placeholder="blur" blurDataURL={dataUrl}/>
41
+ {!!aside && (<div className="absolute inset-x-0 bottom-0 flex flex-col gap-3 bg-linear-to-t from-black/90 via-black/70 to-transparent px-10 pt-32 pb-8 text-white">
42
+ {aside}
43
+ </div>)}
25
44
  </div>
26
45
  <main className="flex min-h-svh w-[460px] items-center justify-center bg-white text-black dark:bg-black dark:text-white">
27
46
  <div className="flex flex-col items-center justify-center gap-4">
28
- {props.logo ?? (<Logo width={94} height={40} aria-label={props.logoAriaLabel}/>)}
29
- {props.children}
47
+ {logo ?? <Logo width={94} height={40} aria-label={logoAriaLabel}/>}
48
+ {children}
30
49
  </div>
31
50
  </main>
32
51
  </div>);
@@ -1 +1 @@
1
- {"version":3,"file":"LoginTemplate.jsx","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,OAAO,QAAQ,MAAM,4CAA4C,CAAC;AAClE,OAAO,EAAW,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,OAAO,CACL,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CACnB;MAAA,CAAC,GAAG,CAAC,SAAS,CAAC,oCAAoC,CACjD;QAAA,CAAC,KAAK,CACJ,GAAG,CAAC,CAAE,KAAK,CAAC,QAA4B,IAAI,QAAQ,CAAC,CACrD,GAAG,CAAC,EAAE,CACN,WAAW,CAAC,MAAM,CAClB,KAAK,CAAC,mCAAmC,CACzC,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,SAAS,CAAC,cAAc,CACxB,WAAW,CAAC,MAAM,CAClB,WAAW,CAAC,CAAC,OAAO,CAAC,EAEzB;MAAA,EAAE,GAAG,CACL;MAAA,CAAC,IAAI,CAAC,SAAS,CAAC,wGAAwG,CACtH;QAAA,CAAC,GAAG,CAAC,SAAS,CAAC,iDAAiD,CAC9D;UAAA,CAAC,KAAK,CAAC,IAAI,IAAI,CACb,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,EAAG,CACjE,CACD;UAAA,CAAC,KAAK,CAAC,QAAQ,CACjB;QAAA,EAAE,GAAG,CACP;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"LoginTemplate.jsx","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/LoginTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,OAAO,QAAQ,MAAM,4CAA4C,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,IAAI,EACJ,KAAK,EACL,aAAa,GACM;IACnB,OAAO,CACL,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CACnB;MAAA,CAAC,GAAG,CAAC,SAAS,CAAC,oDAAoD,CACjE;QAAA,CAAC,KAAK,CACJ,GAAG,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAC1B,GAAG,CAAC,EAAE,CACN,WAAW,CAAC,MAAM,CAClB,KAAK,CAAC,mCAAmC,CACzC,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,SAAS,CAAC,cAAc,CACxB,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CACrE,WAAW,CAAC,MAAM,CAClB,WAAW,CAAC,CAAC,OAAO,CAAC,EAEvB;QAAA,CAAC,CAAC,CAAC,KAAK,IAAI,CACV,CAAC,GAAG,CAAC,SAAS,CAAC,sIAAsI,CACnJ;YAAA,CAAC,KAAK,CACR;UAAA,EAAE,GAAG,CAAC,CACP,CACH;MAAA,EAAE,GAAG,CACL;MAAA,CAAC,IAAI,CAAC,SAAS,CAAC,wGAAwG,CACtH;QAAA,CAAC,GAAG,CAAC,SAAS,CAAC,iDAAiD,CAC9D;UAAA,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,EAAG,CACnE;UAAA,CAAC,QAAQ,CACX;QAAA,EAAE,GAAG,CACP;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { LoginTemplate } from './LoginTemplate';
2
2
  export { LoginForm } from './LoginForm';
3
+ export type { LoginFormErrorStyle, LoginFormLabels, LoginFormSubmitState, } from './LoginForm';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/04-templates/LoginTemplate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { ReactNode } from 'react';
2
+ export type ExpEnterIconProps = {
3
+ /** Width and height in pixels. */
4
+ size?: number;
5
+ /** Steps the arrow in and out of the door while the action runs. */
6
+ busy?: boolean;
7
+ /** Grays out, to match a disabled button. */
8
+ disabled?: boolean;
9
+ };
10
+ /**
11
+ * A door with an arrow going in, for the `iconL` of a core `Button` that
12
+ * signs in or enters somewhere. The arrow steps towards the door while the
13
+ * button is hovered and goes in and out while `busy`. It takes the text color
14
+ * of its button and is decorative.
15
+ *
16
+ * Outside an `ExpScope` it falls back to the plain sign-in icon.
17
+ *
18
+ * @component
19
+ * @example
20
+ * <Button type="submit" iconL={<ExpEnterIcon busy={isSending} />}>
21
+ * Sign in
22
+ * </Button>
23
+ *
24
+ * @param {Object} props - The properties of the ExpEnterIcon component.
25
+ * @param {number} [props.size=16] - Width and height in pixels.
26
+ * @param {boolean} [props.busy=false] - Steps the arrow in and out of the door while the action runs.
27
+ * @param {boolean} [props.disabled=false] - Grays out, to match a disabled button.
28
+ *
29
+ * @returns {ReactNode} The door and arrow, or `FiLogIn` outside an `ExpScope`.
30
+ */
31
+ export declare function ExpEnterIcon({ size, busy, disabled, }: ExpEnterIconProps): ReactNode;
32
+ //# sourceMappingURL=ExpEnterIcon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpEnterIcon.d.ts","sourceRoot":"","sources":["../../src/expresivo/ExpEnterIcon/ExpEnterIcon.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAS,EACT,IAAY,EACZ,QAAgB,GACjB,EAAE,iBAAiB,GAAG,SAAS,CAM/B"}
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ import { FiLogIn } from 'react-icons/fi';
3
+ import { useExpScope } from '../ExpScope/ExpScope';
4
+ import { EnterGlyph } from '../shared/glyphs';
5
+ /**
6
+ * A door with an arrow going in, for the `iconL` of a core `Button` that
7
+ * signs in or enters somewhere. The arrow steps towards the door while the
8
+ * button is hovered and goes in and out while `busy`. It takes the text color
9
+ * of its button and is decorative.
10
+ *
11
+ * Outside an `ExpScope` it falls back to the plain sign-in icon.
12
+ *
13
+ * @component
14
+ * @example
15
+ * <Button type="submit" iconL={<ExpEnterIcon busy={isSending} />}>
16
+ * Sign in
17
+ * </Button>
18
+ *
19
+ * @param {Object} props - The properties of the ExpEnterIcon component.
20
+ * @param {number} [props.size=16] - Width and height in pixels.
21
+ * @param {boolean} [props.busy=false] - Steps the arrow in and out of the door while the action runs.
22
+ * @param {boolean} [props.disabled=false] - Grays out, to match a disabled button.
23
+ *
24
+ * @returns {ReactNode} The door and arrow, or `FiLogIn` outside an `ExpScope`.
25
+ */
26
+ export function ExpEnterIcon({ size = 16, busy = false, disabled = false, }) {
27
+ const inScope = useExpScope();
28
+ if (!inScope)
29
+ return <FiLogIn aria-hidden="true"/>;
30
+ return <EnterGlyph size={size} busy={busy} disabled={disabled}/>;
31
+ }
32
+ //# sourceMappingURL=ExpEnterIcon.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpEnterIcon.jsx","sourceRoot":"","sources":["../../src/expresivo/ExpEnterIcon/ExpEnterIcon.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAW9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,IAAI,GAAG,EAAE,EACT,IAAI,GAAG,KAAK,EACZ,QAAQ,GAAG,KAAK,GACE;IAClB,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAE9B,IAAI,CAAC,OAAO;QAAE,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,EAAG,CAAC;IAEpD,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAG,CAAC;AACpE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { ExpEnterIcon } from './ExpEnterIcon';
2
+ export type { ExpEnterIconProps } from './ExpEnterIcon';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/expresivo/ExpEnterIcon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { ExpEnterIcon } from './ExpEnterIcon';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/expresivo/ExpEnterIcon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { type HTMLAttributes, type ReactNode } from 'react';
2
+ import type { ExpMascotName } from '../ExpMascot/catalog';
3
+ export type ExpPeekProps = {
4
+ /** What the mascots peek from behind, usually a single button. */
5
+ children: ReactNode;
6
+ /**
7
+ * Mascots in the order they take turns, as groups of poses. Each turn shows
8
+ * one pose of its group, picked at random, and the order repeats.
9
+ */
10
+ cast?: readonly (readonly ExpMascotName[])[];
11
+ /** Width and height of the mascot, in pixels. */
12
+ size?: number;
13
+ /** Hides the mascot and stops the turns, for instance while the action runs. */
14
+ paused?: boolean;
15
+ /** How long each mascot stays out, in milliseconds. */
16
+ visibleMs?: number;
17
+ /** Pause between one mascot and the next, in milliseconds. */
18
+ gapMs?: number;
19
+ } & Omit<HTMLAttributes<HTMLDivElement>, 'children'>;
20
+ /**
21
+ * Wraps a button so the clicOH mascots peek out from behind its edges, one at
22
+ * a time: from the top edge at any point, or from the left or right side, with
23
+ * a random pose and tilt. Each one springs out, stays a few seconds, hides and
24
+ * makes room for the next, in the order of `cast`.
25
+ *
26
+ * The mascot sits behind the wrapped element, which covers its lower part;
27
+ * nothing is clipped, so leave some room around it. It is decorative and
28
+ * never takes clicks. Pause it while the action runs.
29
+ *
30
+ * Shows no mascot with reduced motion, outside an `ExpScope`, or when the
31
+ * scope hides mascots; the wrapped element renders as usual.
32
+ *
33
+ * @component
34
+ * @example
35
+ * <ExpPeek paused={isSending} className="w-full">
36
+ * <Button type="submit" className="w-full">Sign in</Button>
37
+ * </ExpPeek>
38
+ *
39
+ * @example
40
+ * // Only Fixi, bigger and slower
41
+ * <ExpPeek cast={[['fixi-01-feliz', 'fixi-06-celebrando']]} size={56} visibleMs={4000}>
42
+ * <Button>Fix it</Button>
43
+ * </ExpPeek>
44
+ *
45
+ * @param {Object} props - The properties of the ExpPeek component.
46
+ * @param {ReactNode} props.children - What the mascots peek from behind, usually a single button.
47
+ * @param {ExpMascotName[][]} [props.cast] - Mascots in turn order, as groups of poses; each turn picks one pose of its group. Defaults to Oculus searching, Bugi showing up and Fixi fixing.
48
+ * @param {number} [props.size=44] - Width and height of the mascot, in pixels.
49
+ * @param {boolean} [props.paused=false] - Hides the mascot and stops the turns.
50
+ * @param {number} [props.visibleMs=3000] - How long each mascot stays out, in milliseconds.
51
+ * @param {number} [props.gapMs=2000] - Pause between one mascot and the next, in milliseconds.
52
+ *
53
+ * @returns {ReactNode} The wrapped element with the mascots behind it.
54
+ */
55
+ export declare function ExpPeek({ children, cast, size, paused, visibleMs, gapMs, className, ...restProps }: ExpPeekProps): ReactNode;
56
+ //# sourceMappingURL=ExpPeek.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpPeek.d.ts","sourceRoot":"","sources":["../../src/expresivo/ExpPeek/ExpPeek.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAe1D,MAAM,MAAM,YAAY,GAAG;IACzB,kEAAkE;IAClE,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,aAAa,EAAE,CAAC,EAAE,CAAC;IAC7C,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,CAAC;AAoDrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,IAAiB,EACjB,IAAS,EACT,MAAc,EACd,SAAgB,EAChB,KAAY,EACZ,SAAS,EACT,GAAG,SAAS,EACb,EAAE,YAAY,GAAG,SAAS,CA6D1B"}
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+ import clsx from 'clsx';
3
+ import { useEffect, useState, } from 'react';
4
+ import { ExpMascot } from '../ExpMascot/ExpMascot';
5
+ import { useExpScopeOptions } from '../ExpScope/ExpScope';
6
+ /** Oculus searches, Bugi shows up, Fixi fixes it. */
7
+ const STORY_CAST = [
8
+ [
9
+ 'oculus-02-investigando',
10
+ 'oculus-07-buscando-rapido',
11
+ 'oculus-04-analizando-documento',
12
+ ],
13
+ ['bugi-01-alerta', 'bugi-05-sorprendido', 'bugi-02-investigando'],
14
+ ['fixi-04-reparando', 'fixi-01-feliz', 'fixi-06-celebrando'],
15
+ ];
16
+ /** The top edge comes up three times as often as each side. */
17
+ const SPOTS = ['top', 'top', 'top', 'left', 'right'];
18
+ const FIRST_DELAY_MS = 900;
19
+ const RISE_DELAY_MS = 40;
20
+ const HIDE_MS = 420;
21
+ const BOUNCE = 'cubic-bezier(.34,1.56,.64,1)';
22
+ const SINK = 'cubic-bezier(.55,0,.75,.2)';
23
+ function pick(items) {
24
+ return items[Math.floor(Math.random() * items.length)];
25
+ }
26
+ function peekStyle(peek, size, out) {
27
+ const sideways = { top: '50%', marginTop: -size / 2 };
28
+ const place = {
29
+ top: { top: 0, left: `calc(${12 + peek.along * 74}% - ${size / 2}px)` },
30
+ left: { ...sideways, left: 10 },
31
+ right: { ...sideways, right: 10 },
32
+ };
33
+ const outTransform = {
34
+ top: `translateY(-${Math.round(size * 0.68)}px) rotate(${peek.tilt}deg)`,
35
+ left: `translateX(-${size * 0.95}px) rotate(-10deg)`,
36
+ right: `translateX(${size * 0.95}px) rotate(10deg)`,
37
+ };
38
+ return {
39
+ width: size,
40
+ height: size,
41
+ ...place[peek.spot],
42
+ transformOrigin: peek.spot === 'top' ? '50% 100%' : '50% 50%',
43
+ transform: out ? outTransform[peek.spot] : 'none',
44
+ opacity: out ? 1 : 0,
45
+ transition: out
46
+ ? `transform 520ms ${BOUNCE}, opacity 80ms linear`
47
+ : `transform 360ms ${SINK}, opacity 120ms linear 260ms`,
48
+ };
49
+ }
50
+ /**
51
+ * Wraps a button so the clicOH mascots peek out from behind its edges, one at
52
+ * a time: from the top edge at any point, or from the left or right side, with
53
+ * a random pose and tilt. Each one springs out, stays a few seconds, hides and
54
+ * makes room for the next, in the order of `cast`.
55
+ *
56
+ * The mascot sits behind the wrapped element, which covers its lower part;
57
+ * nothing is clipped, so leave some room around it. It is decorative and
58
+ * never takes clicks. Pause it while the action runs.
59
+ *
60
+ * Shows no mascot with reduced motion, outside an `ExpScope`, or when the
61
+ * scope hides mascots; the wrapped element renders as usual.
62
+ *
63
+ * @component
64
+ * @example
65
+ * <ExpPeek paused={isSending} className="w-full">
66
+ * <Button type="submit" className="w-full">Sign in</Button>
67
+ * </ExpPeek>
68
+ *
69
+ * @example
70
+ * // Only Fixi, bigger and slower
71
+ * <ExpPeek cast={[['fixi-01-feliz', 'fixi-06-celebrando']]} size={56} visibleMs={4000}>
72
+ * <Button>Fix it</Button>
73
+ * </ExpPeek>
74
+ *
75
+ * @param {Object} props - The properties of the ExpPeek component.
76
+ * @param {ReactNode} props.children - What the mascots peek from behind, usually a single button.
77
+ * @param {ExpMascotName[][]} [props.cast] - Mascots in turn order, as groups of poses; each turn picks one pose of its group. Defaults to Oculus searching, Bugi showing up and Fixi fixing.
78
+ * @param {number} [props.size=44] - Width and height of the mascot, in pixels.
79
+ * @param {boolean} [props.paused=false] - Hides the mascot and stops the turns.
80
+ * @param {number} [props.visibleMs=3000] - How long each mascot stays out, in milliseconds.
81
+ * @param {number} [props.gapMs=2000] - Pause between one mascot and the next, in milliseconds.
82
+ *
83
+ * @returns {ReactNode} The wrapped element with the mascots behind it.
84
+ */
85
+ export function ExpPeek({ children, cast = STORY_CAST, size = 44, paused = false, visibleMs = 3000, gapMs = 2000, className, ...restProps }) {
86
+ const options = useExpScopeOptions();
87
+ const [peek, setPeek] = useState(null);
88
+ const [out, setOut] = useState(false);
89
+ const active = !!options && options.mascots !== 'hidden' && !paused;
90
+ const castKey = cast.map((group) => group.join(',')).join('|');
91
+ useEffect(() => {
92
+ const groups = castKey
93
+ .split('|')
94
+ .map((group) => group.split(','))
95
+ .filter((group) => group[0] !== '');
96
+ const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
97
+ if (!active || reduceMotion || groups.length === 0)
98
+ return;
99
+ let turn = 0;
100
+ const timers = [];
101
+ const later = (run, ms) => {
102
+ timers.push(setTimeout(run, ms));
103
+ };
104
+ const next = () => {
105
+ const group = groups[turn % groups.length];
106
+ turn += 1;
107
+ setPeek({
108
+ turn,
109
+ name: pick(group),
110
+ spot: pick(SPOTS),
111
+ along: Math.random(),
112
+ tilt: Math.round((Math.random() - 0.5) * 24),
113
+ });
114
+ later(() => setOut(true), RISE_DELAY_MS);
115
+ later(() => setOut(false), RISE_DELAY_MS + visibleMs);
116
+ later(next, RISE_DELAY_MS + visibleMs + HIDE_MS + gapMs);
117
+ };
118
+ later(next, FIRST_DELAY_MS);
119
+ return () => {
120
+ timers.forEach(clearTimeout);
121
+ setOut(false);
122
+ };
123
+ }, [active, castKey, visibleMs, gapMs]);
124
+ return (<div {...restProps} className={clsx('relative isolate', className)}>
125
+ {!!peek && (<span key={peek.turn} aria-hidden="true" className="pointer-events-none absolute z-0" style={peekStyle(peek, size, out && active)}>
126
+ <ExpMascot name={peek.name} size={size}/>
127
+ </span>)}
128
+ <div className="relative z-1">{children}</div>
129
+ </div>);
130
+ }
131
+ //# sourceMappingURL=ExpPeek.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpPeek.jsx","sourceRoot":"","sources":["../../src/expresivo/ExpPeek/ExpPeek.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { ExpPeek } from './ExpPeek';
2
+ export type { ExpPeekProps } from './ExpPeek';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/expresivo/ExpPeek/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { ExpPeek } from './ExpPeek';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/expresivo/ExpPeek/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -1,6 +1,8 @@
1
1
  export * from './ExpScope';
2
2
  export * from './ExpMascot';
3
3
  export * from './ExpLensIcon';
4
+ export * from './ExpEnterIcon';
5
+ export * from './ExpPeek';
4
6
  export * from './ExpKeyButton';
5
7
  export * from './ExpPillButton';
6
8
  export * from './ExpMedalBadge';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/expresivo/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/expresivo/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
@@ -1,6 +1,8 @@
1
1
  export * from './ExpScope';
2
2
  export * from './ExpMascot';
3
3
  export * from './ExpLensIcon';
4
+ export * from './ExpEnterIcon';
5
+ export * from './ExpPeek';
4
6
  export * from './ExpKeyButton';
5
7
  export * from './ExpPillButton';
6
8
  export * from './ExpMedalBadge';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/expresivo/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/expresivo/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clicoh/orion-library",
3
- "version": "1.2.0-beta.16",
3
+ "version": "1.2.0-beta.18",
4
4
  "main": "index.js",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "0.26.19",