@xenosystem/components 0.3.0 → 0.3.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.
@@ -122,12 +122,6 @@ declare function OrDivider({ children }: {
122
122
  children?: string;
123
123
  }): react.JSX.Element;
124
124
 
125
- /**
126
- * `EmailDisclosure` — the divider that is a BUTTON. On the origin page the email/password form starts
127
- * collapsed because it is the minority path (most people press a provider), so the "or continue with
128
- * email" rule opens it. A real button with `aria-expanded`/`aria-controls`, never a styled span, so it is
129
- * keyboard-reachable and announced as what it is.
130
- */
131
125
  interface EmailDisclosureProps {
132
126
  open: boolean;
133
127
  onToggle: () => void;
@@ -1,4 +1,5 @@
1
1
  // src/auth/styles.ts
2
+ import { useInsertionEffect } from "react";
2
3
  var STYLE_ID = "xeno-components-auth";
3
4
  var CSS = `
4
5
  .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}
@@ -45,7 +46,7 @@ var CSS = `
45
46
  .xc-cred__mode{width:100%}
46
47
  .xc-cred__collapse{display:grid;grid-template-rows:1fr;opacity:1;transition:grid-template-rows var(--xeno-dur-entrance) var(--xeno-ease),opacity var(--xeno-dur-entrance) var(--xeno-ease)}
47
48
  .xc-cred__collapse[data-open=false]{grid-template-rows:0fr;opacity:0}
48
- .xc-cred__collapse > *{overflow:hidden;min-height:0}
49
+ .xc-cred__collapseIn{overflow:hidden;min-height:0;display:flex;flex-direction:column;gap:24px}
49
50
  .xc-cred__fields{display:flex;flex-direction:column;gap:16px}
50
51
  .xc-cred__labelRow{display:flex;justify-content:space-between;align-items:baseline}
51
52
  .xc-cred__labelRow a{font-size:12px;color:var(--xeno-muted);text-decoration:none}
@@ -84,6 +85,11 @@ function ensureAuthStyles() {
84
85
  style.textContent = CSS;
85
86
  document.head.appendChild(style);
86
87
  }
88
+ function useAuthStyles() {
89
+ useInsertionEffect(() => {
90
+ ensureAuthStyles();
91
+ }, []);
92
+ }
87
93
 
88
94
  // src/auth/XenoMark.tsx
89
95
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -99,6 +105,7 @@ function XenoMark() {
99
105
  // src/auth/AuthHero.tsx
100
106
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
101
107
  function AuthHero({ headline, lead, stats, imageSrc, compact }) {
108
+ useAuthStyles();
102
109
  return /* @__PURE__ */ jsxs2("div", { className: "xc-hero", "data-xc": "auth-hero", children: [
103
110
  imageSrc && /* @__PURE__ */ jsx2("img", { className: "xc-hero__img", src: imageSrc, alt: "", draggable: false }),
104
111
  /* @__PURE__ */ jsxs2("div", { className: "xc-hero__in", children: [
@@ -128,6 +135,7 @@ import { useEffect, useState } from "react";
128
135
  import { Button } from "@xenosystem/elements-react";
129
136
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
130
137
  function SignInForm({ tag, title, body, actions, note, warning, identity, animate = true, phase }) {
138
+ useAuthStyles();
131
139
  const [visible, setVisible] = useState(!animate);
132
140
  useEffect(() => {
133
141
  if (!animate) return;
@@ -191,6 +199,7 @@ var L = {
191
199
  signup: "Sign Up"
192
200
  };
193
201
  function CredentialForm({ mode, onModeChange, values, onChange, errors = {}, submitting = false, onSubmit, title, body, before, after, labels, passwordRules, passwordAside, open = true, id = "xc-credential-fields" }) {
202
+ useAuthStyles();
194
203
  const [showPassword, setShowPassword] = useState3(false);
195
204
  const [passwordFocused, setPasswordFocused] = useState3(false);
196
205
  const showRules = mode === "signup" && !!passwordRules?.length && (passwordFocused || values.password.length > 0);
@@ -217,35 +226,37 @@ function CredentialForm({ mode, onModeChange, values, onChange, errors = {}, sub
217
226
  }
218
227
  ),
219
228
  before,
220
- /* @__PURE__ */ jsx5("div", { className: "xc-cred__collapse", "data-open": open, id, "aria-hidden": !open, children: /* @__PURE__ */ jsxs5("div", { className: "xc-cred__fields", children: [
221
- /* @__PURE__ */ jsx5("div", { className: "xc-cred__reveal", "data-open": mode === "signup", "aria-hidden": mode !== "signup", children: /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
222
- /* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.name }),
223
- /* @__PURE__ */ jsx5(TextInput, { size: "lg", value: values.name, onChange: set("name"), placeholder: "Your name", autoComplete: "name", tabIndex: mode === "signup" && open ? 0 : -1, "aria-invalid": !!errors.name, "data-field": "name" }),
224
- errors.name && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.name })
225
- ] }) }),
226
- /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
227
- /* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.email }),
228
- /* @__PURE__ */ jsx5(TextInput, { size: "lg", type: "email", value: values.email, onChange: set("email"), placeholder: "you@example.com", autoComplete: "email", required: true, tabIndex: open ? 0 : -1, "aria-invalid": !!errors.email, "data-field": "email" }),
229
- errors.email && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.email })
230
- ] }),
231
- /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
232
- /* @__PURE__ */ jsxs5("span", { className: "xc-cred__labelRow", children: [
233
- /* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.password }),
234
- passwordAside
229
+ /* @__PURE__ */ jsx5("div", { className: "xc-cred__collapse", "data-open": open, id, "aria-hidden": !open, children: /* @__PURE__ */ jsxs5("div", { className: "xc-cred__collapseIn", children: [
230
+ /* @__PURE__ */ jsxs5("div", { className: "xc-cred__fields", children: [
231
+ /* @__PURE__ */ jsx5("div", { className: "xc-cred__reveal", "data-open": mode === "signup", "aria-hidden": mode !== "signup", children: /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
232
+ /* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.name }),
233
+ /* @__PURE__ */ jsx5(TextInput, { size: "lg", value: values.name, onChange: set("name"), placeholder: "Your name", autoComplete: "name", tabIndex: mode === "signup" && open ? 0 : -1, "aria-invalid": !!errors.name, "data-field": "name" }),
234
+ errors.name && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.name })
235
+ ] }) }),
236
+ /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
237
+ /* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.email }),
238
+ /* @__PURE__ */ jsx5(TextInput, { size: "lg", type: "email", value: values.email, onChange: set("email"), placeholder: "you@example.com", autoComplete: "email", required: true, tabIndex: open ? 0 : -1, "aria-invalid": !!errors.email, "data-field": "email" }),
239
+ errors.email && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.email })
235
240
  ] }),
236
- /* @__PURE__ */ jsxs5("span", { className: "xc-cred__pw", children: [
237
- /* @__PURE__ */ jsx5(TextInput, { size: "lg", type: showPassword ? "text" : "password", value: values.password, onChange: set("password"), onFocus: () => setPasswordFocused(true), onBlur: () => setPasswordFocused(false), 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" }),
238
- /* @__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" })
239
- ] }),
240
- errors.password && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.password }),
241
- passwordRules && /* @__PURE__ */ jsx5("ul", { className: "xc-cred__rules", "data-open": showRules, "aria-live": "polite", children: passwordRules.map((r, i) => /* @__PURE__ */ jsxs5("li", { className: "xc-cred__rule", "data-met": r.met, style: { transitionDelay: `${i * 60}ms` }, children: [
242
- /* @__PURE__ */ jsx5("svg", { className: "xc-cred__ruleMark", viewBox: "0 0 16 16", "aria-hidden": "true", children: r.met ? /* @__PURE__ */ jsx5("path", { d: "M3.5 8.5l3 3 6-6", fill: "none", stroke: "currentColor", strokeWidth: "1.6" }) : /* @__PURE__ */ jsx5("rect", { x: "4", y: "7.25", width: "8", height: "1.5", fill: "currentColor" }) }),
243
- /* @__PURE__ */ jsx5("span", { children: r.label })
244
- ] }, r.label)) })
245
- ] })
241
+ /* @__PURE__ */ jsxs5("label", { className: "xc-cred__field", children: [
242
+ /* @__PURE__ */ jsxs5("span", { className: "xc-cred__labelRow", children: [
243
+ /* @__PURE__ */ jsx5("span", { className: "xc-cred__label", children: t.password }),
244
+ passwordAside
245
+ ] }),
246
+ /* @__PURE__ */ jsxs5("span", { className: "xc-cred__pw", children: [
247
+ /* @__PURE__ */ jsx5(TextInput, { size: "lg", type: showPassword ? "text" : "password", value: values.password, onChange: set("password"), onFocus: () => setPasswordFocused(true), onBlur: () => setPasswordFocused(false), placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", tabIndex: open ? 0 : -1, autoComplete: mode === "signup" ? "new-password" : "current-password", required: true, "aria-invalid": !!errors.password, "data-field": "password" }),
248
+ /* @__PURE__ */ jsx5(Button2, { type: "button", variant: "ghost", size: "sm", className: "xc-cred__eye", tabIndex: open ? 0 : -1, onClick: () => setShowPassword((v) => !v), "aria-label": showPassword ? "Hide password" : "Show password", "aria-pressed": showPassword, children: showPassword ? "Hide" : "Show" })
249
+ ] }),
250
+ errors.password && /* @__PURE__ */ jsx5("span", { className: "xc-cred__error", role: "alert", children: errors.password }),
251
+ passwordRules && /* @__PURE__ */ jsx5("ul", { className: "xc-cred__rules", "data-open": showRules, "aria-live": "polite", children: passwordRules.map((r, i) => /* @__PURE__ */ jsxs5("li", { className: "xc-cred__rule", "data-met": r.met, style: { transitionDelay: `${i * 60}ms` }, children: [
252
+ /* @__PURE__ */ jsx5("svg", { className: "xc-cred__ruleMark", viewBox: "0 0 16 16", "aria-hidden": "true", children: r.met ? /* @__PURE__ */ jsx5("path", { d: "M3.5 8.5l3 3 6-6", fill: "none", stroke: "currentColor", strokeWidth: "1.6" }) : /* @__PURE__ */ jsx5("rect", { x: "4", y: "7.25", width: "8", height: "1.5", fill: "currentColor" }) }),
253
+ /* @__PURE__ */ jsx5("span", { children: r.label })
254
+ ] }, r.label)) })
255
+ ] })
256
+ ] }),
257
+ errors.form && /* @__PURE__ */ jsx5("p", { className: "xc-form__warn", role: "alert", children: errors.form }),
258
+ /* @__PURE__ */ jsx5("div", { className: "xc-form__actions", children: /* @__PURE__ */ jsx5(Button2, { type: "submit", variant: "primary", size: "lg", busy: submitting, tabIndex: open ? 0 : -1, "data-intent": "submit", children: mode === "signin" ? t.submitSignIn : t.submitSignUp }) })
246
259
  ] }) }),
247
- errors.form && /* @__PURE__ */ jsx5("p", { className: "xc-form__warn", role: "alert", children: errors.form }),
248
- /* @__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 }) }),
249
260
  after && /* @__PURE__ */ jsx5("div", { className: "xc-cred__after", children: after })
250
261
  ] });
251
262
  }
@@ -265,18 +276,21 @@ function Mark({ p }) {
265
276
  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" }) });
266
277
  }
267
278
  function SocialSignIn({ providers = ["google", "github", "x"], onSelect, disabled }) {
279
+ useAuthStyles();
268
280
  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)) });
