@sanity/sdk-react 0.0.0-alpha.19 → 0.0.0-alpha.2
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 +67 -38
- package/dist/_chunks-es/useLogOut.js +44 -0
- package/dist/_chunks-es/useLogOut.js.map +1 -0
- package/dist/assets/bundle-CcAyERuZ.css +11 -0
- package/dist/components.d.ts +257 -0
- package/dist/components.js +316 -0
- package/dist/components.js.map +1 -0
- package/dist/hooks.d.ts +187 -0
- package/dist/hooks.js +81 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +2 -4641
- package/dist/index.js +2 -960
- package/dist/index.js.map +1 -1
- package/package.json +56 -25
- package/src/_exports/components.ts +13 -0
- package/src/_exports/hooks.ts +9 -0
- package/src/_exports/index.ts +10 -58
- package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +113 -0
- package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +42 -0
- package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +21 -0
- package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +105 -0
- package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +42 -0
- package/src/components/DocumentListLayout/DocumentListLayout.tsx +12 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +49 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +39 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +30 -0
- package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +171 -0
- package/src/components/Login/LoginLinks.test.tsx +12 -2
- package/src/components/Login/LoginLinks.tsx +29 -14
- package/src/components/auth/AuthBoundary.test.tsx +17 -4
- package/src/components/auth/AuthBoundary.tsx +4 -20
- package/src/components/auth/Login.test.tsx +16 -2
- package/src/components/auth/Login.tsx +30 -11
- package/src/components/auth/LoginCallback.test.tsx +17 -2
- package/src/components/auth/LoginCallback.tsx +10 -5
- package/src/components/auth/LoginError.test.tsx +17 -2
- package/src/components/auth/LoginError.tsx +16 -11
- package/src/components/auth/LoginFooter.test.tsx +16 -2
- package/src/components/auth/LoginFooter.tsx +24 -8
- package/src/components/auth/LoginLayout.test.tsx +16 -2
- package/src/components/auth/LoginLayout.tsx +38 -8
- package/src/{context → components/context}/SanityProvider.test.tsx +2 -2
- package/src/components/context/SanityProvider.tsx +42 -0
- package/src/css/css.config.js +220 -0
- package/src/css/paramour.css +2347 -0
- package/src/css/styles.css +11 -0
- package/src/hooks/auth/useAuthState.tsx +5 -4
- package/src/hooks/auth/useAuthToken.tsx +1 -1
- package/src/hooks/auth/useCurrentUser.tsx +4 -27
- package/src/hooks/auth/useHandleCallback.tsx +0 -1
- package/src/hooks/auth/useLogOut.tsx +1 -1
- package/src/hooks/auth/useLoginUrls.tsx +0 -1
- package/src/hooks/client/useClient.test.tsx +130 -0
- package/src/hooks/client/useClient.ts +30 -8
- package/src/hooks/context/useSanityInstance.test.tsx +2 -2
- package/src/hooks/context/useSanityInstance.ts +8 -24
- package/src/hooks/documentCollection/useDocuments.test.ts +130 -0
- package/src/hooks/documentCollection/useDocuments.ts +87 -0
- package/src/hooks/helpers/createCallbackHook.tsx +2 -3
- package/src/hooks/helpers/createStateSourceHook.test.tsx +0 -66
- package/src/hooks/helpers/createStateSourceHook.tsx +10 -29
- package/src/hooks/preview/usePreview.test.tsx +10 -19
- package/src/hooks/preview/usePreview.tsx +13 -67
- package/src/components/SDKProvider.test.tsx +0 -79
- package/src/components/SDKProvider.tsx +0 -42
- package/src/components/SanityApp.test.tsx +0 -156
- package/src/components/SanityApp.tsx +0 -90
- package/src/components/auth/authTestHelpers.tsx +0 -11
- package/src/components/utils.ts +0 -22
- package/src/context/SanityInstanceContext.ts +0 -4
- package/src/context/SanityProvider.tsx +0 -50
- package/src/hooks/_synchronous-groq-js.mjs +0 -4
- package/src/hooks/comlink/useFrameConnection.test.tsx +0 -157
- package/src/hooks/comlink/useFrameConnection.ts +0 -130
- package/src/hooks/comlink/useManageFavorite.test.ts +0 -106
- package/src/hooks/comlink/useManageFavorite.ts +0 -98
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.test.ts +0 -77
- package/src/hooks/comlink/useRecordDocumentHistoryEvent.ts +0 -75
- package/src/hooks/comlink/useWindowConnection.test.ts +0 -125
- package/src/hooks/comlink/useWindowConnection.ts +0 -94
- package/src/hooks/datasets/useDatasets.ts +0 -37
- package/src/hooks/document/useApplyActions.test.ts +0 -25
- package/src/hooks/document/useApplyActions.ts +0 -74
- package/src/hooks/document/useDocument.test.ts +0 -81
- package/src/hooks/document/useDocument.ts +0 -107
- package/src/hooks/document/useDocumentEvent.test.ts +0 -63
- package/src/hooks/document/useDocumentEvent.ts +0 -54
- package/src/hooks/document/useDocumentSyncStatus.test.ts +0 -16
- package/src/hooks/document/useDocumentSyncStatus.ts +0 -30
- package/src/hooks/document/useEditDocument.test.ts +0 -179
- package/src/hooks/document/useEditDocument.ts +0 -195
- package/src/hooks/document/usePermissions.ts +0 -82
- package/src/hooks/infiniteList/useInfiniteList.test.tsx +0 -152
- package/src/hooks/infiniteList/useInfiniteList.ts +0 -174
- package/src/hooks/paginatedList/usePaginatedList.test.tsx +0 -259
- package/src/hooks/paginatedList/usePaginatedList.ts +0 -290
- package/src/hooks/projection/useProjection.test.tsx +0 -218
- package/src/hooks/projection/useProjection.ts +0 -135
- package/src/hooks/projects/useProject.ts +0 -45
- package/src/hooks/projects/useProjects.ts +0 -41
- package/src/hooks/query/useQuery.test.tsx +0 -188
- package/src/hooks/query/useQuery.ts +0 -103
- package/src/hooks/users/useUsers.test.ts +0 -163
- package/src/hooks/users/useUsers.ts +0 -107
- package/src/utils/getEnv.ts +0 -21
- package/src/version.ts +0 -8
- package/src/vite-env.d.ts +0 -10
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {Button, Card, Container, Flex, Heading, Stack} from '@sanity/ui'
|
|
1
2
|
import {type ReactElement} from 'react'
|
|
2
3
|
|
|
3
4
|
import {useAuthState} from '../../hooks/auth/useAuthState'
|
|
@@ -29,30 +30,44 @@ export const LoginLinks = (): ReactElement => {
|
|
|
29
30
|
useHandleCallback()
|
|
30
31
|
|
|
31
32
|
if (authState.type === 'logging-in') {
|
|
32
|
-
return <div
|
|
33
|
+
return <div>Logging in...</div>
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
// Show success state after authentication
|
|
36
37
|
if (authState.type === 'logged-in') {
|
|
37
|
-
return <div
|
|
38
|
+
return <div>You are logged in</div>
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
* Render provider selection UI
|
|
43
|
+
* Uses Sanity UI components for consistent styling
|
|
42
44
|
*/
|
|
43
45
|
return (
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
+
<Card height="fill" overflow="auto" paddingX={4}>
|
|
47
|
+
<Flex height="fill" direction="column" align="center" justify="center" paddingTop={4}>
|
|
48
|
+
<Container width={0}>
|
|
49
|
+
<Stack space={4}>
|
|
50
|
+
<Heading align="center" size={1}>
|
|
51
|
+
Choose login provider
|
|
52
|
+
</Heading>
|
|
46
53
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
<Stack space={2}>
|
|
55
|
+
{loginUrls.map((provider, index) => (
|
|
56
|
+
<Button
|
|
57
|
+
key={`${provider.url}_${index}`}
|
|
58
|
+
as="a"
|
|
59
|
+
href={provider.url}
|
|
60
|
+
mode="ghost"
|
|
61
|
+
tone="default"
|
|
62
|
+
space={3}
|
|
63
|
+
padding={3}
|
|
64
|
+
text={provider.title}
|
|
65
|
+
/>
|
|
66
|
+
))}
|
|
67
|
+
</Stack>
|
|
68
|
+
</Stack>
|
|
69
|
+
</Container>
|
|
70
|
+
</Flex>
|
|
71
|
+
</Card>
|
|
57
72
|
)
|
|
58
73
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {AuthStateType} from '@sanity/sdk'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {AuthStateType, createSanityInstance} from '@sanity/sdk'
|
|
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'
|
|
4
6
|
import {beforeEach, describe, expect, it, type MockInstance, vi} from 'vitest'
|
|
5
7
|
|
|
8
|
+
import {useAuthState} from '../../hooks/auth/useAuthState'
|
|
9
|
+
import {SanityProvider} from '../context/SanityProvider'
|
|
6
10
|
import {AuthBoundary} from './AuthBoundary'
|
|
7
|
-
import {renderWithWrappers} from './authTestHelpers'
|
|
8
11
|
|
|
9
12
|
// Mock hooks
|
|
10
13
|
vi.mock('../../hooks/auth/useAuthState', () => ({
|
|
@@ -35,6 +38,16 @@ vi.mock('./AuthError', async (importOriginal) => {
|
|
|
35
38
|
}
|
|
36
39
|
})
|
|
37
40
|
|
|
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
|
+
|
|
38
51
|
describe('AuthBoundary', () => {
|
|
39
52
|
let consoleErrorSpy: MockInstance
|
|
40
53
|
beforeEach(() => {
|
|
@@ -3,32 +3,16 @@ import {useMemo} from 'react'
|
|
|
3
3
|
import {ErrorBoundary, type FallbackProps} from 'react-error-boundary'
|
|
4
4
|
|
|
5
5
|
import {useAuthState} from '../../hooks/auth/useAuthState'
|
|
6
|
-
import {isInIframe} from '../utils'
|
|
7
6
|
import {AuthError} from './AuthError'
|
|
8
7
|
import {Login} from './Login'
|
|
9
8
|
import {LoginCallback} from './LoginCallback'
|
|
10
9
|
import {LoginError, type LoginErrorProps} from './LoginError'
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
// Only import bridge if we're in an iframe. This assumes that the app is
|
|
14
|
-
// running within SanityOS if it is in an iframe.
|
|
15
|
-
if (isInIframe()) {
|
|
16
|
-
const parsedUrl = new URL(window.location.href)
|
|
17
|
-
const mode = new URLSearchParams(parsedUrl.hash.slice(1)).get('mode')
|
|
18
|
-
const script = document.createElement('script')
|
|
19
|
-
script.src =
|
|
20
|
-
mode === 'core-ui--staging'
|
|
21
|
-
? 'https://core.sanity-cdn.work/bridge.js'
|
|
22
|
-
: 'https://core.sanity-cdn.com/bridge.js'
|
|
23
|
-
script.type = 'module'
|
|
24
|
-
script.async = true
|
|
25
|
-
document.head.appendChild(script)
|
|
26
|
-
}
|
|
10
|
+
import type {LoginLayoutProps} from './LoginLayout'
|
|
27
11
|
|
|
28
12
|
/**
|
|
29
|
-
* @
|
|
13
|
+
* @alpha
|
|
30
14
|
*/
|
|
31
|
-
interface AuthBoundaryProps extends LoginLayoutProps {
|
|
15
|
+
export interface AuthBoundaryProps extends LoginLayoutProps {
|
|
32
16
|
/**
|
|
33
17
|
* Custom component to render the login screen.
|
|
34
18
|
* Receives all login layout props. Defaults to {@link Login}.
|
|
@@ -68,7 +52,7 @@ interface AuthBoundaryProps extends LoginLayoutProps {
|
|
|
68
52
|
* }
|
|
69
53
|
* ```
|
|
70
54
|
*
|
|
71
|
-
* @
|
|
55
|
+
* @alpha
|
|
72
56
|
*/
|
|
73
57
|
export function AuthBoundary({
|
|
74
58
|
LoginErrorComponent = LoginError,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {createSanityInstance} from '@sanity/sdk'
|
|
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'
|
|
2
6
|
import {describe, expect, it, vi} from 'vitest'
|
|
3
7
|
|
|
4
|
-
import {
|
|
8
|
+
import {SanityProvider} from '../context/SanityProvider'
|
|
5
9
|
import {Login} from './Login'
|
|
6
10
|
|
|
7
11
|
vi.mock('../../hooks/auth/useLoginUrls', () => ({
|
|
@@ -11,6 +15,16 @@ vi.mock('../../hooks/auth/useLoginUrls', () => ({
|
|
|
11
15
|
]),
|
|
12
16
|
}))
|
|
13
17
|
|
|
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
|
+
|
|
14
28
|
describe('Login', () => {
|
|
15
29
|
it('renders login providers', () => {
|
|
16
30
|
renderWithWrappers(<Login />)
|
|
@@ -1,25 +1,46 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {Button, Flex, Heading, Spinner} from '@sanity/ui'
|
|
2
|
+
import {Suspense} from 'react'
|
|
3
|
+
import styled from 'styled-components'
|
|
2
4
|
|
|
3
5
|
import {useLoginUrls} from '../../hooks/auth/useLoginUrls'
|
|
4
6
|
import {LoginLayout, type LoginLayoutProps} from './LoginLayout'
|
|
5
7
|
|
|
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
|
+
|
|
6
20
|
/**
|
|
7
21
|
* Login component that displays available authentication providers.
|
|
8
22
|
* Renders a list of login options with a loading fallback while providers load.
|
|
9
23
|
*
|
|
10
24
|
* @alpha
|
|
11
|
-
* @internal
|
|
12
25
|
*/
|
|
13
26
|
export function Login({header, footer}: LoginLayoutProps): JSX.Element {
|
|
14
27
|
return (
|
|
15
28
|
<LoginLayout header={header} footer={footer}>
|
|
16
|
-
<
|
|
17
|
-
<
|
|
29
|
+
<Flex direction="column" gap={4}>
|
|
30
|
+
<Heading as="h1" size={1} align="center">
|
|
31
|
+
Choose login provider
|
|
32
|
+
</Heading>
|
|
18
33
|
|
|
19
|
-
<Suspense
|
|
34
|
+
<Suspense
|
|
35
|
+
fallback={
|
|
36
|
+
<FallbackRoot align="center" justify="center">
|
|
37
|
+
<Spinner />
|
|
38
|
+
</FallbackRoot>
|
|
39
|
+
}
|
|
40
|
+
>
|
|
20
41
|
<Providers />
|
|
21
42
|
</Suspense>
|
|
22
|
-
</
|
|
43
|
+
</Flex>
|
|
23
44
|
</LoginLayout>
|
|
24
45
|
)
|
|
25
46
|
}
|
|
@@ -28,12 +49,10 @@ function Providers() {
|
|
|
28
49
|
const loginUrls = useLoginUrls()
|
|
29
50
|
|
|
30
51
|
return (
|
|
31
|
-
<
|
|
52
|
+
<Flex direction="column" gap={3}>
|
|
32
53
|
{loginUrls.map(({title, url}) => (
|
|
33
|
-
<
|
|
34
|
-
{title}
|
|
35
|
-
</a>
|
|
54
|
+
<Button key={url} text={title} as="a" href={url} mode="ghost" />
|
|
36
55
|
))}
|
|
37
|
-
</
|
|
56
|
+
</Flex>
|
|
38
57
|
)
|
|
39
58
|
}
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {createSanityInstance} from '@sanity/sdk'
|
|
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'
|
|
2
6
|
import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from 'vitest'
|
|
3
7
|
|
|
4
|
-
import {
|
|
8
|
+
import {SanityProvider} from '../context/SanityProvider'
|
|
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
|
+
}
|
|
5
20
|
|
|
6
21
|
// Mock `useHandleCallback`
|
|
7
22
|
vi.mock('../../hooks/auth/useHandleCallback', () => ({
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import {Flex, Spinner, Text} from '@sanity/ui'
|
|
1
2
|
import {useEffect} from 'react'
|
|
3
|
+
import styled from 'styled-components'
|
|
2
4
|
|
|
3
5
|
import {useHandleCallback} from '../../hooks/auth/useHandleCallback'
|
|
4
6
|
import {LoginLayout, type LoginLayoutProps} from './LoginLayout'
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
const StyledFlex = styled(Flex)`
|
|
9
|
+
margin: auto;
|
|
10
|
+
`
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Component shown during auth callback processing that handles login completion.
|
|
9
14
|
* Automatically processes the auth callback when mounted and updates the URL
|
|
@@ -27,10 +32,10 @@ export function LoginCallback({header, footer}: LoginLayoutProps): React.ReactNo
|
|
|
27
32
|
|
|
28
33
|
return (
|
|
29
34
|
<LoginLayout header={header} footer={footer}>
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
</
|
|
35
|
+
<StyledFlex direction="column" justify="center" align="center" gap={4}>
|
|
36
|
+
<Text size={1}>Logging you in…</Text>
|
|
37
|
+
<Spinner size={4} />
|
|
38
|
+
</StyledFlex>
|
|
34
39
|
</LoginLayout>
|
|
35
40
|
)
|
|
36
41
|
}
|
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {createSanityInstance} from '@sanity/sdk'
|
|
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'
|
|
2
6
|
import {describe, expect, it, vi} from 'vitest'
|
|
3
7
|
|
|
8
|
+
import {SanityProvider} from '../context/SanityProvider'
|
|
4
9
|
import {AuthError} from './AuthError'
|
|
5
|
-
import {renderWithWrappers} from './authTestHelpers'
|
|
6
10
|
import {LoginError} from './LoginError'
|
|
7
11
|
|
|
8
12
|
vi.mock('../../hooks/auth/useLogOut', () => ({
|
|
9
13
|
useLogOut: vi.fn(() => async () => {}),
|
|
10
14
|
}))
|
|
11
15
|
|
|
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
|
+
|
|
12
27
|
describe('LoginError', () => {
|
|
13
28
|
it('shows authentication error and retry button', async () => {
|
|
14
29
|
const mockReset = vi.fn()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import {Button, Flex, Text} from '@sanity/ui'
|
|
1
2
|
import {useCallback} from 'react'
|
|
2
3
|
import {type FallbackProps} from 'react-error-boundary'
|
|
4
|
+
import styled from 'styled-components'
|
|
3
5
|
|
|
4
6
|
import {useLogOut} from '../../hooks/auth/useLogOut'
|
|
5
7
|
import {AuthError} from './AuthError'
|
|
@@ -10,6 +12,10 @@ import {LoginLayout, type LoginLayoutProps} from './LoginLayout'
|
|
|
10
12
|
*/
|
|
11
13
|
export type LoginErrorProps = FallbackProps & LoginLayoutProps
|
|
12
14
|
|
|
15
|
+
const StyledFlex = styled(Flex)`
|
|
16
|
+
margin: auto;
|
|
17
|
+
`
|
|
18
|
+
|
|
13
19
|
/**
|
|
14
20
|
* Displays authentication error details and provides retry functionality.
|
|
15
21
|
* Only handles {@link AuthError} instances - rethrows other error types.
|
|
@@ -32,18 +38,17 @@ export function LoginError({
|
|
|
32
38
|
|
|
33
39
|
return (
|
|
34
40
|
<LoginLayout header={header} footer={footer}>
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
<h2
|
|
38
|
-
|
|
41
|
+
<StyledFlex direction="column" gap={4}>
|
|
42
|
+
<Flex direction="column" gap={3}>
|
|
43
|
+
<Text as="h2" align="center" weight="bold" size={3}>
|
|
44
|
+
Authentication Error
|
|
45
|
+
</Text>
|
|
46
|
+
<Text size={1} align="center">
|
|
39
47
|
Please try again or contact support if the problem persists.
|
|
40
|
-
</
|
|
41
|
-
</
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Retry
|
|
45
|
-
</button>
|
|
46
|
-
</div>
|
|
48
|
+
</Text>
|
|
49
|
+
</Flex>
|
|
50
|
+
<Button text="Retry" tone="primary" onClick={handleRetry} />
|
|
51
|
+
</StyledFlex>
|
|
47
52
|
</LoginLayout>
|
|
48
53
|
)
|
|
49
54
|
}
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {createSanityInstance} from '@sanity/sdk'
|
|
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'
|
|
2
6
|
import {describe, expect, it} from 'vitest'
|
|
3
7
|
|
|
4
|
-
import {
|
|
8
|
+
import {SanityProvider} from '../context/SanityProvider'
|
|
5
9
|
import {LoginFooter} from './LoginFooter'
|
|
6
10
|
|
|
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
|
+
|
|
7
21
|
describe('LoginFooter', () => {
|
|
8
22
|
it('renders footer links', () => {
|
|
9
23
|
renderWithWrappers(<LoginFooter />)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {SanityLogo} from '@sanity/logos'
|
|
2
|
+
import {Flex, Text} from '@sanity/ui'
|
|
2
3
|
import {Fragment} from 'react'
|
|
4
|
+
import styled from 'styled-components'
|
|
3
5
|
|
|
4
6
|
const LINKS = [
|
|
5
7
|
{
|
|
@@ -24,6 +26,12 @@ const LINKS = [
|
|
|
24
26
|
},
|
|
25
27
|
]
|
|
26
28
|
|
|
29
|
+
const StyledText = styled(Text)`
|
|
30
|
+
a {
|
|
31
|
+
color: inherit;
|
|
32
|
+
}
|
|
33
|
+
`
|
|
34
|
+
|
|
27
35
|
/**
|
|
28
36
|
* Default footer component for login screens showing Sanity branding and legal
|
|
29
37
|
* links.
|
|
@@ -32,20 +40,28 @@ const LINKS = [
|
|
|
32
40
|
*/
|
|
33
41
|
export function LoginFooter(): React.ReactNode {
|
|
34
42
|
return (
|
|
35
|
-
<
|
|
36
|
-
<
|
|
43
|
+
<Flex direction="column" gap={4} justify="center" align="center" paddingTop={2}>
|
|
44
|
+
<Text size={3}>
|
|
45
|
+
<SanityLogo />
|
|
46
|
+
</Text>
|
|
37
47
|
|
|
38
|
-
<
|
|
39
|
-
{LINKS.map((link) => (
|
|
48
|
+
<Flex align="center" gap={2}>
|
|
49
|
+
{LINKS.map((link, index) => (
|
|
40
50
|
<Fragment key={link.title}>
|
|
41
|
-
<
|
|
51
|
+
<StyledText muted size={1}>
|
|
42
52
|
<a href={link.url} target="_blank" rel="noopener noreferrer">
|
|
43
53
|
{link.title}
|
|
44
54
|
</a>
|
|
45
|
-
</
|
|
55
|
+
</StyledText>
|
|
56
|
+
|
|
57
|
+
{index < LINKS.length - 1 && (
|
|
58
|
+
<Text size={1} muted>
|
|
59
|
+
•
|
|
60
|
+
</Text>
|
|
61
|
+
)}
|
|
46
62
|
</Fragment>
|
|
47
63
|
))}
|
|
48
|
-
</
|
|
49
|
-
</
|
|
64
|
+
</Flex>
|
|
65
|
+
</Flex>
|
|
50
66
|
)
|
|
51
67
|
}
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {createSanityInstance} from '@sanity/sdk'
|
|
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'
|
|
2
6
|
import {describe, expect, it} from 'vitest'
|
|
3
7
|
|
|
4
|
-
import {
|
|
8
|
+
import {SanityProvider} from '../context/SanityProvider'
|
|
5
9
|
import {LoginLayout} from './LoginLayout'
|
|
6
10
|
|
|
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
|
+
|
|
7
21
|
describe('LoginLayout', () => {
|
|
8
22
|
it('renders header, children, and footer', () => {
|
|
9
23
|
renderWithWrappers(
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {Card, Flex} from '@sanity/ui'
|
|
2
|
+
import styled from 'styled-components'
|
|
3
|
+
|
|
1
4
|
import {LoginFooter} from './LoginFooter'
|
|
2
5
|
|
|
3
6
|
/**
|
|
@@ -14,6 +17,23 @@ export interface LoginLayoutProps {
|
|
|
14
17
|
children?: React.ReactNode
|
|
15
18
|
}
|
|
16
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
|
+
|
|
17
37
|
/**
|
|
18
38
|
* Layout component for login-related screens providing consistent styling and structure.
|
|
19
39
|
* Renders content in a centered card with optional header and footer sections.
|
|
@@ -54,16 +74,26 @@ export function LoginLayout({
|
|
|
54
74
|
header,
|
|
55
75
|
}: LoginLayoutProps): React.ReactNode {
|
|
56
76
|
return (
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
77
|
+
<Root>
|
|
78
|
+
<Container direction="column" gap={4}>
|
|
79
|
+
<StyledCard border radius={2} paddingY={4}>
|
|
80
|
+
<Flex direction="column" gap={4}>
|
|
81
|
+
{header && (
|
|
82
|
+
<Card borderBottom paddingX={4} paddingBottom={3}>
|
|
83
|
+
{header}
|
|
84
|
+
</Card>
|
|
85
|
+
)}
|
|
61
86
|
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
{children && (
|
|
88
|
+
<ChildrenFlex paddingX={4} direction="column">
|
|
89
|
+
{children}
|
|
90
|
+
</ChildrenFlex>
|
|
91
|
+
)}
|
|
92
|
+
</Flex>
|
|
93
|
+
</StyledCard>
|
|
64
94
|
|
|
65
95
|
{footer}
|
|
66
|
-
</
|
|
67
|
-
</
|
|
96
|
+
</Container>
|
|
97
|
+
</Root>
|
|
68
98
|
)
|
|
69
99
|
}
|
|
@@ -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', () => {
|
|
@@ -15,7 +15,7 @@ describe('SanityProvider', () => {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const {getByTestId} = render(
|
|
18
|
-
<SanityProvider
|
|
18
|
+
<SanityProvider sanityInstance={sanityInstance}>
|
|
19
19
|
<TestComponent />
|
|
20
20
|
</SanityProvider>,
|
|
21
21
|
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {type SanityInstance} from '@sanity/sdk'
|
|
2
|
+
import {createContext, type ReactElement} from 'react'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export interface SanityProviderProps {
|
|
8
|
+
children: React.ReactNode
|
|
9
|
+
sanityInstance: SanityInstance
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const SanityInstanceContext = createContext<SanityInstance | null>(null)
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Top-level context provider that provides a Sanity configuration instance.
|
|
16
|
+
* This must wrap any Sanity SDK React component.
|
|
17
|
+
* @public
|
|
18
|
+
* @param props - Sanity project and dataset configuration
|
|
19
|
+
* @returns Rendered component
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* import {createSanityInstance} from '@sanity/sdk'
|
|
23
|
+
* import {ExampleComponent, SanityProvider} from '@sanity/sdk-react'
|
|
24
|
+
*
|
|
25
|
+
* const sanityInstance = createSanityInstance({projectId: 'your-project-id', dataset: 'production'})
|
|
26
|
+
*
|
|
27
|
+
* export default function MyApp() {
|
|
28
|
+
* return (
|
|
29
|
+
* <SanityProvider sanityInstance={sanityInstance}>
|
|
30
|
+
* <ExampleComponent />
|
|
31
|
+
* </SanityProvider>
|
|
32
|
+
* )
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export const SanityProvider = ({children, sanityInstance}: SanityProviderProps): ReactElement => {
|
|
37
|
+
return (
|
|
38
|
+
<SanityInstanceContext.Provider value={sanityInstance}>
|
|
39
|
+
{children}
|
|
40
|
+
</SanityInstanceContext.Provider>
|
|
41
|
+
)
|
|
42
|
+
}
|