@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.
Files changed (87) hide show
  1. package/README.md +163 -0
  2. package/dist/_chunks-es/context.js +8 -0
  3. package/dist/_chunks-es/context.js.map +1 -0
  4. package/dist/_chunks-es/useLogOut.js +29 -20
  5. package/dist/_chunks-es/useLogOut.js.map +1 -1
  6. package/dist/components.d.ts +25 -149
  7. package/dist/components.js +54 -151
  8. package/dist/components.js.map +1 -1
  9. package/dist/context.d.ts +45 -0
  10. package/dist/context.js +5 -0
  11. package/dist/context.js.map +1 -0
  12. package/dist/hooks.d.ts +3401 -12
  13. package/dist/hooks.js +210 -15
  14. package/dist/hooks.js.map +1 -1
  15. package/package.json +43 -32
  16. package/src/_exports/components.ts +2 -12
  17. package/src/_exports/context.ts +2 -0
  18. package/src/_exports/hooks.ts +25 -0
  19. package/src/components/SanityApp.test.tsx +54 -0
  20. package/src/components/SanityApp.tsx +53 -0
  21. package/src/components/auth/AuthBoundary.test.tsx +18 -22
  22. package/src/components/auth/AuthBoundary.tsx +14 -7
  23. package/src/components/auth/Login.test.tsx +3 -17
  24. package/src/components/auth/Login.tsx +27 -31
  25. package/src/components/auth/LoginCallback.test.tsx +2 -17
  26. package/src/components/auth/LoginCallback.tsx +8 -10
  27. package/src/components/auth/LoginError.test.tsx +2 -17
  28. package/src/components/auth/LoginError.tsx +8 -17
  29. package/src/components/auth/LoginFooter.test.tsx +2 -16
  30. package/src/components/auth/LoginFooter.tsx +18 -27
  31. package/src/components/auth/LoginLayout.test.tsx +2 -16
  32. package/src/components/auth/LoginLayout.tsx +8 -37
  33. package/src/components/auth/authTestHelpers.tsx +18 -0
  34. package/src/{components/context → context}/SanityProvider.test.tsx +1 -1
  35. package/src/{components/context → context}/SanityProvider.tsx +12 -6
  36. package/src/hooks/auth/useAuthState.test.tsx +10 -100
  37. package/src/hooks/auth/useAuthState.tsx +5 -10
  38. package/src/hooks/auth/useAuthToken.test.tsx +10 -88
  39. package/src/hooks/auth/useAuthToken.tsx +4 -10
  40. package/src/hooks/auth/useCurrentUser.test.tsx +10 -44
  41. package/src/hooks/auth/useCurrentUser.tsx +22 -22
  42. package/src/hooks/auth/useHandleCallback.test.tsx +10 -19
  43. package/src/hooks/auth/useHandleCallback.tsx +4 -9
  44. package/src/hooks/auth/useLogOut.test.tsx +11 -62
  45. package/src/hooks/auth/useLogOut.tsx +4 -9
  46. package/src/hooks/auth/useLoginUrls.test.tsx +47 -40
  47. package/src/hooks/auth/useLoginUrls.tsx +7 -6
  48. package/src/hooks/client/useClient.test.tsx +1 -1
  49. package/src/hooks/client/useClient.ts +3 -3
  50. package/src/hooks/comlink/useFrameConnection.test.tsx +122 -0
  51. package/src/hooks/comlink/useFrameConnection.ts +111 -0
  52. package/src/hooks/comlink/useWindowConnection.test.ts +94 -0
  53. package/src/hooks/comlink/useWindowConnection.ts +82 -0
  54. package/src/hooks/context/useSanityInstance.test.tsx +1 -1
  55. package/src/hooks/context/useSanityInstance.ts +4 -4
  56. package/src/hooks/document/useApplyActions.test.ts +24 -0
  57. package/src/hooks/document/useApplyActions.ts +24 -0
  58. package/src/hooks/document/useDocument.test.ts +81 -0
  59. package/src/hooks/document/useDocument.ts +38 -0
  60. package/src/hooks/document/useDocumentEvent.test.ts +53 -0
  61. package/src/hooks/document/useDocumentEvent.ts +22 -0
  62. package/src/hooks/document/useDocumentSyncStatus.test.ts +16 -0
  63. package/src/hooks/document/useDocumentSyncStatus.ts +6 -0
  64. package/src/hooks/document/useEditDocument.test.ts +172 -0
  65. package/src/hooks/document/useEditDocument.ts +80 -0
  66. package/src/hooks/documentCollection/useDocuments.test.ts +130 -0
  67. package/src/hooks/documentCollection/useDocuments.ts +135 -0
  68. package/src/hooks/helpers/createCallbackHook.test.tsx +106 -0
  69. package/src/hooks/helpers/createCallbackHook.tsx +15 -0
  70. package/src/hooks/helpers/createStateSourceHook.test.tsx +130 -0
  71. package/src/hooks/helpers/createStateSourceHook.tsx +21 -0
  72. package/src/hooks/preview/usePreview.test.tsx +175 -0
  73. package/src/hooks/preview/usePreview.tsx +120 -0
  74. package/src/vite-env.d.ts +10 -0
  75. package/src/components/DocumentGridLayout/DocumentGridLayout.stories.tsx +0 -95
  76. package/src/components/DocumentGridLayout/DocumentGridLayout.test.tsx +0 -42
  77. package/src/components/DocumentGridLayout/DocumentGridLayout.tsx +0 -23
  78. package/src/components/DocumentListLayout/DocumentListLayout.stories.tsx +0 -95
  79. package/src/components/DocumentListLayout/DocumentListLayout.test.tsx +0 -42
  80. package/src/components/DocumentListLayout/DocumentListLayout.tsx +0 -15
  81. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.md +0 -49
  82. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.stories.tsx +0 -34
  83. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.test.tsx +0 -30
  84. package/src/components/DocumentPreviewLayout/DocumentPreviewLayout.tsx +0 -115
  85. package/src/components/Login/LoginLinks.test.tsx +0 -100
  86. package/src/components/Login/LoginLinks.tsx +0 -73
  87. package/src/hooks/Documents/.keep +0 -0
