feat(bubbles): ✨ Add image bubble
This commit is contained in:
@ -34,3 +34,6 @@ FACEBOOK_CLIENT_SECRET=
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY=
|
||||
STRIPE_SECRET_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
|
||||
# (Optional) Used for GIF search
|
||||
NEXT_PUBLIC_GIPHY_API_KEY=
|
||||
|
@ -344,3 +344,25 @@ export const GoogleAnalyticsLogo = (props: IconProps) => (
|
||||
</defs>
|
||||
</Icon>
|
||||
)
|
||||
|
||||
export const GiphyLogo = (props: IconProps) => (
|
||||
<Icon viewBox="0 0 163.79999999999998 35" {...props}>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path d="M4 4h20v27H4z" fill="#000" />
|
||||
<g fillRule="nonzero">
|
||||
<path d="M0 3h4v29H0z" fill="#04ff8e" />
|
||||
<path d="M24 11h4v21h-4z" fill="#8e2eff" />
|
||||
<path d="M0 31h28v4H0z" fill="#00c5ff" />
|
||||
<path d="M0 0h16v4H0z" fill="#fff152" />
|
||||
<path d="M24 8V4h-4V0h-4v12h12V8" fill="#ff5b5b" />
|
||||
<path d="M24 16v-4h4" fill="#551c99" />
|
||||
</g>
|
||||
<path d="M16 0v4h-4" fill="#999131" />
|
||||
<path
|
||||
d="M59.1 12c-2-1.9-4.4-2.4-6.2-2.4-4.4 0-7.3 2.6-7.3 8 0 3.5 1.8 7.8 7.3 7.8 1.4 0 3.7-.3 5.2-1.4v-3.5h-6.9v-6h13.3v12.1c-1.7 3.5-6.4 5.3-11.7 5.3-10.7 0-14.8-7.2-14.8-14.3S42.7 3.2 52.9 3.2c3.8 0 7.1.8 10.7 4.4zm9.1 19.2V4h7.6v27.2zm20.1-7.4v7.3h-7.7V4h13.2c7.3 0 10.9 4.6 10.9 9.9 0 5.6-3.6 9.9-10.9 9.9zm0-6.5h5.5c2.1 0 3.2-1.6 3.2-3.3 0-1.8-1.1-3.4-3.2-3.4h-5.5zM125 31.2V20.9h-9.8v10.3h-7.7V4h7.7v10.3h9.8V4h7.6v27.2zm24.2-17.9l5.9-9.3h8.7v.3l-10.8 16v10.8h-7.7V20.3L135 4.3V4h8.7z"
|
||||
fill="#000"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</g>
|
||||
</Icon>
|
||||
)
|
||||
|
@ -15,7 +15,6 @@ import { UploadIcon } from 'assets/icons'
|
||||
import { UploadButton } from 'components/shared/buttons/UploadButton'
|
||||
import { useUser } from 'contexts/UserContext'
|
||||
import React, { ChangeEvent, useState } from 'react'
|
||||
import { uploadFile } from 'services/utils'
|
||||
|
||||
export const PersonalInfoForm = () => {
|
||||
const {
|
||||
@ -27,14 +26,10 @@ export const PersonalInfoForm = () => {
|
||||
isOAuthProvider,
|
||||
} = useUser()
|
||||
const [reloadParam, setReloadParam] = useState('')
|
||||
const [isUploading, setIsUploading] = useState(false)
|
||||
|
||||
const handleFileChange = async (file: File) => {
|
||||
setIsUploading(true)
|
||||
const { url } = await uploadFile(file, `${user?.id}/avatar`)
|
||||
const handleFileUploaded = async (url: string) => {
|
||||
setReloadParam(Date.now().toString())
|
||||
updateUser({ image: url })
|
||||
setIsUploading(false)
|
||||
}
|
||||
|
||||
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
@ -60,9 +55,9 @@ export const PersonalInfoForm = () => {
|
||||
<Stack>
|
||||
<UploadButton
|
||||
size="sm"
|
||||
filePath={`users/${user?.id}/avatar`}
|
||||
leftIcon={<UploadIcon />}
|
||||
isLoading={isUploading}
|
||||
onUploadChange={handleFileChange}
|
||||
onFileUploaded={handleFileUploaded}
|
||||
>
|
||||
Change photo
|
||||
</UploadButton>
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
FilterIcon,
|
||||
FlagIcon,
|
||||
GlobeIcon,
|
||||
ImageIcon,
|
||||
NumberIcon,
|
||||
PhoneIcon,
|
||||
TextIcon,
|
||||
@ -29,6 +30,8 @@ export const StepIcon = ({ type, ...props }: StepIconProps) => {
|
||||
switch (type) {
|
||||
case BubbleStepType.TEXT:
|
||||
return <ChatIcon {...props} />
|
||||
case BubbleStepType.IMAGE:
|
||||
return <ImageIcon {...props} />
|
||||
case InputStepType.TEXT:
|
||||
return <TextIcon {...props} />
|
||||
case InputStepType.NUMBER:
|
||||
|
@ -16,6 +16,8 @@ export const StepTypeLabel = ({ type }: Props) => {
|
||||
case InputStepType.TEXT: {
|
||||
return <Text>Text</Text>
|
||||
}
|
||||
case BubbleStepType.IMAGE:
|
||||
return <Text>Image</Text>
|
||||
case InputStepType.NUMBER: {
|
||||
return <Text>Number</Text>
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ export const StepTypesList = () => {
|
||||
const x = e.clientX - rect.left
|
||||
const y = e.clientY - rect.top
|
||||
setRelativeCoordinates({ x, y })
|
||||
console.log({ x: rect.left, y: rect.top })
|
||||
setDraggedStepType(type)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
import {
|
||||
Portal,
|
||||
PopoverContent,
|
||||
PopoverArrow,
|
||||
PopoverBody,
|
||||
} from '@chakra-ui/react'
|
||||
import { ImagePopoverContent } from 'components/shared/ImageUploadContent'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import {
|
||||
BubbleStep,
|
||||
BubbleStepType,
|
||||
ImageBubbleContent,
|
||||
ImageBubbleStep,
|
||||
TextBubbleStep,
|
||||
} from 'models'
|
||||
import { useRef } from 'react'
|
||||
|
||||
type Props = {
|
||||
step: Exclude<BubbleStep, TextBubbleStep>
|
||||
}
|
||||
|
||||
export const ContentPopover = ({ step }: Props) => {
|
||||
const ref = useRef<HTMLDivElement | null>(null)
|
||||
const handleMouseDown = (e: React.MouseEvent) => e.stopPropagation()
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<PopoverContent onMouseDown={handleMouseDown} w="500px">
|
||||
<PopoverArrow />
|
||||
<PopoverBody ref={ref} shadow="lg">
|
||||
<StepContent step={step} />
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export const StepContent = ({ step }: Props) => {
|
||||
const { updateStep } = useTypebot()
|
||||
const handleContentChange = (content: ImageBubbleContent) =>
|
||||
updateStep(step.id, { content } as Partial<ImageBubbleStep>)
|
||||
|
||||
const handleNewImageSubmit = (url: string) => handleContentChange({ url })
|
||||
switch (step.type) {
|
||||
case BubbleStepType.IMAGE: {
|
||||
return (
|
||||
<ImagePopoverContent
|
||||
url={step.content?.url}
|
||||
onSubmit={handleNewImageSubmit}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { ContentPopover } from './ContentPopover'
|
@ -15,6 +15,7 @@ import {
|
||||
LogicStepType,
|
||||
Step,
|
||||
StepOptions,
|
||||
TextBubbleStep,
|
||||
} from 'models'
|
||||
import { useRef } from 'react'
|
||||
import {
|
||||
@ -33,7 +34,7 @@ import { RedirectSettings } from './bodies/RedirectSettings'
|
||||
import { SetVariableSettingsBody } from './bodies/SetVariableSettingsBody'
|
||||
|
||||
type Props = {
|
||||
step: Step
|
||||
step: Exclude<Step, TextBubbleStep>
|
||||
onExpandClick: () => void
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,10 @@ import {
|
||||
useEventListener,
|
||||
} from '@chakra-ui/react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { DraggableStep, Step } from 'models'
|
||||
import { BubbleStep, DraggableStep, Step, TextBubbleStep } from 'models'
|
||||
import { useGraph } from 'contexts/GraphContext'
|
||||
import { StepIcon } from 'components/board/StepTypesList/StepIcon'
|
||||
import {
|
||||
isInputStep,
|
||||
isLogicStep,
|
||||
isTextBubbleStep,
|
||||
isIntegrationStep,
|
||||
} from 'utils'
|
||||
import { isBubbleStep, isTextBubbleStep } from 'utils'
|
||||
import { Coordinates } from '@dnd-kit/core/dist/types'
|
||||
import { TextEditor } from './TextEditor/TextEditor'
|
||||
import { StepNodeContent } from './StepNodeContent'
|
||||
@ -29,6 +24,7 @@ import { TargetEndpoint } from './TargetEndpoint'
|
||||
import { useRouter } from 'next/router'
|
||||
import { SettingsModal } from './SettingsPopoverContent/SettingsModal'
|
||||
import { StepSettings } from './SettingsPopoverContent/SettingsPopoverContent'
|
||||
import { ContentPopover } from './ContentPopover'
|
||||
|
||||
export const StepNode = ({
|
||||
step,
|
||||
@ -185,15 +181,16 @@ export const StepNode = ({
|
||||
}}
|
||||
pos="absolute"
|
||||
right="15px"
|
||||
top="18px"
|
||||
bottom="18px"
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
</Flex>
|
||||
</PopoverTrigger>
|
||||
{hasPopover(step) && (
|
||||
{hasSettingsPopover(step) && (
|
||||
<SettingsPopoverContent step={step} onExpandClick={onModalOpen} />
|
||||
)}
|
||||
{hasContentPopover(step) && <ContentPopover step={step} />}
|
||||
<SettingsModal isOpen={isModalOpen} onClose={onModalClose}>
|
||||
<StepSettings step={step} />
|
||||
</SettingsModal>
|
||||
@ -203,5 +200,10 @@ export const StepNode = ({
|
||||
)
|
||||
}
|
||||
|
||||
const hasPopover = (step: Step) =>
|
||||
isInputStep(step) || isLogicStep(step) || isIntegrationStep(step)
|
||||
const hasSettingsPopover = (step: Step): step is Exclude<Step, BubbleStep> =>
|
||||
!isBubbleStep(step)
|
||||
|
||||
const hasContentPopover = (
|
||||
step: Step
|
||||
): step is Exclude<BubbleStep, TextBubbleStep> =>
|
||||
isBubbleStep(step) && !isTextBubbleStep(step)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Flex, HStack, Stack, Tag, Text } from '@chakra-ui/react'
|
||||
import { Box, Flex, HStack, Image, Stack, Tag, Text } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import {
|
||||
Step,
|
||||
@ -34,6 +34,20 @@ export const StepNodeContent = ({ step }: Props) => {
|
||||
/>
|
||||
)
|
||||
}
|
||||
case BubbleStepType.IMAGE: {
|
||||
return !step.content?.url ? (
|
||||
<Text color={'gray.500'}>Click to edit...</Text>
|
||||
) : (
|
||||
<Box w="full">
|
||||
<Image
|
||||
src={step.content?.url}
|
||||
alt="Step image"
|
||||
rounded="md"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
case InputStepType.TEXT: {
|
||||
return (
|
||||
<Text color={'gray.500'}>
|
||||
|
@ -12,7 +12,7 @@ import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
|
||||
import { BaseSelection, createEditor, Transforms } from 'slate'
|
||||
import { ToolBar } from './ToolBar'
|
||||
import { parseHtmlStringToPlainText } from 'services/utils'
|
||||
import { TextStep, Variable } from 'models'
|
||||
import { TextBubbleStep, Variable } from 'models'
|
||||
import { VariableSearchInput } from 'components/shared/VariableSearchInput'
|
||||
import { ReactEditor } from 'slate-react'
|
||||
|
||||
@ -87,7 +87,7 @@ export const TextEditor = ({
|
||||
richText: value,
|
||||
plainText: parseHtmlStringToPlainText(html),
|
||||
},
|
||||
} as TextStep)
|
||||
} as TextBubbleStep)
|
||||
}
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
|
@ -0,0 +1,61 @@
|
||||
import { Flex, Input, Stack } from '@chakra-ui/react'
|
||||
import { GiphyFetch } from '@giphy/js-fetch-api'
|
||||
import { Grid, SearchContext } from '@giphy/react-components'
|
||||
import { GiphyLogo } from 'assets/logos'
|
||||
import React, { useContext, useState, useEffect } from 'react'
|
||||
import { useDebounce } from 'use-debounce'
|
||||
|
||||
type GiphySearchProps = {
|
||||
onSubmit: (url: string) => void
|
||||
}
|
||||
|
||||
const giphyFetch = new GiphyFetch(
|
||||
process.env.NEXT_PUBLIC_GIPHY_API_KEY as string
|
||||
)
|
||||
|
||||
export const GiphySearch = ({ onSubmit }: GiphySearchProps) => {
|
||||
const { fetchGifs, searchKey, setSearch } = useContext(SearchContext)
|
||||
const fetchGifsTrending = (offset: number) =>
|
||||
giphyFetch.trending({ offset, limit: 10 })
|
||||
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
const [debouncedInputValue] = useDebounce(inputValue, 300)
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedInputValue === '') return
|
||||
setSearch(debouncedInputValue)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [debouncedInputValue])
|
||||
|
||||
const updateUrl = (url: string) => {
|
||||
onSubmit(url)
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Flex align="center">
|
||||
<Input
|
||||
flex="1"
|
||||
autoFocus
|
||||
placeholder="Search..."
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
value={inputValue}
|
||||
/>
|
||||
<GiphyLogo w="100px" />
|
||||
</Flex>
|
||||
<Flex overflowY="scroll" maxH="400px">
|
||||
<Grid
|
||||
onGifClick={(gif, e) => {
|
||||
e.preventDefault()
|
||||
updateUrl(gif.images.downsized.url)
|
||||
}}
|
||||
key={searchKey}
|
||||
fetchGifs={searchKey === '' ? fetchGifsTrending : fetchGifs}
|
||||
width={475}
|
||||
columns={3}
|
||||
className="my-4"
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
import { ChangeEvent, FormEvent, useState } from 'react'
|
||||
import { Button, HStack, Input, Stack } from '@chakra-ui/react'
|
||||
import { SearchContextManager } from '@giphy/react-components'
|
||||
import { UploadButton } from '../buttons/UploadButton'
|
||||
import { GiphySearch } from './GiphySearch'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
|
||||
type Props = {
|
||||
url?: string
|
||||
onSubmit: (url: string) => void
|
||||
}
|
||||
|
||||
export const ImageUploadContent = ({ url, onSubmit }: Props) => {
|
||||
const [currentTab, setCurrentTab] = useState<'link' | 'upload' | 'giphy'>(
|
||||
'upload'
|
||||
)
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<HStack>
|
||||
<Button
|
||||
variant={currentTab === 'upload' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('upload')}
|
||||
size="sm"
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
<Button
|
||||
variant={currentTab === 'link' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('link')}
|
||||
size="sm"
|
||||
>
|
||||
Embed link
|
||||
</Button>
|
||||
{process.env.NEXT_PUBLIC_GIPHY_API_KEY && (
|
||||
<Button
|
||||
variant={currentTab === 'giphy' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('giphy')}
|
||||
size="sm"
|
||||
>
|
||||
Giphy
|
||||
</Button>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
<BodyContent tab={currentTab} onSubmit={onSubmit} url={url} />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const BodyContent = ({
|
||||
tab,
|
||||
url,
|
||||
onSubmit,
|
||||
}: {
|
||||
tab: 'upload' | 'link' | 'giphy'
|
||||
url?: string
|
||||
onSubmit: (url: string) => void
|
||||
}) => {
|
||||
switch (tab) {
|
||||
case 'upload':
|
||||
return <UploadFileContent onNewUrl={onSubmit} />
|
||||
case 'link':
|
||||
return <EmbedLinkContent initialUrl={url} onNewUrl={onSubmit} />
|
||||
case 'giphy':
|
||||
return <GiphyContent onNewUrl={onSubmit} />
|
||||
}
|
||||
}
|
||||
|
||||
type ContentProps = { initialUrl?: string; onNewUrl: (url: string) => void }
|
||||
|
||||
const UploadFileContent = ({ onNewUrl }: ContentProps) => {
|
||||
const { typebot } = useTypebot()
|
||||
return (
|
||||
<Stack>
|
||||
<UploadButton
|
||||
filePath={`typebots/${typebot?.id}`}
|
||||
onFileUploaded={onNewUrl}
|
||||
includeFileName
|
||||
colorScheme="blue"
|
||||
>
|
||||
Choose an image
|
||||
</UploadButton>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const EmbedLinkContent = ({ initialUrl, onNewUrl }: ContentProps) => {
|
||||
const [imageUrl, setImageUrl] = useState(initialUrl ?? '')
|
||||
|
||||
const handleImageUrlChange = (e: ChangeEvent<HTMLInputElement>) =>
|
||||
setImageUrl(e.target.value)
|
||||
|
||||
const handleUrlSubmit = (e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
onNewUrl(imageUrl)
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack as="form" onSubmit={handleUrlSubmit}>
|
||||
<Input
|
||||
placeholder={'Paste the image link...'}
|
||||
onChange={handleImageUrlChange}
|
||||
value={imageUrl}
|
||||
/>
|
||||
<Button type="submit" disabled={imageUrl === ''} colorScheme="blue">
|
||||
Embed image
|
||||
</Button>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const GiphyContent = ({ onNewUrl }: ContentProps) => (
|
||||
<SearchContextManager
|
||||
apiKey={process.env.NEXT_PUBLIC_GIPHY_API_KEY as string}
|
||||
>
|
||||
<GiphySearch onSubmit={onNewUrl} />
|
||||
</SearchContextManager>
|
||||
)
|
@ -0,0 +1 @@
|
||||
export { ImageUploadContent as ImagePopoverContent } from './ImageUploadContent'
|
@ -1,19 +1,37 @@
|
||||
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
|
||||
import React, { ChangeEvent } from 'react'
|
||||
import React, { ChangeEvent, useState } from 'react'
|
||||
import { compressFile, uploadFile } from 'services/utils'
|
||||
|
||||
type UploadButtonProps = { onUploadChange: (file: File) => void } & ButtonProps
|
||||
type UploadButtonProps = {
|
||||
filePath: string
|
||||
includeFileName?: boolean
|
||||
onFileUploaded: (url: string) => void
|
||||
} & ButtonProps
|
||||
|
||||
export const UploadButton = ({
|
||||
onUploadChange,
|
||||
filePath,
|
||||
includeFileName,
|
||||
onFileUploaded,
|
||||
...props
|
||||
}: UploadButtonProps) => {
|
||||
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const [isUploading, setIsUploading] = useState(false)
|
||||
|
||||
const handleInputChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target?.files) return
|
||||
onUploadChange(e.target.files[0])
|
||||
setIsUploading(true)
|
||||
const file = e.target.files[0]
|
||||
const { url } = await uploadFile(
|
||||
await compressFile(file),
|
||||
filePath + (includeFileName ? `/${file.name}` : '')
|
||||
)
|
||||
if (url) onFileUploaded(url)
|
||||
setIsUploading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<chakra.input
|
||||
data-testid="file-upload-input"
|
||||
type="file"
|
||||
id="file-input"
|
||||
display="none"
|
||||
@ -25,6 +43,7 @@ export const UploadButton = ({
|
||||
size="sm"
|
||||
htmlFor="file-input"
|
||||
cursor="pointer"
|
||||
isLoading={isUploading}
|
||||
{...props}
|
||||
>
|
||||
{props.children}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { userIds } from 'cypress/plugins/data'
|
||||
|
||||
describe('Dashboard page', () => {
|
||||
describe('Account page', () => {
|
||||
before(() => {
|
||||
cy.intercept({
|
||||
url: 'https://s3.eu-west-3.amazonaws.com/typebot',
|
||||
@ -35,7 +35,7 @@ describe('Dashboard page', () => {
|
||||
.should('have.attr', 'src')
|
||||
.should(
|
||||
'include',
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/${userIds[0]}/avatar`
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/users/${userIds[0]}/avatar`
|
||||
)
|
||||
cy.findByRole('button', { name: 'Save' }).should('exist').click()
|
||||
cy.wait('@getUpdatedSession')
|
||||
@ -45,7 +45,7 @@ describe('Dashboard page', () => {
|
||||
.should('have.attr', 'src')
|
||||
.should(
|
||||
'include',
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/${userIds[0]}/avatar`
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/users/${userIds[0]}/avatar`
|
||||
)
|
||||
cy.findByRole('button', { name: 'Save' }).should('not.exist')
|
||||
})
|
||||
|
86
apps/builder/cypress/tests/bubbles/image.ts
Normal file
86
apps/builder/cypress/tests/bubbles/image.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { createTypebotWithStep } from 'cypress/plugins/data'
|
||||
import { preventUserFromRefreshing } from 'cypress/plugins/utils'
|
||||
import { getIframeBody } from 'cypress/support'
|
||||
import { BubbleStepType, Step } from 'models'
|
||||
|
||||
const unsplashImageSrc =
|
||||
'https://images.unsplash.com/photo-1504297050568-910d24c426d3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
|
||||
|
||||
describe('Image bubbles', () => {
|
||||
before(() => {
|
||||
cy.intercept({
|
||||
url: 'https://s3.eu-west-3.amazonaws.com/typebot',
|
||||
method: 'POST',
|
||||
}).as('postImage')
|
||||
})
|
||||
afterEach(() => {
|
||||
cy.window().then((win) => {
|
||||
win.removeEventListener('beforeunload', preventUserFromRefreshing)
|
||||
})
|
||||
})
|
||||
describe('Content settings', () => {
|
||||
beforeEach(() => {
|
||||
cy.task('seed')
|
||||
createTypebotWithStep({
|
||||
type: BubbleStepType.IMAGE,
|
||||
} as Omit<Step, 'id' | 'blockId'>)
|
||||
cy.signOut()
|
||||
cy.signIn('test2@gmail.com')
|
||||
cy.visit('/typebots/typebot3/edit')
|
||||
cy.findByText('Click to edit...').click()
|
||||
})
|
||||
|
||||
it('upload image file correctly', () => {
|
||||
cy.findByTestId('file-upload-input').attachFile('avatar.jpg')
|
||||
cy.wait('@postImage')
|
||||
cy.findByRole('img')
|
||||
.should('have.attr', 'src')
|
||||
.should(
|
||||
'include',
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/typebots/typebot3/avatar.jpg`
|
||||
)
|
||||
})
|
||||
|
||||
it('should import image links correctly', () => {
|
||||
cy.findByRole('button', { name: 'Embed link' }).click()
|
||||
cy.findByPlaceholderText('Paste the image link...')
|
||||
.clear()
|
||||
.type(unsplashImageSrc)
|
||||
cy.findByRole('button', { name: 'Embed image' }).click()
|
||||
cy.findByRole('img')
|
||||
.should('have.attr', 'src')
|
||||
.should('include', unsplashImageSrc)
|
||||
})
|
||||
|
||||
it.only('should import giphy gifs correctly', () => {
|
||||
cy.findByRole('button', { name: 'Giphy' }).click()
|
||||
cy.findAllByRole('img').eq(3).click()
|
||||
cy.findAllByRole('img')
|
||||
.first()
|
||||
.should('have.attr', 'src')
|
||||
.should('contain', `giphy.com/media`)
|
||||
})
|
||||
})
|
||||
describe('Preview', () => {
|
||||
beforeEach(() => {
|
||||
cy.task('seed')
|
||||
createTypebotWithStep({
|
||||
type: BubbleStepType.IMAGE,
|
||||
content: {
|
||||
url: unsplashImageSrc,
|
||||
},
|
||||
} as Omit<Step, 'id' | 'blockId'>)
|
||||
cy.signOut()
|
||||
cy.signIn('test2@gmail.com')
|
||||
cy.visit('/typebots/typebot3/edit')
|
||||
})
|
||||
|
||||
it('should display correctly', () => {
|
||||
cy.findByRole('button', { name: 'Preview' }).click()
|
||||
getIframeBody()
|
||||
.findByRole('img')
|
||||
.should('have.attr', 'src')
|
||||
.should('eq', unsplashImageSrc)
|
||||
})
|
||||
})
|
||||
})
|
@ -1,43 +1,15 @@
|
||||
import { userIds } from 'cypress/plugins/data'
|
||||
import {
|
||||
parseTestTypebot,
|
||||
preventUserFromRefreshing,
|
||||
} from 'cypress/plugins/utils'
|
||||
import { BubbleStepType } from 'models'
|
||||
import { createTypebotWithStep } from 'cypress/plugins/data'
|
||||
import { preventUserFromRefreshing } from 'cypress/plugins/utils'
|
||||
import { getIframeBody } from 'cypress/support'
|
||||
import { BubbleStepType, Step } from 'models'
|
||||
|
||||
describe('Text bubbles', () => {
|
||||
beforeEach(() => {
|
||||
cy.task('seed')
|
||||
cy.task(
|
||||
'createTypebot',
|
||||
parseTestTypebot({
|
||||
id: 'typebot3',
|
||||
name: 'Typebot #3',
|
||||
ownerId: userIds[1],
|
||||
steps: {
|
||||
byId: {
|
||||
step1: {
|
||||
id: 'step1',
|
||||
blockId: 'block1',
|
||||
type: BubbleStepType.TEXT,
|
||||
content: { html: '', plainText: '', richText: [] },
|
||||
},
|
||||
},
|
||||
allIds: ['step1'],
|
||||
},
|
||||
blocks: {
|
||||
byId: {
|
||||
block1: {
|
||||
id: 'block1',
|
||||
graphCoordinates: { x: 400, y: 200 },
|
||||
title: 'Block #1',
|
||||
stepIds: ['step1'],
|
||||
},
|
||||
},
|
||||
allIds: ['block1'],
|
||||
},
|
||||
})
|
||||
)
|
||||
createTypebotWithStep({
|
||||
type: BubbleStepType.TEXT,
|
||||
content: { html: '', plainText: '', richText: [] },
|
||||
} as Omit<Step, 'id' | 'blockId'>)
|
||||
cy.signOut()
|
||||
})
|
||||
|
||||
@ -78,11 +50,3 @@ describe('Text bubbles', () => {
|
||||
.should('contain.text', 'Underlined text')
|
||||
})
|
||||
})
|
||||
|
||||
const getIframeBody = () => {
|
||||
return cy
|
||||
.get('#typebot-iframe')
|
||||
.its('0.contentDocument.body')
|
||||
.should('not.be.empty')
|
||||
.then(cy.wrap)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import path from 'path'
|
||||
import { parse } from 'papaparse'
|
||||
|
||||
describe('ResultsPage', () => {
|
||||
describe('Results page', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept({ url: '/api/typebots/typebot2/results*', method: 'GET' }).as(
|
||||
'getResults'
|
||||
@ -35,7 +35,7 @@ describe('ResultsPage', () => {
|
||||
cy.findByText('content50').should('not.exist')
|
||||
cy.findByText('content199').should('exist')
|
||||
cy.findByTestId('table-wrapper').scrollTo('bottom')
|
||||
cy.findByText('content149').should('exist')
|
||||
cy.findByText('content149', { timeout: 10000 }).should('exist')
|
||||
cy.findByTestId('table-wrapper').scrollTo('bottom')
|
||||
cy.findByText('content99').should('exist')
|
||||
cy.findByTestId('table-wrapper').scrollTo('bottom')
|
||||
|
@ -16,6 +16,9 @@
|
||||
"@dnd-kit/sortable": "^5.1.0",
|
||||
"@emotion/react": "^11.7.1",
|
||||
"@emotion/styled": "^11.6.0",
|
||||
"@giphy/js-fetch-api": "^4.1.2",
|
||||
"@giphy/js-types": "^4.1.0",
|
||||
"@giphy/react-components": "^5.4.0",
|
||||
"@googleapis/drive": "^2.1.0",
|
||||
"@next-auth/prisma-adapter": "next",
|
||||
"@udecode/plate-basic-marks": "^9.0.0",
|
||||
@ -26,6 +29,7 @@
|
||||
"@udecode/plate-ui-toolbar": "^9.0.0",
|
||||
"aws-sdk": "^2.1051.0",
|
||||
"bot-engine": "*",
|
||||
"browser-image-compression": "^1.0.17",
|
||||
"db": "*",
|
||||
"fast-equals": "^2.0.4",
|
||||
"focus-visible": "^5.2.0",
|
||||
|
@ -8,39 +8,35 @@ const handler = async (
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
): Promise<void> => {
|
||||
try {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
if (req.method === 'GET') {
|
||||
const session = await getSession({ req })
|
||||
if (!session) {
|
||||
res.status(401)
|
||||
return
|
||||
}
|
||||
aws.config.update({
|
||||
accessKeyId: process.env.S3_UPLOAD_KEY,
|
||||
secretAccessKey: process.env.S3_UPLOAD_SECRET,
|
||||
region: process.env.S3_UPLOAD_REGION,
|
||||
signatureVersion: 'v4',
|
||||
})
|
||||
|
||||
const s3 = new aws.S3()
|
||||
const post = s3.createPresignedPost({
|
||||
Bucket: process.env.S3_UPLOAD_BUCKET,
|
||||
Fields: {
|
||||
ACL: 'public-read',
|
||||
key: req.query.key,
|
||||
'Content-Type': req.query.fileType,
|
||||
},
|
||||
Expires: 120, // seconds
|
||||
Conditions: [['content-length-range', 0, maxUploadFileSize]],
|
||||
})
|
||||
|
||||
return res.status(200).json(post)
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
if (req.method === 'GET') {
|
||||
const session = await getSession({ req })
|
||||
if (!session) {
|
||||
res.status(401)
|
||||
return
|
||||
}
|
||||
return methodNotAllowed(res)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
aws.config.update({
|
||||
accessKeyId: process.env.S3_UPLOAD_KEY,
|
||||
secretAccessKey: process.env.S3_UPLOAD_SECRET,
|
||||
region: process.env.S3_UPLOAD_REGION,
|
||||
signatureVersion: 'v4',
|
||||
})
|
||||
|
||||
const s3 = new aws.S3()
|
||||
const post = s3.createPresignedPost({
|
||||
Bucket: process.env.S3_UPLOAD_BUCKET,
|
||||
Fields: {
|
||||
ACL: 'public-read',
|
||||
key: req.query.key,
|
||||
'Content-Type': req.query.fileType,
|
||||
},
|
||||
Expires: 120, // seconds
|
||||
Conditions: [['content-length-range', 0, maxUploadFileSize]],
|
||||
})
|
||||
|
||||
return res.status(200).json(post)
|
||||
}
|
||||
return methodNotAllowed(res)
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
Block,
|
||||
TextStep,
|
||||
TextBubbleStep,
|
||||
PublicTypebot,
|
||||
BackgroundType,
|
||||
Settings,
|
||||
@ -119,7 +119,7 @@ export const parseNewStep = (
|
||||
const id = `s${shortId.generate()}`
|
||||
switch (type) {
|
||||
case BubbleStepType.TEXT: {
|
||||
const textStep: Pick<TextStep, 'type' | 'content'> = {
|
||||
const textStep: Pick<TextBubbleStep, 'type' | 'content'> = {
|
||||
type,
|
||||
content: { html: '', richText: [], plainText: '' },
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import imageCompression from 'browser-image-compression'
|
||||
import { Parser } from 'htmlparser2'
|
||||
import { Step } from 'models'
|
||||
|
||||
@ -78,6 +79,16 @@ export const uploadFile = async (file: File, key: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const compressFile = async (file: File) => {
|
||||
const options = {
|
||||
maxSizeMB: 0.5,
|
||||
maxWidthOrHeight: 1600,
|
||||
}
|
||||
return ['image/jpg', 'image/jpeg', 'image/png'].includes(file.type)
|
||||
? imageCompression(file, options)
|
||||
: file
|
||||
}
|
||||
|
||||
export const removeUndefinedFields = <T>(obj: T): T =>
|
||||
Object.keys(obj).reduce(
|
||||
(acc, key) =>
|
||||
|
@ -13,7 +13,6 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
column: req.query['referenceCell[column]'],
|
||||
value: req.query['referenceCell[value]'],
|
||||
} as Cell
|
||||
console.log(referenceCell)
|
||||
const extractingColumns = req.query.columns as string[]
|
||||
const doc = new GoogleSpreadsheet(spreadsheetId)
|
||||
doc.useOAuth2Client(await getAuthenticatedGoogleClient(credentialsId))
|
||||
|
@ -4,14 +4,14 @@ import { TransitionGroup, CSSTransition } from 'react-transition-group'
|
||||
import { ChatStep } from './ChatStep'
|
||||
import { AvatarSideContainer } from './AvatarSideContainer'
|
||||
import { HostAvatarsContext } from '../../contexts/HostAvatarsContext'
|
||||
import { Edge, Step, Target } from 'models'
|
||||
import { Step } from 'models'
|
||||
import { useTypebot } from '../../contexts/TypebotContext'
|
||||
import {
|
||||
isBubbleStep,
|
||||
isChoiceInput,
|
||||
isInputStep,
|
||||
isIntegrationStep,
|
||||
isLogicStep,
|
||||
isTextBubbleStep,
|
||||
} from 'utils'
|
||||
import { executeLogic } from 'services/logic'
|
||||
import { getSingleChoiceTargetId } from 'services/inputs'
|
||||
@ -104,7 +104,7 @@ export const ChatBlock = ({
|
||||
<div className="flex flex-col w-full">
|
||||
<TransitionGroup>
|
||||
{displayedSteps
|
||||
.filter((step) => isInputStep(step) || isTextBubbleStep(step))
|
||||
.filter((step) => isInputStep(step) || isBubbleStep(step))
|
||||
.map((step) => (
|
||||
<CSSTransition
|
||||
key={step.id}
|
||||
|
@ -3,11 +3,11 @@ import { useAnswers } from '../../../contexts/AnswersContext'
|
||||
import { useHostAvatars } from '../../../contexts/HostAvatarsContext'
|
||||
import { InputStep, InputStepType, Step } from 'models'
|
||||
import { GuestBubble } from './bubbles/GuestBubble'
|
||||
import { HostMessageBubble } from './bubbles/HostMessageBubble'
|
||||
import { TextForm } from './inputs/TextForm'
|
||||
import { isInputStep, isTextBubbleStep } from 'utils'
|
||||
import { isBubbleStep, isInputStep } from 'utils'
|
||||
import { DateForm } from './inputs/DateForm'
|
||||
import { ChoiceForm } from './inputs/ChoiceForm'
|
||||
import { HostBubble } from './bubbles/HostBubble'
|
||||
|
||||
export const ChatStep = ({
|
||||
step,
|
||||
@ -23,8 +23,8 @@ export const ChatStep = ({
|
||||
onTransitionEnd(content)
|
||||
}
|
||||
|
||||
if (isTextBubbleStep(step))
|
||||
return <HostMessageBubble step={step} onTransitionEnd={onTransitionEnd} />
|
||||
if (isBubbleStep(step))
|
||||
return <HostBubble step={step} onTransitionEnd={onTransitionEnd} />
|
||||
if (isInputStep(step))
|
||||
return <InputChatStep step={step} onSubmit={handleInputSubmit} />
|
||||
return <span>No step</span>
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { BubbleStep, BubbleStepType } from 'models'
|
||||
import React from 'react'
|
||||
import { ImageBubble } from './ImageBubble'
|
||||
import { TextBubble } from './TextBubble'
|
||||
|
||||
type Props = {
|
||||
step: BubbleStep
|
||||
onTransitionEnd: () => void
|
||||
}
|
||||
|
||||
export const HostBubble = ({ step, onTransitionEnd }: Props) => {
|
||||
switch (step.type) {
|
||||
case BubbleStepType.TEXT:
|
||||
return <TextBubble step={step} onTransitionEnd={onTransitionEnd} />
|
||||
case BubbleStepType.IMAGE:
|
||||
return <ImageBubble step={step} onTransitionEnd={onTransitionEnd} />
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useHostAvatars } from 'contexts/HostAvatarsContext'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { ImageBubbleStep } from 'models'
|
||||
import { TypingContent } from './TypingContent'
|
||||
import { parseVariables } from 'services/variable'
|
||||
|
||||
type Props = {
|
||||
step: ImageBubbleStep
|
||||
onTransitionEnd: () => void
|
||||
}
|
||||
|
||||
export const showAnimationDuration = 400
|
||||
|
||||
export const mediaLoadingFallbackTimeout = 5000
|
||||
|
||||
export const ImageBubble = ({ step, onTransitionEnd }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
const { updateLastAvatarOffset } = useHostAvatars()
|
||||
const messageContainer = useRef<HTMLDivElement | null>(null)
|
||||
const image = useRef<HTMLImageElement | null>(null)
|
||||
const [isTyping, setIsTyping] = useState(true)
|
||||
|
||||
const url = useMemo(
|
||||
() =>
|
||||
parseVariables({ text: step.content?.url, variables: typebot.variables }),
|
||||
[typebot.variables]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
showContentAfterMediaLoad()
|
||||
}, [])
|
||||
|
||||
const showContentAfterMediaLoad = () => {
|
||||
if (!image.current) return
|
||||
const timeout = setTimeout(() => {
|
||||
setIsTyping(false)
|
||||
onTypingEnd()
|
||||
}, mediaLoadingFallbackTimeout)
|
||||
image.current.onload = () => {
|
||||
clearTimeout(timeout)
|
||||
setIsTyping(false)
|
||||
onTypingEnd()
|
||||
}
|
||||
}
|
||||
|
||||
const onTypingEnd = () => {
|
||||
setIsTyping(false)
|
||||
setTimeout(() => {
|
||||
sendAvatarOffset()
|
||||
onTransitionEnd()
|
||||
}, showAnimationDuration)
|
||||
}
|
||||
|
||||
const sendAvatarOffset = () => {
|
||||
if (!messageContainer.current) return
|
||||
const containerDimensions = messageContainer.current.getBoundingClientRect()
|
||||
updateLastAvatarOffset(containerDimensions.top + containerDimensions.height)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col" ref={messageContainer}>
|
||||
<div className="flex mb-2 w-full lg:w-11/12 items-center">
|
||||
<div className={'flex relative z-10 items-start typebot-host-bubble'}>
|
||||
<div
|
||||
className="flex items-center absolute px-4 py-2 rounded-lg bubble-typing z-10 "
|
||||
style={{
|
||||
width: isTyping ? '4rem' : '100%',
|
||||
height: isTyping ? '2rem' : '100%',
|
||||
}}
|
||||
>
|
||||
{isTyping ? <TypingContent /> : <></>}
|
||||
</div>
|
||||
<img
|
||||
ref={image}
|
||||
src={url}
|
||||
className={
|
||||
'p-4 content-opacity z-10 w-auto ' +
|
||||
(isTyping ? 'opacity-0' : 'opacity-100')
|
||||
}
|
||||
style={{
|
||||
maxHeight: '32rem',
|
||||
height: isTyping ? '2rem' : 'auto',
|
||||
maxWidth: '100%',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,24 +1,19 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useHostAvatars } from 'contexts/HostAvatarsContext'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { BubbleStepType, TextStep } from 'models'
|
||||
import { BubbleStepType, TextBubbleStep } from 'models'
|
||||
import { computeTypingTimeout } from 'services/chat'
|
||||
import { TypingContent } from './TypingContent'
|
||||
import { parseVariables } from 'services/variable'
|
||||
|
||||
type HostMessageBubbleProps = {
|
||||
step: TextStep
|
||||
type Props = {
|
||||
step: TextBubbleStep
|
||||
onTransitionEnd: () => void
|
||||
}
|
||||
|
||||
export const showAnimationDuration = 400
|
||||
|
||||
export const mediaLoadingFallbackTimeout = 5000
|
||||
|
||||
export const HostMessageBubble = ({
|
||||
step,
|
||||
onTransitionEnd,
|
||||
}: HostMessageBubbleProps) => {
|
||||
export const TextBubble = ({ step, onTransitionEnd }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
const { typingEmulation } = typebot.settings
|
||||
const { updateLastAvatarOffset } = useHostAvatars()
|
@ -1,12 +1,28 @@
|
||||
import { StepBase } from '.'
|
||||
|
||||
export type BubbleStep = TextStep
|
||||
export type BubbleStep = TextBubbleStep | ImageBubbleStep
|
||||
|
||||
export enum BubbleStepType {
|
||||
TEXT = 'text',
|
||||
IMAGE = 'image',
|
||||
}
|
||||
|
||||
export type TextStep = StepBase & {
|
||||
export type TextBubbleStep = StepBase & {
|
||||
type: BubbleStepType.TEXT
|
||||
content: { html: string; richText: unknown[]; plainText: string }
|
||||
content: TextBubbleContent
|
||||
}
|
||||
|
||||
export type ImageBubbleStep = StepBase & {
|
||||
type: BubbleStepType.IMAGE
|
||||
content?: ImageBubbleContent
|
||||
}
|
||||
|
||||
export type TextBubbleContent = {
|
||||
html: string
|
||||
richText: unknown[]
|
||||
plainText: string
|
||||
}
|
||||
|
||||
export type ImageBubbleContent = {
|
||||
url?: string
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
Step,
|
||||
Table,
|
||||
TextInputStep,
|
||||
TextStep,
|
||||
TextBubbleStep,
|
||||
} from 'models'
|
||||
|
||||
export const sendRequest = async <ResponseData>({
|
||||
@ -57,7 +57,7 @@ export const isBubbleStep = (step: Step): step is BubbleStep =>
|
||||
export const isLogicStep = (step: Step): step is LogicStep =>
|
||||
(Object.values(LogicStepType) as string[]).includes(step.type)
|
||||
|
||||
export const isTextBubbleStep = (step: Step): step is TextStep =>
|
||||
export const isTextBubbleStep = (step: Step): step is TextBubbleStep =>
|
||||
step.type === BubbleStepType.TEXT
|
||||
|
||||
export const isTextInputStep = (step: Step): step is TextInputStep =>
|
||||
|
248
yarn.lock
248
yarn.lock
@ -824,6 +824,16 @@
|
||||
source-map "^0.5.7"
|
||||
stylis "4.0.13"
|
||||
|
||||
"@emotion/cache@^10.0.27":
|
||||
version "10.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
|
||||
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
|
||||
dependencies:
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/stylis" "0.8.5"
|
||||
"@emotion/utils" "0.11.3"
|
||||
"@emotion/weak-memoize" "0.2.5"
|
||||
|
||||
"@emotion/cache@^11.7.1":
|
||||
version "11.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539"
|
||||
@ -835,12 +845,33 @@
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
stylis "4.0.13"
|
||||
|
||||
"@emotion/hash@^0.8.0":
|
||||
"@emotion/core@10.1.1":
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3"
|
||||
integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
"@emotion/cache" "^10.0.27"
|
||||
"@emotion/css" "^10.0.27"
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
"@emotion/css@^10.0.27":
|
||||
version "10.0.27"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
|
||||
integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
|
||||
dependencies:
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/utils" "0.11.3"
|
||||
babel-plugin-emotion "^10.0.27"
|
||||
|
||||
"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/is-prop-valid@^0.8.2", "@emotion/is-prop-valid@^0.8.8":
|
||||
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.2", "@emotion/is-prop-valid@^0.8.8":
|
||||
version "0.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||
@ -877,6 +908,17 @@
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
hoist-non-react-statics "^3.3.1"
|
||||
|
||||
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
|
||||
version "0.11.16"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
|
||||
integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
|
||||
dependencies:
|
||||
"@emotion/hash" "0.8.0"
|
||||
"@emotion/memoize" "0.7.4"
|
||||
"@emotion/unitless" "0.7.5"
|
||||
"@emotion/utils" "0.11.3"
|
||||
csstype "^2.5.7"
|
||||
|
||||
"@emotion/serialize@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965"
|
||||
@ -888,11 +930,34 @@
|
||||
"@emotion/utils" "^1.0.0"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@emotion/sheet@0.9.4":
|
||||
version "0.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
|
||||
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
|
||||
|
||||
"@emotion/sheet@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2"
|
||||
integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==
|
||||
|
||||
"@emotion/styled-base@^10.0.27":
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.3.0.tgz#9aa2c946100f78b47316e4bc6048321afa6d4e36"
|
||||
integrity sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
"@emotion/is-prop-valid" "0.8.8"
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
"@emotion/styled@10.0.27":
|
||||
version "10.0.27"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf"
|
||||
integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==
|
||||
dependencies:
|
||||
"@emotion/styled-base" "^10.0.27"
|
||||
babel-plugin-emotion "^10.0.27"
|
||||
|
||||
"@emotion/styled@^11.6.0":
|
||||
version "11.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.6.0.tgz#9230d1a7bcb2ebf83c6a579f4c80e0664132d81d"
|
||||
@ -904,22 +969,27 @@
|
||||
"@emotion/serialize" "^1.0.2"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
|
||||
"@emotion/stylis@^0.8.4":
|
||||
"@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4":
|
||||
version "0.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
|
||||
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
|
||||
|
||||
"@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5":
|
||||
"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@emotion/utils@0.11.3":
|
||||
version "0.11.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
|
||||
integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
|
||||
|
||||
"@emotion/utils@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
|
||||
integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
|
||||
|
||||
"@emotion/weak-memoize@^0.2.5":
|
||||
"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
||||
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
|
||||
@ -939,6 +1009,63 @@
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@giphy/js-analytics@^4.0.7":
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@giphy/js-analytics/-/js-analytics-4.0.7.tgz#98f5179e933719da00c9f01ae70d9205449026c3"
|
||||
integrity sha512-s4+GUXWwyxJVm6i7GHiQvQlMaXkHGCkh4uqjpisX5IiHxTNheSDMHHX0SyRLpTL5rdnvBkiBxlH8iOv9w3pNwg==
|
||||
dependencies:
|
||||
"@giphy/js-types" "^4.1.0"
|
||||
"@giphy/js-util" "^4.0.1"
|
||||
append-query "^2.1.0"
|
||||
throttle-debounce "^3.0.1"
|
||||
|
||||
"@giphy/js-brand@^2.0.4":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@giphy/js-brand/-/js-brand-2.0.4.tgz#3a1e31aa7861088963ff634418078f6ec70c5f02"
|
||||
integrity sha512-q2iRyRWmKpCLAt1G7LzcHjw8s/cvSSoA1SfoQL47Tx0/yGwo8xCiFcFPFZJZsCcVMLCwA7/UmxTkdRydQVhCNw==
|
||||
dependencies:
|
||||
emotion "10.0.27"
|
||||
|
||||
"@giphy/js-fetch-api@^4.1.2":
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@giphy/js-fetch-api/-/js-fetch-api-4.1.2.tgz#0c4a975567efa6591fd47d04d5d7f7012a2c527f"
|
||||
integrity sha512-wDfDQu8HiVkLb+YXcZf8QFbznmMHWbg86ZBydYmnp2mfuHyaHKsz9n9PnxdH3RorMS9YM/Ca/zqAM5y89Qj+Hw==
|
||||
dependencies:
|
||||
"@giphy/js-types" "^4.1.0"
|
||||
"@giphy/js-util" "^4.0.1"
|
||||
qs "^6.9.4"
|
||||
|
||||
"@giphy/js-types@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@giphy/js-types/-/js-types-4.1.0.tgz#987b184bf848c81092ba61ab10895096eefa78de"
|
||||
integrity sha512-+qSN4Mx4TmrjLQm4SC0I/ZBkb5eWM94sljXwfjIlqn0GMSR3geqEqwmE9Uf/ldgzFh+XMMCasQjIdUl2nWc++Q==
|
||||
|
||||
"@giphy/js-util@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@giphy/js-util/-/js-util-4.0.1.tgz#dc1987465cf69267a1aa92ae027c7de3d3dab3b2"
|
||||
integrity sha512-46wXgt5Y+MxZjuzjE6JlvMLE+6Vlag+PYxbyTxpsunhmOKNoYK99d51E09iynmXTFuZWYgWJR9LcfnzqsWHy+Q==
|
||||
dependencies:
|
||||
"@giphy/js-types" "^4.1.0"
|
||||
dompurify "^2.2.2"
|
||||
uuid "^8.3.0"
|
||||
|
||||
"@giphy/react-components@^5.4.0":
|
||||
version "5.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@giphy/react-components/-/react-components-5.4.0.tgz#9f4135934554696eb7736fadaee0187876be68a5"
|
||||
integrity sha512-n8BhFzVZoETPsdYVDBuqXc1yCzsX0lypEkNQAIuouY4VEoGfb4yvRT507O79FPLwYLAXxGWiGE9S2h/0TLJvLw==
|
||||
dependencies:
|
||||
"@emotion/core" "10.1.1"
|
||||
"@emotion/styled" "10.0.27"
|
||||
"@giphy/js-analytics" "^4.0.7"
|
||||
"@giphy/js-brand" "^2.0.4"
|
||||
"@giphy/js-fetch-api" "^4.1.2"
|
||||
"@giphy/js-types" "^4.1.0"
|
||||
"@giphy/js-util" "^4.0.1"
|
||||
emotion-theming "10.0.27"
|
||||
intersection-observer "^0.11.0"
|
||||
react-use "17.2.4"
|
||||
throttle-debounce "^3.0.1"
|
||||
|
||||
"@googleapis/drive@^2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@googleapis/drive/-/drive-2.1.0.tgz#2c62ce6184784f433725810edc5dc1798f9da4a3"
|
||||
@ -1935,6 +2062,13 @@ anymatch@~3.1.1, anymatch@~3.1.2:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
append-query@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/append-query/-/append-query-2.1.1.tgz#0682e8c3ad6f2fa01e78153c4c73a6283d2a88f6"
|
||||
integrity sha512-adm0E8o1o7ay+HbkWvGIpNNeciLB/rxJ0heThHuzSSVq5zcdQ5/ZubFnUoY0imFmk6gZVghSpwoubLVtwi9EHQ==
|
||||
dependencies:
|
||||
extend "^3.0.2"
|
||||
|
||||
arch@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
|
||||
@ -2142,7 +2276,23 @@ axobject-query@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
||||
integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
|
||||
|
||||
babel-plugin-macros@^2.6.1:
|
||||
babel-plugin-emotion@^10.0.27:
|
||||
version "10.2.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz#a1fe3503cff80abfd0bdda14abd2e8e57a79d17d"
|
||||
integrity sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@emotion/hash" "0.8.0"
|
||||
"@emotion/memoize" "0.7.4"
|
||||
"@emotion/serialize" "^0.11.16"
|
||||
babel-plugin-macros "^2.0.0"
|
||||
babel-plugin-syntax-jsx "^6.18.0"
|
||||
convert-source-map "^1.5.0"
|
||||
escape-string-regexp "^1.0.5"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.5.7"
|
||||
|
||||
babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
|
||||
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
|
||||
@ -2243,6 +2393,14 @@ brorand@^1.0.1, brorand@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
||||
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
||||
|
||||
browser-image-compression@^1.0.17:
|
||||
version "1.0.17"
|
||||
resolved "https://registry.yarnpkg.com/browser-image-compression/-/browser-image-compression-1.0.17.tgz#5b97bb65297dadfee123be6c40ecb355c4758cf2"
|
||||
integrity sha512-TMDh3gyNlVA5Vvn0D0AdWr33s2ftIeokHK406z8cYlLJ4ANAq1x6eMaSzqedDoZwUGyTVB+0rhNVaSFgM3YAZg==
|
||||
dependencies:
|
||||
core-js "^3.16.1"
|
||||
uzip "0.20201231.0"
|
||||
|
||||
browserify-aes@^1.0.0, browserify-aes@^1.0.4:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
|
||||
@ -2698,6 +2856,11 @@ core-js-pure@^3.19.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.20.2.tgz#5d263565f0e34ceeeccdc4422fae3e84ca6b8c0f"
|
||||
integrity sha512-CmWHvSKn2vNL6p6StNp1EmMIfVY/pqn3JLAjfZQ8WZGPOlGoO92EkX9/Mk81i6GxvoPXjUqEQnpM3rJ5QxxIOg==
|
||||
|
||||
core-js@^3.16.1:
|
||||
version "3.20.3"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.20.3.tgz#c710d0a676e684522f3db4ee84e5e18a9d11d69a"
|
||||
integrity sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==
|
||||
|
||||
core-util-is@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
@ -2743,6 +2906,16 @@ create-ecdh@^4.0.0:
|
||||
bn.js "^4.1.0"
|
||||
elliptic "^6.5.3"
|
||||
|
||||
create-emotion@^10.0.27:
|
||||
version "10.0.27"
|
||||
resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.27.tgz#cb4fa2db750f6ca6f9a001a33fbf1f6c46789503"
|
||||
integrity sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==
|
||||
dependencies:
|
||||
"@emotion/cache" "^10.0.27"
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
|
||||
@ -2948,6 +3121,11 @@ csso@^4.2.0:
|
||||
dependencies:
|
||||
css-tree "^1.1.2"
|
||||
|
||||
csstype@^2.5.7:
|
||||
version "2.6.19"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.19.tgz#feeb5aae89020bb389e1f63669a5ed490e391caa"
|
||||
integrity sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==
|
||||
|
||||
csstype@^3.0.2, csstype@^3.0.6, csstype@^3.0.9:
|
||||
version "3.0.10"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
|
||||
@ -3209,6 +3387,11 @@ domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.0:
|
||||
dependencies:
|
||||
domelementtype "^2.2.0"
|
||||
|
||||
dompurify@^2.2.2:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.4.tgz#1cf5cf0105ccb4debdf6db162525bd41e6ddacc6"
|
||||
integrity sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==
|
||||
|
||||
domutils@^2.8.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
||||
@ -3286,6 +3469,23 @@ emojis-list@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
|
||||
|
||||
emotion-theming@10.0.27:
|
||||
version "10.0.27"
|
||||
resolved "https://registry.yarnpkg.com/emotion-theming/-/emotion-theming-10.0.27.tgz#1887baaec15199862c89b1b984b79806f2b9ab10"
|
||||
integrity sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
"@emotion/weak-memoize" "0.2.5"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
emotion@10.0.27:
|
||||
version "10.0.27"
|
||||
resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.27.tgz#f9ca5df98630980a23c819a56262560562e5d75e"
|
||||
integrity sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==
|
||||
dependencies:
|
||||
babel-plugin-emotion "^10.0.27"
|
||||
create-emotion "^10.0.27"
|
||||
|
||||
encoding@0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
@ -4265,7 +4465,7 @@ hmac-drbg@^1.0.1:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.1:
|
||||
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@ -4492,6 +4692,11 @@ internal-slot@^1.0.3:
|
||||
has "^1.0.3"
|
||||
side-channel "^1.0.4"
|
||||
|
||||
intersection-observer@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.11.0.tgz#f4ea067070326f68393ee161cc0a2ca4c0040c6f"
|
||||
integrity sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ==
|
||||
|
||||
invariant@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
@ -6280,7 +6485,7 @@ qs@^6.10.2, qs@^6.6.0:
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@^6.10.3, qs@^6.7.0:
|
||||
qs@^6.10.3, qs@^6.7.0, qs@^6.9.4:
|
||||
version "6.10.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e"
|
||||
integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==
|
||||
@ -6487,6 +6692,26 @@ react-universal-interface@^0.6.2:
|
||||
resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b"
|
||||
integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==
|
||||
|
||||
react-use@17.2.4:
|
||||
version "17.2.4"
|
||||
resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.2.4.tgz#1f89be3db0a8237c79253db0a15e12bbe3cfeff1"
|
||||
integrity sha512-vQGpsAM0F5UIlshw5UI8ULGPS4yn5rm7/qvn3T1Gnkrz7YRMEEMh+ynKcmRloOyiIeLvKWiQjMiwRGtdbgs5qQ==
|
||||
dependencies:
|
||||
"@types/js-cookie" "^2.2.6"
|
||||
"@xobotyi/scrollbar-width" "^1.9.5"
|
||||
copy-to-clipboard "^3.3.1"
|
||||
fast-deep-equal "^3.1.3"
|
||||
fast-shallow-equal "^1.0.0"
|
||||
js-cookie "^2.2.1"
|
||||
nano-css "^5.3.1"
|
||||
react-universal-interface "^0.6.2"
|
||||
resize-observer-polyfill "^1.5.1"
|
||||
screenfull "^5.1.0"
|
||||
set-harmonic-interval "^1.0.1"
|
||||
throttle-debounce "^3.0.1"
|
||||
ts-easing "^0.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
react-use@^17.1.1:
|
||||
version "17.3.2"
|
||||
resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.3.2.tgz#448abf515f47c41c32455024db28167cb6e53be8"
|
||||
@ -7807,11 +8032,16 @@ uuid@3.3.2:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
||||
|
||||
uuid@^8.0.0, uuid@^8.3.2:
|
||||
uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
uzip@0.20201231.0:
|
||||
version "0.20201231.0"
|
||||
resolved "https://registry.yarnpkg.com/uzip/-/uzip-0.20201231.0.tgz#9e64b065b9a8ebf26eb7583fe8e77e1d9a15ed14"
|
||||
integrity sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
|
Reference in New Issue
Block a user