♻️ Add shared eslint config
This commit is contained in:
@@ -1,48 +1,8 @@
|
||||
module.exports = {
|
||||
ignorePatterns: ['node_modules'],
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
},
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react/recommended',
|
||||
'next/core-web-vitals',
|
||||
'prettier',
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
|
||||
sourceType: 'module', // Allows for the use of imports
|
||||
ecmaFeatures: {
|
||||
jsx: true, // Allows for the parsing of JSX
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
|
||||
},
|
||||
},
|
||||
plugins: ['prettier', 'react', '@typescript-eslint'],
|
||||
ignorePatterns: 'dist',
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
rules: {
|
||||
'react/no-unescaped-entities': [0],
|
||||
'prettier/prettier': 'error',
|
||||
'react/display-name': [0],
|
||||
'@next/next/no-img-element': [0],
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
'*/src/*',
|
||||
'src/*',
|
||||
'*/src',
|
||||
'@/features/*/*',
|
||||
'@/index',
|
||||
'!@/features/blocks/*',
|
||||
'!@/features/*/api',
|
||||
],
|
||||
},
|
||||
],
|
||||
'@next/next/no-img-element': 'off',
|
||||
'@next/next/no-html-link-for-pages': 'off',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"build": "pnpm tsc --noEmit && tsup",
|
||||
"dev": "tsup --watch",
|
||||
"lint": "eslint --fix -c ./.eslintrc.js \"./src/**/*.ts*\""
|
||||
"lint": "eslint \"src/**/*.ts*\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@stripe/react-stripe-js": "1.15.0",
|
||||
@@ -28,16 +28,11 @@
|
||||
"@types/react-phone-number-input": "3.0.14",
|
||||
"@types/react-scroll": "1.8.5",
|
||||
"@types/react-transition-group": "4.4.5",
|
||||
"@typescript-eslint/eslint-plugin": "5.43.0",
|
||||
"@typescript-eslint/parser": "5.43.0",
|
||||
"autoprefixer": "10.4.13",
|
||||
"baptistearno-tsup": "^0.1.0",
|
||||
"tsup": "6.5.0",
|
||||
"db": "workspace:*",
|
||||
"eslint": "8.27.0",
|
||||
"eslint-config-next": "13.0.3",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"eslint-plugin-react": "7.31.10",
|
||||
"eslint": "8.28.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"models": "workspace:*",
|
||||
"postcss": "8.4.19",
|
||||
"prettier": "2.7.1",
|
||||
@@ -46,7 +41,8 @@
|
||||
"tailwindcss": "3.2.4",
|
||||
"typescript": "4.8.4",
|
||||
"utils": "workspace:*",
|
||||
"typebot-js": "workspace:*"
|
||||
"typebot-js": "workspace:*",
|
||||
"tsconfig": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"db": "workspace:*",
|
||||
|
||||
@@ -13,59 +13,60 @@ import { ResizeObserver } from 'resize-observer'
|
||||
|
||||
type Props = { hostAvatarSrc?: string; keepShowing: boolean }
|
||||
|
||||
export const AvatarSideContainer = forwardRef(
|
||||
({ hostAvatarSrc, keepShowing }: Props, ref: ForwardedRef<unknown>) => {
|
||||
const { document } = useFrame()
|
||||
const [show, setShow] = useState(false)
|
||||
const [avatarTopOffset, setAvatarTopOffset] = useState(0)
|
||||
export const AvatarSideContainer = forwardRef(function AvatarSideContainer(
|
||||
{ hostAvatarSrc, keepShowing }: Props,
|
||||
ref: ForwardedRef<unknown>
|
||||
) {
|
||||
const { document } = useFrame()
|
||||
const [show, setShow] = useState(false)
|
||||
const [avatarTopOffset, setAvatarTopOffset] = useState(0)
|
||||
|
||||
const refreshTopOffset = () => {
|
||||
if (!scrollingSideGroupRef.current || !avatarContainer.current) return
|
||||
const { height } = scrollingSideGroupRef.current.getBoundingClientRect()
|
||||
const { height: avatarHeight } =
|
||||
avatarContainer.current.getBoundingClientRect()
|
||||
setAvatarTopOffset(height - avatarHeight)
|
||||
}
|
||||
const scrollingSideGroupRef = useRef<HTMLDivElement>(null)
|
||||
const avatarContainer = useRef<HTMLDivElement>(null)
|
||||
useImperativeHandle(ref, () => ({
|
||||
refreshTopOffset,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
if (!document) return
|
||||
setShow(true)
|
||||
const resizeObserver = new ResizeObserver(refreshTopOffset)
|
||||
resizeObserver.observe(document.body)
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex w-6 xs:w-10 mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container "
|
||||
ref={scrollingSideGroupRef}
|
||||
>
|
||||
<CSSTransition
|
||||
classNames="bubble"
|
||||
timeout={500}
|
||||
in={show && keepShowing}
|
||||
unmountOnExit
|
||||
>
|
||||
<div
|
||||
className="absolute w-6 xs:w-10 h-6 xs:h-10 mb-4 xs:mb-2 flex items-center top-0"
|
||||
ref={avatarContainer}
|
||||
style={{
|
||||
top: `${avatarTopOffset}px`,
|
||||
transition: 'top 350ms ease-out, opacity 500ms',
|
||||
}}
|
||||
>
|
||||
<Avatar avatarSrc={hostAvatarSrc} />
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
)
|
||||
const refreshTopOffset = () => {
|
||||
if (!scrollingSideGroupRef.current || !avatarContainer.current) return
|
||||
const { height } = scrollingSideGroupRef.current.getBoundingClientRect()
|
||||
const { height: avatarHeight } =
|
||||
avatarContainer.current.getBoundingClientRect()
|
||||
setAvatarTopOffset(height - avatarHeight)
|
||||
}
|
||||
)
|
||||
const scrollingSideGroupRef = useRef<HTMLDivElement>(null)
|
||||
const avatarContainer = useRef<HTMLDivElement>(null)
|
||||
useImperativeHandle(ref, () => ({
|
||||
refreshTopOffset,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
if (!document) return
|
||||
setShow(true)
|
||||
const resizeObserver = new ResizeObserver(refreshTopOffset)
|
||||
resizeObserver.observe(document.body)
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex w-6 xs:w-10 mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container "
|
||||
ref={scrollingSideGroupRef}
|
||||
>
|
||||
<CSSTransition
|
||||
classNames="bubble"
|
||||
timeout={500}
|
||||
in={show && keepShowing}
|
||||
unmountOnExit
|
||||
>
|
||||
<div
|
||||
className="absolute w-6 xs:w-10 h-6 xs:h-10 mb-4 xs:mb-2 flex items-center top-0"
|
||||
ref={avatarContainer}
|
||||
style={{
|
||||
top: `${avatarTopOffset}px`,
|
||||
transition: 'top 350ms ease-out, opacity 500ms',
|
||||
}}
|
||||
>
|
||||
<Avatar avatarSrc={hostAvatarSrc} />
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ export const InputChatBlock = ({
|
||||
blockId: block.id,
|
||||
groupId: block.groupId,
|
||||
content: value,
|
||||
variableId: variableId ?? null,
|
||||
variableId,
|
||||
uploadedFiles: block.type === InputBlockType.FILE,
|
||||
})
|
||||
if (!isEditting) onTransitionEnd({ label, value, itemId }, isRetry)
|
||||
|
||||
@@ -246,7 +246,6 @@ const ChatChunks = ({
|
||||
}: Props) => {
|
||||
const [isSkipped, setIsSkipped] = useState(false)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const avatarSideContainerRef = useRef<any>()
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ConversationContainer } from './ConversationContainer'
|
||||
import { AnswersProvider } from '../providers/AnswersProvider'
|
||||
import {
|
||||
Answer,
|
||||
AnswerInput,
|
||||
BackgroundType,
|
||||
Edge,
|
||||
PublicTypebot,
|
||||
@@ -27,7 +28,9 @@ export type TypebotViewerProps = {
|
||||
startGroupId?: string
|
||||
isLoading?: boolean
|
||||
onNewGroupVisible?: (edge: Edge) => void
|
||||
onNewAnswer?: (answer: Answer & { uploadedFiles: boolean }) => Promise<void>
|
||||
onNewAnswer?: (
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => Promise<void>
|
||||
onNewLog?: (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) => void
|
||||
onCompleted?: () => void
|
||||
onVariablesUpdated?: (variables: VariableWithValue[]) => void
|
||||
@@ -58,7 +61,7 @@ export const TypebotViewer = ({
|
||||
const handleNewGroupVisible = (edge: Edge) =>
|
||||
onNewGroupVisible && onNewGroupVisible(edge)
|
||||
|
||||
const handleNewAnswer = (answer: Answer & { uploadedFiles: boolean }) =>
|
||||
const handleNewAnswer = (answer: AnswerInput & { uploadedFiles: boolean }) =>
|
||||
onNewAnswer && onNewAnswer(answer)
|
||||
|
||||
const handleNewLog = (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) =>
|
||||
|
||||
@@ -5,21 +5,19 @@ type ShortTextInputProps = {
|
||||
onChange: (value: string) => void
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>
|
||||
|
||||
export const ShortTextInput = React.forwardRef(
|
||||
(
|
||||
{ onChange, ...props }: ShortTextInputProps,
|
||||
ref: React.ForwardedRef<HTMLInputElement>
|
||||
) => {
|
||||
return (
|
||||
<input
|
||||
ref={ref}
|
||||
className="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
type="text"
|
||||
style={{ fontSize: '16px' }}
|
||||
autoFocus={!isMobile}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
export const ShortTextInput = React.forwardRef(function ShortTextInput(
|
||||
{ onChange, ...props }: ShortTextInputProps,
|
||||
ref: React.ForwardedRef<HTMLInputElement>
|
||||
) {
|
||||
return (
|
||||
<input
|
||||
ref={ref}
|
||||
className="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
type="text"
|
||||
style={{ fontSize: '16px' }}
|
||||
autoFocus={!isMobile}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -5,11 +5,11 @@ type TextareaProps = {
|
||||
onChange: (value: string) => void
|
||||
} & Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange'>
|
||||
|
||||
export const Textarea = React.forwardRef(
|
||||
(
|
||||
{ onChange, ...props }: TextareaProps,
|
||||
ref: React.ForwardedRef<HTMLTextAreaElement>
|
||||
) => (
|
||||
export const Textarea = React.forwardRef(function Textarea(
|
||||
{ onChange, ...props }: TextareaProps,
|
||||
ref: React.ForwardedRef<HTMLTextAreaElement>
|
||||
) {
|
||||
return (
|
||||
<textarea
|
||||
ref={ref}
|
||||
className="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
@@ -22,4 +22,4 @@ export const Textarea = React.forwardRef(
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ import { parseVariables } from '@/features/variables'
|
||||
import { useChat } from '@/providers/ChatProvider'
|
||||
import { useTypebot } from '@/providers/TypebotProvider'
|
||||
import { createPaymentIntentQuery } from '../../queries/createPaymentIntentQuery'
|
||||
import { Stripe } from '@stripe/stripe-js'
|
||||
|
||||
type Props = {
|
||||
options: PaymentInputOptions
|
||||
@@ -23,8 +24,7 @@ export const StripePaymentForm = ({ options, onSuccess }: Props) => {
|
||||
onNewLog,
|
||||
} = useTypebot()
|
||||
const { window: frameWindow, document: frameDocument } = useFrame()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [stripe, setStripe] = useState<any>(null)
|
||||
const [stripe, setStripe] = useState<Stripe | null>(null)
|
||||
const [clientSecret, setClientSecret] = useState('')
|
||||
const [amountLabel, setAmountLabel] = useState('')
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ export const PhoneInput = ({
|
||||
hasGuestAvatar,
|
||||
}: PhoneInputProps) => {
|
||||
const [inputValue, setInputValue] = useState(defaultValue ?? '')
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const inputRef = useRef<any>(null)
|
||||
|
||||
const handleChange = (inputValue: Value | undefined) =>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { GoogleAnalyticsOptions } from 'models'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
declare const gtag: any
|
||||
declare const gtag: (
|
||||
type: string,
|
||||
action: string | undefined,
|
||||
options: {
|
||||
event_category: string | undefined
|
||||
event_label: string | undefined
|
||||
value: number | undefined
|
||||
}
|
||||
) => void
|
||||
|
||||
const initGoogleAnalytics = (id: string): Promise<void> =>
|
||||
new Promise((resolve) => {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { safeStringify } from '@/features/variables'
|
||||
import {
|
||||
Answer,
|
||||
AnswerInput,
|
||||
ResultValues,
|
||||
VariableWithUnknowValue,
|
||||
VariableWithValue,
|
||||
} from 'models'
|
||||
import React, { createContext, ReactNode, useContext, useState } from 'react'
|
||||
import { createContext, ReactNode, useContext, useState } from 'react'
|
||||
|
||||
const answersContext = createContext<{
|
||||
resultId?: string
|
||||
resultValues: ResultValues
|
||||
addAnswer: (
|
||||
answer: Answer & { uploadedFiles: boolean }
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => Promise<void> | undefined
|
||||
updateVariables: (variables: VariableWithUnknowValue[]) => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
|
||||
@@ -26,7 +26,7 @@ export const AnswersProvider = ({
|
||||
}: {
|
||||
resultId?: string
|
||||
onNewAnswer: (
|
||||
answer: Answer & { uploadedFiles: boolean }
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => Promise<void> | undefined
|
||||
onVariablesUpdated?: (variables: VariableWithValue[]) => void
|
||||
children: ReactNode
|
||||
@@ -34,10 +34,10 @@ export const AnswersProvider = ({
|
||||
const [resultValues, setResultValues] = useState<ResultValues>({
|
||||
answers: [],
|
||||
variables: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
createdAt: new Date(),
|
||||
})
|
||||
|
||||
const addAnswer = (answer: Answer & { uploadedFiles: boolean }) => {
|
||||
const addAnswer = (answer: AnswerInput & { uploadedFiles: boolean }) => {
|
||||
setResultValues((resultValues) => ({
|
||||
...resultValues,
|
||||
answers: [...resultValues.answers, answer],
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { createContext, ReactNode, useContext } from 'react'
|
||||
|
||||
const chatContext = createContext<{
|
||||
scroll: () => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ const typebotContext = createContext<{
|
||||
edgeId: string
|
||||
}) => void
|
||||
onNewLog: (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) => void
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
}>({})
|
||||
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
{
|
||||
"extends": "tsconfig/react-library.json",
|
||||
"include": ["src/**/*"],
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2017", "DOM"],
|
||||
"target": "es5",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react",
|
||||
"module": "ESNext",
|
||||
"declaration": true,
|
||||
"declarationDir": "types",
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"downlevelIteration": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineConfig } from 'baptistearno-tsup'
|
||||
import { defineConfig } from 'tsup'
|
||||
|
||||
export default defineConfig((options) => ({
|
||||
entry: ['src/index.ts'],
|
||||
|
||||
Reference in New Issue
Block a user