@xenosystem/components 0.2.0 → 0.2.1
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.
- package/dist/auth/index.d.ts +57 -1
- package/dist/auth/index.js +172 -36
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/auth/index.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import { ButtonVariant } from '@xenosystem/elements-react';
|
|
4
4
|
|
|
5
5
|
declare function ensureAuthStyles(): void;
|
|
6
|
+
|
|
6
7
|
declare function XenoMark(): ReactNode;
|
|
8
|
+
|
|
7
9
|
interface AuthHeroStat {
|
|
8
10
|
value: string;
|
|
9
11
|
label: string;
|
|
@@ -17,6 +19,7 @@ interface AuthHeroProps {
|
|
|
17
19
|
compact?: boolean;
|
|
18
20
|
}
|
|
19
21
|
declare function AuthHero({ headline, lead, stats, imageSrc, compact }: AuthHeroProps): react.JSX.Element;
|
|
22
|
+
|
|
20
23
|
interface SignInAction {
|
|
21
24
|
id: string;
|
|
22
25
|
label: string;
|
|
@@ -45,6 +48,7 @@ interface SignInFormProps {
|
|
|
45
48
|
declare function SignInForm({ tag, title, body, actions, note, warning, identity, animate, phase }: SignInFormProps): react.JSX.Element;
|
|
46
49
|
/** The licence plates are the same form with a tag; kept as a name so a panel reads honestly. */
|
|
47
50
|
declare const LicencePlate: typeof SignInForm;
|
|
51
|
+
|
|
48
52
|
interface AuthDoorProps {
|
|
49
53
|
hero: Omit<AuthHeroProps, 'compact'>;
|
|
50
54
|
/** Aria label of the dialog. */
|
|
@@ -59,9 +63,61 @@ interface AuthDoorProps {
|
|
|
59
63
|
* was given.
|
|
60
64
|
*/
|
|
61
65
|
declare function AuthDoor({ hero, label, children, rootAttributes }: AuthDoorProps): react.JSX.Element;
|
|
66
|
+
|
|
67
|
+
type CredentialMode = 'signin' | 'signup';
|
|
68
|
+
interface CredentialValues {
|
|
69
|
+
name: string;
|
|
70
|
+
email: string;
|
|
71
|
+
password: string;
|
|
72
|
+
}
|
|
73
|
+
interface CredentialErrors {
|
|
74
|
+
name?: string;
|
|
75
|
+
email?: string;
|
|
76
|
+
password?: string;
|
|
77
|
+
form?: string;
|
|
78
|
+
}
|
|
79
|
+
interface CredentialFormProps {
|
|
80
|
+
mode: CredentialMode;
|
|
81
|
+
onModeChange: (mode: CredentialMode) => void;
|
|
82
|
+
values: CredentialValues;
|
|
83
|
+
onChange: (values: CredentialValues) => void;
|
|
84
|
+
errors?: CredentialErrors;
|
|
85
|
+
submitting?: boolean;
|
|
86
|
+
onSubmit: () => void;
|
|
87
|
+
/** Rendered above the switch — the page's "Welcome back" / "Get started" copy. */
|
|
88
|
+
title?: ReactNode;
|
|
89
|
+
body?: ReactNode;
|
|
90
|
+
/** Rendered between the switch and the fields — `SocialSignIn` + `OrDivider`, when the page has them. */
|
|
91
|
+
before?: ReactNode;
|
|
92
|
+
/** Rendered under the submit — "Forgot password?", terms, the other-mode link. */
|
|
93
|
+
after?: ReactNode;
|
|
94
|
+
/** Copy overrides; defaults are the platform page's. */
|
|
95
|
+
labels?: Partial<Record<'name' | 'email' | 'password' | 'submitSignIn' | 'submitSignUp' | 'signin' | 'signup', string>>;
|
|
96
|
+
}
|
|
97
|
+
declare function CredentialForm({ mode, onModeChange, values, onChange, errors, submitting, onSubmit, title, body, before, after, labels }: CredentialFormProps): react.JSX.Element;
|
|
98
|
+
|
|
99
|
+
type SocialProvider = 'google' | 'github' | 'x';
|
|
100
|
+
interface SocialSignInProps {
|
|
101
|
+
providers?: readonly SocialProvider[];
|
|
102
|
+
onSelect: (provider: SocialProvider) => void;
|
|
103
|
+
disabled?: boolean;
|
|
104
|
+
}
|
|
105
|
+
declare function SocialSignIn({ providers, onSelect, disabled }: SocialSignInProps): react.JSX.Element;
|
|
106
|
+
|
|
107
|
+
/** The "or continue with email" rule between the social row and the fields. */
|
|
108
|
+
declare function OrDivider({ children }: {
|
|
109
|
+
children?: string;
|
|
110
|
+
}): react.JSX.Element;
|
|
111
|
+
|
|
62
112
|
declare const STATES: {
|
|
63
113
|
id: string;
|
|
64
114
|
props: SignInFormProps;
|
|
65
115
|
}[];
|
|
116
|
+
/** The origin page's states — everything but the callbacks, which the page supplies. */
|
|
117
|
+
type CredentialStateProps = Omit<CredentialFormProps, 'onModeChange' | 'onChange' | 'onSubmit'>;
|
|
118
|
+
declare const CREDENTIAL_STATES: {
|
|
119
|
+
id: string;
|
|
120
|
+
props: CredentialStateProps;
|
|
121
|
+
}[];
|
|
66
122
|
|
|
67
|
-
export { AuthDoor, type AuthDoorProps, AuthHero, type AuthHeroProps, type AuthHeroStat, LicencePlate, STATES, type SignInAction, SignInForm, type SignInFormProps, XenoMark, ensureAuthStyles };
|
|
123
|
+
export { AuthDoor, type AuthDoorProps, AuthHero, type AuthHeroProps, type AuthHeroStat, CREDENTIAL_STATES, type CredentialErrors, CredentialForm, type CredentialFormProps, type CredentialMode, type CredentialValues, LicencePlate, OrDivider, STATES, type SignInAction, SignInForm, type SignInFormProps, type SocialProvider, SocialSignIn, type SocialSignInProps, XenoMark, ensureAuthStyles };
|
package/dist/auth/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
// src/auth/
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { Button } from "@xenosystem/elements-react";
|
|
4
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
// src/auth/styles.ts
|
|
5
2
|
var STYLE_ID = "xeno-components-auth";
|
|
6
3
|
var CSS = `
|
|
7
4
|
.xc-auth{position:absolute;inset:0;display:flex;background:var(--xeno-canvas);color:var(--xeno-text);font-family:var(--xeno-font-sans);-webkit-font-smoothing:antialiased;overflow:hidden}
|
|
@@ -42,6 +39,27 @@ var CSS = `
|
|
|
42
39
|
.xc-form__warn{margin-top:16px;font-size:12px;line-height:1.6;color:var(--xeno-danger)}
|
|
43
40
|
.xc-form__who{margin-top:24px;padding-top:16px;border-top:1px solid var(--xeno-border-subtle);font-size:12px;color:var(--xeno-muted)}
|
|
44
41
|
.xc-form__who b{color:var(--xeno-text);font-weight:500}
|
|
42
|
+
|
|
43
|
+
.xc-cred{width:100%;max-width:400px;display:flex;flex-direction:column;gap:24px}
|
|
44
|
+
.xc-cred__head .xc-form__h2{font-size:30px}
|
|
45
|
+
.xc-cred__mode{width:100%}
|
|
46
|
+
.xc-cred__fields{display:flex;flex-direction:column;gap:16px}
|
|
47
|
+
.xc-cred__reveal{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--xeno-dur-entrance) var(--xeno-ease),opacity var(--xeno-dur-entrance) var(--xeno-ease)}
|
|
48
|
+
.xc-cred__reveal[data-open=true]{grid-template-rows:1fr;opacity:1}
|
|
49
|
+
.xc-cred__reveal > *{overflow:hidden;min-height:0}
|
|
50
|
+
.xc-cred__field{display:flex;flex-direction:column;gap:8px}
|
|
51
|
+
.xc-cred__label{font-size:13px;font-weight:500;color:var(--xeno-muted)}
|
|
52
|
+
.xc-cred__pw{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center}
|
|
53
|
+
.xc-cred__error{font-size:12px;color:var(--xeno-danger)}
|
|
54
|
+
.xc-cred__after{font-size:13px;color:var(--xeno-muted);text-align:center}
|
|
55
|
+
.xc-cred .xc-form__actions{margin-top:0}
|
|
56
|
+
.xc-social{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
|
|
57
|
+
.xc-social > *{width:100%}
|
|
58
|
+
.xc-social__mark{width:20px;height:20px;opacity:.75;transition:opacity var(--xeno-dur-fast) var(--xeno-ease)}
|
|
59
|
+
.xc-social button:hover .xc-social__mark{opacity:1}
|
|
60
|
+
.xc-or{position:relative;display:flex;justify-content:center;margin:4px 0}
|
|
61
|
+
.xc-or::before{content:'';position:absolute;inset:50% 0 auto 0;border-top:1px solid var(--xeno-border-subtle)}
|
|
62
|
+
.xc-or__label{position:relative;padding:0 16px;background:var(--xeno-canvas);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--xeno-muted)}
|
|
45
63
|
`;
|
|
46
64
|
function ensureAuthStyles() {
|
|
47
65
|
if (typeof document === "undefined" || document.getElementById(STYLE_ID)) return;
|
|
@@ -50,6 +68,9 @@ function ensureAuthStyles() {
|
|
|
50
68
|
style.textContent = CSS;
|
|
51
69
|
document.head.appendChild(style);
|
|
52
70
|
}
|
|
71
|
+
|
|
72
|
+
// src/auth/XenoMark.tsx
|
|
73
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
53
74
|
function XenoMark() {
|
|
54
75
|
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 1082 1082", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
55
76
|
/* @__PURE__ */ jsx("path", { d: "M489.1 219.763L323.457 39.7072L101.649 30.4597C51.6926 28.3769 39.5494 67.5718 39.7224 87.4296L30.4124 310.735L347.816 655.757L475.833 537.987L241.73 283.514C207.644 246.462 222.019 240.156 233.467 241.634L455.275 250.881L489.1 219.763Z", fill: "currentColor" }),
|
|
@@ -58,30 +79,38 @@ function XenoMark() {
|
|
|
58
79
|
/* @__PURE__ */ jsx("path", { d: "M220.763 592.907L40.7063 758.55L31.4588 980.358C29.3761 1030.31 68.5709 1042.46 88.4287 1042.28L311.735 1051.59L656.756 734.191L538.986 606.174L284.514 840.277C247.462 874.363 241.155 859.988 242.633 848.54L251.881 626.733L220.763 592.907Z", fill: "currentColor" })
|
|
59
80
|
] });
|
|
60
81
|
}
|
|
82
|
+
|
|
83
|
+
// src/auth/AuthHero.tsx
|
|
84
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
61
85
|
function AuthHero({ headline, lead, stats, imageSrc, compact }) {
|
|
62
|
-
return /* @__PURE__ */
|
|
63
|
-
imageSrc && /* @__PURE__ */
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
-
/* @__PURE__ */
|
|
66
|
-
/* @__PURE__ */
|
|
67
|
-
/* @__PURE__ */
|
|
86
|
+
return /* @__PURE__ */ jsxs2("div", { className: "xc-hero", "data-xc": "auth-hero", children: [
|
|
87
|
+
imageSrc && /* @__PURE__ */ jsx2("img", { className: "xc-hero__img", src: imageSrc, alt: "", draggable: false }),
|
|
88
|
+
/* @__PURE__ */ jsxs2("div", { className: "xc-hero__in", children: [
|
|
89
|
+
/* @__PURE__ */ jsxs2("div", { className: "xc-brand", children: [
|
|
90
|
+
/* @__PURE__ */ jsx2(XenoMark, {}),
|
|
91
|
+
/* @__PURE__ */ jsx2("span", { className: "xc-brand__word", children: "XENO" })
|
|
68
92
|
] }),
|
|
69
|
-
compact ? /* @__PURE__ */
|
|
70
|
-
/* @__PURE__ */
|
|
71
|
-
/* @__PURE__ */
|
|
72
|
-
lead && /* @__PURE__ */
|
|
93
|
+
compact ? /* @__PURE__ */ jsx2("h1", { className: "xc-hero__h1", children: headline }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
94
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
95
|
+
/* @__PURE__ */ jsx2("h1", { className: "xc-hero__h1", children: headline }),
|
|
96
|
+
lead && /* @__PURE__ */ jsx2("p", { className: "xc-hero__lead", children: lead })
|
|
73
97
|
] }),
|
|
74
|
-
stats && stats.length > 0 && /* @__PURE__ */
|
|
75
|
-
i > 0 && /* @__PURE__ */
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
-
/* @__PURE__ */
|
|
98
|
+
stats && stats.length > 0 && /* @__PURE__ */ jsx2("div", { className: "xc-hero__stats", children: stats.map((s, i) => /* @__PURE__ */ jsxs2("div", { style: { display: "contents" }, children: [
|
|
99
|
+
i > 0 && /* @__PURE__ */ jsx2("div", { className: "xc-hero__sep" }),
|
|
100
|
+
/* @__PURE__ */ jsxs2("div", { className: "xc-hero__stat", children: [
|
|
101
|
+
/* @__PURE__ */ jsx2("b", { children: s.value }),
|
|
102
|
+
/* @__PURE__ */ jsx2("span", { children: s.label })
|
|
79
103
|
] })
|
|
80
104
|
] }, s.label)) })
|
|
81
105
|
] })
|
|
82
106
|
] })
|
|
83
107
|
] });
|
|
84
108
|
}
|
|
109
|
+
|
|
110
|
+
// src/auth/SignInForm.tsx
|
|
111
|
+
import { useEffect, useState } from "react";
|
|
112
|
+
import { Button } from "@xenosystem/elements-react";
|
|
113
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
85
114
|
function SignInForm({ tag, title, body, actions, note, warning, identity, animate = true, phase }) {
|
|
86
115
|
const [visible, setVisible] = useState(!animate);
|
|
87
116
|
useEffect(() => {
|
|
@@ -89,25 +118,29 @@ function SignInForm({ tag, title, body, actions, note, warning, identity, animat
|
|
|
89
118
|
const t = window.setTimeout(() => setVisible(true), 100);
|
|
90
119
|
return () => window.clearTimeout(t);
|
|
91
120
|
}, [animate]);
|
|
92
|
-
return /* @__PURE__ */
|
|
93
|
-
tag && /* @__PURE__ */
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
-
/* @__PURE__ */
|
|
96
|
-
actions.length > 0 && /* @__PURE__ */
|
|
97
|
-
note && /* @__PURE__ */
|
|
98
|
-
warning && /* @__PURE__ */
|
|
99
|
-
identity && /* @__PURE__ */
|
|
121
|
+
return /* @__PURE__ */ jsxs3("div", { className: "xc-form", "data-xc": "sign-in-form", "data-visible": visible, "data-phase": phase, children: [
|
|
122
|
+
tag && /* @__PURE__ */ jsx3("span", { className: "xc-form__tag", children: tag }),
|
|
123
|
+
/* @__PURE__ */ jsx3("h2", { className: "xc-form__h2", children: title }),
|
|
124
|
+
/* @__PURE__ */ jsx3("p", { className: "xc-form__sub", children: body }),
|
|
125
|
+
actions.length > 0 && /* @__PURE__ */ jsx3("div", { className: "xc-form__actions", children: actions.map((a) => /* @__PURE__ */ jsx3(Button, { variant: a.variant ?? "secondary", size: "lg", disabled: a.disabled, onClick: a.onClick, "data-intent": a.id, children: a.label }, a.id)) }),
|
|
126
|
+
note && /* @__PURE__ */ jsx3("p", { className: "xc-form__note", children: note }),
|
|
127
|
+
warning && /* @__PURE__ */ jsx3("p", { className: "xc-form__warn", children: warning }),
|
|
128
|
+
identity && /* @__PURE__ */ jsxs3("p", { className: "xc-form__who", children: [
|
|
100
129
|
"Signed in as ",
|
|
101
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ jsx3("b", { children: identity })
|
|
102
131
|
] })
|
|
103
132
|
] });
|
|
104
133
|
}
|
|
105
134
|
var LicencePlate = SignInForm;
|
|
135
|
+
|
|
136
|
+
// src/auth/AuthDoor.tsx
|
|
137
|
+
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
138
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
106
139
|
var aspectOf = (w, h) => h <= 0 ? "landscape" : w / h > 1.2 ? "landscape" : w / h < 0.85 ? "portrait" : "square";
|
|
107
140
|
function AuthDoor({ hero, label, children, rootAttributes }) {
|
|
108
141
|
const ref = useRef(null);
|
|
109
|
-
const [aspect, setAspect] =
|
|
110
|
-
|
|
142
|
+
const [aspect, setAspect] = useState2("landscape");
|
|
143
|
+
useEffect2(() => {
|
|
111
144
|
ensureAuthStyles();
|
|
112
145
|
const el = ref.current;
|
|
113
146
|
if (!el || typeof ResizeObserver === "undefined") return;
|
|
@@ -118,15 +151,105 @@ function AuthDoor({ hero, label, children, rootAttributes }) {
|
|
|
118
151
|
ro.observe(el);
|
|
119
152
|
return () => ro.disconnect();
|
|
120
153
|
}, []);
|
|
121
|
-
const brand = /* @__PURE__ */
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
-
/* @__PURE__ */
|
|
154
|
+
const brand = /* @__PURE__ */ jsxs4("div", { className: "xc-brand", children: [
|
|
155
|
+
/* @__PURE__ */ jsx4(XenoMark, {}),
|
|
156
|
+
/* @__PURE__ */ jsx4("span", { className: "xc-brand__word", children: "XENO" })
|
|
157
|
+
] });
|
|
158
|
+
return /* @__PURE__ */ jsxs4("div", { ref, className: "xc-auth", "data-xc": "auth-door", "data-aspect": aspect, role: "dialog", "aria-label": label, ...rootAttributes, children: [
|
|
159
|
+
aspect === "portrait" ? /* @__PURE__ */ jsx4("header", { className: "xc-auth__head", children: brand }) : /* @__PURE__ */ jsx4("div", { className: "xc-auth__heroWrap", children: /* @__PURE__ */ jsx4(AuthHero, { ...hero, compact: aspect === "square" }) }),
|
|
160
|
+
/* @__PURE__ */ jsx4("div", { className: "xc-auth__side", children: /* @__PURE__ */ jsx4("div", { className: "xc-auth__center", children }) })
|
|
161
|
+
] });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/auth/CredentialForm.tsx
|
|
165
|
+
import { useState as useState3 } from "react";
|
|
166
|
+
import { Button as Button2, SegmentedControl, TextInput } from "@xenosystem/elements-react";
|
|
167
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
168
|
+
var L = {
|
|
169
|
+
name: "Full name",
|
|
170
|
+
email: "Email",
|
|
171
|
+
password: "Password",
|
|
172
|
+
submitSignIn: "Sign in",
|
|
173
|
+
submitSignUp: "Create account",
|
|
174
|
+
signin: "Sign In",
|
|
175
|
+
signup: "Sign Up"
|
|
176
|
+
};
|
|
177
|
+
function CredentialForm({ mode, onModeChange, values, onChange, errors = {}, submitting = false, onSubmit, title, body, before, after, labels }) {
|
|
178
|
+
const [showPassword, setShowPassword] = useState3(false);
|
|
179
|
+
const t = { ...L, ...labels };
|
|
180
|
+
const set = (k) => (e) => onChange({ ...values, [k]: e.target.value });
|
|
181
|
+
const submit = (e) => {
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
if (!submitting) onSubmit();
|
|
184
|
+
};
|
|
185
|
+
return /* @__PURE__ */ jsxs5("form", { className: "xc-cred", "data-xc": "credential-form", "data-mode": mode, onSubmit: submit, noValidate: true, children: [
|
|
186
|
+
(title || body) && /* @__PURE__ */ jsxs5("div", { className: "xc-cred__head", children: [
|
|
187
|
+
title && /* @__PURE__ */ jsx5("h2", { className: "xc-form__h2", children: title }),
|
|
188
|
+
body && /* @__PURE__ */ jsx5("p", { className: "xc-form__sub", children: body })
|
|
189
|
+
] }),
|
|
190
|
+
/* @__PURE__ */ jsx5(
|
|
191
|
+
SegmentedControl,
|
|
192
|
+
{
|
|
193
|
+
className: "xc-cred__mode",
|
|
194
|
+
value: mode,
|
|
195
|
+
onValueChange: (v) => onModeChange(v),
|
|
196
|
+
options: [{ value: "signin", label: t.signin }, { value: "signup", label: t.signup }],
|
|
197
|
+
size: "lg",
|
|
198
|
+
"aria-label": "Sign in or sign up"
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
before,
|
|
202
|
+
/* @__PURE__ */ jsxs5("div", { className: "xc-cred__fields", children: [
|
|
203
|
+
/* @__PURE__ */ jsx5("div", { className: "xc-cred__reveal", "data-open": mode === "signup", "aria-hidden": mode !== "signup", children: /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
|
|
204
|
+
/* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.name }),
|
|
205
|
+
/* @__PURE__ */ jsx5(TextInput, { size: "lg", value: values.name, onChange: set("name"), placeholder: "Your name", autoComplete: "name", tabIndex: mode === "signup" ? 0 : -1, "aria-invalid": !!errors.name, "data-field": "name" }),
|
|
206
|
+
errors.name && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.name })
|
|
207
|
+
] }) }),
|
|
208
|
+
/* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
|
|
209
|
+
/* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.email }),
|
|
210
|
+
/* @__PURE__ */ jsx5(TextInput, { size: "lg", type: "email", value: values.email, onChange: set("email"), placeholder: "you@example.com", autoComplete: "email", required: true, "aria-invalid": !!errors.email, "data-field": "email" }),
|
|
211
|
+
errors.email && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.email })
|
|
212
|
+
] }),
|
|
213
|
+
/* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
|
|
214
|
+
/* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.password }),
|
|
215
|
+
/* @__PURE__ */ jsxs5("span", { className: "xc-cred__pw", children: [
|
|
216
|
+
/* @__PURE__ */ jsx5(TextInput, { size: "lg", type: showPassword ? "text" : "password", value: values.password, onChange: set("password"), placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", autoComplete: mode === "signup" ? "new-password" : "current-password", required: true, "aria-invalid": !!errors.password, "data-field": "password" }),
|
|
217
|
+
/* @__PURE__ */ jsx5(Button2, { type: "button", variant: "ghost", size: "sm", className: "xc-cred__eye", onClick: () => setShowPassword((v) => !v), "aria-label": showPassword ? "Hide password" : "Show password", "aria-pressed": showPassword, children: showPassword ? "Hide" : "Show" })
|
|
218
|
+
] }),
|
|
219
|
+
errors.password && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.password })
|
|
220
|
+
] })
|
|
221
|
+
] }),
|
|
222
|
+
errors.form && /* @__PURE__ */ jsx5("p", { className: "xc-form__warn", role: "alert", children: errors.form }),
|
|
223
|
+
/* @__PURE__ */ jsx5("div", { className: "xc-form__actions", children: /* @__PURE__ */ jsx5(Button2, { type: "submit", variant: "primary", size: "lg", busy: submitting, "data-intent": "submit", children: mode === "signin" ? t.submitSignIn : t.submitSignUp }) }),
|
|
224
|
+
after && /* @__PURE__ */ jsx5("div", { className: "xc-cred__after", children: after })
|
|
124
225
|
] });
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/auth/SocialSignIn.tsx
|
|
229
|
+
import { Button as Button3 } from "@xenosystem/elements-react";
|
|
230
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
231
|
+
var NAMES = { google: "Google", github: "GitHub", x: "X" };
|
|
232
|
+
function Mark({ p }) {
|
|
233
|
+
if (p === "google") return /* @__PURE__ */ jsxs6("svg", { className: "xc-social__mark", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
|
|
234
|
+
/* @__PURE__ */ jsx6("path", { fill: "#FFC107", d: "M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z" }),
|
|
235
|
+
/* @__PURE__ */ jsx6("path", { fill: "#FF3D00", d: "M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z" }),
|
|
236
|
+
/* @__PURE__ */ jsx6("path", { fill: "#4CAF50", d: "M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z" }),
|
|
237
|
+
/* @__PURE__ */ jsx6("path", { fill: "#1976D2", d: "M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z" })
|
|
128
238
|
] });
|
|
239
|
+
if (p === "github") return /* @__PURE__ */ jsx6("svg", { className: "xc-social__mark", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx6("path", { d: "M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.1.79-.25.79-.56v-2c-3.2.7-3.87-1.37-3.87-1.37-.52-1.33-1.28-1.69-1.28-1.69-1.05-.71.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.29 1.19-3.09-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.17 1.18a11 11 0 0 1 5.77 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.11 3.05.74.8 1.19 1.83 1.19 3.09 0 4.42-2.69 5.39-5.25 5.68.41.36.78 1.06.78 2.13v3.16c0 .31.21.67.8.56A11.5 11.5 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5z" }) });
|
|
240
|
+
return /* @__PURE__ */ jsx6("svg", { className: "xc-social__mark", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx6("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) });
|
|
129
241
|
}
|
|
242
|
+
function SocialSignIn({ providers = ["google", "github", "x"], onSelect, disabled }) {
|
|
243
|
+
return /* @__PURE__ */ jsx6("div", { className: "xc-social", "data-xc": "social-sign-in", role: "group", "aria-label": "Continue with", children: providers.map((p) => /* @__PURE__ */ jsx6(Button3, { variant: "quiet", size: "lg", disabled, onClick: () => onSelect(p), "aria-label": `Continue with ${NAMES[p]}`, "data-provider": p, children: /* @__PURE__ */ jsx6(Mark, { p }) }, p)) });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/auth/OrDivider.tsx
|
|
247
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
248
|
+
function OrDivider({ children = "or continue with email" }) {
|
|
249
|
+
return /* @__PURE__ */ jsx7("div", { className: "xc-or", role: "separator", "aria-label": children, children: /* @__PURE__ */ jsx7("span", { className: "xc-or__label", children }) });
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/auth/states.ts
|
|
130
253
|
var STATES = [
|
|
131
254
|
{ id: "sign-in", props: { title: "Welcome back", body: "Sign in to your XENO account to use XENO Canvas.", actions: [{ id: "signIn", label: "Sign in to XENO", variant: "primary" }], note: "Your browser opens at xenostudio.ai, where you can continue with Google, GitHub or email. XENO Canvas never sees your password.", animate: false } },
|
|
132
255
|
{ id: "pending", props: { title: "Welcome back", body: "Sign in to your XENO account to use XENO Canvas.", actions: [{ id: "pending", label: "Finish in your browser\u2026", variant: "primary", disabled: true }, { id: "cancelSignIn", label: "Cancel", variant: "quiet" }], animate: false } },
|
|
@@ -135,12 +258,25 @@ var STATES = [
|
|
|
135
258
|
{ id: "expired-offline", props: { tag: "Offline too long", title: "Your plan couldn\u2019t be confirmed", body: "XENO Canvas hasn\u2019t been able to reach XENO for 14 days \u2014 last confirmed 16 days ago. Your plan may be fine; connect once and it will pick up where it left off.", actions: [{ id: "refresh", label: "Check again", variant: "primary" }, { id: "signOut", label: "Sign out", variant: "quiet" }], identity: "emilian@bnkrsys.com", animate: false } },
|
|
136
259
|
{ id: "update-required", props: { tag: "Update required", title: "Update XENO Canvas to continue", body: "Versions before 0.39.0 are no longer supported. The latest version is a short download away.", actions: [{ id: "openDownload", label: "Download the latest XENO Canvas", variant: "primary" }, { id: "signOut", label: "Sign out", variant: "quiet" }], identity: "emilian@bnkrsys.com", animate: false } }
|
|
137
260
|
];
|
|
261
|
+
var empty = { name: "", email: "", password: "" };
|
|
262
|
+
var CREDENTIAL_STATES = [
|
|
263
|
+
{ id: "signin", props: { mode: "signin", values: empty, title: "Welcome back", body: "Enter your credentials to access your account" } },
|
|
264
|
+
{ id: "signup", props: { mode: "signup", values: empty, title: "Get started", body: "Create your account and start creating" } },
|
|
265
|
+
{ id: "filled", props: { mode: "signin", values: { name: "", email: "you@example.com", password: "hunter22" }, title: "Welcome back", body: "Enter your credentials to access your account" } },
|
|
266
|
+
{ id: "errors", props: { mode: "signup", values: { name: "", email: "not-an-email", password: "123" }, errors: { name: "Please enter your full name", email: "Please enter a valid email address", password: "Password must be at least 6 characters" }, title: "Get started", body: "Create your account and start creating" } },
|
|
267
|
+
{ id: "submitting", props: { mode: "signin", values: { name: "", email: "you@example.com", password: "hunter22" }, submitting: true, title: "Welcome back", body: "Enter your credentials to access your account" } },
|
|
268
|
+
{ id: "rejected", props: { mode: "signin", values: { name: "", email: "you@example.com", password: "hunter22" }, errors: { form: "Invalid email or password." }, title: "Welcome back", body: "Enter your credentials to access your account" } }
|
|
269
|
+
];
|
|
138
270
|
export {
|
|
139
271
|
AuthDoor,
|
|
140
272
|
AuthHero,
|
|
273
|
+
CREDENTIAL_STATES,
|
|
274
|
+
CredentialForm,
|
|
141
275
|
LicencePlate,
|
|
276
|
+
OrDivider,
|
|
142
277
|
STATES,
|
|
143
278
|
SignInForm,
|
|
279
|
+
SocialSignIn,
|
|
144
280
|
XenoMark,
|
|
145
281
|
ensureAuthStyles
|
|
146
282
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* Families are subpaths: `@xenosystem/components/auth`, `/navigation`, `/feedback`, `/data`.
|
|
4
4
|
* This root re-exports nothing on purpose: import the family you use, so a bundle carries only it.
|
|
5
5
|
*/
|
|
6
|
-
declare const COMPONENTS_VERSION = "0.1
|
|
6
|
+
declare const COMPONENTS_VERSION = "0.2.1";
|
|
7
7
|
|
|
8
8
|
export { COMPONENTS_VERSION };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenosystem/components",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "XENO Components — rung 2 of the front ladder: molecules composed from @xenosystem/elements, with no host contract. Families as subpaths: /auth, /navigation, /feedback, /data.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|