@object-ui/auth 3.3.0 → 3.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,107 @@
1
+ # @object-ui/auth
2
+
3
+ ## 3.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@3.3.1
8
+
9
+ ## 3.3.0
10
+
11
+ ### Patch Changes
12
+
13
+ - @object-ui/types@3.3.0
14
+
15
+ ## 3.2.0
16
+
17
+ ### Patch Changes
18
+
19
+ - @object-ui/types@3.2.0
20
+
21
+ ## 3.1.5
22
+
23
+ ### Patch Changes
24
+
25
+ - @object-ui/types@3.1.5
26
+
27
+ ## 3.1.4
28
+
29
+ ### Patch Changes
30
+
31
+ - @object-ui/types@3.1.4
32
+
33
+ ## 3.1.3
34
+
35
+ ### Patch Changes
36
+
37
+ - @object-ui/types@3.1.3
38
+
39
+ ## 3.1.2
40
+
41
+ ### Patch Changes
42
+
43
+ - @object-ui/types@3.1.2
44
+
45
+ ## 3.1.1
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies
50
+ - @object-ui/types@3.1.1
51
+
52
+ ## 3.0.3
53
+
54
+ ### Patch Changes
55
+
56
+ - @object-ui/types@3.0.3
57
+
58
+ ## 3.0.2
59
+
60
+ ### Patch Changes
61
+
62
+ - @object-ui/types@3.0.2
63
+
64
+ ## 3.0.1
65
+
66
+ ### Patch Changes
67
+
68
+ - @object-ui/types@3.0.1
69
+
70
+ ### Added
71
+
72
+ - **Preview Mode** (`previewMode` prop on `AuthProvider`): Auto-login with simulated identity for marketplace demos and app showcases. Configurable role, display name, session expiry, read-only mode, and banner message.
73
+ - **PreviewBanner** component: Renders a status banner when preview mode is active.
74
+ - `isPreviewMode` and `previewMode` fields exposed on `AuthContextValue` / `useAuth()` hook.
75
+ - New `PreviewModeOptions` type mirroring spec's `PreviewModeConfig`.
76
+
77
+ ### Changed
78
+
79
+ - Upgraded `@objectstack/spec` from `^3.0.2` to `^3.0.4`.
80
+
81
+ ## 3.0.0
82
+
83
+ ### Minor Changes
84
+
85
+ - 87979c3: Upgrade to @objectstack v3.0.0 and console bundle optimization
86
+ - Upgraded all @objectstack/\* packages from ^2.0.7 to ^3.0.0
87
+ - Breaking change migrations: Hub → Cloud namespace, definePlugin removed, PaginatedResult.value → .records, PaginatedResult.count → .total, client.meta.getObject() → client.meta.getItem()
88
+ - Console bundle optimization: split monolithic 3.7 MB chunk into 17 granular cacheable chunks (95% main entry reduction)
89
+ - Added gzip + brotli pre-compression via vite-plugin-compression2
90
+ - Lazy MSW loading for build:server (~150 KB gzip saved)
91
+ - Added bundle analysis with rollup-plugin-visualizer
92
+
93
+ ### Patch Changes
94
+
95
+ - Updated dependencies [87979c3]
96
+ - @object-ui/types@3.0.0
97
+
98
+ ## 2.0.0
99
+
100
+ ### Major Changes
101
+
102
+ - b859617: Release v1.0.0 — unify all package versions to 1.0.0
103
+
104
+ ### Patch Changes
105
+
106
+ - Updated dependencies [b859617]
107
+ - @object-ui/types@2.0.0
package/README.md CHANGED
@@ -201,6 +201,26 @@ function MyComponent() {
201
201
 
202
202
  > **⚠️ Security:** Preview mode should **never** be used in production environments.
203
203
 
204
+ <!-- release-metadata:v3.3.0 -->
205
+
206
+ ## Compatibility
207
+
208
+ - **React:** 18.x or 19.x
209
+ - **Node.js:** ≥ 18
210
+ - **TypeScript:** ≥ 5.0 (strict mode)
211
+ - **`@objectstack/spec`:** ^3.3.0
212
+ - **`@objectstack/client`:** ^3.3.0
213
+ - **Tailwind CSS:** ≥ 3.4 (for packages with UI)
214
+
215
+ ## Links
216
+
217
+ - 📚 [Documentation](https://www.objectui.org/docs/packages/auth)
218
+ - 📦 [npm package](https://www.npmjs.com/package/@object-ui/auth)
219
+ - 📝 [Changelog](./CHANGELOG.md)
220
+ - 🐛 [Report an issue](https://github.com/objectstack-ai/objectui/issues)
221
+ - 🤝 [Contributing Guide](https://github.com/objectstack-ai/objectui/blob/main/CONTRIBUTING.md)
222
+ - 🗺️ [Roadmap](https://github.com/objectstack-ai/objectui/blob/main/ROADMAP.md)
223
+
204
224
  ## License
205
225
 
206
- MIT
226
+ MIT — see [LICENSE](./LICENSE).
@@ -5,7 +5,7 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
- import type { AuthUser, AuthSession, PreviewModeOptions } from './types';
8
+ import type { AuthUser, AuthSession, PreviewModeOptions, AuthOrganization, AuthOrganizationMember, AuthInvitation, AuthPublicConfig, SignInWithProviderOptions } from './types';
9
9
  export interface AuthContextValue {
10
10
  /** Current authenticated user */
11
11
  user: AuthUser | null;
@@ -33,6 +33,63 @@ export interface AuthContextValue {
33
33
  forgotPassword: (email: string) => Promise<void>;
34
34
  /** Reset password with token */
35
35
  resetPassword: (token: string, newPassword: string) => Promise<void>;
36
+ /** Fetch the public auth configuration (providers, features) */
37
+ getAuthConfig: () => Promise<AuthPublicConfig>;
38
+ /** Initiate sign-in with a third-party provider (Google, GitHub, OIDC, etc.) */
39
+ signInWithProvider: (providerId: string, options?: SignInWithProviderOptions) => Promise<void>;
40
+ /** All organizations the user belongs to */
41
+ organizations: AuthOrganization[];
42
+ /** Currently active organization */
43
+ activeOrganization: AuthOrganization | null;
44
+ /** Whether organizations are loading */
45
+ isOrganizationsLoading: boolean;
46
+ /** Switch the active organization (workspace) */
47
+ switchOrganization: (orgId: string) => Promise<void>;
48
+ /** Create a new organization */
49
+ createOrganization: (data: {
50
+ name: string;
51
+ slug: string;
52
+ logo?: string;
53
+ }) => Promise<AuthOrganization>;
54
+ /** Refresh the organizations list */
55
+ refreshOrganizations: () => Promise<void>;
56
+ /** Update organization details (owner/admin) */
57
+ updateOrganization: (orgId: string, data: Partial<Pick<AuthOrganization, 'name' | 'slug' | 'logo' | 'metadata'>>) => Promise<AuthOrganization>;
58
+ /** Delete an organization (owner) */
59
+ deleteOrganization: (orgId: string) => Promise<void>;
60
+ /** Current user leaves the given organization */
61
+ leaveOrganization: (orgId: string) => Promise<void>;
62
+ /** List members of an organization */
63
+ getMembers: (orgId: string) => Promise<AuthOrganizationMember[]>;
64
+ /** Invite a user by email */
65
+ inviteMember: (data: {
66
+ organizationId: string;
67
+ email: string;
68
+ role: string;
69
+ }) => Promise<AuthInvitation>;
70
+ /** Remove a member by id */
71
+ removeMember: (data: {
72
+ organizationId: string;
73
+ memberIdOrUserId: string;
74
+ }) => Promise<void>;
75
+ /** Update a member's role */
76
+ updateMemberRole: (data: {
77
+ organizationId: string;
78
+ memberId: string;
79
+ role: string;
80
+ }) => Promise<void>;
81
+ /** List pending invitations for an organization */
82
+ listInvitations: (orgId: string) => Promise<AuthInvitation[]>;
83
+ /** Cancel an invitation */
84
+ cancelInvitation: (invitationId: string) => Promise<void>;
85
+ /** Get invitation details by id */
86
+ getInvitation: (invitationId: string) => Promise<AuthInvitation>;
87
+ /** Accept an invitation as the current user */
88
+ acceptInvitation: (invitationId: string) => Promise<void>;
89
+ /** Reject an invitation as the current user */
90
+ rejectInvitation: (invitationId: string) => Promise<void>;
91
+ /** List invitations addressed to the current user */
92
+ listUserInvitations: () => Promise<AuthInvitation[]>;
36
93
  }
37
94
  export declare const AuthCtx: import("react").Context<AuthContextValue | null>;
38
95
  //# sourceMappingURL=AuthContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,kCAAkC;IAClC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,2BAA2B;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,iDAAiD;IACjD,aAAa,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACvC,sCAAsC;IACtC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,6CAA6C;IAC7C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,gCAAgC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,0BAA0B;IAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,6BAA6B;IAC7B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,gCAAgC;IAChC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE;AAED,eAAO,MAAM,OAAO,kDAA+C,CAAC"}
1
+ {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAwB,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAI5F,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,iBAAiB,EACjB,OAAc,EACd,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,2CAkNnB"}
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAwB,kBAAkB,EAAE,kBAAkB,EAAyG,MAAM,SAAS,CAAC;AAKnM,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,iBAAiB,EACjB,OAAc,EACd,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,2CA4anB"}
@@ -9,6 +9,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import { useState, useEffect, useCallback, useMemo } from 'react';
10
10
  import { AuthCtx } from './AuthContext';
11
11
  import { createAuthClient } from './createAuthClient';
12
+ import { ActiveOrganizationStorage } from './createAuthenticatedFetch';
12
13
  /**
13
14
  * Authentication context provider.
14
15
  *
@@ -41,6 +42,10 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
41
42
  const [session, setSession] = useState(null);
42
43
  const [isLoading, setIsLoading] = useState(true);
43
44
  const [error, setError] = useState(null);
45
+ // Organization / workspace state
46
+ const [organizations, setOrganizations] = useState([]);
47
+ const [activeOrganization, setActiveOrganization] = useState(null);
48
+ const [isOrganizationsLoading, setIsOrganizationsLoading] = useState(false);
44
49
  // Determine if we're in preview mode
45
50
  const isPreviewMode = previewMode != null;
46
51
  // If auth is disabled or in preview mode, automatically set as authenticated
@@ -204,6 +209,125 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
204
209
  throw authError;
205
210
  }
206
211
  }, [client]);
212
+ const getAuthConfig = useCallback(() => client.getConfig(), [client]);
213
+ const signInWithProvider = useCallback(async (providerId, options) => {
214
+ setError(null);
215
+ try {
216
+ await client.signInWithProvider(providerId, options);
217
+ }
218
+ catch (err) {
219
+ const authError = err instanceof Error ? err : new Error(String(err));
220
+ setError(authError);
221
+ throw authError;
222
+ }
223
+ }, [client]);
224
+ // --- Organization methods ---
225
+ const refreshOrganizations = useCallback(async () => {
226
+ if (!enabled || isPreviewMode)
227
+ return;
228
+ setIsOrganizationsLoading(true);
229
+ try {
230
+ const orgs = await client.listOrganizations();
231
+ setOrganizations(orgs);
232
+ // If no active org is set but orgs exist, try to get active from server
233
+ if (orgs.length > 0 && !activeOrganization) {
234
+ try {
235
+ const active = await client.getActiveOrganization();
236
+ if (active) {
237
+ setActiveOrganization(active);
238
+ ActiveOrganizationStorage.set(active.id);
239
+ }
240
+ }
241
+ catch {
242
+ // No active org set — that's fine
243
+ }
244
+ }
245
+ }
246
+ catch (err) {
247
+ console.warn('[AuthProvider] Failed to load organizations:', err);
248
+ }
249
+ finally {
250
+ setIsOrganizationsLoading(false);
251
+ }
252
+ }, [client, enabled, isPreviewMode, activeOrganization]);
253
+ // Load organizations once user is authenticated
254
+ useEffect(() => {
255
+ if (user && enabled && !isPreviewMode) {
256
+ refreshOrganizations();
257
+ }
258
+ }, [user, enabled, isPreviewMode]); // eslint-disable-line react-hooks/exhaustive-deps
259
+ const switchOrganization = useCallback(async (orgId) => {
260
+ setError(null);
261
+ try {
262
+ const org = await client.setActiveOrganization(orgId);
263
+ setActiveOrganization(org);
264
+ // Persist for header injection
265
+ if (org) {
266
+ ActiveOrganizationStorage.set(org.id);
267
+ }
268
+ else {
269
+ ActiveOrganizationStorage.clear();
270
+ }
271
+ }
272
+ catch (err) {
273
+ const authError = err instanceof Error ? err : new Error(String(err));
274
+ setError(authError);
275
+ throw authError;
276
+ }
277
+ }, [client]);
278
+ const createOrganization = useCallback(async (data) => {
279
+ setError(null);
280
+ try {
281
+ const org = await client.createOrganization(data);
282
+ // Refresh the list and set as active
283
+ await refreshOrganizations();
284
+ await switchOrganization(org.id);
285
+ return org;
286
+ }
287
+ catch (err) {
288
+ const authError = err instanceof Error ? err : new Error(String(err));
289
+ setError(authError);
290
+ throw authError;
291
+ }
292
+ }, [client, refreshOrganizations, switchOrganization]);
293
+ const updateOrganization = useCallback(async (orgId, data) => {
294
+ const updated = await client.updateOrganization(orgId, data);
295
+ // Refresh local list & active org reference if it matches
296
+ await refreshOrganizations();
297
+ if (activeOrganization?.id === orgId) {
298
+ setActiveOrganization(updated);
299
+ }
300
+ return updated;
301
+ }, [client, refreshOrganizations, activeOrganization]);
302
+ const deleteOrganization = useCallback(async (orgId) => {
303
+ await client.deleteOrganization(orgId);
304
+ if (activeOrganization?.id === orgId) {
305
+ setActiveOrganization(null);
306
+ ActiveOrganizationStorage.clear();
307
+ }
308
+ await refreshOrganizations();
309
+ }, [client, activeOrganization, refreshOrganizations]);
310
+ const leaveOrganization = useCallback(async (orgId) => {
311
+ await client.leaveOrganization(orgId);
312
+ if (activeOrganization?.id === orgId) {
313
+ setActiveOrganization(null);
314
+ ActiveOrganizationStorage.clear();
315
+ }
316
+ await refreshOrganizations();
317
+ }, [client, activeOrganization, refreshOrganizations]);
318
+ const getMembers = useCallback((orgId) => client.getMembers(orgId), [client]);
319
+ const inviteMember = useCallback((data) => client.inviteMember(data), [client]);
320
+ const removeMember = useCallback((data) => client.removeMember(data), [client]);
321
+ const updateMemberRole = useCallback((data) => client.updateMemberRole(data), [client]);
322
+ const listInvitations = useCallback((orgId) => client.listInvitations(orgId), [client]);
323
+ const cancelInvitation = useCallback((invitationId) => client.cancelInvitation(invitationId), [client]);
324
+ const getInvitation = useCallback((invitationId) => client.getInvitation(invitationId), [client]);
325
+ const acceptInvitation = useCallback(async (invitationId) => {
326
+ await client.acceptInvitation(invitationId);
327
+ await refreshOrganizations();
328
+ }, [client, refreshOrganizations]);
329
+ const rejectInvitation = useCallback((invitationId) => client.rejectInvitation(invitationId), [client]);
330
+ const listUserInvitations = useCallback(() => client.listUserInvitations(), [client]);
207
331
  const value = useMemo(() => ({
208
332
  user,
209
333
  session,
@@ -218,6 +342,34 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
218
342
  updateUser,
219
343
  forgotPassword,
220
344
  resetPassword,
221
- }), [user, session, isAuthenticated, isLoading, error, isPreviewMode, previewMode, signIn, signUp, signOut, updateUser, forgotPassword, resetPassword]);
345
+ getAuthConfig,
346
+ signInWithProvider,
347
+ organizations,
348
+ activeOrganization,
349
+ isOrganizationsLoading,
350
+ switchOrganization,
351
+ createOrganization,
352
+ refreshOrganizations,
353
+ updateOrganization,
354
+ deleteOrganization,
355
+ leaveOrganization,
356
+ getMembers,
357
+ inviteMember,
358
+ removeMember,
359
+ updateMemberRole,
360
+ listInvitations,
361
+ cancelInvitation,
362
+ getInvitation,
363
+ acceptInvitation,
364
+ rejectInvitation,
365
+ listUserInvitations,
366
+ }), [
367
+ user, session, isAuthenticated, isLoading, error, isPreviewMode, previewMode,
368
+ signIn, signUp, signOut, updateUser, forgotPassword, resetPassword, getAuthConfig, signInWithProvider,
369
+ organizations, activeOrganization, isOrganizationsLoading, switchOrganization, createOrganization, refreshOrganizations,
370
+ updateOrganization, deleteOrganization, leaveOrganization,
371
+ getMembers, inviteMember, removeMember, updateMemberRole,
372
+ listInvitations, cancelInvitation, getInvitation, acceptInvitation, rejectInvitation, listUserInvitations,
373
+ ]);
222
374
  return _jsx(AuthCtx.Provider, { value: value, children: children });
223
375
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEtD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,cAAc,2CA6GhB"}
1
+ {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEtD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,cAAc,2CA+GhB"}
package/dist/LoginForm.js CHANGED
@@ -8,6 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  */
9
9
  import { useState } from 'react';
10
10
  import { useAuth } from './useAuth';
11
+ import { SocialSignInButtons } from './SocialSignInButtons';
11
12
  const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
12
13
  /**
13
14
  * Login form component with email/password authentication.
@@ -51,5 +52,5 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
51
52
  onError?.(authError);
52
53
  }
53
54
  };
54
- return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[380px]", children: [_jsxs("div", { className: "flex flex-col space-y-2 text-center", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: "text-sm font-medium leading-none", children: l.emailLabel }), _jsx("input", { id: "login-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: "text-sm font-medium leading-none", children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-sm text-primary underline-offset-4 hover:underline", children: l.forgotPasswordText }))] }), _jsx("input", { id: "login-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsx("button", { type: "submit", disabled: isLoading, className: "inline-flex h-10 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: isLoading ? l.submittingButton : l.submitButton })] }), registerUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: "text-primary underline-offset-4 hover:underline", children: l.signUpText })] }))] }));
55
+ return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[380px]", children: [_jsxs("div", { className: "flex flex-col space-y-2 text-center", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsx(SocialSignInButtons, { mode: "sign-in" }), error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: "text-sm font-medium leading-none", children: l.emailLabel }), _jsx("input", { id: "login-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: "text-sm font-medium leading-none", children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-sm text-primary underline-offset-4 hover:underline", children: l.forgotPasswordText }))] }), _jsx("input", { id: "login-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsx("button", { type: "submit", disabled: isLoading, className: "inline-flex h-10 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: isLoading ? l.submittingButton : l.submitButton })] }), registerUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: "text-primary underline-offset-4 hover:underline", children: l.signUpText })] }))] }));
55
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RegisterForm.d.ts","sourceRoot":"","sources":["../src/RegisterForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEtD,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,OAAO,EACP,QAAmB,EACnB,KAA2B,EAC3B,WAAqD,EACrD,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,iBAAiB,2CAwJnB"}
1
+ {"version":3,"file":"RegisterForm.d.ts","sourceRoot":"","sources":["../src/RegisterForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEtD,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,OAAO,EACP,QAAmB,EACnB,KAA2B,EAC3B,WAAqD,EACrD,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,iBAAiB,2CA0JnB"}
@@ -8,6 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  */
9
9
  import { useState } from 'react';
10
10
  import { useAuth } from './useAuth';
11
+ import { SocialSignInButtons } from './SocialSignInButtons';
11
12
  const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
12
13
  /**
13
14
  * Registration form component with name, email, and password fields.
@@ -65,5 +66,5 @@ export function RegisterForm({ onSuccess, onError, loginUrl = '/login', title =
65
66
  onError?.(authError);
66
67
  }
67
68
  };
68
- return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[380px]", children: [_jsxs("div", { className: "flex flex-col space-y-2 text-center", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-name", className: "text-sm font-medium leading-none", children: l.nameLabel }), _jsx("input", { id: "register-name", type: "text", placeholder: l.namePlaceholder, value: name, onChange: (e) => setName(e.target.value), required: true, autoComplete: "name", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-email", className: "text-sm font-medium leading-none", children: l.emailLabel }), _jsx("input", { id: "register-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-password", className: "text-sm font-medium leading-none", children: l.passwordLabel }), _jsx("input", { id: "register-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-confirm-password", className: "text-sm font-medium leading-none", children: l.confirmPasswordLabel }), _jsx("input", { id: "register-confirm-password", type: "password", placeholder: l.confirmPasswordPlaceholder, value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsx("button", { type: "submit", disabled: isLoading, className: "inline-flex h-10 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: isLoading ? l.submittingButton : l.submitButton })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.hasAccountText, ' ', _jsx(LinkComp, { href: loginUrl, className: "text-primary underline-offset-4 hover:underline", children: l.signInText })] }))] }));
69
+ return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[380px]", children: [_jsxs("div", { className: "flex flex-col space-y-2 text-center", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsx(SocialSignInButtons, { mode: "sign-up" }), error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-name", className: "text-sm font-medium leading-none", children: l.nameLabel }), _jsx("input", { id: "register-name", type: "text", placeholder: l.namePlaceholder, value: name, onChange: (e) => setName(e.target.value), required: true, autoComplete: "name", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-email", className: "text-sm font-medium leading-none", children: l.emailLabel }), _jsx("input", { id: "register-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-password", className: "text-sm font-medium leading-none", children: l.passwordLabel }), _jsx("input", { id: "register-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-confirm-password", className: "text-sm font-medium leading-none", children: l.confirmPasswordLabel }), _jsx("input", { id: "register-confirm-password", type: "password", placeholder: l.confirmPasswordPlaceholder, value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsx("button", { type: "submit", disabled: isLoading, className: "inline-flex h-10 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: isLoading ? l.submittingButton : l.submitButton })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.hasAccountText, ' ', _jsx(LinkComp, { href: loginUrl, className: "text-primary underline-offset-4 hover:underline", children: l.signInText })] }))] }));
69
70
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ export interface SocialSignInButtonsProps {
9
+ /** Sign-in vs sign-up changes the button label ("Continue with" vs "Sign up with") */
10
+ mode?: 'sign-in' | 'sign-up';
11
+ /** Where the provider should redirect after success. Defaults to current page. */
12
+ callbackURL?: string;
13
+ /** Where the provider should redirect on error. Defaults to current page. */
14
+ errorCallbackURL?: string;
15
+ /** Divider text shown between social buttons and the email form */
16
+ dividerText?: string;
17
+ }
18
+ /**
19
+ * Renders one button per enabled third-party provider returned by
20
+ * `GET {authUrl}/config`. Clicking a button initiates an OAuth redirect via
21
+ * better-auth (`signIn.social` or `signIn.oauth2`).
22
+ *
23
+ * Returns `null` while loading or when the server reports no providers.
24
+ */
25
+ export declare function SocialSignInButtons({ mode, callbackURL, errorCallbackURL, dividerText, }: SocialSignInButtonsProps): import("react/jsx-runtime").JSX.Element | null;
26
+ //# sourceMappingURL=SocialSignInButtons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocialSignInButtons.d.ts","sourceRoot":"","sources":["../src/SocialSignInButtons.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmFH,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,WAAsC,GACvC,EAAE,wBAAwB,kDA2E1B"}
@@ -0,0 +1,97 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ObjectUI
4
+ * Copyright (c) 2024-present ObjectStack Inc.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ import { useEffect, useState } from 'react';
10
+ import { useAuth } from './useAuth';
11
+ // Brand name overrides for providers whose `name` from the server may be unset
12
+ // or where we want to canonicalize casing.
13
+ const PROVIDER_LABEL = {
14
+ google: 'Google',
15
+ github: 'GitHub',
16
+ microsoft: 'Microsoft',
17
+ apple: 'Apple',
18
+ facebook: 'Facebook',
19
+ twitter: 'Twitter',
20
+ discord: 'Discord',
21
+ gitlab: 'GitLab',
22
+ linkedin: 'LinkedIn',
23
+ };
24
+ // Inline brand-mark SVGs (single-color, currentColor where possible). Kept inline
25
+ // so the package has zero new icon-library dependencies.
26
+ const PROVIDER_ICON = {
27
+ google: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": "true", children: _jsx("path", { fill: "#EA4335", d: "M12 10.2v3.9h5.5c-.24 1.4-1.7 4.1-5.5 4.1-3.3 0-6-2.74-6-6.1s2.7-6.1 6-6.1c1.88 0 3.14.8 3.86 1.5l2.64-2.55C16.84 3.36 14.66 2.4 12 2.4 6.92 2.4 2.8 6.52 2.8 11.6S6.92 20.8 12 20.8c6.92 0 9.2-4.86 9.2-7.4 0-.5-.06-.88-.14-1.2H12z" }) })),
28
+ github: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 fill-current", "aria-hidden": "true", children: _jsx("path", { d: "M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.11.79-.25.79-.56v-2.07c-3.2.7-3.87-1.37-3.87-1.37-.52-1.33-1.27-1.69-1.27-1.69-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.75 2.68 1.25 3.34.96.1-.74.4-1.25.73-1.54-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.29 1.18-3.1-.12-.29-.51-1.46.11-3.04 0 0 .97-.31 3.18 1.18a11.04 11.04 0 015.79 0c2.21-1.49 3.18-1.18 3.18-1.18.62 1.58.23 2.75.11 3.04.74.81 1.18 1.84 1.18 3.1 0 4.42-2.7 5.39-5.27 5.68.41.36.78 1.06.78 2.13v3.16c0 .31.21.68.8.56C20.21 21.39 23.5 17.08 23.5 12 23.5 5.65 18.35.5 12 .5z" }) })),
29
+ microsoft: (_jsxs("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": "true", children: [_jsx("path", { fill: "#F25022", d: "M2 2h9.5v9.5H2z" }), _jsx("path", { fill: "#7FBA00", d: "M12.5 2H22v9.5h-9.5z" }), _jsx("path", { fill: "#00A4EF", d: "M2 12.5h9.5V22H2z" }), _jsx("path", { fill: "#FFB900", d: "M12.5 12.5H22V22h-9.5z" })] })),
30
+ apple: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 fill-current", "aria-hidden": "true", children: _jsx("path", { d: "M16.37 12.55c-.02-2.27 1.85-3.36 1.94-3.42-1.06-1.55-2.71-1.76-3.3-1.79-1.4-.14-2.74.83-3.45.83-.71 0-1.81-.81-2.98-.79-1.53.02-2.95.89-3.74 2.27-1.6 2.77-.41 6.86 1.14 9.11.76 1.1 1.66 2.34 2.83 2.3 1.14-.05 1.57-.74 2.94-.74 1.37 0 1.76.74 2.96.71 1.22-.02 2-1.12 2.75-2.23.87-1.28 1.22-2.52 1.24-2.59-.03-.01-2.38-.91-2.4-3.66zM14.1 5.31c.62-.76 1.05-1.81.93-2.86-.9.04-2 .6-2.65 1.35-.58.66-1.1 1.74-.96 2.76 1.01.08 2.04-.51 2.68-1.25z" }) })),
31
+ facebook: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": "true", children: _jsx("path", { fill: "#1877F2", d: "M24 12C24 5.37 18.63 0 12 0S0 5.37 0 12c0 5.99 4.39 10.95 10.13 11.85V15.47H7.08V12h3.05V9.36c0-3.01 1.79-4.67 4.53-4.67 1.31 0 2.69.23 2.69.23v2.96h-1.51c-1.49 0-1.96.93-1.96 1.88V12h3.33l-.53 3.47h-2.8v8.38C19.61 22.95 24 17.99 24 12z" }) })),
32
+ twitter: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4 fill-current", "aria-hidden": "true", children: _jsx("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" }) })),
33
+ discord: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": "true", children: _jsx("path", { fill: "#5865F2", d: "M20.32 4.37A19.79 19.79 0 0016.56 3l-.18.36a18.27 18.27 0 00-8.76 0L7.44 3a19.79 19.79 0 00-3.76 1.37C.99 8.4.27 12.34.63 16.22a19.94 19.94 0 006.07 3.07l.49-.7a13.2 13.2 0 01-2.07-.99c.17-.13.34-.27.5-.41a14.13 14.13 0 0012.76 0c.16.14.33.28.5.41-.66.4-1.36.73-2.07.99l.49.7a19.92 19.92 0 006.07-3.07c.43-4.5-.66-8.41-2.95-11.85zM8.52 14.12c-1.18 0-2.15-1.08-2.15-2.41 0-1.33.95-2.42 2.15-2.42 1.2 0 2.17 1.09 2.15 2.42 0 1.33-.96 2.41-2.15 2.41zm6.96 0c-1.18 0-2.15-1.08-2.15-2.41 0-1.33.95-2.42 2.15-2.42 1.2 0 2.17 1.09 2.15 2.42 0 1.33-.95 2.41-2.15 2.41z" }) })),
34
+ gitlab: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": "true", children: _jsx("path", { fill: "#FC6D26", d: "M23.6 9.6L23.57 9.5 20.3.81a.84.84 0 00-1.6.05L16.5 7.6H7.5L5.3.86a.84.84 0 00-1.6-.05L.43 9.5l-.03.1a5.84 5.84 0 001.94 6.74l.01.01.03.02 4.8 3.6 2.38 1.8 1.45 1.1a1 1 0 001.2 0l1.45-1.1 2.38-1.8 4.83-3.62.01-.01a5.84 5.84 0 001.93-6.74z" }) })),
35
+ linkedin: (_jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", "aria-hidden": "true", children: _jsx("path", { fill: "#0A66C2", d: "M20.45 20.45h-3.55v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.13 1.45-2.13 2.94v5.67H9.36V9h3.41v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.45v6.29zM5.34 7.43a2.06 2.06 0 11.01-4.13 2.06 2.06 0 010 4.13zM7.12 20.45H3.56V9h3.56v11.45zM22.22 0H1.77C.79 0 0 .77 0 1.72v20.56C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.72V1.72C24 .77 23.2 0 22.22 0z" }) })),
36
+ };
37
+ function ProviderIcon({ id }) {
38
+ const icon = PROVIDER_ICON[id];
39
+ if (icon)
40
+ return _jsx("span", { className: "mr-2 flex h-4 w-4 items-center justify-center", children: icon });
41
+ return (_jsx("span", { className: "mr-2 flex h-4 w-4 items-center justify-center rounded-sm bg-muted text-[10px] font-bold uppercase", children: id[0] }));
42
+ }
43
+ /**
44
+ * Renders one button per enabled third-party provider returned by
45
+ * `GET {authUrl}/config`. Clicking a button initiates an OAuth redirect via
46
+ * better-auth (`signIn.social` or `signIn.oauth2`).
47
+ *
48
+ * Returns `null` while loading or when the server reports no providers.
49
+ */
50
+ export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallbackURL, dividerText = 'or continue with email', }) {
51
+ const { getAuthConfig, signInWithProvider } = useAuth();
52
+ const [providers, setProviders] = useState([]);
53
+ const [loading, setLoading] = useState(true);
54
+ const [error, setError] = useState(null);
55
+ useEffect(() => {
56
+ let cancelled = false;
57
+ // Wrap in Promise.resolve so synchronous throws (e.g. mock client without
58
+ // getConfig) become rejections we can swallow rather than uncaught errors.
59
+ Promise.resolve()
60
+ .then(() => getAuthConfig())
61
+ .then((config) => {
62
+ if (cancelled)
63
+ return;
64
+ const list = config?.socialProviders ?? [];
65
+ setProviders(list.filter((p) => p.enabled));
66
+ })
67
+ .catch((err) => {
68
+ if (cancelled)
69
+ return;
70
+ // Don't surface as a hard error — providers are an enhancement, not required.
71
+ console.warn('[SocialSignInButtons] failed to load auth config', err);
72
+ })
73
+ .finally(() => {
74
+ if (!cancelled)
75
+ setLoading(false);
76
+ });
77
+ return () => { cancelled = true; };
78
+ }, [getAuthConfig]);
79
+ if (loading || providers.length === 0)
80
+ return null;
81
+ const label = mode === 'sign-in' ? 'Continue with' : 'Sign up with';
82
+ const defaultCallback = typeof window !== 'undefined' ? window.location.href : undefined;
83
+ const onClick = async (provider) => {
84
+ setError(null);
85
+ try {
86
+ await signInWithProvider(provider.id, {
87
+ callbackURL: callbackURL ?? defaultCallback,
88
+ errorCallbackURL: errorCallbackURL ?? callbackURL ?? defaultCallback,
89
+ type: provider.type ?? 'social',
90
+ });
91
+ }
92
+ catch (err) {
93
+ setError(err instanceof Error ? err.message : String(err));
94
+ }
95
+ };
96
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), providers.map((p) => (_jsxs("button", { type: "button", onClick: () => onClick(p), className: "inline-flex h-10 w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: [_jsx(ProviderIcon, { id: p.id }), label, " ", PROVIDER_LABEL[p.id] ?? p.name] }, p.id))), _jsxs("div", { className: "relative my-1", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("span", { className: "w-full border-t" }) }), _jsx("div", { className: "relative flex justify-center text-xs uppercase", children: _jsx("span", { className: "bg-background px-2 text-muted-foreground", children: dividerText }) })] })] }));
97
+ }