sanity-plugin-dashboard-widget-vercel 3.1.6 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +8 -36
  2. package/dist/index.d.ts +6 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +1380 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +42 -85
  7. package/lib/index.d.mts +0 -6
  8. package/lib/index.d.ts +0 -6
  9. package/lib/index.js +0 -1007
  10. package/lib/index.js.map +0 -1
  11. package/lib/index.mjs +0 -1005
  12. package/lib/index.mjs.map +0 -1
  13. package/sanity.json +0 -8
  14. package/src/app.tsx +0 -135
  15. package/src/client.ts +0 -7
  16. package/src/components/DeployButton/index.tsx +0 -86
  17. package/src/components/Deployment/index.tsx +0 -126
  18. package/src/components/DeploymentPlaceholder/index.tsx +0 -41
  19. package/src/components/DeploymentTarget/index.tsx +0 -51
  20. package/src/components/DeploymentTargets/index.tsx +0 -24
  21. package/src/components/Deployments/index.tsx +0 -187
  22. package/src/components/DialogForm/index.tsx +0 -220
  23. package/src/components/FormFieldInputLabel/index.tsx +0 -65
  24. package/src/components/FormFieldInputText/index.tsx +0 -43
  25. package/src/components/PlaceholderAvatar/index.tsx +0 -20
  26. package/src/components/PlaceholderText/index.tsx +0 -32
  27. package/src/components/StateDebug/index.tsx +0 -46
  28. package/src/components/StatusDot/index.tsx +0 -22
  29. package/src/components/TableCell/index.tsx +0 -81
  30. package/src/constants.ts +0 -26
  31. package/src/hooks/useDeployments.ts +0 -89
  32. package/src/index.ts +0 -16
  33. package/src/machines/deploy.ts +0 -117
  34. package/src/machines/deploymentTargetList.ts +0 -149
  35. package/src/machines/dialog.ts +0 -62
  36. package/src/machines/form.ts +0 -155
  37. package/src/machines/refresh.ts +0 -47
  38. package/src/types/index.ts +0 -49
  39. package/src/utils/fetcher.ts +0 -37
  40. package/src/utils/sanitizeFormData.ts +0 -26
  41. package/src/utils/useCardColor.ts +0 -5
  42. package/v2-incompatible.js +0 -11
