@base316/react 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -87,7 +87,7 @@
87
87
  {
88
88
  "name": "SignIn",
89
89
  "kind": "component",
90
- "summary": "Password, passkey, magic-link and text-message sign-in in one form.",
90
+ "summary": "Sign in the ways the environment offers — password, magic link, passkeys, text message, social providers and SSO, as switched on in the dashboard (`GET /v1/auth/methods`).",
91
91
  "useWhen": "The application renders its own sign-in rather than redirecting to the hosted page.",
92
92
  "requires": [],
93
93
  "props": [
@@ -96,19 +96,54 @@
96
96
  "summary": "Called once a session exists.",
97
97
  "required": false
98
98
  },
99
+ {
100
+ "name": "password",
101
+ "summary": "`false` hides the password form. Every method prop can only turn a method off.",
102
+ "required": false
103
+ },
99
104
  {
100
105
  "name": "passkeys",
101
- "summary": "Offer passkeys where supported. On by default.",
106
+ "summary": "`false` hides passkeys; otherwise offered where the environment and browser allow.",
107
+ "required": false
108
+ },
109
+ {
110
+ "name": "magicLink",
111
+ "summary": "`false` hides the emailed sign-in link.",
102
112
  "required": false
103
113
  },
104
114
  {
105
115
  "name": "magicLinkRedirectUrl",
106
- "summary": "Where an emailed link lands, which must be registered on the environment. Without it, magic link is not offered at all.",
116
+ "summary": "Where an emailed link lands; defaults to the page rendering the form, which redeems `?token=`. Must be on the environment's redirect allow-list.",
107
117
  "required": false
108
118
  },
109
119
  {
110
120
  "name": "phone",
111
- "summary": "Offer signing in with a code sent by text message. Needs text messages switched on for the environment, and its own Twilio account in production.",
121
+ "summary": "`false` hides text-message codes.",
122
+ "required": false
123
+ },
124
+ {
125
+ "name": "social",
126
+ "summary": "`false` hides the social buttons; a list of slugs keeps only those providers.",
127
+ "required": false
128
+ },
129
+ {
130
+ "name": "sso",
131
+ "summary": "`false` hides \"Sign in with SSO\".",
132
+ "required": false
133
+ },
134
+ {
135
+ "name": "socialRedirectUrl",
136
+ "summary": "Your server route a social or SSO sign-in returns to with `?code=&state=`: check `state` against the `b316_oauth_state` cookie (`readOAuthState`), then `base316.auth.exchangeCode` with the secret key. On the redirect allow-list. Without it no social or SSO button is shown.",
137
+ "required": false
138
+ },
139
+ {
140
+ "name": "socialState",
141
+ "summary": "A short value carried through a social or SSO sign-in, returned by `readOAuthState`.",
142
+ "required": false
143
+ },
144
+ {
145
+ "name": "labels",
146
+ "summary": "Wording for the form, for translation.",
112
147
  "required": false
113
148
  },
114
149
  {
@@ -133,6 +168,49 @@
133
168
  "SecondFactorStep"
134
169
  ]
135
170
  },
171
+ {
172
+ "name": "SocialSignIn",
173
+ "kind": "component",
174
+ "summary": "The environment's social sign-in buttons alone (\"Continue with Google\"), for a sign-in or sign-up form you draw yourself.",
175
+ "useWhen": "Your own form needs the social providers switched on in the dashboard. SignIn and SignUp already include them.",
176
+ "requires": [],
177
+ "props": [
178
+ {
179
+ "name": "socialRedirectUrl",
180
+ "summary": "Your server route the code lands on with `?code=&state=`; check with `readOAuthState`, redeem with `exchangeCode`. On the redirect allow-list. Without it nothing is drawn.",
181
+ "required": false
182
+ },
183
+ {
184
+ "name": "socialState",
185
+ "summary": "A short value carried through, returned by `readOAuthState`.",
186
+ "required": false
187
+ },
188
+ {
189
+ "name": "social",
190
+ "summary": "`false` hides every button; a list of slugs keeps only those providers.",
191
+ "required": false
192
+ },
193
+ {
194
+ "name": "intent",
195
+ "summary": "`sign-up` hides the buttons when the environment is closed to new accounts.",
196
+ "required": false
197
+ },
198
+ {
199
+ "name": "divider",
200
+ "summary": "Draw an \"or\" rule under the buttons.",
201
+ "required": false
202
+ },
203
+ {
204
+ "name": "labels",
205
+ "summary": "`continueWith` and `or`, for translation.",
206
+ "required": false
207
+ }
208
+ ],
209
+ "seeAlso": [
210
+ "SignIn",
211
+ "SignUp"
212
+ ]
213
+ },
136
214
  {
137
215
  "name": "SignUp",
138
216
  "kind": "component",
@@ -165,6 +243,21 @@
165
243
  "summary": "Wording for the second-factor step, for translation.",
166
244
  "required": false
167
245
  },