@@ -1,13 +1,10 @@
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'
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({type: 'logged-out', isDestroyingSession: false})
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({type: 'logging-in', isExchangingToken: false})
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: 'logged-in',
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({type: 'error', error: new Error('test error')})
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 {LoginLayoutProps} from './LoginLayout'
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
- * @alpha
19
+ * @internal
13
20
  */
14
- export interface AuthBoundaryProps extends LoginLayoutProps {
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
- * @alpha
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 'error': {
95
+ case AuthStateType.ERROR: {
89
96
  throw new AuthError(authState.error)
90
97
  }
91
- case 'logging-in': {
98
+ case AuthStateType.LOGGING_IN: {
92
99
  return <CallbackComponent {...props} />
93
100
  }
94
- case 'logged-in': {
101
+ case AuthStateType.LOGGED_IN: {
95
102
  return children
96
103
  }
97
104
  default: {
@@ -1,11 +1,7 @@
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'
1
+ import {screen} from '@testing-library/react'
6
2
  import {describe, expect, it, vi} from 'vitest'
7
3
 
8
- import {SanityProvider} from '../context/SanityProvider'
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
- <Flex direction="column" gap={4}>
30
- <Heading as="h1" size={1} align="center">
31
- Choose login provider
32
- </Heading>
17
+ <Heading as="h6" align="center">
18
+ Choose login provider:
19
+ </Heading>
33
20
 
34
- <Suspense
35
- fallback={
36
- <FallbackRoot align="center" justify="center">
21
+ <Suspense
22
+ fallback={
23
+ <Box padding={5}>
24
+ <Flex align="center" justify="center">
37
25
  <Spinner />
38
- </FallbackRoot>
39
- }
40
- >
41
- <Providers />
42
- </Suspense>
43
- </Flex>
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
- <Flex direction="column" gap={3}>
40
+ <Stack space={3} marginY={5}>
53
41
  {loginUrls.map(({title, url}) => (
54
- <Button key={url} text={title} as="a" href={url} mode="ghost" />
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
- </Flex>
52
+ </Stack>
57
53
  )
58
54
  }
@@ -1,22 +1,7 @@
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'
1
+ import {screen, waitFor} from '@testing-library/react'
6
2
  import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from 'vitest'
7
3
 
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
- }
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, Spinner, Text} from '@sanity/ui'
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
- const StyledFlex = styled(Flex)`
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
- <StyledFlex direction="column" justify="center" align="center" gap={4}>
36
- <Text size={1}>Logging you in…</Text>
37
- <Spinner size={4} />
38
- </StyledFlex>
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 {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'
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, Flex, Text} from '@sanity/ui'
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
- <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">
47
- Please try again or contact support if the problem persists.
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 {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'
1
+ import {screen} from '@testing-library/react'
6
2
  import {describe, expect, it} from 'vitest'
7
3
 
8
- import {SanityProvider} from '../context/SanityProvider'
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
- <Flex direction="column" gap={4} justify="center" align="center" paddingTop={2}>
44
- <Text size={3}>
35
+ <Box>
36
+ <Flex justify="center">
45
37
  <SanityLogo />
46
- </Text>
38
+ </Flex>
47
39
 
48
- <Flex align="center" gap={2}>
49
- {LINKS.map((link, index) => (
50
- <Fragment key={link.title}>
51
- <StyledText muted size={1}>
52
- <a href={link.url} target="_blank" rel="noopener noreferrer">
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
- </StyledText>
56
-
57
- {index < LINKS.length - 1 && (
58
- <Text size={1} muted>
59
-
60
- </Text>
61
- )}
62
- </Fragment>
63
- ))}
52
+ </Text>
53
+ ))}
54
+ </Inline>
64
55
  </Flex>
65
- </Flex>
56
+ </Box>
66
57
  )
67
58
  }
@@ -1,23 +1,9 @@
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'
1
+ import {screen} from '@testing-library/react'
6
2
  import {describe, expect, it} from 'vitest'
7
3
 
8
- import {SanityProvider} from '../context/SanityProvider'
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, Flex} from '@sanity/ui'
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
- <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
- )}
60
+ <Container width={0}>
61
+ <Card shadow={1} radius={2} padding={4}>
62
+ {header && header}
86
63
 
87
- {children && (
88
- <ChildrenFlex paddingX={4} direction="column">
89
- {children}
90
- </ChildrenFlex>
91
- )}
92
- </Flex>
93
- </StyledCard>
64
+ {children && children}
94
65
 
95
66
  {footer}
96
- </Container>
97
- </Root>
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 '../../hooks/context/useSanityInstance'
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 a Sanity configuration instance.
16
- * This must wrap any Sanity SDK React component.
17
- * @public
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 {ExampleComponent, SanityProvider} from '@sanity/sdk-react'
24
+ * import {SanityProvider} from '@sanity/sdk-react'
25
+ *
26
+ * import MyAppRoot from './Root'
24
27
  *
25
- * const sanityInstance = createSanityInstance({projectId: 'your-project-id', dataset: 'production'})
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
- * <ExampleComponent />
36
+ * <MyAppRoot />
31
37
  * </SanityProvider>
32
38
  * )
33
39
  * }