@@ -1,51 +0,0 @@
1
- import {EditIcon} from '@sanity/icons'
2
- import {Box, Button, Flex, Text, Tooltip} from '@sanity/ui'
3
- import React, {FC} from 'react'
4
-
5
- import Deployments from '../Deployments'
6
- import {Sanity} from '../../types'
7
-
8
- type Props = {
9
- item: Sanity.DeploymentTarget
10
- onDialogEdit: (deploymentTarget: Sanity.DeploymentTarget) => void
11
- }
12
-
13
- const DeploymentTarget: FC<Props> = (props: Props) => {
14
- const {item, onDialogEdit} = props
15
-
16
- const deploymentTarget = {
17
- deployHook: item.deployHook,
18
- deployLimit: item.deployLimit,
19
- name: item.name,
20
- projectId: item.projectId,
21
- teamId: item.teamId,
22
- token: item.token,
23
- } as Sanity.DeploymentTarget
24
-
25
- return (
26
- <Box style={{position: 'relative'}}>
27
- {/* Header */}
28
- <Flex align="center" justify="space-between" marginTop={2} paddingX={3}>
29
- <Text size={2}>{item.name}</Text>
30
-
31
- <Tooltip
32
- content={
33
- <Box padding={2}>
34
- <Text muted size={1}>
35
- Edit deployment target
36
- </Text>
37
- </Box>
38
- }
39
- placement="left"
40
- >
41
- <Button fontSize={1} icon={EditIcon} mode="bleed" onClick={() => onDialogEdit(item)} />
42
- </Tooltip>
43
- </Flex>
44
-
45
- {/* Content */}
46
- <Deployments deploymentTarget={deploymentTarget} />
47
- </Box>
48
- )
49
- }
50
-
51
- export default DeploymentTarget
@@ -1,24 +0,0 @@
1
- import React from 'react'
2
- import {Stack} from '@sanity/ui'
3
-
4
- import DeploymentTarget from '../DeploymentTarget'
5
- import {Sanity} from '../../types'
6
-
7
- type Props = {
8
- items: Sanity.DeploymentTarget[]
9
- onDialogEdit: (deploymentTarget: Sanity.DeploymentTarget) => void
10
- }
11
-
12
- const DeploymentTargets = (props: Props) => {
13
- const {items, onDialogEdit} = props
14
-
15
- return (
16
- <Stack space={5}>
17
- {items?.map((item) => (
18
- <DeploymentTarget item={item} key={item._id} onDialogEdit={onDialogEdit} />
19
- ))}
20
- </Stack>
21
- )
22
- }
23
-
24
- export default DeploymentTargets
@@ -1,187 +0,0 @@
1
- import {Box, Text, useToast} from '@sanity/ui'
2
- import {useMachine} from '@xstate/react'
3
- import React, {useEffect, useRef} from 'react'
4
- import useDeepCompareEffect from 'use-deep-compare-effect'
5
-
6
- import {WIDGET_NAME} from '../../constants'
7
- import useDeployments from '../../hooks/useDeployments'
8
- import refreshMachine from '../../machines/refresh'
9
- import Deployment from '../Deployment'
10
- import DeployButton from '../DeployButton'
11
- import DeploymentPlaceholder from '../DeploymentPlaceholder'
12
- import StateDebug from '../StateDebug'
13
- import TableCell from '../TableCell'
14
- import {Sanity} from '../../types'
15
- import {useCardColor} from '../../utils/useCardColor'
16
-
17
- type Props = {
18
- deploymentTarget: Sanity.DeploymentTarget
19
- }
20
-
21
- const Deployments = (props: Props) => {
22
- const {deploymentTarget} = props
23
-
24
- // Refs
25
- const refTimeout = useRef<ReturnType<typeof setTimeout> | null>(null)
26
-
27
- // XState
28
- const [refreshState, refreshStateTransition] = useMachine(refreshMachine)
29
-
30
- // Fetch deployments - disable hook / auto-refetching on error state
31
- const {deployments, error, isFetching, isSuccess, refetch} = useDeployments(deploymentTarget, {
32
- enabled: !refreshState.matches('error'),
33
- })
34
-
35
- const toast = useToast()
36
- const isError = refreshState.matches('error')
37
-
38
- const handleDeploySuccess = () => {
39
- if (refTimeout.current) {
40
- clearTimeout(refTimeout.current)
41
- }
42
- refTimeout.current = setTimeout(() => {
43
- refetch({
44
- cancelRefetch: true,
45
- throwOnError: true,
46
- })
47
- }, 4000)
48
- }
49
-
50
- useEffect(() => {
51
- return () => {
52
- if (refTimeout.current) {
53
- clearTimeout(refTimeout.current)
54
- }
55
- }
56
- }, [])
57
-
58
- useEffect(() => {
59
- if (error) {
60
- refreshStateTransition({type: 'ERROR'})
61
- }
62
-
63
- if (isFetching) {
64
- refreshStateTransition({type: 'REFRESH'})
65
- }
66
-
67
- if (!isFetching && isSuccess) {
68
- refreshStateTransition({type: 'REFRESHED'})
69
- }
70
- }, [error, isFetching, isSuccess, refreshStateTransition])
71
-
72
- useDeepCompareEffect(() => {
73
- if (!refreshState.matches('refreshing')) {
74
- refreshStateTransition({type: 'REFRESH'})
75
- }
76
- }, [deploymentTarget])
77
-
78
- useDeepCompareEffect(() => {
79
- if (isError) {
80
- toast.push({
81
- closable: true,
82
- description: `Unable to fetch deployments for ${deploymentTarget.name}`,
83
- duration: 8000,
84
- status: 'error',
85
- title: WIDGET_NAME,
86
- })
87
- }
88
- }, [deploymentTarget, isError])
89
-
90
- const hasFetched = typeof deployments !== 'undefined'
91
- const hasDeployments = deployments && deployments.length > 0
92
-
93
- const {border} = useCardColor()
94
- return (
95
- <Box marginTop={3} style={{position: 'relative'}}>
96
- {/* xstate debug */}
97
- <StateDebug name="Refresh" state={refreshState} />
98
-
99
- {!refreshState.matches('error') && (
100
- <>
101
- <Box
102
- as="table"
103
- style={{
104
- borderBottom: `1px solid ${border}`,
105
- borderCollapse: 'collapse',
106
- display: 'table',
107
- tableLayout: 'fixed',
108
- width: '100%',
109
- }}
110
- >
111
- <Box as="thead" style={{display: 'table-header-group'}}>
112
- <tr>
113
- {/* Deployment */}
114
- <TableCell header>Deployment</TableCell>
115
-
116
- {/* State */}
117
- <TableCell header variant="state">
118
- State
119
- </TableCell>
120
-
121
- {/* Branch */}
122
- <TableCell header variant="branch">
123
- Branch
124
- </TableCell>
125
-
126
- {/* Age */}
127
- <TableCell header variant="age">
128
- Age
129
- </TableCell>
130
-
131
- {/* Creator */}
132
- <TableCell header variant="age">
133
- Creator
134
- </TableCell>
135
- </tr>
136
- </Box>
137
-
138
- <Box as="tbody" style={{display: 'table-header-group'}}>
139
- {/* Placeholders */}
140
- {!deployments &&
141
- new Array(deploymentTarget?.deployLimit)
142
- .fill(undefined)
143
- .map((_, index) => <DeploymentPlaceholder key={index} />)}
144
- {/* Deployments */}
145
- {hasDeployments &&
146
- deployments?.map((deployment) => (
147
- <Deployment deployment={deployment} key={deployment.uid} />
148
- ))}
149
- </Box>
150
- </Box>
151
-
152
- {/* No results */}
153
- {hasFetched && !hasDeployments && (
154
- <Box padding={3} style={{width: '100%'}}>
155
- <Text muted size={1}>
156
- No deployments found. Don't forget to specify a valid team ID if your project
157
- belongs to a team.
158
- </Text>
159
- </Box>
160
- )}
161
- </>
162
- )}
163
-
164
- {/* Error message */}
165
- {refreshState.matches('error') && (
166
- <Box padding={3}>
167
- <Text muted size={1}>
168
- Unable to fetch recent deployments. Please check your network and deployment settings.
169
- </Text>
170
- </Box>
171
- )}
172
-
173
- {/* Deploy button */}
174
- {!refreshState.matches('error') && deploymentTarget.deployHook && (
175
- <Box>
176
- <DeployButton
177
- deployHook={deploymentTarget.deployHook}
178
- onDeploySuccess={handleDeploySuccess}
179
- targetName={deploymentTarget.name}
180
- />
181
- </Box>
182
- )}
183
- </Box>
184
- )
185
- }
186
-
187
- export default Deployments
@@ -1,220 +0,0 @@
1
- import {yupResolver} from '@hookform/resolvers/yup'
2
- import {Box, Button, Dialog, Flex, Stack, useToast} from '@sanity/ui'
3
- import {useActor} from '@xstate/react'
4
- import React, {FC, useEffect} from 'react'
5
- import {useForm} from 'react-hook-form'
6
- import * as yup from 'yup'
7
-
8
- import {Z_INDEX_DIALOG} from '../../constants'
9
- import {formMachine} from '../../machines/form'
10
- import sanitizeFormData from '../../utils/sanitizeFormData'
11
- import FormFieldInputText from '../FormFieldInputText'
12
- import {Sanity} from '../../types'
13
- import {useSanityClient} from '../../client'
14
- import {toPromise} from 'xstate'
15
-
16
- type Props = {
17
- deploymentTarget?: Sanity.DeploymentTarget
18
- onClose: () => void
19
- onCreate?: (deploymentTarget: Sanity.DeploymentTarget) => void
20
- onDelete?: (id: string) => void
21
- onUpdate?: (deploymentTarget: Sanity.DeploymentTarget) => void
22
- }
23
-
24
- type FormData = yup.InferType<typeof formSchema>
25
-
26
- const formSchema = yup.object().shape({
27
- deployHook: yup.string().url('Deploy hook must be a valid URL'),
28
- deployLimit: yup
29
- .number()
30
- .positive()
31
- .integer()
32
- .min(1, 'Deploy limit must no less than 1')
33
- .max(15, 'Deploy limit must no higher than 15')
34
- .typeError('Deploy limit must be a number')
35
- .required('Deploy limit must be a positive integer between 1 and 15'),
36
- name: yup.string().required('Name cannot be empty'),
37
- projectId: yup.string().required('Vercel Project ID cannot be empty'),
38
- teamId: yup.string(),
39
- token: yup.string().required('Vercel Account Token cannot be empty'),
40
- })
41
-
42
- const DialogForm: FC<Props> = (props: Props) => {
43
- const {deploymentTarget, onClose, onCreate, onDelete, onUpdate} = props
44
- const client = useSanityClient()
45
- const toast = useToast()
46
-
47
- const [formState, formStateTransition, formStateActorRef] = useActor(formMachine, {
48
- input: {client},
49
- })
50
-
51
- const formUpdating = formState.hasTag('busy')
52
-
53
- // react-hook-form v7
54
- const {
55
- formState: {errors, isDirty, isValid},
56
- handleSubmit,
57
- register,
58
- } = useForm<FormData>({
59
- // @ts-expect-error - fix typings later
60
- defaultValues: {
61
- deployHook: deploymentTarget?.deployHook || '',
62
- deployLimit: deploymentTarget?.deployLimit || 5,
63
- name: deploymentTarget?.name || '',
64
- projectId: deploymentTarget?.projectId || '',
65
- teamId: deploymentTarget?.teamId || '',
66
- token: deploymentTarget?.token || '',
67
- },
68
- mode: 'onChange',
69
- resolver: yupResolver(formSchema),
70
- })
71
-
72
- /**
73
- * Handle errors and reaching the done state
74
- */
75
- useEffect(() => {
76
- if (formState.matches('error')) {
77
- toast.push({
78
- status: 'error',
79
- title: formState.context.message || 'An error occurred',
80
- })
81
- }
82
- /**
83
- * If the machine is done it means it reached updated, created, deleted or error state.
84
- * We don't care which one, we just want to close the dialog
85
- */
86
- if (formState.status === 'done') {
87
- onClose()
88
- }
89
- }, [formState, onClose, toast])
90
-
91
- // Callbacks
92
- // - submit react-hook-form
93
- const onSubmit = async (formData: FormData) => {
94
- const sanitizedFormData = sanitizeFormData(formData)
95
- if (deploymentTarget) {
96
- formStateTransition({type: 'UPDATE', id: deploymentTarget._id, formData: sanitizedFormData})
97
- } else {
98
- formStateTransition({type: 'CREATE', formData: sanitizedFormData})
99
- }
100
- await toPromise(formStateActorRef)
101
- const snapshot = formStateActorRef.getSnapshot()
102
- const {document} = snapshot.context
103
- if (!document) return
104
- if (snapshot.matches('created')) {
105
- onCreate?.(document)
106
- } else if (snapshot.matches('updated')) {
107
- onUpdate?.(document)
108
- }
109
- }
110
-
111
- const handleDelete = async () => {
112
- const id = deploymentTarget!._id
113
- formStateTransition({type: 'DELETE', id})
114
- await toPromise(formStateActorRef)
115
- if (formStateActorRef.getSnapshot().matches('deleted')) {
116
- onDelete?.(id)
117
- }
118
- }
119
-
120
- return (
121
- <Dialog
122
- footer={
123
- <Box padding={3}>
124
- <Flex justify={deploymentTarget ? 'space-between' : 'flex-end'}>
125
- {/* Delete button */}
126
- {deploymentTarget && (
127
- <Button
128
- loading={formState.matches('deleting')}
129
- disabled={formUpdating}
130
- fontSize={1}
131
- mode="bleed"
132
- onClick={handleDelete}
133
- text="Delete"
134
- tone="critical"
135
- />
136
- )}
137
-
138
- {/* Submit button */}
139
- <Button
140
- loading={formState.matches('creating') || formState.matches('updating')}
141
- disabled={!isDirty || !isValid}
142
- fontSize={1}
143
- onClick={handleSubmit(onSubmit)}
144
- text={deploymentTarget ? 'Update and close' : 'Create'}
145
- tone="primary"
146
- />
147
- </Flex>
148
- </Box>
149
- }
150
- header={`${deploymentTarget ? 'Edit' : 'Create'} deployment target`}
151
- id="create"
152
- onClose={onClose}
153
- width={1}
154
- zOffset={Z_INDEX_DIALOG}
155
- >
156
- {/* We reverse direction to ensure that inline links dont autofocus before other form elements */}
157
- <Box as="form" padding={4} onSubmit={handleSubmit(onSubmit)}>
158
- {/* Hidden button to enable enter key submissions */}
159
- <button style={{display: 'none'}} tabIndex={-1} type="submit" />
160
-
161
- {/* Form fields */}
162
- <Stack space={5}>
163
- {/* Title */}
164
- <FormFieldInputText
165
- disabled={formUpdating}
166
- description="Name displayed in this plugin (e.g. production, staging)"
167
- error={errors?.name}
168
- label="Name"
169
- // @ts-expect-error - fix typings later
170
- {...register('name')}
171
- />
172
-
173
- <FormFieldInputText
174
- disabled={formUpdating}
175
- error={errors?.token}
176
- label="Vercel Account Token"
177
- // @ts-expect-error - fix typings later
178
- {...register('token')}
179
- />
180
-
181
- <FormFieldInputText
182
- disabled={formUpdating}
183
- error={errors?.projectId}
184
- label="Vercel Project ID"
185
- // @ts-expect-error - fix typings later
186
- {...register('projectId')}
187
- />
188
-
189
- <FormFieldInputText
190
- description="Required only if your project is owned by a team account"
191
- disabled={formUpdating}
192
- error={errors?.teamId}
193
- label="Vercel Team ID (optional)"
194
- // @ts-expect-error - fix typings later
195
- {...register('teamId')}
196
- />
197
-
198
- <FormFieldInputText
199
- description="Enter a valid deploy hook URL to enable manual deploys"
200
- disabled={formUpdating}
201
- error={errors?.deployHook}
202
- label="Vercel Deploy Hook (optional)"
203
- // @ts-expect-error - fix typings later
204
- {...register('deployHook')}
205
- />
206
-
207
- <FormFieldInputText
208
- disabled={formUpdating}
209
- error={errors?.deployLimit}
210
- label="Number of deploys to display"
211
- // @ts-expect-error - fix typings later
212
- {...register('deployLimit', {valueAsNumber: true})}
213
- />
214
- </Stack>
215
- </Box>
216
- </Dialog>
217
- )
218
- }
219
-
220
- export default DialogForm
@@ -1,65 +0,0 @@
1
- import {ErrorOutlineIcon} from '@sanity/icons'
2
- import {Box, Inline, Text, Tooltip} from '@sanity/ui'
3
- import React, {FC} from 'react'
4
- import {FieldError} from 'react-hook-form'
5
- import {styled} from 'styled-components'
6
-
7
- type Props = {
8
- description?: string
9
- error?: FieldError
10
- label: string
11
- name: string
12
- }
13
-
14
- const StyledErrorOutlineIcon = styled(ErrorOutlineIcon)(({theme}) => {
15
- return {
16
- color: theme.sanity.color.spot.red,
17
- }
18
- })
19
-
20
- const FormFieldInputLabel: FC<Props> = (props: Props) => {
21
- const {description, error, label, name} = props
22
-
23
- return (
24
- <Box marginBottom={3}>
25
- {/* Label */}
26
- <Inline space={2}>
27
- <Text as="label" htmlFor={name} size={1} weight="semibold">
28
- {label}
29
- </Text>
30
-
31
- {/* Error icon + tooltip */}
32
- {error && (
33
- <Text size={1}>
34
- <Tooltip
35
- content={
36
- <Box padding={2}>
37
- <Text muted size={1}>
38
- <StyledErrorOutlineIcon style={{marginRight: '0.1em'}} />
39
- {error.message}
40
- </Text>
41
- </Box>
42
- }
43
- fallbackPlacements={['top', 'left']}
44
- placement="right"
45
- portal
46
- >
47
- <StyledErrorOutlineIcon />
48
- </Tooltip>
49
- </Text>
50
- )}
51
- </Inline>
52
-
53
- {/* Description */}
54
- {description && (
55
- <Box marginY={3}>
56
- <Text htmlFor={name} muted size={1}>
57
- {description}
58
- </Text>
59
- </Box>
60
- )}
61
- </Box>
62
- )
63
- }
64
-
65
- export default FormFieldInputLabel
@@ -1,43 +0,0 @@
1
- import {Box, TextInput} from '@sanity/ui'
2
- import React, {forwardRef} from 'react'
3
- import {FieldError} from 'react-hook-form'
4
-
5
- import FormFieldInputLabel from '../FormFieldInputLabel'
6
-
7
- type Props = {
8
- description?: string
9
- disabled?: boolean
10
- error?: FieldError
11
- label: string
12
- name: string
13
- placeholder?: string
14
- value?: string
15
- onChange?: React.ChangeEventHandler<HTMLInputElement>
16
- onBlur?: React.FocusEventHandler<HTMLInputElement>
17
- }
18
-
19
- const FormFieldInputText = forwardRef<HTMLInputElement, Props>((props: Props, ref) => {
20
- const {description, disabled, error, label, name, placeholder, value, onChange, onBlur} = props
21
-
22
- return (
23
- <Box>
24
- {/* Label */}
25
- <FormFieldInputLabel description={description} error={error} label={label} name={name} />
26
- {/* Input */}
27
- <TextInput
28
- autoComplete="off"
29
- autoFocus
30
- defaultValue={value}
31
- disabled={disabled}
32
- id={name}
33
- name={name}
34
- placeholder={placeholder}
35
- onChange={onChange}
36
- onBlur={onBlur}
37
- ref={ref}
38
- />
39
- </Box>
40
- )
41
- })
42
-
43
- export default FormFieldInputText
@@ -1,20 +0,0 @@
1
- import {Box} from '@sanity/ui'
2
- import React from 'react'
3
- import {useCardColor} from '../../utils/useCardColor'
4
-
5
- const PlaceholderAvatar = () => {
6
- const {border} = useCardColor()
7
- return (
8
- <Box
9
- style={{
10
- backgroundColor: border,
11
- borderRadius: '20px',
12
- height: '20px',
13
- userSelect: 'none',
14
- width: '20px',
15
- }}
16
- />
17
- )
18
- }
19
-
20
- export default PlaceholderAvatar
@@ -1,32 +0,0 @@
1
- import {Box, Stack, Text} from '@sanity/ui'
2
- import React from 'react'
3
- import {useCardColor} from '../../utils/useCardColor'
4
-
5
- type Props = {
6
- rows: number
7
- }
8
-
9
- const PlaceholderText = (props: Props) => {
10
- const {rows} = props
11
- const {border} = useCardColor()
12
- return (
13
- <Box
14
- style={{
15
- backgroundColor: border,
16
- borderRadius: '3px',
17
- userSelect: 'none',
18
- width: '100%',
19
- }}
20
- >
21
- <Stack space={2}>
22
- {new Array(rows).fill(undefined).map((_, index) => (
23
- <Text key={index} size={1}>
24
- &nbsp;
25
- </Text>
26
- ))}
27
- </Stack>
28
- </Box>
29
- )
30
- }
31
-
32
- export default PlaceholderText
@@ -1,46 +0,0 @@
1
- import {Box, Card, Stack, Text} from '@sanity/ui'
2
- import React from 'react'
3
-
4
- import {DEBUG_MODE} from '../../constants'
5
-
6
- type Props = {
7
- name: string
8
- state: any // TODO: type correctly
9
- }
10
-
11
- const StateDebug = (props: Props) => {
12
- const {name, state} = props
13
-
14
- if (!DEBUG_MODE) {
15
- return null
16
- }
17
-
18
- return (
19
- <Card
20
- scheme="dark"
21
- style={{
22
- backgroundColor: 'rgba(0, 0, 255, 0.9)',
23
- borderRadius: '3px',
24
- fontSize: 1,
25
- fontWeight: 500,
26
- lineHeight: 'body',
27
- right: 0,
28
- opacity: 0.75,
29
- pointerEvents: 'none',
30
- position: 'absolute',
31
- textAlign: 'left',
32
- top: 0,
33
- zIndex: 9000,
34
- }}
35
- >
36
- <Box padding={2}>
37
- <Stack space={2}>
38
- <Text size={0}>Name: {name}</Text>
39
- <Text size={0}>state.value: {JSON.stringify(state.value)}</Text>
40
- </Stack>
41
- </Box>
42
- </Card>
43
- )
44
- }
45
-
46
- export default StateDebug