@sanity/sdk-react 0.0.0-alpha.1 → 0.0.0-alpha.10
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/README.md +163 -0
- package/dist/_chunks-es/context.js +8 -0
- package/dist/_chunks-es/context.js.map +1 -0
- package/dist/_chunks-es/useLogOut.js +29 -20
- package/dist/_chunks-es/useLogOut.js.map +1 -1
- package/dist/components.d.ts +25 -149
- package/dist/components.js +54 -151
- package/dist/components.js.map +1 -1
- package/dist/context.d.ts +45 -0
- package/dist/context.js +5 -0
- package/dist/context.js.map +1 -0
- package/dist/hooks.d.ts +3401 -12
- package/dist/hooks.js +210 -15
- package/dist/hooks.js.map +1 -1
- package/package.json +43 -32
- package/src/_exports/components.ts +2 -12
- package/src/_exports/context.ts +2 -0
- package/src/_exports/hooks.ts +25 -0
- package/src/components/SanityApp.test.tsx +54 -0
- package/src/components/SanityApp.tsx +53 -0
- package/src/components/auth/AuthBoundary.test.tsx +18 -22
- package/src/components/auth/AuthBoundary.tsx +14 -7
- package/src/components/auth/Login.test.tsx +3 -17
- package/src/components/auth/Login.tsx +27 -31
- package/src/components/auth/LoginCallback.test.tsx +2 -17
- package/src/components/auth/LoginCallback.tsx +8 -10
- package/src/components/auth/LoginError.test.tsx +2 -17
- package/src/components/auth/LoginError.tsx +8 -17
- package/src/components/auth/LoginFooter.test.tsx +2 -16
- package/src/components/auth/LoginFooter.tsx +18 -27
- package/src/components/auth/LoginLayout.test.tsx +2 -16
- package/src/components/auth/LoginLayout.tsx +8 -37
- package/src/components/auth/authTestHelpers.tsx +18 -0
- package/src/{components/context → context}/SanityProvider.test.tsx +1 -1
- package/src/{components/context → context}/SanityProvider.tsx +12 -6
- package/src/hooks/auth/useAuthState.test.tsx +10 -100
- package/src/hooks/auth/useAuthState.tsx +5 -10
- package/src/hooks/auth/useAuthToken.test.tsx +10 -88
- package/src/hooks/auth/useAuthToken.tsx +4 -10
- package/src/hooks/auth/useCurrentUser.test.tsx +10 -44
- package/src/hooks/auth/useCurrentUser.tsx +22 -22
- package/src/hooks/auth/useHandleCallback.test.tsx +10 -19
- package/src/hooks/auth/useHandleCallback.tsx +4 -9
- package/src/hooks/auth/useLogOut.test.tsx +11 -62
- package/src/hooks/auth/useLogOut.tsx +4 -9
- package/src/hooks/auth/useLoginUrls.test.tsx +47 -40
- package/src/hooks/auth/useLoginUrls.tsx +7 -6
- package/src/hooks/client/useClient.test.tsx +1 -1
- package/src/hooks/client/useClient.ts +3 -3
- package/src/hooks/comlink/useFrameConnection.test.tsx +122 -0
- package/src/hooks/comlink/useFrameConnection.ts +111 -0
- package/src/hooks/comlink/useWindowConnection.test.ts +94 -0
- package/src/hooks/comlink/useWindowConnection.ts +82 -0
- package/src/hooks/context/useSanityInstance.test.tsx +1 -1
- package/src/hooks/context/useSanityInstance.ts +4 -4
- package/src/hooks/document/useApplyActions.test.ts +24 -0
- package/src/hooks/document/useApplyActions.ts +24 -0
- package/src/hooks/document/useDocument.test.ts +81 -0
- package/src/hooks/document/useDocument.ts +38 -0
- package/src/hooks/document/useDocumentEvent.test.ts +53 -0
- package/src/hooks/document/useDocumentEvent.ts +22 -0
- package/src/hooks/document/useDocumentSyncStatus.test.ts +16 -0
- package/src/hooks/document/useDocumentSyncStatus.ts +6 -0
- package/src/hooks/document/useEditDocument.test.ts +172 -0
- package/src/hooks/document/useEditDocument.ts +80 -0
- package/src/hooks/documentCollection/useDocuments.test.ts +130 -0
- package/src/hooks/documentCollection/useDocuments.ts +135 -0
- package/src/hooks/helpers/createCallbackHook.test.tsx +106 -0
- package/src/hooks/helpers/createCallbackHook.tsx +15 -0
- package/src/hooks/helpers/createStateSourceHook.test.tsx +130 -0
- package/src/hooks/helpers/createStateSourceHook.tsx +21 -0
- package/src/hooks/preview/usePreview.test.tsx +175 -0
- package/src/hooks/preview/usePreview.tsx +120 -0
- package/src/vite-env.d.ts +10 -0
- package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +0 -95
- package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +0 -42
- package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +0 -23
- package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +0 -95
- package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +0 -42
- package/src/components/DocumentListLayout/DocumentListLayout.tsx +0 -15
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +0 -49
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +0 -34
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +0 -30
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +0 -115
- package/src/components/Login/LoginLinks.test.tsx +0 -100
- package/src/components/Login/LoginLinks.tsx +0 -73
- package/src/hooks/Documents/.keep +0 -0
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {render, screen, waitFor} from '@testing-library/react'
|
|
5
|
-
import React from 'react'
|
|
1
|
+
import {AuthStateType} from '@sanity/sdk'
|
|
2
|
+
import {useAuthState} from '@sanity/sdk-react/hooks'
|
|
3
|
+
import {screen, waitFor} from '@testing-library/react'
|
|
6
4
|
import {beforeEach, describe, expect, it, type MockInstance, vi} from 'vitest'
|
|
7
5
|
|
|
8
|
-
import {useAuthState} from '../../hooks/auth/useAuthState'
|
|
9
|
-
import {SanityProvider} from '../context/SanityProvider'
|
|
10
6
|
import {AuthBoundary} from './AuthBoundary'
|
|
7
|
+
import {renderWithWrappers} from './authTestHelpers'
|
|
11
8
|
|
|
12
9
|
// Mock hooks
|
|
13
10
|
vi.mock('../../hooks/auth/useAuthState', () => ({
|
|
@@ -38,16 +35,6 @@ vi.mock('./AuthError', async (importOriginal) => {
|
|
|
38
35
|
}
|
|
39
36
|
})
|
|
40
37
|
|
|
41
|
-
const theme = buildTheme({})
|
|
42
|
-
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
43
|
-
const renderWithWrappers = (ui: React.ReactElement) => {
|
|
44
|
-
return render(
|
|
45
|
-
<ThemeProvider theme={theme}>
|
|
46
|
-
<SanityProvider sanityInstance={sanityInstance}>{ui}</SanityProvider>
|
|
47
|
-
</ThemeProvider>,
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
38
|
describe('AuthBoundary', () => {
|
|
52
39
|
let consoleErrorSpy: MockInstance
|
|
53
40
|
beforeEach(() => {
|
|
@@ -60,16 +47,22 @@ describe('AuthBoundary', () => {
|
|
|
60
47
|
})
|
|
61
48
|
|
|
62
49
|
it('renders the Login component when authState="logged-out"', () => {
|
|
63
|
-
vi.mocked(useAuthState).mockReturnValue({
|
|
50
|
+
vi.mocked(useAuthState).mockReturnValue({
|
|
51
|
+
type: AuthStateType.LOGGED_OUT,
|
|
52
|
+
isDestroyingSession: false,
|
|
53
|
+
})
|
|
64
54
|
renderWithWrappers(<AuthBoundary>Protected Content</AuthBoundary>)
|
|
65
55
|
|
|
66
56
|
// The login screen should show "Choose login provider" by default
|
|
67
|
-
expect(screen.getByText('Choose login provider')).toBeInTheDocument()
|
|
57
|
+
expect(screen.getByText('Choose login provider:')).toBeInTheDocument()
|
|
68
58
|
expect(screen.queryByText('Protected Content')).not.toBeInTheDocument()
|
|
69
59
|
})
|
|
70
60
|
|
|
71
61
|
it('renders the LoginCallback component when authState="logging-in"', () => {
|
|
72
|
-
vi.mocked(useAuthState).mockReturnValue({
|
|
62
|
+
vi.mocked(useAuthState).mockReturnValue({
|
|
63
|
+
type: AuthStateType.LOGGING_IN,
|
|
64
|
+
isExchangingToken: false,
|
|
65
|
+
})
|
|
73
66
|
renderWithWrappers(<AuthBoundary>Protected Content</AuthBoundary>)
|
|
74
67
|
|
|
75
68
|
// The callback screen shows "Logging you in…"
|
|
@@ -78,7 +71,7 @@ describe('AuthBoundary', () => {
|
|
|
78
71
|
|
|
79
72
|
it('renders children when authState="logged-in"', () => {
|
|
80
73
|
vi.mocked(useAuthState).mockReturnValue({
|
|
81
|
-
type:
|
|
74
|
+
type: AuthStateType.LOGGED_IN,
|
|
82
75
|
currentUser: null,
|
|
83
76
|
token: 'exampleToken',
|
|
84
77
|
})
|
|
@@ -88,7 +81,10 @@ describe('AuthBoundary', () => {
|
|
|
88
81
|
})
|
|
89
82
|
|
|
90
83
|
it('shows the LoginError (via ErrorBoundary) when authState="error"', async () => {
|
|
91
|
-
vi.mocked(useAuthState).mockReturnValue({
|
|
84
|
+
vi.mocked(useAuthState).mockReturnValue({
|
|
85
|
+
type: AuthStateType.ERROR,
|
|
86
|
+
error: new Error('test error'),
|
|
87
|
+
})
|
|
92
88
|
renderWithWrappers(<AuthBoundary>Protected Content</AuthBoundary>)
|
|
93
89
|
|
|
94
90
|
// The AuthBoundary should throw an AuthError internally
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {AuthStateType} from '@sanity/sdk'
|
|
1
2
|
import {useMemo} from 'react'
|
|
2
3
|
import {ErrorBoundary, type FallbackProps} from 'react-error-boundary'
|
|
3
4
|
|
|
@@ -6,12 +7,18 @@ import {AuthError} from './AuthError'
|
|
|
6
7
|
import {Login} from './Login'
|
|
7
8
|
import {LoginCallback} from './LoginCallback'
|
|
8
9
|
import {LoginError, type LoginErrorProps} from './LoginError'
|
|
9
|
-
import type
|
|
10
|
+
import {type LoginLayoutProps} from './LoginLayout'
|
|
11
|
+
|
|
12
|
+
// Only import bridge if we're in an iframe. This assumes that the app is
|
|
13
|
+
// running withing SanityOS if it is in an iframe.
|
|
14
|
+
if (typeof window !== 'undefined' && window.self !== window.top) {
|
|
15
|
+
import('@sanity/os/bridge')
|
|
16
|
+
}
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
|
-
* @
|
|
19
|
+
* @internal
|
|
13
20
|
*/
|
|
14
|
-
|
|
21
|
+
interface AuthBoundaryProps extends LoginLayoutProps {
|
|
15
22
|
/**
|
|
16
23
|
* Custom component to render the login screen.
|
|
17
24
|
* Receives all login layout props. Defaults to {@link Login}.
|
|
@@ -51,7 +58,7 @@ export interface AuthBoundaryProps extends LoginLayoutProps {
|
|
|
51
58
|
* }
|
|
52
59
|
* ```
|
|
53
60
|
*
|
|
54
|
-
* @
|
|
61
|
+
* @internal
|
|
55
62
|
*/
|
|
56
63
|
export function AuthBoundary({
|
|
57
64
|
LoginErrorComponent = LoginError,
|
|
@@ -85,13 +92,13 @@ function AuthSwitch({
|
|
|
85
92
|
const authState = useAuthState()
|
|
86
93
|
|
|
87
94
|
switch (authState.type) {
|
|
88
|
-
case
|
|
95
|
+
case AuthStateType.ERROR: {
|
|
89
96
|
throw new AuthError(authState.error)
|
|
90
97
|
}
|
|
91
|
-
case
|
|
98
|
+
case AuthStateType.LOGGING_IN: {
|
|
92
99
|
return <CallbackComponent {...props} />
|
|
93
100
|
}
|
|
94
|
-
case
|
|
101
|
+
case AuthStateType.LOGGED_IN: {
|
|
95
102
|
return children
|
|
96
103
|
}
|
|
97
104
|
default: {
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {ThemeProvider} from '@sanity/ui'
|
|
3
|
-
import {buildTheme} from '@sanity/ui/theme'
|
|
4
|
-
import {render, screen} from '@testing-library/react'
|
|
5
|
-
import React from 'react'
|
|
1
|
+
import {screen} from '@testing-library/react'
|
|
6
2
|
import {describe, expect, it, vi} from 'vitest'
|
|
7
3
|
|
|
8
|
-
import {
|
|
4
|
+
import {renderWithWrappers} from './authTestHelpers'
|
|
9
5
|
import {Login} from './Login'
|
|
10
6
|
|
|
11
7
|
vi.mock('../../hooks/auth/useLoginUrls', () => ({
|
|
@@ -15,20 +11,10 @@ vi.mock('../../hooks/auth/useLoginUrls', () => ({
|
|
|
15
11
|
]),
|
|
16
12
|
}))
|
|
17
13
|
|
|
18
|
-
const theme = buildTheme({})
|
|
19
|
-
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
20
|
-
const renderWithWrappers = (ui: React.ReactElement) => {
|
|
21
|
-
return render(
|
|
22
|
-
<ThemeProvider theme={theme}>
|
|
23
|
-
<SanityProvider sanityInstance={sanityInstance}>{ui}</SanityProvider>
|
|
24
|
-
</ThemeProvider>,
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
14
|
describe('Login', () => {
|
|
29
15
|
it('renders login providers', () => {
|
|
30
16
|
renderWithWrappers(<Login />)
|
|
31
|
-
expect(screen.getByText('Choose login provider')).toBeInTheDocument()
|
|
17
|
+
expect(screen.getByText('Choose login provider:')).toBeInTheDocument()
|
|
32
18
|
expect(screen.getByRole('link', {name: 'Provider A'})).toHaveAttribute(
|
|
33
19
|
'href',
|
|
34
20
|
'https://provider-a.com/auth',
|
|
@@ -1,46 +1,34 @@
|
|
|
1
|
-
import {Button, Flex, Heading, Spinner} from '@sanity/ui'
|
|
2
|
-
import {Suspense} from 'react'
|
|
3
|
-
import styled from 'styled-components'
|
|
1
|
+
import {Box, Button, Flex, Heading, Spinner, Stack} from '@sanity/ui'
|
|
2
|
+
import {type JSX, Suspense} from 'react'
|
|
4
3
|
|
|
5
4
|
import {useLoginUrls} from '../../hooks/auth/useLoginUrls'
|
|
6
5
|
import {LoginLayout, type LoginLayoutProps} from './LoginLayout'
|
|
7
6
|
|
|
8
|
-
/**
|
|
9
|
-
* @alpha
|
|
10
|
-
*/
|
|
11
|
-
export interface LoginProps {
|
|
12
|
-
header?: React.ReactNode
|
|
13
|
-
footer?: React.ReactNode
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const FallbackRoot = styled(Flex)`
|
|
17
|
-
height: 123px;
|
|
18
|
-
`
|
|
19
|
-
|
|
20
7
|
/**
|
|
21
8
|
* Login component that displays available authentication providers.
|
|
22
9
|
* Renders a list of login options with a loading fallback while providers load.
|
|
23
10
|
*
|
|
24
11
|
* @alpha
|
|
12
|
+
* @internal
|
|
25
13
|
*/
|
|
26
14
|
export function Login({header, footer}: LoginLayoutProps): JSX.Element {
|
|
27
15
|
return (
|
|
28
16
|
<LoginLayout header={header} footer={footer}>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
</Heading>
|
|
17
|
+
<Heading as="h6" align="center">
|
|
18
|
+
Choose login provider:
|
|
19
|
+
</Heading>
|
|
33
20
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
<Suspense
|
|
22
|
+
fallback={
|
|
23
|
+
<Box padding={5}>
|
|
24
|
+
<Flex align="center" justify="center">
|
|
37
25
|
<Spinner />
|
|
38
|
-
</
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
</
|
|
26
|
+
</Flex>
|
|
27
|
+
</Box>
|
|
28
|
+
}
|
|
29
|
+
>
|
|
30
|
+
<Providers />
|
|
31
|
+
</Suspense>
|
|
44
32
|
</LoginLayout>
|
|
45
33
|
)
|
|
46
34
|
}
|
|
@@ -49,10 +37,18 @@ function Providers() {
|
|
|
49
37
|
const loginUrls = useLoginUrls()
|
|
50
38
|
|
|
51
39
|
return (
|
|
52
|
-
<
|
|
40
|
+
<Stack space={3} marginY={5}>
|
|
53
41
|
{loginUrls.map(({title, url}) => (
|
|
54
|
-
<Button
|
|
42
|
+
<Button
|
|
43
|
+
key={url}
|
|
44
|
+
as="a"
|
|
45
|
+
href={url}
|
|
46
|
+
mode="ghost"
|
|
47
|
+
text={title}
|
|
48
|
+
textAlign="center"
|
|
49
|
+
fontSize={2}
|
|
50
|
+
></Button>
|
|
55
51
|
))}
|
|
56
|
-
</
|
|
52
|
+
</Stack>
|
|
57
53
|
)
|
|
58
54
|
}
|
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {ThemeProvider} from '@sanity/ui'
|
|
3
|
-
import {buildTheme} from '@sanity/ui/theme'
|
|
4
|
-
import {render, screen, waitFor} from '@testing-library/react'
|
|
5
|
-
import React from 'react'
|
|
1
|
+
import {screen, waitFor} from '@testing-library/react'
|
|
6
2
|
import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from 'vitest'
|
|
7
3
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const theme = buildTheme({})
|
|
11
|
-
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
12
|
-
|
|
13
|
-
const renderWithWrappers = (ui: React.ReactElement) => {
|
|
14
|
-
return render(
|
|
15
|
-
<ThemeProvider theme={theme}>
|
|
16
|
-
<SanityProvider sanityInstance={sanityInstance}>{ui}</SanityProvider>
|
|
17
|
-
</ThemeProvider>,
|
|
18
|
-
)
|
|
19
|
-
}
|
|
4
|
+
import {renderWithWrappers} from './authTestHelpers'
|
|
20
5
|
|
|
21
6
|
// Mock `useHandleCallback`
|
|
22
7
|
vi.mock('../../hooks/auth/useHandleCallback', () => ({
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import {Flex,
|
|
1
|
+
import {Flex, Heading, Spinner} from '@sanity/ui'
|
|
2
2
|
import {useEffect} from 'react'
|
|
3
|
-
import styled from 'styled-components'
|
|
4
3
|
|
|
5
4
|
import {useHandleCallback} from '../../hooks/auth/useHandleCallback'
|
|
6
5
|
import {LoginLayout, type LoginLayoutProps} from './LoginLayout'
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
margin: auto;
|
|
10
|
-
`
|
|
11
|
-
|
|
7
|
+
/**
|
|
12
8
|
/**
|
|
13
9
|
* Component shown during auth callback processing that handles login completion.
|
|
14
10
|
* Automatically processes the auth callback when mounted and updates the URL
|
|
@@ -32,10 +28,12 @@ export function LoginCallback({header, footer}: LoginLayoutProps): React.ReactNo
|
|
|
32
28
|
|
|
33
29
|
return (
|
|
34
30
|
<LoginLayout header={header} footer={footer}>
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
<Heading as="h6" align="center">
|
|
32
|
+
Logging you in…
|
|
33
|
+
</Heading>
|
|
34
|
+
<Flex paddingY={5} align="center" justify="center">
|
|
35
|
+
<Spinner />
|
|
36
|
+
</Flex>
|
|
39
37
|
</LoginLayout>
|
|
40
38
|
)
|
|
41
39
|
}
|
|
@@ -1,29 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {ThemeProvider} from '@sanity/ui'
|
|
3
|
-
import {buildTheme} from '@sanity/ui/theme'
|
|
4
|
-
import {fireEvent, render, screen, waitFor} from '@testing-library/react'
|
|
5
|
-
import React from 'react'
|
|
1
|
+
import {fireEvent, screen, waitFor} from '@testing-library/react'
|
|
6
2
|
import {describe, expect, it, vi} from 'vitest'
|
|
7
3
|
|
|
8
|
-
import {SanityProvider} from '../context/SanityProvider'
|
|
9
4
|
import {AuthError} from './AuthError'
|
|
5
|
+
import {renderWithWrappers} from './authTestHelpers'
|
|
10
6
|
import {LoginError} from './LoginError'
|
|
11
7
|
|
|
12
8
|
vi.mock('../../hooks/auth/useLogOut', () => ({
|
|
13
9
|
useLogOut: vi.fn(() => async () => {}),
|
|
14
10
|
}))
|
|
15
11
|
|
|
16
|
-
const theme = buildTheme({})
|
|
17
|
-
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
18
|
-
|
|
19
|
-
const renderWithWrappers = (ui: React.ReactElement) => {
|
|
20
|
-
return render(
|
|
21
|
-
<ThemeProvider theme={theme}>
|
|
22
|
-
<SanityProvider sanityInstance={sanityInstance}>{ui}</SanityProvider>
|
|
23
|
-
</ThemeProvider>,
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
12
|
describe('LoginError', () => {
|
|
28
13
|
it('shows authentication error and retry button', async () => {
|
|
29
14
|
const mockReset = vi.fn()
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {Button,
|
|
1
|
+
import {Button, Heading, Stack, Text} from '@sanity/ui'
|
|
2
2
|
import {useCallback} from 'react'
|
|
3
3
|
import {type FallbackProps} from 'react-error-boundary'
|
|
4
|
-
import styled from 'styled-components'
|
|
5
4
|
|
|
6
5
|
import {useLogOut} from '../../hooks/auth/useLogOut'
|
|
7
6
|
import {AuthError} from './AuthError'
|
|
@@ -12,10 +11,6 @@ import {LoginLayout, type LoginLayoutProps} from './LoginLayout'
|
|
|
12
11
|
*/
|
|
13
12
|
export type LoginErrorProps = FallbackProps & LoginLayoutProps
|
|
14
13
|
|
|
15
|
-
const StyledFlex = styled(Flex)`
|
|
16
|
-
margin: auto;
|
|
17
|
-
`
|
|
18
|
-
|
|
19
14
|
/**
|
|
20
15
|
* Displays authentication error details and provides retry functionality.
|
|
21
16
|
* Only handles {@link AuthError} instances - rethrows other error types.
|
|
@@ -38,17 +33,13 @@ export function LoginError({
|
|
|
38
33
|
|
|
39
34
|
return (
|
|
40
35
|
<LoginLayout header={header} footer={footer}>
|
|
41
|
-
<
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</Text>
|
|
49
|
-
</Flex>
|
|
50
|
-
<Button text="Retry" tone="primary" onClick={handleRetry} />
|
|
51
|
-
</StyledFlex>
|
|
36
|
+
<Stack space={5} marginBottom={5}>
|
|
37
|
+
<Heading as="h6" align="center">
|
|
38
|
+
Authentication Error
|
|
39
|
+
</Heading>
|
|
40
|
+
<Text align="center">Please try again or contact support if the problem persists.</Text>
|
|
41
|
+
<Button mode="ghost" onClick={handleRetry} text="Retry" fontSize={2} />
|
|
42
|
+
</Stack>
|
|
52
43
|
</LoginLayout>
|
|
53
44
|
)
|
|
54
45
|
}
|
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {ThemeProvider} from '@sanity/ui'
|
|
3
|
-
import {buildTheme} from '@sanity/ui/theme'
|
|
4
|
-
import {render, screen} from '@testing-library/react'
|
|
5
|
-
import React from 'react'
|
|
1
|
+
import {screen} from '@testing-library/react'
|
|
6
2
|
import {describe, expect, it} from 'vitest'
|
|
7
3
|
|
|
8
|
-
import {
|
|
4
|
+
import {renderWithWrappers} from './authTestHelpers'
|
|
9
5
|
import {LoginFooter} from './LoginFooter'
|
|
10
6
|
|
|
11
|
-
const theme = buildTheme({})
|
|
12
|
-
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
13
|
-
const renderWithWrappers = (ui: React.ReactElement) => {
|
|
14
|
-
return render(
|
|
15
|
-
<ThemeProvider theme={theme}>
|
|
16
|
-
<SanityProvider sanityInstance={sanityInstance}>{ui}</SanityProvider>
|
|
17
|
-
</ThemeProvider>,
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
7
|
describe('LoginFooter', () => {
|
|
22
8
|
it('renders footer links', () => {
|
|
23
9
|
renderWithWrappers(<LoginFooter />)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import {SanityLogo} from '@sanity/logos'
|
|
2
|
-
import {Flex, Text} from '@sanity/ui'
|
|
3
|
-
import {Fragment} from 'react'
|
|
4
|
-
import styled from 'styled-components'
|
|
2
|
+
import {Box, Flex, Inline, Text} from '@sanity/ui'
|
|
5
3
|
|
|
6
4
|
const LINKS = [
|
|
7
5
|
{
|
|
@@ -26,12 +24,6 @@ const LINKS = [
|
|
|
26
24
|
},
|
|
27
25
|
]
|
|
28
26
|
|
|
29
|
-
const StyledText = styled(Text)`
|
|
30
|
-
a {
|
|
31
|
-
color: inherit;
|
|
32
|
-
}
|
|
33
|
-
`
|
|
34
|
-
|
|
35
27
|
/**
|
|
36
28
|
* Default footer component for login screens showing Sanity branding and legal
|
|
37
29
|
* links.
|
|
@@ -40,28 +32,27 @@ const StyledText = styled(Text)`
|
|
|
40
32
|
*/
|
|
41
33
|
export function LoginFooter(): React.ReactNode {
|
|
42
34
|
return (
|
|
43
|
-
<
|
|
44
|
-
<
|
|
35
|
+
<Box>
|
|
36
|
+
<Flex justify="center">
|
|
45
37
|
<SanityLogo />
|
|
46
|
-
</
|
|
38
|
+
</Flex>
|
|
47
39
|
|
|
48
|
-
<Flex
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
<a
|
|
40
|
+
<Flex justify="center">
|
|
41
|
+
<Inline space={2} paddingY={3}>
|
|
42
|
+
{LINKS.map((link) => (
|
|
43
|
+
<Text size={0} key={link.url}>
|
|
44
|
+
<a
|
|
45
|
+
href={link.url}
|
|
46
|
+
target="_blank"
|
|
47
|
+
rel="noopener noreferrer"
|
|
48
|
+
style={{color: 'inherit'}}
|
|
49
|
+
>
|
|
53
50
|
{link.title}
|
|
54
51
|
</a>
|
|
55
|
-
</
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<Text size={1} muted>
|
|
59
|
-
•
|
|
60
|
-
</Text>
|
|
61
|
-
)}
|
|
62
|
-
</Fragment>
|
|
63
|
-
))}
|
|
52
|
+
</Text>
|
|
53
|
+
))}
|
|
54
|
+
</Inline>
|
|
64
55
|
</Flex>
|
|
65
|
-
</
|
|
56
|
+
</Box>
|
|
66
57
|
)
|
|
67
58
|
}
|
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {ThemeProvider} from '@sanity/ui'
|
|
3
|
-
import {buildTheme} from '@sanity/ui/theme'
|
|
4
|
-
import {render, screen} from '@testing-library/react'
|
|
5
|
-
import React from 'react'
|
|
1
|
+
import {screen} from '@testing-library/react'
|
|
6
2
|
import {describe, expect, it} from 'vitest'
|
|
7
3
|
|
|
8
|
-
import {
|
|
4
|
+
import {renderWithWrappers} from './authTestHelpers'
|
|
9
5
|
import {LoginLayout} from './LoginLayout'
|
|
10
6
|
|
|
11
|
-
const theme = buildTheme({})
|
|
12
|
-
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
13
|
-
const renderWithWrappers = (ui: React.ReactElement) => {
|
|
14
|
-
return render(
|
|
15
|
-
<ThemeProvider theme={theme}>
|
|
16
|
-
<SanityProvider sanityInstance={sanityInstance}>{ui}</SanityProvider>
|
|
17
|
-
</ThemeProvider>,
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
7
|
describe('LoginLayout', () => {
|
|
22
8
|
it('renders header, children, and footer', () => {
|
|
23
9
|
renderWithWrappers(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {Card,
|
|
2
|
-
import styled from 'styled-components'
|
|
1
|
+
import {Card, Container} from '@sanity/ui'
|
|
3
2
|
|
|
4
3
|
import {LoginFooter} from './LoginFooter'
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* @alpha
|
|
7
|
+
* @internal
|
|
8
8
|
*/
|
|
9
9
|
export interface LoginLayoutProps {
|
|
10
10
|
/** Optional header content rendered at top of card */
|
|
@@ -17,23 +17,6 @@ export interface LoginLayoutProps {
|
|
|
17
17
|
children?: React.ReactNode
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const Root = styled.div`
|
|
21
|
-
width: 100%;
|
|
22
|
-
display: flex;
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
const Container = styled(Flex)`
|
|
26
|
-
width: 320px;
|
|
27
|
-
margin: auto;
|
|
28
|
-
display: flex;
|
|
29
|
-
`
|
|
30
|
-
|
|
31
|
-
const StyledCard = styled(Card)``
|
|
32
|
-
|
|
33
|
-
const ChildrenFlex = styled(Flex)`
|
|
34
|
-
min-height: 154px;
|
|
35
|
-
`
|
|
36
|
-
|
|
37
20
|
/**
|
|
38
21
|
* Layout component for login-related screens providing consistent styling and structure.
|
|
39
22
|
* Renders content in a centered card with optional header and footer sections.
|
|
@@ -74,26 +57,14 @@ export function LoginLayout({
|
|
|
74
57
|
header,
|
|
75
58
|
}: LoginLayoutProps): React.ReactNode {
|
|
76
59
|
return (
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
<Flex direction="column" gap={4}>
|
|
81
|
-
{header && (
|
|
82
|
-
<Card borderBottom paddingX={4} paddingBottom={3}>
|
|
83
|
-
{header}
|
|
84
|
-
</Card>
|
|
85
|
-
)}
|
|
60
|
+
<Container width={0}>
|
|
61
|
+
<Card shadow={1} radius={2} padding={4}>
|
|
62
|
+
{header && header}
|
|
86
63
|
|
|
87
|
-
|
|
88
|
-
<ChildrenFlex paddingX={4} direction="column">
|
|
89
|
-
{children}
|
|
90
|
-
</ChildrenFlex>
|
|
91
|
-
)}
|
|
92
|
-
</Flex>
|
|
93
|
-
</StyledCard>
|
|
64
|
+
{children && children}
|
|
94
65
|
|
|
95
66
|
{footer}
|
|
96
|
-
</
|
|
97
|
-
</
|
|
67
|
+
</Card>
|
|
68
|
+
</Container>
|
|
98
69
|
)
|
|
99
70
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {createSanityInstance} from '@sanity/sdk'
|
|
2
|
+
import {ThemeProvider} from '@sanity/ui'
|
|
3
|
+
import {buildTheme} from '@sanity/ui/theme'
|
|
4
|
+
import {render, type RenderResult} from '@testing-library/react'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
|
|
7
|
+
import {SanityProvider} from '../../context/SanityProvider'
|
|
8
|
+
|
|
9
|
+
const sanityInstance = createSanityInstance({projectId: 'test-project-id', dataset: 'production'})
|
|
10
|
+
const theme = buildTheme()
|
|
11
|
+
|
|
12
|
+
export const renderWithWrappers = (ui: React.ReactElement): RenderResult => {
|
|
13
|
+
return render(
|
|
14
|
+
<SanityProvider sanityInstance={sanityInstance}>
|
|
15
|
+
<ThemeProvider theme={theme}>{ui}</ThemeProvider>
|
|
16
|
+
</SanityProvider>,
|
|
17
|
+
)
|
|
18
|
+
}
|
|
@@ -2,7 +2,7 @@ import {createSanityInstance} from '@sanity/sdk'
|
|
|
2
2
|
import {render} from '@testing-library/react'
|
|
3
3
|
import {describe, expect, it} from 'vitest'
|
|
4
4
|
|
|
5
|
-
import {useSanityInstance} from '
|
|
5
|
+
import {useSanityInstance} from '../hooks/context/useSanityInstance'
|
|
6
6
|
import {SanityProvider} from './SanityProvider'
|
|
7
7
|
|
|
8
8
|
describe('SanityProvider', () => {
|
|
@@ -12,22 +12,28 @@ export interface SanityProviderProps {
|
|
|
12
12
|
export const SanityInstanceContext = createContext<SanityInstance | null>(null)
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Top-level context provider that provides
|
|
16
|
-
* This must wrap any Sanity SDK React
|
|
17
|
-
* @
|
|
15
|
+
* Top-level context provider that provides access to the Sanity configuration instance.
|
|
16
|
+
* This must wrap any components making use of the Sanity SDK React hooks.
|
|
17
|
+
* @remarks In most cases, SanityApp should be used rather than SanityProvider directly; SanityApp bundles both SanityProvider and an authentication layer.
|
|
18
|
+
* @internal
|
|
18
19
|
* @param props - Sanity project and dataset configuration
|
|
19
20
|
* @returns Rendered component
|
|
20
21
|
* @example
|
|
21
22
|
* ```tsx
|
|
22
23
|
* import {createSanityInstance} from '@sanity/sdk'
|
|
23
|
-
* import {
|
|
24
|
+
* import {SanityProvider} from '@sanity/sdk-react'
|
|
25
|
+
*
|
|
26
|
+
* import MyAppRoot from './Root'
|
|
24
27
|
*
|
|
25
|
-
* const sanityInstance = createSanityInstance({
|
|
28
|
+
* const sanityInstance = createSanityInstance({
|
|
29
|
+
* projectId: 'your-project-id',
|
|
30
|
+
* dataset: 'production',
|
|
31
|
+
* })
|
|
26
32
|
*
|
|
27
33
|
* export default function MyApp() {
|
|
28
34
|
* return (
|
|
29
35
|
* <SanityProvider sanityInstance={sanityInstance}>
|
|
30
|
-
*
|
|
36
|
+
* <MyAppRoot />
|
|
31
37
|
* </SanityProvider>
|
|
32
38
|
* )
|
|
33
39
|
* }
|