269
281
  }
270
282
 
271
283
  // src/auth/OrDivider.tsx
272
284
  import { jsx as jsx7 } from "react/jsx-runtime";
273
285
  function OrDivider({ children = "or continue with email" }) {
286
+ useAuthStyles();
274
287
  return /* @__PURE__ */ jsx7("div", { className: "xc-or", role: "separator", "aria-label": children, children: /* @__PURE__ */ jsx7("span", { className: "xc-or__label", children }) });
275
288
  }
276
289
 
277
290
  // src/auth/EmailDisclosure.tsx
278
291
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
279
292
  function EmailDisclosure({ open, onToggle, controls, openLabel = "hide email sign-in", closedLabel = "or continue with email" }) {
293
+ useAuthStyles();
280
294
  return /* @__PURE__ */ jsx8("div", { className: "xc-or", "data-xc": "email-disclosure", children: /* @__PURE__ */ jsxs7("button", { type: "button", className: "xc-or__label xc-or__btn", onClick: onToggle, "aria-expanded": open, "aria-controls": controls, children: [
281
295
  open ? openLabel : closedLabel,
282
296
  /* @__PURE__ */ jsx8("svg", { className: "xc-or__caret", "data-open": open, viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }) })
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.3.0";
6
+ declare const COMPONENTS_VERSION = "0.3.1";
7
7
 
8
8
  export { COMPONENTS_VERSION };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- var COMPONENTS_VERSION = "0.3.0";
2
+ var COMPONENTS_VERSION = "0.3.1";
3
3
  export {
4
4
  COMPONENTS_VERSION
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/components",
3
- "version": "0.3.0",
3
+ "version": "0.3.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",