246
+ {
247
+ "name": "social",
248
+ "summary": "`false` hides the social buttons; a list of slugs keeps only those providers.",
249
+ "required": false
250
+ },
251
+ {
252
+ "name": "socialRedirectUrl",
253
+ "summary": "Where a social sign-up returns with `?code=&state=`, as on SignIn. Without it no social button is shown.",
254
+ "required": false
255
+ },
256
+ {
257
+ "name": "socialState",
258
+ "summary": "A short value carried through a social sign-up, returned by `readOAuthState`.",
259
+ "required": false
260
+ },
168
261
  {
169
262
  "name": "className",
170
263
  "summary": "Your own classes on the wrapper.",
@@ -1,39 +1,100 @@
1
1
  import { type CSSProperties } from "react";
2
2
  import { type SecondFactorLabels } from "./SecondFactorStep";
3
3
  /**
4
- * Email and password sign-in, and — where the application turns them on — a
5
- * magic link or a code by text message.
4
+ * Sign in the ways the environment offers: the dashboard's sign-in switches
5
+ * (password, magic link, passkeys, text message), its enabled social providers
6
+ * and enterprise SSO, read from `GET /v1/auth/methods` — so turning a method on
7
+ * or off in Base316 changes this form without a release. Props can only turn a
8
+ * method off.
6
9
  *
7
10
  * Handles the MFA branch, because an account with a second factor gets a
8
11
  * challenge instead of a session, and a form that ignores that case appears to
9
12
  * fail for exactly the users who most need it to work. That includes the case
10
13
  * where the environment requires a factor and the person has none: they enrol
11
14
  * one here (`SecondFactorStep`), see their recovery codes, and are signed in.
15
+ *
16
+ * Social and SSO sign-in leave the page: the browser goes to the provider and
17
+ * comes back to `socialRedirectUrl` with a single-use `code` (and `state`),
18
+ * which the application's server redeems with its secret key
19
+ * (`base316.auth.exchangeCode`) after checking `state` against the
20
+ * `b316_oauth_state` cookie this form writes (`readOAuthState`).
12
21
  */
13
- export declare function SignIn({ onSignedIn, passkeys, magicLinkRedirectUrl, phone, secondFactorLabels, className, style, }: {
22
+ export interface SignInLabels {
23
+ email: string;
24
+ password: string;
25
+ mobileNumber: string;
26
+ code: string;
27
+ tabPassword: string;
28
+ tabMagicLink: string;
29
+ tabPhone: string;
30
+ submit: string;
31
+ working: string;
32
+ emailMeALink: string;
33
+ textMeACode: string;
34
+ includeCountryCode: string;
35
+ codeSent: (destination: string) => string;
36
+ useDifferentNumber: string;
37
+ or: string;
38
+ passkey: string;
39
+ /** A social button: "Continue with Google". */
40
+ continueWith: (name: string, provider: string) => string;
41
+ sso: string;
42
+ ssoEmail: string;
43
+ ssoContinue: string;
44
+ back: string;
45
+ checkEmailTitle: string;
46
+ checkEmail: (email: string) => string;
47
+ backToSignIn: string;
48
+ wrongPassword: string;
49
+ passkeyFailed: string;
50
+ linkInvalid: string;
51
+ linkFailed: string;
52
+ wrongCode: string;
53
+ codeFailed: string;
54
+ /** Nothing the form can offer: every method is off, or none survives the props. */
55
+ noMethods: string;
56
+ }
57
+ export declare const DEFAULT_SIGN_IN_LABELS: SignInLabels;
58
+ export interface SignInProps {
14
59
  onSignedIn?: () => void;
15
- /** Offer passkeys alongside the password. On by default where supported. */
60
+ /** `false` hides the password form even where the environment offers it. */
61
+ password?: boolean;
62
+ /** `false` hides passkeys. Otherwise offered where the environment and the browser allow. */
16
63
  passkeys?: boolean;
64
+ /** `false` hides the emailed sign-in link. */
65
+ magicLink?: boolean;
17
66
  /**
18
- * Where an emailed sign-in link lands. Offering magic link at all requires
19
- * it, because the link has to point somewhere this application controls —
20
- * and the URL must be registered on the environment's sign-in page, the same
21
- * list that governs redirects.
22
- *
23
- * The page it names should render this component: arriving with `?token=`
24
- * redeems it automatically.
67
+ * Where an emailed sign-in link lands. Defaults to the page rendering this
68
+ * form, which redeems `?token=` on arrival. Either way the URL must be on
69
+ * the environment's redirect allow-list.
25
70
  */
26
71
  magicLinkRedirectUrl?: string;
72
+ /** `false` hides signing in with a code by text message. */
73
+ phone?: boolean;
27
74
  /**
28
- * Offer signing in with a code sent by text message.
29
- *
30
- * Off by default, because it needs the environment switched on for it and,
31
- * in production, the environment's own Twilio account.
75
+ * `false` hides the social buttons; a list (`["google", "apple"]`) keeps
76
+ * only those providers.
32
77
  */
33
- phone?: boolean;
78
+ social?: boolean | readonly string[];
79
+ /** `false` hides "Sign in with SSO". */
80
+ sso?: boolean;
81
+ /**
82
+ * Where a social or SSO sign-in comes back to, with `?code=&state=`: a
83
+ * route on your server that checks the state and redeems the code with a
84
+ * secret key. On the environment's redirect allow-list. Without it no
85
+ * social or SSO button is shown — a code has nowhere safe to land.
86
+ */
87
+ socialRedirectUrl?: string;
88
+ /**
89
+ * A short value of yours carried through a social or SSO sign-in (where to
90
+ * go next), returned as `appState` by `readOAuthState`. Treat it as input.
91
+ */
92
+ socialState?: string;
93
+ labels?: Partial<SignInLabels>;
34
94
  /** Override the second-factor step's wording, for translation. */
35
95
  secondFactorLabels?: Partial<SecondFactorLabels>;
36
96
  className?: string;
37
97
  style?: CSSProperties;
38
- }): import("react").JSX.Element;
98
+ }
99
+ export declare function SignIn({ onSignedIn, password: passwordProp, passkeys: passkeysProp, magicLink: magicLinkProp, magicLinkRedirectUrl, phone: phoneProp, social: socialProp, sso: ssoProp, socialRedirectUrl, socialState, labels: overrides, secondFactorLabels, className, style, }: SignInProps): import("react").JSX.Element;
39
100
  //# sourceMappingURL=SignIn.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SignIn.d.ts","sourceRoot":"","sources":["../../src/SignIn.tsx"],"names":[],"mappings":"AASA,OAAO,EAA+B,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAIxF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE/E;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,EACtB,UAAU,EACV,QAAe,EACf,oBAAoB,EACpB,KAAa,EACb,kBAAkB,EAClB,SAAS,EACT,KAAK,GACL,EAAE;IACF,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;OAQG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACtB,+BAwbA"}
1
+ {"version":3,"file":"SignIn.d.ts","sourceRoot":"","sources":["../../src/SignIn.tsx"],"names":[],"mappings":"AASA,OAAO,EAA+B,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAIxF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAI/E;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,sBAAsB,EAAE,YAiCpC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IACrC,wCAAwC;IACxC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACtB;AAID,wBAAgB,MAAM,CAAC,EACtB,UAAU,EACV,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,aAAa,EACxB,oBAAoB,EACpB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,OAAO,EACZ,iBAAiB,EACjB,WAAW,EACX,MAAM,EAAE,SAAS,EACjB,kBAAkB,EAClB,SAAS,EACT,KAAK,GACL,EAAE,WAAW,+BAmjBb"}
@@ -22,6 +22,12 @@ import { type SecondFactorLabels } from "./SecondFactorStep";
22
22
  * into the inviting team — no personal workspace — with its address counted as
23
23
  * verified, because the token reached that mailbox. The form says which team
24
24
  * and fills in the address the invitation went to.
25
+ *
26
+ * The environment's social providers are offered above the form, as on the
27
+ * hosted sign-up page ("Continue with Google" creates the account on first
28
+ * use), when `socialRedirectUrl` says where the code may land. A closed
29
+ * sign-up (the dashboard's switch) says so instead of offering a form the
30
+ * server would refuse — unless the page carries an invitation, which admits.
25
31
  */
26
32
  export interface SignUpLabels {
27
33
  name: string;
@@ -45,6 +51,11 @@ export interface SignUpLabels {
45
51
  genericError: string;
46
52
  /** Above the form when the page came from an invitation. */
47
53
  joining: (organizationName: string, roleName: string) => string;
54
+ /** A social button: "Continue with Google". */
55
+ continueWith: (name: string, provider: string) => string;
56
+ or: string;
57
+ /** The environment is not accepting new accounts. */
58
+ closed: string;
48
59
  }
49
60
  export declare const DEFAULT_SIGN_UP_LABELS: SignUpLabels;
50
61
  export interface SignUpProps {
@@ -59,8 +70,21 @@ export interface SignUpProps {
59
70
  labels?: Partial<SignUpLabels>;
60
71
  /** Override the second-factor step's wording, for translation. */
61
72
  secondFactorLabels?: Partial<SecondFactorLabels>;
73
+ /**
74
+ * `false` hides the social buttons; a list (`["google", "apple"]`) keeps
75
+ * only those providers.
76
+ */
77
+ social?: boolean | readonly string[];
78
+ /**
79
+ * Where a social sign-up comes back to with `?code=&state=`, as on
80
+ * `<SignIn>`: a route on your server that checks the state and redeems the
81
+ * code with a secret key. Without it no social button is shown.
82
+ */
83
+ socialRedirectUrl?: string;
84
+ /** A short value of yours carried through a social sign-up (`readOAuthState`). */
85
+ socialState?: string;
62
86
  className?: string;
63
87
  style?: CSSProperties;
64
88
  }
65
- export declare function SignUp({ onSignedUp, invitationToken: suppliedInvitation, onJoined, labels: overrides, secondFactorLabels, className, style, }: SignUpProps): import("react").JSX.Element;
89
+ export declare function SignUp({ onSignedUp, invitationToken: suppliedInvitation, onJoined, labels: overrides, secondFactorLabels, social, socialRedirectUrl, socialState, className, style, }: SignUpProps): import("react").JSX.Element;
66
90
  //# sourceMappingURL=SignUp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SignUp.d.ts","sourceRoot":"","sources":["../../src/SignUp.tsx"],"names":[],"mappings":"AASA,OAAO,EAAuB,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAIhF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,6EAA6E;IAC7E,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,OAAO,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CAChE;AAED,eAAO,MAAM,sBAAsB,EAAE,YAoBpC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACtB;AAiBD,wBAAgB,MAAM,CAAC,EACtB,UAAU,EACV,eAAe,EAAE,kBAAkB,EACnC,QAAQ,EACR,MAAM,EAAE,SAAS,EACjB,kBAAkB,EAClB,SAAS,EACT,KAAK,GACL,EAAE,WAAW,+BA+Nb"}
1
+ {"version":3,"file":"SignUp.d.ts","sourceRoot":"","sources":["../../src/SignUp.tsx"],"names":[],"mappings":"AASA,OAAO,EAAuB,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAIhF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAI/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,6EAA6E;IAC7E,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,OAAO,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAChE,+CAA+C;IAC/C,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,sBAAsB,EAAE,YAuBpC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjD;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACtB;AAiBD,wBAAgB,MAAM,CAAC,EACtB,UAAU,EACV,eAAe,EAAE,kBAAkB,EACnC,QAAQ,EACR,MAAM,EAAE,SAAS,EACjB,kBAAkB,EAClB,MAAM,EACN,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,KAAK,GACL,EAAE,WAAW,+BA+Qb"}
@@ -0,0 +1,16 @@
1
+ import type { SocialSignInOption } from "@base316/sdk";
2
+ /**
3
+ * "Continue with Google", "Continue with Apple" — one button per enabled
4
+ * provider, drawn as each provider's guidelines ask: its own mark, its own
5
+ * colours (Google white with a grey outline, Apple black with the white logo,
6
+ * Microsoft its four squares), and a label naming it. "Continue with" is a
7
+ * title both Google's and Apple's guidelines accept, and it reads right on a
8
+ * sign-up form as well as a sign-in one.
9
+ */
10
+ export declare function SocialButtons({ options, continueWith, disabled, onChoose, }: {
11
+ options: SocialSignInOption[];
12
+ continueWith: (name: string, provider: string) => string;
13
+ disabled?: boolean;
14
+ onChoose: (option: SocialSignInOption) => void;
15
+ }): import("react").JSX.Element | null;
16
+ //# sourceMappingURL=SocialButtons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocialButtons.d.ts","sourceRoot":"","sources":["../../src/SocialButtons.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAIvE;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC7B,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,QAAQ,GACR,EAAE;IACF,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C,sCAyCA"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The environment's social sign-in buttons on their own, for an application
3
+ * that draws the rest of its sign-in or sign-up form itself.
4
+ *
5
+ * The same buttons `<SignIn>` and `<SignUp>` show, from the same
6
+ * `GET /v1/auth/methods`: each enabled provider with its mark and colours,
7
+ * leaving for Base316's host with a `b316_oauth_state` cookie and the same
8
+ * value as `state`, and coming back to `socialRedirectUrl` with a single-use
9
+ * code for your server to check (`readOAuthState`) and redeem
10
+ * (`base316.auth.exchangeCode`). Renders nothing until the environment answers,
11
+ * when it has no provider on, or without `socialRedirectUrl`.
12
+ */
13
+ export declare function SocialSignIn({ socialRedirectUrl, socialState, social, intent, divider, labels, }: {
14
+ /**
15
+ * Your server route the code lands on; on the environment's redirect
16
+ * allow-list. Without it nothing is drawn: a code has nowhere safe to land.
17
+ */
18
+ socialRedirectUrl?: string;
19
+ /** A short value of yours carried through (`readOAuthState` returns it as `appState`). */
20
+ socialState?: string;
21
+ /** `false` hides every button; a list (`["google", "apple"]`) keeps only those. */
22
+ social?: boolean | readonly string[];
23
+ /** On a sign-up form the buttons disappear when the environment is closed to new accounts. */
24
+ intent?: "sign-in" | "sign-up";
25
+ /** Draw an "or" rule under the buttons, before a form of your own. */
26
+ divider?: boolean;
27
+ labels?: {
28
+ continueWith?: (name: string, provider: string) => string;
29
+ or?: string;
30
+ };
31
+ }): import("react").JSX.Element | null;
32
+ //# sourceMappingURL=SocialSignIn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocialSignIn.d.ts","sourceRoot":"","sources":["../../src/SocialSignIn.tsx"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC5B,iBAAiB,EACjB,WAAW,EACX,MAAM,EACN,MAAkB,EAClB,OAAe,EACf,MAAM,GACN,EAAE;IACF;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IACrC,8FAA8F;IAC9F,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpF,sCAmCA"}
@@ -59,5 +59,5 @@ export declare function cls(base: string, extra?: string): string;
59
59
  * Appended as a second block so the print rules stay next to the invoice they
60
60
  * apply to, rather than being buried in the middle of the component styles.
61
61
  */
62
- export declare const STYLESHEET_EXTRA = "\n.b316-pay__element { margin-bottom: var(--b316-spacing); min-height: 40px; }\n\n.b316-pay__submit {\n width: 100%;\n padding: 11px 14px;\n border: 0;\n border-radius: calc(var(--b316-radius) / 1.6);\n background: var(--b316-color-primary);\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.b316-pay__submit[disabled] { opacity: 0.55; cursor: progress; }\n\n.b316-pay__error {\n background: var(--b316-color-danger-bg);\n color: var(--b316-color-danger);\n padding: 8px 10px;\n border-radius: calc(var(--b316-radius) / 2);\n font-size: 0.9em;\n margin-bottom: var(--b316-spacing);\n}\n\n.b316-pay__done {\n background: var(--b316-color-success-bg, #f0fdf4);\n color: var(--b316-color-success);\n padding: 12px 14px;\n border-radius: calc(var(--b316-radius) / 2);\n text-align: center;\n margin: 0;\n}\n\n.b316-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--b316-color-border); }\n.b316-tab {\n flex: 1; padding: 8px 4px; background: none; border: 0; cursor: pointer;\n font: inherit; font-size: .95em; color: var(--b316-color-muted);\n border-bottom: 2px solid transparent; margin-bottom: -1px;\n}\n.b316-tab-on { color: var(--b316-color-text); border-bottom-color: var(--b316-color-primary); }\n.b316-branding { display: flex; flex-direction: column; gap: 4px; }\n.b316-branding-logo { max-height: 40px; width: auto; align-self: flex-start; }\n.b316-branding-name { font-size: 1.5em; font-weight: 650; letter-spacing: -.01em; }\n.b316-branding-tagline { color: var(--b316-color-muted); }\n\n.b316-invoice-table { width: 100%; border-collapse: collapse; font-size: 0.94em; }\n.b316-invoice-table th {\n text-align: left;\n font-weight: 500;\n color: var(--b316-color-muted);\n font-size: 0.85em;\n padding: 0 0 6px;\n border-bottom: 1px solid var(--b316-color-border);\n}\n.b316-invoice-table td { padding: 9px 0; border-bottom: 1px solid var(--b316-color-border); }\n/* Columns need breathing room or the amount runs straight into the action \u2014\n \"$49.00View\" \u2014 which is what happens when only the row has padding. */\n.b316-invoice-table th + th,\n.b316-invoice-table td + td { padding-left: 16px; }\n.b316-invoice-table td:last-child,\n.b316-invoice-table th:last-child { text-align: right; width: 1%; white-space: nowrap; }\n.b316-invoice-table tr:last-child td { border-bottom: 0; }\n.b316-num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.b316-invoice-view {\n margin-top: calc(var(--b316-spacing) * 1.4);\n border-top: 1px solid var(--b316-color-border);\n padding-top: calc(var(--b316-spacing) * 1.4);\n}\n.b316-invoice-actions { display: flex; gap: 8px; justify-content: flex-end; margin-bottom: var(--b316-spacing); }\n.b316-invoice-doc { display: flex; flex-direction: column; gap: calc(var(--b316-spacing) * 1.4); }\n.b316-invoice-meta { display: grid; grid-template-columns: 1fr 1fr; gap: var(--b316-spacing); }\n.b316-invoice-totals { display: flex; flex-direction: column; gap: 6px; margin-left: auto; min-width: 240px; }\n.b316-invoice-total { font-weight: 650; border-top: 1px solid var(--b316-color-border); padding-top: 6px; }\n\n/* Printing an invoice emits the invoice alone, and printing anything else is\n none of this package's business.\n\n This used to start with a bare \"body * { visibility: hidden }\", which is the\n usual recipe for printing one element \u2014 and it is scoped to the document,\n not to us. The stylesheet is injected into the host page's head the first\n time any Base316 component mounts, so from that moment every print in the\n host application came out blank unless the content happened to sit inside\n .b316-invoice-doc. A customer printing their own page had no way to connect\n it back to us.\n\n Scoped to a root the invoice sets on <html> while it is being printed\n instead, so nothing applies unless an invoice asked for it. */\n@media print {\n [data-b316-printing] body * { visibility: hidden; }\n [data-b316-printing] .b316-invoice-doc,\n [data-b316-printing] .b316-invoice-doc * { visibility: visible; }\n [data-b316-printing] .b316-invoice-doc {\n position: absolute;\n inset: 0 auto auto 0;\n width: 100%;\n padding: 24px;\n }\n .b316-invoice-actions { display: none; }\n}\n\n/* --- Collections: tables, forms and detail views ------------------------- */\n\n.b316-table-wrap { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-table-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--b316-spacing); flex-wrap: wrap; }\n.b316-table-actions { display: flex; align-items: center; gap: var(--b316-spacing); }\n\n/* The table scrolls inside its own box rather than pushing the page sideways:\n a collection with twenty fields is normal, and a horizontally scrolling page\n makes every other component on it unreachable. */\n.b316-table-scroll { overflow-x: auto; border: 1px solid var(--b316-color-border); border-radius: var(--b316-radius); }\n.b316-table { width: 100%; border-collapse: collapse; font-size: 0.95em; }\n.b316-table th, .b316-table td { padding: 10px 12px; text-align: left; vertical-align: top; white-space: nowrap; }\n.b316-table thead th { background: var(--b316-color-surface-muted, rgba(0,0,0,.03)); font-weight: 600; font-size: 0.87em; color: var(--b316-color-muted); border-bottom: 1px solid var(--b316-color-border); }\n.b316-table tbody tr + tr td { border-top: 1px solid var(--b316-color-border); }\n.b316-row-clickable { cursor: pointer; }\n.b316-row-clickable:hover td { background: var(--b316-color-surface-muted, rgba(0,0,0,.02)); }\n.b316-table-rowactions { text-align: right; white-space: nowrap; }\n.b316-table-more { display: flex; justify-content: center; }\n\n.b316-sort { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer; }\n.b316-sort:focus-visible { outline: 2px solid var(--b316-color-primary); outline-offset: 2px; }\n\n.b316-empty { padding: calc(var(--b316-spacing) * 2); text-align: center; color: var(--b316-color-muted); }\n\n.b316-button-quiet {\n background: none;\n border: 0;\n padding: 4px 6px;\n font: inherit;\n font-size: 0.9em;\n color: var(--b316-color-primary);\n cursor: pointer;\n border-radius: calc(var(--b316-radius) / 2);\n}\n.b316-button-quiet:hover:not([disabled]) { background: var(--b316-color-surface-muted, rgba(0,0,0,.05)); }\n.b316-button-quiet:focus-visible { outline: 2px solid var(--b316-color-primary); outline-offset: 1px; }\n.b316-button-quiet[disabled] { opacity: .55; cursor: not-allowed; }\n.b316-danger { color: var(--b316-color-danger, #b42318); }\n\n.b316-chip {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--b316-color-surface-muted, rgba(0,0,0,.05));\n font-size: 0.87em;\n}\n.b316-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; }\n\n.b316-form { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-form-title { margin: 0; font-size: 1.05em; }\n.b316-form-actions { display: flex; justify-content: flex-end; gap: 8px; }\n.b316-field { display: flex; flex-direction: column; gap: 4px; }\n.b316-hint { font-size: 0.82em; color: var(--b316-color-muted); }\n.b316-input-invalid { border-color: var(--b316-color-danger, #b42318); }\n.b316-choices { display: flex; flex-wrap: wrap; gap: 10px; }\n.b316-choice { display: inline-flex; align-items: center; gap: 6px; font-size: 0.95em; }\n.b316-suffixed { display: flex; align-items: center; gap: 8px; }\n.b316-address { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }\n\n.b316-relation-chosen { display: flex; align-items: center; gap: 8px; }\n.b316-relation-results {\n list-style: none;\n margin: 4px 0 0;\n padding: 4px;\n border: 1px solid var(--b316-color-border);\n border-radius: var(--b316-radius);\n max-height: 220px;\n overflow-y: auto;\n background: var(--b316-color-surface, #fff);\n}\n.b316-relation-result { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 6px 8px; font: inherit; cursor: pointer; border-radius: calc(var(--b316-radius) / 2); }\n.b316-relation-result:hover, .b316-relation-result:focus-visible { background: var(--b316-color-surface-muted, rgba(0,0,0,.05)); outline: none; }\n.b316-relation-empty { padding: 6px 8px; }\n\n.b316-detail { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--b316-spacing); }\n.b316-detail-title { margin: 0; font-size: 1.1em; }\n.b316-detail-actions { display: flex; gap: 4px; }\n.b316-detail-fields { display: grid; grid-template-columns: minmax(120px, 200px) 1fr; gap: 8px var(--b316-spacing); margin: 0; }\n.b316-detail-row { display: contents; }\n.b316-detail-fields dd { margin: 0; }\n\n/* One column on a narrow screen. A label column of 200px beside a value leaves\n nothing for the value on a phone. */\n/* --- Teams --------------------------------------------------------------- */\n\n.b316-team { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-team-title { margin: 0; font-size: 1em; font-weight: 600; }\n.b316-team-subtitle { margin: 0; font-size: .9em; font-weight: 600; color: var(--b316-color-muted); }\n.b316-team-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }\n.b316-team-member { display: flex; align-items: center; justify-content: space-between; gap: var(--b316-spacing); }\n.b316-team-member-side { display: flex; align-items: center; gap: 8px; }\n.b316-team-invite { display: flex; flex-direction: column; gap: 4px; }\n.b316-team-invite-row { display: flex; gap: 8px; }\n.b316-team-invite-row input { flex: 1; }\n/* Selectable and wrapping: this is copied by hand and pasted into an email. */\n.b316-team-link { display: flex; flex-direction: column; gap: 4px; }\n.b316-team-link code { word-break: break-all; user-select: all; padding: 8px; border: 1px solid var(--b316-color-border); border-radius: var(--b316-radius); }\n\n.b316-invitation { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-invitation-actions { display: flex; align-items: center; gap: var(--b316-spacing); }\n\n/* --- Sessions, two-factor and the password flows ------------------------- */\n\n.b316-sessions { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-sessions-head { display: flex; align-items: center; justify-content: space-between; gap: var(--b316-spacing); flex-wrap: wrap; }\n.b316-sessions-title, .b316-mfa-title { margin: 0; font-size: 1em; font-weight: 600; }\n.b316-sessions-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }\n.b316-session { display: flex; flex-direction: column; gap: 2px; }\n.b316-session-device { display: flex; align-items: center; gap: 6px; font-size: 0.95em; }\n\n.b316-device { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-device-title { margin: 0; font-size: 1em; font-weight: 600; }\n/* What is being granted, listed rather than run together: somebody is deciding\n on this, and a comma-separated line is read as one thing. */\n.b316-device-scopes { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }\n.b316-device-scopes li { padding: 2px 8px; border-radius: 999px; font-size: 0.85em; background: var(--b316-color-surface-muted, rgba(0,0,0,.05)); }\n.b316-device-actions { display: flex; gap: 8px; }\n\n.b316-privacy { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-privacy-title { margin: 0; font-size: 1em; font-weight: 600; }\n/* Wraps rather than squeezes: the explanation beside each control is the part\n that matters, and on a narrow screen it belongs above the button. */\n.b316-privacy-row { display: flex; flex-wrap: wrap; align-items: start; justify-content: space-between; gap: 10px; }\n.b316-privacy-row p { margin: 0; }\n.b316-privacy-confirm { display: flex; flex-direction: column; gap: 8px; }\n.b316-privacy-actions { display: flex; justify-content: flex-end; gap: 8px; }\n\n.b316-mfa { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-mfa-enrol, .b316-mfa-codes, .b316-mfa-on, .b316-mfa-off { display: flex; flex-direction: column; gap: 10px; }\n.b316-mfa-actions { display: flex; justify-content: flex-end; gap: 8px; }\n/* Selectable and wrapping: this is copied by hand on the device that cannot\n scan its own screen. */\n.b316-mfa-secret code {\n display: block;\n padding: 10px;\n border: 1px solid var(--b316-color-border);\n border-radius: var(--b316-radius);\n font-size: 1.05em;\n letter-spacing: .08em;\n word-break: break-all;\n user-select: all;\n}\n.b316-mfa-uri { font-size: 0.9em; }\n.b316-mfa-code-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\n.b316-mfa-code-list code { user-select: all; }\n/* The enrolment choices: whole-width buttons with their explanation inside,\n so the explanation is part of what a screen reader announces. */\n.b316-mfa-methods { display: flex; flex-direction: column; gap: 8px; border: 0; margin: 0; padding: 0; min-width: 0; }\n.b316-mfa-method { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; text-align: left; }\n.b316-mfa-method .b316-muted { font-weight: 400; }\n/* Always on white with a margin: a QR code on a dark theme does not scan. */\n.b316-mfa-qr { align-self: center; width: 180px; height: 180px; padding: 8px; background: #fff; border-radius: var(--b316-radius); }\n\n@media (max-width: 560px) {\n .b316-mfa-code-list { grid-template-columns: 1fr; }\n .b316-detail-fields { grid-template-columns: 1fr; }\n .b316-detail-row { display: block; margin-bottom: 10px; }\n .b316-address { grid-template-columns: 1fr; }\n}\n\n/* --- Board --------------------------------------------------------------- */\n\n.b316-board-wrap { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n/* The board scrolls sideways inside itself. Six columns is normal and a page\n that scrolls horizontally puts everything else on it out of reach. */\n.b316-board { display: flex; gap: var(--b316-spacing); overflow-x: auto; align-items: flex-start; padding-bottom: 4px; }\n.b316-board-column {\n flex: 0 0 260px;\n background: var(--b316-color-surface-muted, rgba(0,0,0,.03));\n border: 1px solid transparent;\n border-radius: var(--b316-radius);\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.b316-board-over { border-color: var(--b316-color-primary); }\n.b316-board-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.b316-board-title { font-weight: 600; font-size: 0.92em; }\n.b316-board-cards { display: flex; flex-direction: column; gap: 8px; min-height: 40px; }\n.b316-board-card {\n background: var(--b316-color-surface, #fff);\n border: 1px solid var(--b316-color-border);\n border-radius: calc(var(--b316-radius) * .8);\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 0.9em;\n}\n.b316-board-card[draggable=\"true\"] { cursor: grab; }\n.b316-board-card-title { font-weight: 600; }\n.b316-board-card-field { display: flex; justify-content: space-between; gap: 8px; }\n.b316-board-move { display: flex; align-items: center; gap: 6px; margin-top: 2px; }\n.b316-board-move select { flex: 1; font-size: 0.9em; padding: 2px 4px; }\n.b316-board-empty { color: var(--b316-color-muted); font-size: 0.87em; padding: 6px 2px; }\n\n/* --- Chart --------------------------------------------------------------- */\n\n.b316-chart { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-chart-title { font-weight: 600; font-size: 0.95em; }\n.b316-chart-plot { display: flex; align-items: flex-end; gap: 4px; overflow-x: auto; }\n.b316-chart-col { flex: 1 0 24px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 4px; }\n.b316-chart-bar { width: 100%; background: var(--b316-color-primary); border-radius: 3px 3px 0 0; min-height: 2px; }\n.b316-chart-label { font-size: 0.7em; color: var(--b316-color-muted); white-space: nowrap; transform: rotate(-45deg); transform-origin: top left; height: 1.6em; }\n.b316-chart-data summary { cursor: pointer; font-size: 0.87em; color: var(--b316-color-muted); }\n.b316-chart-data table { margin-top: 8px; }\n\n/* --- Billing portal ------------------------------------------------------ */\n\n.b316-billing-portal { display: grid; gap: var(--b316-spacing); }\n.b316-billing-portal-section-title { font-weight: 600; font-size: 1em; margin: 0 0 8px; }\n.b316-billing-portal .b316-plans { margin: 0; }\n.b316-invoice-row-actions { white-space: nowrap; text-align: right; }\n.b316-invoice-row-actions .b316-button-link + .b316-button-link { margin-left: 8px; }\n.b316-review-table { width: 100%; border-collapse: collapse; font-size: 0.92em; margin: 8px 0; }\n.b316-review-table th, .b316-review-table td { text-align: left; padding: 6px 4px; border-top: 1px solid var(--b316-color-border, #e5e7eb); }\n.b316-review-table th { color: var(--b316-color-muted); font-weight: 500; border-top: 0; }\n.b316-review-gain { color: #065f46; }\n.b316-review-loss { color: var(--b316-color-danger); }\n.b316-review-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }\n@media (max-width: 560px) {\n .b316-invoice-table th:nth-child(2), .b316-invoice-table td:nth-child(2) { display: none; }\n .b316-review-actions .b316-button { flex: 1 1 100%; }\n}\n";
62
+ export declare const STYLESHEET_EXTRA = "\n.b316-pay__element { margin-bottom: var(--b316-spacing); min-height: 40px; }\n\n.b316-pay__submit {\n width: 100%;\n padding: 11px 14px;\n border: 0;\n border-radius: calc(var(--b316-radius) / 1.6);\n background: var(--b316-color-primary);\n color: #fff;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.b316-pay__submit[disabled] { opacity: 0.55; cursor: progress; }\n\n.b316-pay__error {\n background: var(--b316-color-danger-bg);\n color: var(--b316-color-danger);\n padding: 8px 10px;\n border-radius: calc(var(--b316-radius) / 2);\n font-size: 0.9em;\n margin-bottom: var(--b316-spacing);\n}\n\n.b316-pay__done {\n background: var(--b316-color-success-bg, #f0fdf4);\n color: var(--b316-color-success);\n padding: 12px 14px;\n border-radius: calc(var(--b316-radius) / 2);\n text-align: center;\n margin: 0;\n}\n\n.b316-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--b316-color-border); }\n.b316-tab {\n flex: 1; padding: 8px 4px; background: none; border: 0; cursor: pointer;\n font: inherit; font-size: .95em; color: var(--b316-color-muted);\n border-bottom: 2px solid transparent; margin-bottom: -1px;\n}\n.b316-tab-on { color: var(--b316-color-text); border-bottom-color: var(--b316-color-primary); }\n.b316-social { display: flex; flex-direction: column; gap: 8px; }\n.b316-social-button {\n display: flex; align-items: center; justify-content: center; gap: 10px;\n width: 100%; min-height: 40px; padding: 9px 14px;\n border: 1px solid; border-radius: calc(var(--b316-radius) / 1.6);\n font: inherit; font-weight: 500; cursor: pointer;\n}\n.b316-social-button:hover:not([disabled]) { filter: brightness(.96); }\n.b316-social-button:focus-visible { outline: 2px solid var(--b316-color-primary); outline-offset: 2px; }\n.b316-social-button[disabled] { opacity: .55; cursor: not-allowed; }\n.b316-social-icon { display: inline-flex; width: 18px; height: 18px; flex: none; }\n.b316-social-icon svg { width: 18px; height: 18px; }\n.b316-divider {\n display: flex; align-items: center; gap: 10px; margin: 14px 0;\n color: var(--b316-color-muted); font-size: .87em;\n}\n.b316-divider::before, .b316-divider::after { content: \"\"; flex: 1; border-top: 1px solid var(--b316-color-border); }\n.b316-branding { display: flex; flex-direction: column; gap: 4px; }\n.b316-branding-logo { max-height: 40px; width: auto; align-self: flex-start; }\n.b316-branding-name { font-size: 1.5em; font-weight: 650; letter-spacing: -.01em; }\n.b316-branding-tagline { color: var(--b316-color-muted); }\n\n.b316-invoice-table { width: 100%; border-collapse: collapse; font-size: 0.94em; }\n.b316-invoice-table th {\n text-align: left;\n font-weight: 500;\n color: var(--b316-color-muted);\n font-size: 0.85em;\n padding: 0 0 6px;\n border-bottom: 1px solid var(--b316-color-border);\n}\n.b316-invoice-table td { padding: 9px 0; border-bottom: 1px solid var(--b316-color-border); }\n/* Columns need breathing room or the amount runs straight into the action \u2014\n \"$49.00View\" \u2014 which is what happens when only the row has padding. */\n.b316-invoice-table th + th,\n.b316-invoice-table td + td { padding-left: 16px; }\n.b316-invoice-table td:last-child,\n.b316-invoice-table th:last-child { text-align: right; width: 1%; white-space: nowrap; }\n.b316-invoice-table tr:last-child td { border-bottom: 0; }\n.b316-num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.b316-invoice-view {\n margin-top: calc(var(--b316-spacing) * 1.4);\n border-top: 1px solid var(--b316-color-border);\n padding-top: calc(var(--b316-spacing) * 1.4);\n}\n.b316-invoice-actions { display: flex; gap: 8px; justify-content: flex-end; margin-bottom: var(--b316-spacing); }\n.b316-invoice-doc { display: flex; flex-direction: column; gap: calc(var(--b316-spacing) * 1.4); }\n.b316-invoice-meta { display: grid; grid-template-columns: 1fr 1fr; gap: var(--b316-spacing); }\n.b316-invoice-totals { display: flex; flex-direction: column; gap: 6px; margin-left: auto; min-width: 240px; }\n.b316-invoice-total { font-weight: 650; border-top: 1px solid var(--b316-color-border); padding-top: 6px; }\n\n/* Printing an invoice emits the invoice alone, and printing anything else is\n none of this package's business.\n\n This used to start with a bare \"body * { visibility: hidden }\", which is the\n usual recipe for printing one element \u2014 and it is scoped to the document,\n not to us. The stylesheet is injected into the host page's head the first\n time any Base316 component mounts, so from that moment every print in the\n host application came out blank unless the content happened to sit inside\n .b316-invoice-doc. A customer printing their own page had no way to connect\n it back to us.\n\n Scoped to a root the invoice sets on <html> while it is being printed\n instead, so nothing applies unless an invoice asked for it. */\n@media print {\n [data-b316-printing] body * { visibility: hidden; }\n [data-b316-printing] .b316-invoice-doc,\n [data-b316-printing] .b316-invoice-doc * { visibility: visible; }\n [data-b316-printing] .b316-invoice-doc {\n position: absolute;\n inset: 0 auto auto 0;\n width: 100%;\n padding: 24px;\n }\n .b316-invoice-actions { display: none; }\n}\n\n/* --- Collections: tables, forms and detail views ------------------------- */\n\n.b316-table-wrap { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-table-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--b316-spacing); flex-wrap: wrap; }\n.b316-table-actions { display: flex; align-items: center; gap: var(--b316-spacing); }\n\n/* The table scrolls inside its own box rather than pushing the page sideways:\n a collection with twenty fields is normal, and a horizontally scrolling page\n makes every other component on it unreachable. */\n.b316-table-scroll { overflow-x: auto; border: 1px solid var(--b316-color-border); border-radius: var(--b316-radius); }\n.b316-table { width: 100%; border-collapse: collapse; font-size: 0.95em; }\n.b316-table th, .b316-table td { padding: 10px 12px; text-align: left; vertical-align: top; white-space: nowrap; }\n.b316-table thead th { background: var(--b316-color-surface-muted, rgba(0,0,0,.03)); font-weight: 600; font-size: 0.87em; color: var(--b316-color-muted); border-bottom: 1px solid var(--b316-color-border); }\n.b316-table tbody tr + tr td { border-top: 1px solid var(--b316-color-border); }\n.b316-row-clickable { cursor: pointer; }\n.b316-row-clickable:hover td { background: var(--b316-color-surface-muted, rgba(0,0,0,.02)); }\n.b316-table-rowactions { text-align: right; white-space: nowrap; }\n.b316-table-more { display: flex; justify-content: center; }\n\n.b316-sort { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer; }\n.b316-sort:focus-visible { outline: 2px solid var(--b316-color-primary); outline-offset: 2px; }\n\n.b316-empty { padding: calc(var(--b316-spacing) * 2); text-align: center; color: var(--b316-color-muted); }\n\n.b316-button-quiet {\n background: none;\n border: 0;\n padding: 4px 6px;\n font: inherit;\n font-size: 0.9em;\n color: var(--b316-color-primary);\n cursor: pointer;\n border-radius: calc(var(--b316-radius) / 2);\n}\n.b316-button-quiet:hover:not([disabled]) { background: var(--b316-color-surface-muted, rgba(0,0,0,.05)); }\n.b316-button-quiet:focus-visible { outline: 2px solid var(--b316-color-primary); outline-offset: 1px; }\n.b316-button-quiet[disabled] { opacity: .55; cursor: not-allowed; }\n.b316-danger { color: var(--b316-color-danger, #b42318); }\n\n.b316-chip {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--b316-color-surface-muted, rgba(0,0,0,.05));\n font-size: 0.87em;\n}\n.b316-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; }\n\n.b316-form { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-form-title { margin: 0; font-size: 1.05em; }\n.b316-form-actions { display: flex; justify-content: flex-end; gap: 8px; }\n.b316-field { display: flex; flex-direction: column; gap: 4px; }\n.b316-hint { font-size: 0.82em; color: var(--b316-color-muted); }\n.b316-input-invalid { border-color: var(--b316-color-danger, #b42318); }\n.b316-choices { display: flex; flex-wrap: wrap; gap: 10px; }\n.b316-choice { display: inline-flex; align-items: center; gap: 6px; font-size: 0.95em; }\n.b316-suffixed { display: flex; align-items: center; gap: 8px; }\n.b316-address { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }\n\n.b316-relation-chosen { display: flex; align-items: center; gap: 8px; }\n.b316-relation-results {\n list-style: none;\n margin: 4px 0 0;\n padding: 4px;\n border: 1px solid var(--b316-color-border);\n border-radius: var(--b316-radius);\n max-height: 220px;\n overflow-y: auto;\n background: var(--b316-color-surface, #fff);\n}\n.b316-relation-result { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 6px 8px; font: inherit; cursor: pointer; border-radius: calc(var(--b316-radius) / 2); }\n.b316-relation-result:hover, .b316-relation-result:focus-visible { background: var(--b316-color-surface-muted, rgba(0,0,0,.05)); outline: none; }\n.b316-relation-empty { padding: 6px 8px; }\n\n.b316-detail { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--b316-spacing); }\n.b316-detail-title { margin: 0; font-size: 1.1em; }\n.b316-detail-actions { display: flex; gap: 4px; }\n.b316-detail-fields { display: grid; grid-template-columns: minmax(120px, 200px) 1fr; gap: 8px var(--b316-spacing); margin: 0; }\n.b316-detail-row { display: contents; }\n.b316-detail-fields dd { margin: 0; }\n\n/* One column on a narrow screen. A label column of 200px beside a value leaves\n nothing for the value on a phone. */\n/* --- Teams --------------------------------------------------------------- */\n\n.b316-team { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-team-title { margin: 0; font-size: 1em; font-weight: 600; }\n.b316-team-subtitle { margin: 0; font-size: .9em; font-weight: 600; color: var(--b316-color-muted); }\n.b316-team-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }\n.b316-team-member { display: flex; align-items: center; justify-content: space-between; gap: var(--b316-spacing); }\n.b316-team-member-side { display: flex; align-items: center; gap: 8px; }\n.b316-team-invite { display: flex; flex-direction: column; gap: 4px; }\n.b316-team-invite-row { display: flex; gap: 8px; }\n.b316-team-invite-row input { flex: 1; }\n/* Selectable and wrapping: this is copied by hand and pasted into an email. */\n.b316-team-link { display: flex; flex-direction: column; gap: 4px; }\n.b316-team-link code { word-break: break-all; user-select: all; padding: 8px; border: 1px solid var(--b316-color-border); border-radius: var(--b316-radius); }\n\n.b316-invitation { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-invitation-actions { display: flex; align-items: center; gap: var(--b316-spacing); }\n\n/* --- Sessions, two-factor and the password flows ------------------------- */\n\n.b316-sessions { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-sessions-head { display: flex; align-items: center; justify-content: space-between; gap: var(--b316-spacing); flex-wrap: wrap; }\n.b316-sessions-title, .b316-mfa-title { margin: 0; font-size: 1em; font-weight: 600; }\n.b316-sessions-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }\n.b316-session { display: flex; flex-direction: column; gap: 2px; }\n.b316-session-device { display: flex; align-items: center; gap: 6px; font-size: 0.95em; }\n\n.b316-device { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-device-title { margin: 0; font-size: 1em; font-weight: 600; }\n/* What is being granted, listed rather than run together: somebody is deciding\n on this, and a comma-separated line is read as one thing. */\n.b316-device-scopes { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }\n.b316-device-scopes li { padding: 2px 8px; border-radius: 999px; font-size: 0.85em; background: var(--b316-color-surface-muted, rgba(0,0,0,.05)); }\n.b316-device-actions { display: flex; gap: 8px; }\n\n.b316-privacy { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-privacy-title { margin: 0; font-size: 1em; font-weight: 600; }\n/* Wraps rather than squeezes: the explanation beside each control is the part\n that matters, and on a narrow screen it belongs above the button. */\n.b316-privacy-row { display: flex; flex-wrap: wrap; align-items: start; justify-content: space-between; gap: 10px; }\n.b316-privacy-row p { margin: 0; }\n.b316-privacy-confirm { display: flex; flex-direction: column; gap: 8px; }\n.b316-privacy-actions { display: flex; justify-content: flex-end; gap: 8px; }\n\n.b316-mfa { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-mfa-enrol, .b316-mfa-codes, .b316-mfa-on, .b316-mfa-off { display: flex; flex-direction: column; gap: 10px; }\n.b316-mfa-actions { display: flex; justify-content: flex-end; gap: 8px; }\n/* Selectable and wrapping: this is copied by hand on the device that cannot\n scan its own screen. */\n.b316-mfa-secret code {\n display: block;\n padding: 10px;\n border: 1px solid var(--b316-color-border);\n border-radius: var(--b316-radius);\n font-size: 1.05em;\n letter-spacing: .08em;\n word-break: break-all;\n user-select: all;\n}\n.b316-mfa-uri { font-size: 0.9em; }\n.b316-mfa-code-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\n.b316-mfa-code-list code { user-select: all; }\n/* The enrolment choices: whole-width buttons with their explanation inside,\n so the explanation is part of what a screen reader announces. */\n.b316-mfa-methods { display: flex; flex-direction: column; gap: 8px; border: 0; margin: 0; padding: 0; min-width: 0; }\n.b316-mfa-method { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; text-align: left; }\n.b316-mfa-method .b316-muted { font-weight: 400; }\n/* Always on white with a margin: a QR code on a dark theme does not scan. */\n.b316-mfa-qr { align-self: center; width: 180px; height: 180px; padding: 8px; background: #fff; border-radius: var(--b316-radius); }\n\n@media (max-width: 560px) {\n .b316-mfa-code-list { grid-template-columns: 1fr; }\n .b316-detail-fields { grid-template-columns: 1fr; }\n .b316-detail-row { display: block; margin-bottom: 10px; }\n .b316-address { grid-template-columns: 1fr; }\n}\n\n/* --- Board --------------------------------------------------------------- */\n\n.b316-board-wrap { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n/* The board scrolls sideways inside itself. Six columns is normal and a page\n that scrolls horizontally puts everything else on it out of reach. */\n.b316-board { display: flex; gap: var(--b316-spacing); overflow-x: auto; align-items: flex-start; padding-bottom: 4px; }\n.b316-board-column {\n flex: 0 0 260px;\n background: var(--b316-color-surface-muted, rgba(0,0,0,.03));\n border: 1px solid transparent;\n border-radius: var(--b316-radius);\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.b316-board-over { border-color: var(--b316-color-primary); }\n.b316-board-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.b316-board-title { font-weight: 600; font-size: 0.92em; }\n.b316-board-cards { display: flex; flex-direction: column; gap: 8px; min-height: 40px; }\n.b316-board-card {\n background: var(--b316-color-surface, #fff);\n border: 1px solid var(--b316-color-border);\n border-radius: calc(var(--b316-radius) * .8);\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 0.9em;\n}\n.b316-board-card[draggable=\"true\"] { cursor: grab; }\n.b316-board-card-title { font-weight: 600; }\n.b316-board-card-field { display: flex; justify-content: space-between; gap: 8px; }\n.b316-board-move { display: flex; align-items: center; gap: 6px; margin-top: 2px; }\n.b316-board-move select { flex: 1; font-size: 0.9em; padding: 2px 4px; }\n.b316-board-empty { color: var(--b316-color-muted); font-size: 0.87em; padding: 6px 2px; }\n\n/* --- Chart --------------------------------------------------------------- */\n\n.b316-chart { display: flex; flex-direction: column; gap: var(--b316-spacing); }\n.b316-chart-title { font-weight: 600; font-size: 0.95em; }\n.b316-chart-plot { display: flex; align-items: flex-end; gap: 4px; overflow-x: auto; }\n.b316-chart-col { flex: 1 0 24px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 4px; }\n.b316-chart-bar { width: 100%; background: var(--b316-color-primary); border-radius: 3px 3px 0 0; min-height: 2px; }\n.b316-chart-label { font-size: 0.7em; color: var(--b316-color-muted); white-space: nowrap; transform: rotate(-45deg); transform-origin: top left; height: 1.6em; }\n.b316-chart-data summary { cursor: pointer; font-size: 0.87em; color: var(--b316-color-muted); }\n.b316-chart-data table { margin-top: 8px; }\n\n/* --- Billing portal ------------------------------------------------------ */\n\n.b316-billing-portal { display: grid; gap: var(--b316-spacing); }\n.b316-billing-portal-section-title { font-weight: 600; font-size: 1em; margin: 0 0 8px; }\n.b316-billing-portal .b316-plans { margin: 0; }\n.b316-invoice-row-actions { white-space: nowrap; text-align: right; }\n.b316-invoice-row-actions .b316-button-link + .b316-button-link { margin-left: 8px; }\n.b316-review-table { width: 100%; border-collapse: collapse; font-size: 0.92em; margin: 8px 0; }\n.b316-review-table th, .b316-review-table td { text-align: left; padding: 6px 4px; border-top: 1px solid var(--b316-color-border, #e5e7eb); }\n.b316-review-table th { color: var(--b316-color-muted); font-weight: 500; border-top: 0; }\n.b316-review-gain { color: #065f46; }\n.b316-review-loss { color: var(--b316-color-danger); }\n.b316-review-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }\n@media (max-width: 560px) {\n .b316-invoice-table th:nth-child(2), .b316-invoice-table td:nth-child(2) { display: none; }\n .b316-review-actions .b316-button { flex: 1 1 100%; }\n}\n";
63
63
  //# sourceMappingURL=appearance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"appearance.d.ts","sourceRoot":"","sources":["../../src/appearance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,iBAAiB;IACjC,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAkBD,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAgB/E;AAED,eAAO,MAAM,gBAAgB,uBAAuB,CAAC;AAErD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,yiOA8OtB,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,8xiBAyU5B,CAAC"}
1
+ {"version":3,"file":"appearance.d.ts","sourceRoot":"","sources":["../../src/appearance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,iBAAiB;IACjC,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAkBD,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAgB/E;AAED,eAAO,MAAM,gBAAgB,uBAAuB,CAAC;AAErD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,yiOA8OtB,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,2vkBA0V5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;GAIG;AACH,MAAM,MAAM,WAAW;AACtB,8EAA8E;AAC5E,SAAS;AACX,gFAAgF;GAC9E,YAAY;AACd,kDAAkD;GAChD,OAAO;AACT,mFAAmF;GACjF,gBAAgB;AAClB,mEAAmE;GACjE,aAAa,CAAC;AAEjB,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;IACxC,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAOD,eAAO,MAAM,QAAQ,EAAE,aAAa,EAo3BnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;aACvB,KAAK,YACJ,qEAAqE,EACrE,yIAAyI,EACzI,2JAA2J,EAC3J,+QAA+Q,EAC/Q,0ZAA0Z,EAC1Z,4KAA4K;IAE7K,uDAAuD;aACvD,OAAO;CAyBE,CAAC;AAEX,2BAA2B;AAC3B,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEzE;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE,CAE7E"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;GAIG;AACH,MAAM,MAAM,WAAW;AACtB,8EAA8E;AAC5E,SAAS;AACX,gFAAgF;GAC9E,YAAY;AACd,kDAAkD;GAChD,OAAO;AACT,mFAAmF;GACjF,gBAAgB;AAClB,mEAAmE;GACjE,aAAa,CAAC;AAEjB,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;IACxC,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAOD,eAAO,MAAM,QAAQ,EAAE,aAAa,EA67BnC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;aACvB,KAAK,YACJ,qEAAqE,EACrE,yIAAyI,EACzI,2JAA2J,EAC3J,+QAA+Q,EAC/Q,0ZAA0Z,EAC1Z,4KAA4K;IAE7K,uDAAuD;aACvD,OAAO;CAyBE,CAAC;AAEX,2BAA2B;AAC3B,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEzE;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE,CAE7E"}
@@ -0,0 +1,66 @@
1
+ import { type Base316Browser, type SignInMethods, type SocialSignInOption } from "@base316/sdk";
2
+ export declare function loadSignInMethods(client: Base316Browser): Promise<SignInMethods>;
3
+ export type SignInMethodsState = {
4
+ status: "loading";
5
+ methods: null;
6
+ } | {
7
+ status: "ready";
8
+ methods: SignInMethods;
9
+ }
10
+ /** An older API without the endpoint, or a network failure: props decide alone. */
11
+ | {
12
+ status: "unavailable";
13
+ methods: null;
14
+ };
15
+ export declare function useSignInMethods(client: Base316Browser): SignInMethodsState;
16
+ /** What the host asked for. Each can only turn a method off, never on. */
17
+ export interface MethodProps {
18
+ password?: boolean;
19
+ passkeys?: boolean;
20
+ magicLink?: boolean;
21
+ magicLinkRedirectUrl?: string;
22
+ phone?: boolean;
23
+ social?: boolean | readonly string[];
24
+ sso?: boolean;
25
+ socialRedirectUrl?: string;
26
+ }
27
+ export interface ResolvedMethods {
28
+ password: boolean;
29
+ passkeys: boolean;
30
+ /** Where the emailed link lands, or null when magic links are not offered. */
31
+ magicLink: string | null;
32
+ phone: boolean;
33
+ social: SocialSignInOption[];
34
+ sso: boolean;
35
+ signUp: boolean;
36
+ hostedUrl: string | undefined;
37
+ }
38
+ /**
39
+ * The methods a form offers: the environment's switches, narrowed by props.
40
+ *
41
+ * Without the environment's answer (`methods` null: still loading, or an
42
+ * older API) the form falls back to what the props said before the endpoint
43
+ * existed — so the common case, a password form, draws at once rather than
44
+ * after a round trip: password, passkeys unless
45
+ * turned off, a magic link only with a landing URL, text messages only when
46
+ * asked for, and no social or SSO buttons — a button that cannot work is
47
+ * worse than an absent one.
48
+ *
49
+ * Social and SSO need `socialRedirectUrl`: their code has to land on a page
50
+ * whose server redeems it with a secret key, which no default can name. A
51
+ * magic link without `magicLinkRedirectUrl` lands on `currentPage`, the page
52
+ * rendering the form, which redeems `?token=` itself.
53
+ */
54
+ export declare function resolveMethods(methods: SignInMethods | null, props: MethodProps, currentPage: string | null): ResolvedMethods;
55
+ /**
56
+ * Leave for a provider (or an identity provider) with a fresh state.
57
+ *
58
+ * The nonce goes into a cookie on this origin first, so the callback page's
59
+ * server can refuse a code that this browser did not ask for
60
+ * (`readOAuthState`). Not httpOnly — the browser writes it — and it does not
61
+ * need to be: it is a value the browser already holds and sends as `state`.
62
+ */
63
+ export declare function beginRedirect(build: (state: string) => string, appState?: string): void;
64
+ /** The page rendering the form, without its query: where a magic link lands by default. */
65
+ export declare function currentPageUrl(): string | null;
66
+ //# sourceMappingURL=sign-in-methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-in-methods.d.ts","sourceRoot":"","sources":["../../src/sign-in-methods.ts"],"names":[],"mappings":"AAEA,OAAO,EAGN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,MAAM,cAAc,CAAC;AAWtB,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAUhF;AAED,MAAM,MAAM,kBAAkB,GAC3B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GACpC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE;AAC7C,mFAAmF;GACjF;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC;AAE5C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,kBAAkB,CAoB3E;AAED,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IACrC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,aAAa,GAAG,IAAI,EAC7B,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,MAAM,GAAG,IAAI,GACxB,eAAe,CAwCjB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAMvF;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAM9C"}
@@ -0,0 +1,11 @@
1
+ import type { SocialProvider } from "@base316/sdk";
2
+ /**
3
+ * Each provider's mark, as the hosted sign-in page draws it: inline SVG, so a
4
+ * button needs no network request. Static strings from this file only, never
5
+ * anything from a response.
6
+ *
7
+ * Keyed by `SocialProvider`, so a provider added to the SDK without a mark here
8
+ * fails to compile (the API's `PROVIDER_ICON` is the same list).
9
+ */
10
+ export declare const PROVIDER_ICON: Record<SocialProvider, string>;
11
+ //# sourceMappingURL=social-icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"social-icons.d.ts","sourceRoot":"","sources":["../../src/social-icons.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAcxD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base316/react",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Drop-in React components for Base316 authentication and billing.",
5
5
  "homepage": "https://base316.com",
6
6
  "bugs": "https://github.com/ThinkfleetAI/base316/issues",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "qrcode-generator": "2.0.4",
36
- "@base316/sdk": "0.8.0"
36
+ "@base316/sdk": "0.9.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@testing-library/dom": "^10.4.2",