refactor: refactoring MessageInput
This commit is contained in:
parent
129129c455
commit
558540a361
11 changed files with 338 additions and 60 deletions
|
@ -100,6 +100,10 @@
|
|||
"react-nice-avatar": "^1.4.1",
|
||||
"react-use": "^17.4.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remesh": "^4.2.0",
|
||||
"remesh-logger": "^4.1.0",
|
||||
"remesh-react": "^4.1.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"type-fest": "^3.13.0"
|
||||
},
|
||||
|
|
|
@ -53,6 +53,18 @@ dependencies:
|
|||
remark-gfm:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1
|
||||
remesh:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(rxjs@7.8.1)
|
||||
remesh-logger:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0(remesh@4.2.0)
|
||||
remesh-react:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0(react-dom@18.2.0)(react@18.2.0)(remesh@4.2.0)(rxjs@7.8.1)
|
||||
rxjs:
|
||||
specifier: ^7.8.1
|
||||
version: 7.8.1
|
||||
tailwind-merge:
|
||||
specifier: ^1.13.2
|
||||
version: 1.13.2
|
||||
|
@ -4527,6 +4539,11 @@ packages:
|
|||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/is-plain-object@5.0.0:
|
||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/is-regex@1.1.4:
|
||||
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -6726,6 +6743,53 @@ packages:
|
|||
unified: 10.1.2
|
||||
dev: false
|
||||
|
||||
/remesh-debugger-helper@4.1.0(remesh@4.2.0):
|
||||
resolution: {integrity: sha512-nBbfznOEuu9Z1tpLIBOKEYcYrQvOCc+JyyPWYRG3H79JO/jxIUEAGg6YzAw59EUE/nhMPyx6qwyB7exJwFsZug==}
|
||||
peerDependencies:
|
||||
remesh: ^4.0.0
|
||||
dependencies:
|
||||
remesh: 4.2.0(rxjs@7.8.1)
|
||||
tslib: 2.6.0
|
||||
dev: false
|
||||
|
||||
/remesh-logger@4.1.0(remesh@4.2.0):
|
||||
resolution: {integrity: sha512-OEmmBFk6KVtv0JahVhh29JbcF5IeMhxqiBaz2UAqY5x5d8W6UJtYmQFat2/2HUYV/Y1C+ooGi/kzh3Ka6NoyMQ==}
|
||||
peerDependencies:
|
||||
remesh: ^4.0.0
|
||||
dependencies:
|
||||
remesh: 4.2.0(rxjs@7.8.1)
|
||||
remesh-debugger-helper: 4.1.0(remesh@4.2.0)
|
||||
tslib: 2.6.0
|
||||
dev: false
|
||||
|
||||
/remesh-react@4.1.0(react-dom@18.2.0)(react@18.2.0)(remesh@4.2.0)(rxjs@7.8.1):
|
||||
resolution: {integrity: sha512-VaTZ2y3A84tiPNxb2/wgDt6i65zSfsxlAP1sTSDC+5C5vnhTy8Q8O8AaYJMOKqXUDtUNI9ld9Qu0wqfdxig/dg==}
|
||||
peerDependencies:
|
||||
react: ^16.10.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.10.0 || ^17.0.0 || ^18.0.0
|
||||
remesh: ^4.0.0
|
||||
rxjs: ^7.0.0
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
remesh: 4.2.0(rxjs@7.8.1)
|
||||
rxjs: 7.8.1
|
||||
tslib: 2.6.0
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/remesh@4.2.0(rxjs@7.8.1):
|
||||
resolution: {integrity: sha512-t2xwtFYnEwrcWddxtEb/NF7kR+x62Er52gfk+sCa4HmaQC+J5zg41pYZz6TTl4PrDghs2et1tr1dYZpbYGAu6g==}
|
||||
engines: {node: '>=14.x'}
|
||||
peerDependencies:
|
||||
rxjs: ^7.0.0
|
||||
dependencies:
|
||||
is-plain-object: 5.0.0
|
||||
rxjs: 7.8.1
|
||||
shallowequal: 1.1.0
|
||||
tslib: 2.6.0
|
||||
dev: false
|
||||
|
||||
/request@2.88.2:
|
||||
resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -6894,7 +6958,6 @@ packages:
|
|||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||
dependencies:
|
||||
tslib: 2.6.0
|
||||
dev: true
|
||||
|
||||
/sade@1.8.1:
|
||||
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
||||
|
@ -7017,6 +7080,10 @@ packages:
|
|||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/shallowequal@1.1.0:
|
||||
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
|
||||
dev: false
|
||||
|
||||
/shebang-command@1.2.0:
|
||||
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -7921,6 +7988,14 @@ packages:
|
|||
punycode: 2.3.0
|
||||
dev: true
|
||||
|
||||
/use-sync-external-store@1.2.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
|
|
|
@ -1,58 +1,57 @@
|
|||
import { type FC, type ChangeEvent } from 'react'
|
||||
import { type FC, type ChangeEvent, type KeyboardEvent } from 'react'
|
||||
import { Textarea } from '@/components/ui/Textarea'
|
||||
|
||||
import { Markdown } from '@/components/ui/Markdown'
|
||||
import { cn } from '@/utils'
|
||||
import { useRemeshDomain, useRemeshQuery, useRemeshSend } from 'remesh-react'
|
||||
import MessageInputDomain from '@/domain/MessageInput'
|
||||
import { MESSAGE_MAX_LENGTH } from '@/constants'
|
||||
|
||||
export interface MessageInputProps {
|
||||
value?: string
|
||||
focus?: boolean
|
||||
preview?: boolean
|
||||
className?: string
|
||||
maxLength?: number
|
||||
onInput?: (message: string) => void
|
||||
onChange?: (message: string) => void
|
||||
onFocus?: () => void
|
||||
onBlur?: () => void
|
||||
}
|
||||
|
||||
const MessageInput: FC<MessageInputProps> = ({
|
||||
value,
|
||||
focus = true,
|
||||
className,
|
||||
preview,
|
||||
maxLength = 500,
|
||||
onInput,
|
||||
onChange,
|
||||
onFocus,
|
||||
onBlur
|
||||
}) => {
|
||||
const MessageInput: FC<MessageInputProps> = ({ className }) => {
|
||||
const send = useRemeshSend()
|
||||
const messageInputDomain = useRemeshDomain(MessageInputDomain())
|
||||
|
||||
const message = useRemeshQuery(messageInputDomain.query.ValueQuery())
|
||||
const isPreview = useRemeshQuery(messageInputDomain.query.PreviewQuery())
|
||||
|
||||
const handleInput = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
send(messageInputDomain.command.InputCommand(e.target.value))
|
||||
}
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Enter' && !(e.shiftKey || e.ctrlKey || e.altKey || e.metaKey)) {
|
||||
e.preventDefault()
|
||||
send(messageInputDomain.command.EnterCommand())
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('relative', className)}>
|
||||
{preview ? (
|
||||
<Markdown className="max-h-32 rounded-lg border border-input bg-gray-50 2xl:max-h-40">{value}</Markdown>
|
||||
{isPreview ? (
|
||||
<Markdown className="max-h-32 rounded-lg border border-input bg-gray-50 2xl:max-h-40">{message}</Markdown>
|
||||
) : (
|
||||
// Hack: Auto-Growing Textarea
|
||||
<div
|
||||
data-value={value}
|
||||
data-value={message}
|
||||
className="grid after:pointer-events-none after:invisible after:col-start-1 after:col-end-2 after:row-start-1 after:row-end-2 after:box-border after:max-h-28 after:w-full after:overflow-x-hidden after:whitespace-pre-wrap after:break-words after:rounded-lg after:border after:px-3 after:py-2 after:pb-5 after:text-sm after:content-[attr(data-value)] after:2xl:max-h-40"
|
||||
>
|
||||
<Textarea
|
||||
autoFocus={focus}
|
||||
maxLength={maxLength}
|
||||
onKeyDown={handleKeyDown}
|
||||
maxLength={MESSAGE_MAX_LENGTH}
|
||||
className="col-start-1 col-end-2 row-start-1 row-end-2 box-border max-h-28 resize-none overflow-x-hidden break-words rounded-lg bg-gray-50 pb-5 text-sm 2xl:max-h-40"
|
||||
rows={2}
|
||||
value={value}
|
||||
value={message}
|
||||
placeholder="Type your message here."
|
||||
onInput={(e: ChangeEvent<HTMLTextAreaElement>) => onInput?.(e.target.value)}
|
||||
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => onChange?.(e.target.value)}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="absolute bottom-1 right-3 rounded-lg text-xs text-slate-400">
|
||||
{value?.length ?? 0}/{maxLength}
|
||||
{message?.length ?? 0}/{MESSAGE_MAX_LENGTH}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import { useState, type FC } from 'react'
|
||||
|
||||
import { type FC } from 'react'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { SmileIcon, CornerDownLeftIcon, ImageIcon } from 'lucide-react'
|
||||
import MessageInput from './MessageInput'
|
||||
|
||||
const Footer: FC = () => {
|
||||
const [message, setMessage] = useState('')
|
||||
|
||||
const handleInput = (value: string) => {
|
||||
setMessage(value)
|
||||
}
|
||||
const handleSend = () => {}
|
||||
|
||||
return (
|
||||
<div className="grid gap-y-2 p-4">
|
||||
<MessageInput value={message} onInput={handleInput}></MessageInput>
|
||||
<MessageInput></MessageInput>
|
||||
<div className="grid grid-cols-[auto_auto_1fr] items-center justify-items-end">
|
||||
<Button variant="ghost" size="icon">
|
||||
<SmileIcon size={20} />
|
||||
|
@ -21,7 +16,7 @@ const Footer: FC = () => {
|
|||
<Button variant="ghost" size="icon">
|
||||
<ImageIcon size={20} />
|
||||
</Button>
|
||||
<Button size="sm">
|
||||
<Button size="sm" onClick={handleSend}>
|
||||
<span className="mr-2">Send</span>
|
||||
<CornerDownLeftIcon className="text-slate-400" size={12}></CornerDownLeftIcon>
|
||||
</Button>
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
import { FrownIcon, type LucideIcon, ThumbsUpIcon } from 'lucide-react'
|
||||
import { type MouseEvent, type FC } from 'react'
|
||||
import { type MouseEvent, type FC, type ReactElement } from 'react'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { cn } from '@/utils'
|
||||
|
||||
export interface LikeButtonIconProps {
|
||||
children: JSX.Element
|
||||
}
|
||||
|
||||
export const LikeButtonIcon: FC<LikeButtonIconProps> = ({ children }) => children
|
||||
|
||||
export interface LikeButtonProps {
|
||||
type: 'like' | 'hate'
|
||||
count: number
|
||||
checked: boolean
|
||||
onClick?: (e: MouseEvent<HTMLButtonElement>) => void
|
||||
onChange?: (checked: boolean, count: number) => void
|
||||
children: ReactElement<LikeButtonIconProps>
|
||||
}
|
||||
|
||||
const iconMapping: Record<LikeButtonProps['type'], LucideIcon> = {
|
||||
like: ThumbsUpIcon,
|
||||
hate: FrownIcon
|
||||
}
|
||||
|
||||
const LikeButton: FC<LikeButtonProps> = ({ type, checked, count, onClick, onChange }) => {
|
||||
const Icon = iconMapping[type]
|
||||
|
||||
const LikeButton: FC<LikeButtonProps> & { Icon: FC<LikeButtonIconProps> } = ({
|
||||
checked,
|
||||
count,
|
||||
onClick,
|
||||
onChange,
|
||||
children
|
||||
}) => {
|
||||
const handleOnClick = (e: MouseEvent<HTMLButtonElement>) => {
|
||||
onClick?.(e)
|
||||
onChange?.(!checked, checked ? count - 1 : count + 1)
|
||||
|
@ -35,12 +39,14 @@ const LikeButton: FC<LikeButtonProps> = ({ type, checked, count, onClick, onChan
|
|||
)}
|
||||
size="xs"
|
||||
>
|
||||
<Icon size={14} />
|
||||
{children}
|
||||
{!!count && <span className="min-w-0 text-xs">{count}</span>}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
LikeButton.Icon = LikeButtonIcon
|
||||
|
||||
LikeButton.displayName = 'LikeButton'
|
||||
|
||||
export default LikeButton
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/Avatar'
|
|||
import { format } from 'date-fns'
|
||||
|
||||
import LikeButton from './LikeButton'
|
||||
import { FrownIcon, ThumbsUpIcon } from 'lucide-react'
|
||||
export interface MessageProps {
|
||||
data: {
|
||||
id: string
|
||||
|
@ -50,17 +51,23 @@ const Message: FC<MessageProps> = ({ data }) => {
|
|||
</div>
|
||||
<div className="grid grid-flow-col justify-end gap-x-2 leading-none">
|
||||
<LikeButton
|
||||
type="like"
|
||||
checked={formatData.likeChecked}
|
||||
onChange={(...args) => handleLikeChange('like', ...args)}
|
||||
count={formatData.likeCount}
|
||||
></LikeButton>
|
||||
>
|
||||
<LikeButton.Icon>
|
||||
<ThumbsUpIcon size={14}></ThumbsUpIcon>
|
||||
</LikeButton.Icon>
|
||||
</LikeButton>
|
||||
<LikeButton
|
||||
type="hate"
|
||||
checked={formatData.hateChecked}
|
||||
onChange={(...args) => handleLikeChange('hate', ...args)}
|
||||
count={formatData.hateCount}
|
||||
></LikeButton>
|
||||
>
|
||||
<LikeButton.Icon>
|
||||
<FrownIcon size={14}></FrownIcon>
|
||||
</LikeButton.Icon>
|
||||
</LikeButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -69,5 +76,4 @@ const Message: FC<MessageProps> = ({ data }) => {
|
|||
}
|
||||
|
||||
Message.displayName = 'Message'
|
||||
|
||||
export default Message
|
||||
|
|
|
@ -32,7 +32,7 @@ const Main: FC = () => {
|
|||
avatar: 'https://github.com/shadcn.png',
|
||||
date: Date.now(),
|
||||
likeChecked: false,
|
||||
hateChecked: false,
|
||||
hateChecked: true,
|
||||
likeCount: 9999,
|
||||
hateCount: 2
|
||||
}
|
||||
|
|
|
@ -15,3 +15,5 @@ export const BREAKPOINTS = {
|
|||
'2xl': '1536px'
|
||||
// => @media (min-width: 1536px) { ... }
|
||||
} as const
|
||||
|
||||
export const MESSAGE_MAX_LENGTH = 500 as const
|
||||
|
|
59
src/domain/MessageInput.ts
Normal file
59
src/domain/MessageInput.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { Remesh } from 'remesh'
|
||||
import InputModule from './modules/Input'
|
||||
|
||||
const MessageInputDomain = Remesh.domain({
|
||||
name: 'MessageInputDomain',
|
||||
impl: (domain) => {
|
||||
const inputModule = InputModule(domain, {
|
||||
name: 'MessageInput'
|
||||
})
|
||||
|
||||
const PreviewState = domain.state({
|
||||
name: 'PreviewState',
|
||||
default: false
|
||||
})
|
||||
|
||||
const PreviewQuery = domain.query({
|
||||
name: 'PreviewQuery',
|
||||
impl: ({ get }) => {
|
||||
return get(PreviewState())
|
||||
}
|
||||
})
|
||||
|
||||
const PreviewCommand = domain.command({
|
||||
name: 'PreviewCommand',
|
||||
impl: (_, value: boolean) => {
|
||||
return PreviewState().new(value)
|
||||
}
|
||||
})
|
||||
|
||||
const EnterEvent = domain.event({
|
||||
name: 'EnterEvent'
|
||||
})
|
||||
|
||||
const EnterCommand = domain.command({
|
||||
name: 'EnterCommand',
|
||||
impl: () => {
|
||||
return EnterEvent()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
query: {
|
||||
...inputModule.query,
|
||||
PreviewQuery
|
||||
},
|
||||
command: {
|
||||
...inputModule.command,
|
||||
EnterCommand,
|
||||
PreviewCommand
|
||||
},
|
||||
event: {
|
||||
...inputModule.event,
|
||||
EnterEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default MessageInputDomain
|
123
src/domain/modules/Input.ts
Normal file
123
src/domain/modules/Input.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
import { Remesh, type Capitalize, type RemeshDomainContext } from 'remesh'
|
||||
|
||||
export interface InputModuleOptions {
|
||||
name: Capitalize
|
||||
value?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const InputModule = (domain: RemeshDomainContext, options: InputModuleOptions) => {
|
||||
const ValueState = domain.state({
|
||||
name: `${options.name}.ValueState`,
|
||||
default: options.value ?? ''
|
||||
})
|
||||
|
||||
const ValueQuery = domain.query({
|
||||
name: `${options.name}.ValueQuery`,
|
||||
impl: ({ get }) => {
|
||||
return get(ValueState())
|
||||
}
|
||||
})
|
||||
|
||||
const InputEvent = domain.event<string>({
|
||||
name: `${options.name}.InputEvent`
|
||||
})
|
||||
|
||||
const InputCommand = domain.command({
|
||||
name: `${options.name}.InputCommand`,
|
||||
impl: (_, value: string) => {
|
||||
InputEvent(value)
|
||||
return ValueState().new(value)
|
||||
}
|
||||
})
|
||||
|
||||
const ChangeEvent = domain.event<string>({
|
||||
name: `${options.name}.ChangeEvent`
|
||||
})
|
||||
|
||||
const ChangeCommand = domain.command({
|
||||
name: `${options.name}.ChangeCommand`,
|
||||
impl: (_, value: string) => {
|
||||
ChangeEvent(value)
|
||||
return ValueState().new(value)
|
||||
}
|
||||
})
|
||||
|
||||
const FocusState = domain.state({
|
||||
name: `${options.name}.FocusState`,
|
||||
default: false
|
||||
})
|
||||
|
||||
const FocusQuery = domain.query({
|
||||
name: `${options.name}.FocusQuery`,
|
||||
impl: ({ get }) => {
|
||||
return get(FocusState())
|
||||
}
|
||||
})
|
||||
|
||||
const FocusEvent = domain.event<boolean>({
|
||||
name: `${options.name}.FocusEvent`
|
||||
})
|
||||
|
||||
const BlurEvent = domain.event<boolean>({
|
||||
name: `${options.name}.BlurEvent`
|
||||
})
|
||||
|
||||
const BlurCommand = domain.command({
|
||||
name: `${options.name}.BlurCommand`,
|
||||
impl: () => {
|
||||
BlurEvent(false)
|
||||
return FocusState().new(false)
|
||||
}
|
||||
})
|
||||
|
||||
const FocusCommand = domain.command({
|
||||
name: `${options.name}.FocusCommand`,
|
||||
impl: () => {
|
||||
FocusEvent(true)
|
||||
return FocusState().new(true)
|
||||
}
|
||||
})
|
||||
|
||||
const DisabledState = domain.state({
|
||||
name: `${options.name}.DisabledState`,
|
||||
default: options.disabled ?? false
|
||||
})
|
||||
|
||||
const DisabledQuery = domain.query({
|
||||
name: `${options.name}.DisabledQuery`,
|
||||
impl: ({ get }) => {
|
||||
return get(DisabledState())
|
||||
}
|
||||
})
|
||||
|
||||
const DisabledCommand = domain.command({
|
||||
name: `${options.name}.DisabledCommand`,
|
||||
impl: (_, value: boolean) => {
|
||||
return DisabledState().new(value)
|
||||
}
|
||||
})
|
||||
|
||||
return Remesh.module({
|
||||
query: {
|
||||
ValueQuery,
|
||||
FocusQuery,
|
||||
DisabledQuery
|
||||
},
|
||||
command: {
|
||||
InputCommand,
|
||||
ChangeCommand,
|
||||
BlurCommand,
|
||||
FocusCommand,
|
||||
DisabledCommand
|
||||
},
|
||||
event: {
|
||||
InputEvent,
|
||||
ChangeEvent,
|
||||
FocusEvent,
|
||||
BlurEvent
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default InputModule
|
11
src/main.tsx
11
src/main.tsx
|
@ -2,14 +2,23 @@ import React from 'react'
|
|||
import App from './App'
|
||||
import createShadowRoot from './createShadowRoot'
|
||||
import style from './index.css?inline'
|
||||
import { RemeshRoot } from 'remesh-react'
|
||||
import { RemeshLogger } from 'remesh-logger'
|
||||
import { Remesh } from 'remesh'
|
||||
|
||||
void (async () => {
|
||||
const store = Remesh.store({
|
||||
inspectors: [RemeshLogger()]
|
||||
})
|
||||
|
||||
createShadowRoot(__NAME__, {
|
||||
style: __DEV__ ? '' : style,
|
||||
mode: __DEV__ ? 'open' : 'closed'
|
||||
}).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<RemeshRoot store={store}>
|
||||
<App />
|
||||
</RemeshRoot>
|
||||
</React.StrictMode>
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue