Skip to content

Commit

Permalink
fix(tasks): update description input to create blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrobonamin committed Mar 26, 2024
1 parent f568e14 commit ba07e5a
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import {type EditorChange, keyGenerator, PortableTextEditor} from '@sanity/portable-text-editor'
import {
type EditorChange,
keyGenerator,
PortableTextEditor,
type RenderBlockFunction,
} from '@sanity/portable-text-editor'
import {type CurrentUser, type PortableTextBlock} from '@sanity/types'
import {type AvatarSize, focusFirstDescendant, focusLastDescendant, Stack} from '@sanity/ui'
import type * as React from 'react'
import {forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState} from 'react'
import {type UserListWithPermissionsHookValue} from 'sanity'

import {editorSchemaType} from '../config'
import {renderBlock as renderNormalBlock} from '../render'
import {CommentInputDiscardDialog} from './CommentInputDiscardDialog'
import {CommentInputInner} from './CommentInputInner'
import {CommentInputProvider} from './CommentInputProvider'
Expand Down Expand Up @@ -34,6 +40,7 @@ export interface CommentInputProps {
onSubmit?: () => void
placeholder?: React.ReactNode
readOnly?: boolean
renderBlock?: RenderBlockFunction
value: PortableTextBlock[] | null
withAvatar?: boolean
avatarSize?: AvatarSize
Expand Down Expand Up @@ -75,6 +82,7 @@ export const CommentInput = forwardRef<CommentInputHandle, CommentInputProps>(
onSubmit,
placeholder,
readOnly,
renderBlock = renderNormalBlock,
value = EMPTY_ARRAY,
withAvatar = true,
} = props
Expand Down Expand Up @@ -231,6 +239,7 @@ export const CommentInput = forwardRef<CommentInputHandle, CommentInputProps>(
onKeyDown={onKeyDown}
onSubmit={onSubmit && handleSubmit}
placeholder={placeholder}
renderBlock={renderBlock}
withAvatar={withAvatar}
/>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {type RenderBlockFunction} from '@sanity/portable-text-editor'
import {type CurrentUser} from '@sanity/types'
import {type AvatarSize, Box, Card, Flex, MenuDivider, Stack} from '@sanity/ui'
// eslint-disable-next-line camelcase
Expand Down Expand Up @@ -107,6 +108,7 @@ interface CommentInputInnerProps {
onKeyDown?: (e: React.KeyboardEvent<Element>) => void
onSubmit?: () => void
placeholder?: React.ReactNode
renderBlock: RenderBlockFunction
withAvatar?: boolean
}

Expand All @@ -120,6 +122,7 @@ export function CommentInputInner(props: CommentInputInnerProps) {
onKeyDown,
onSubmit,
placeholder,
renderBlock,
withAvatar,
} = props

Expand Down Expand Up @@ -164,6 +167,7 @@ export function CommentInputInner(props: CommentInputInnerProps) {
onKeyDown={onKeyDown}
onSubmit={onSubmit}
placeholder={placeholder}
renderBlock={renderBlock}
/>
</EditableWrap>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
type EditorSelection,
PortableTextEditable,
type RenderBlockFunction,
usePortableTextEditorSelection,
} from '@sanity/portable-text-editor'
import {isPortableTextSpan, isPortableTextTextBlock} from '@sanity/types'
Expand All @@ -15,7 +16,7 @@ import styled, {css} from 'styled-components'
import {Popover, type PopoverProps} from '../../../../../../ui-components'
import {commentsLocaleNamespace} from '../../../../i18n'
import {MentionsMenu, type MentionsMenuHandle} from '../../mentions'
import {renderBlock, renderChild} from '../render'
import {renderChild} from '../render'
import {useCommentInput} from './useCommentInput'
import {useCursorElement} from './useCursorElement'

Expand Down Expand Up @@ -65,6 +66,7 @@ interface EditableProps {
onKeyDown?: (e: React.KeyboardEvent<Element>) => void
onSubmit?: () => void
placeholder?: React.ReactNode
renderBlock: RenderBlockFunction
}

export interface EditableHandle {
Expand All @@ -75,11 +77,12 @@ export function Editable(props: EditableProps) {
const {t} = useTranslation(commentsLocaleNamespace)
const {
focusLock,
placeholder = t('compose.create-comment-placeholder'),
onFocus,
onBlur,
onKeyDown,
onSubmit,
placeholder = t('compose.create-comment-placeholder'),
renderBlock,
} = props
const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null)
const rootElementRef = useRef<HTMLDivElement | null>(null)
Expand Down Expand Up @@ -126,19 +129,21 @@ export function Editable(props: EditableProps) {
if (event.shiftKey) {
break
}
// Enter is being used both to select something from the mentionsMenu
// or to submit the comment. Prevent the default behavior.
event.preventDefault()
event.stopPropagation()

// If the mention menu is open close it, but don't submit.
if (mentionsMenuOpen) {
// Enter is being used both to select something from the mentionsMenu, prevent the default behavior.
event.preventDefault()
event.stopPropagation()
closeMentions()
break
}

// Submit the comment if eligible for submission
if (onSubmit && canSubmit) {
// Enter is being used to submit the comment, prevent the default behavior.
event.preventDefault()
event.stopPropagation()
onSubmit()
}
break
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// eslint-disable-next-line camelcase
import {getTheme_v2} from '@sanity/ui/theme'
import {useCallback, useEffect, useRef, useState} from 'react'
import {startTransition, useCallback, useEffect, useState} from 'react'
import {
type ArrayFieldProps,
type PortableTextBlock,
Expand All @@ -10,10 +10,11 @@ import {
} from 'sanity'
import styled, {css} from 'styled-components'

import {CommentInput} from '../../../../../../structure/comments'
import {tasksLocaleNamespace} from '../../../../../i18n'
import {useMentionUser} from '../../../context'
import {type FormMode} from '../../../types'
import {CommentInput} from '../../../../../../../structure/comments'
import {tasksLocaleNamespace} from '../../../../../../i18n'
import {useMentionUser} from '../../../../context'
import {type FormMode} from '../../../../types'
import {renderBlock} from './render'

const DescriptionInputRoot = styled.div<{$mode: FormMode; $minHeight: number}>((props) => {
const theme = getTheme_v2(props.theme)
Expand Down Expand Up @@ -43,39 +44,42 @@ export function DescriptionInput(props: ArrayFieldProps & {mode: FormMode}) {
inputProps: {onChange},
} = props
const value = _propValue as PortableTextBlock[] | undefined

const currentUser = useCurrentUser()
const {mentionOptions} = useMentionUser()

const handleChange = useCallback((next: PortableTextBlock[]) => onChange(set(next)), [onChange])

const rootRef = useRef<HTMLDivElement | null>(null)
const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null)
const [textBoxScrollHeight, setTextBoxScrollHeight] = useState<number>(200)
const setTextboxHeight = useCallback((ref: HTMLDivElement) => {
const textBox = ref.querySelector('[role="textbox"]')
if (!textBox) return

const height = textBox.scrollHeight
setTextBoxScrollHeight(height)
}, [])

const setRootRef = useCallback(
(ref: HTMLDivElement) => {
if (!ref) return
setTextboxHeight(ref)
rootRef.current = ref
},
[setTextboxHeight],
)
const handleSetRootRef = useCallback((ref: HTMLDivElement) => {
if (!ref) return
startTransition(() => {
setRootRef(ref)
})
}, [])

const {t} = useTranslation(tasksLocaleNamespace)

useEffect(() => {
if (!rootRef.current) return
setTextboxHeight(rootRef.current)
}, [value, setTextboxHeight])
if (!rootRef) return
setTextboxHeight(rootRef)
}, [value, setTextboxHeight, rootRef])

if (!currentUser) return null
return (
<DescriptionInputRoot $mode={mode} ref={setRootRef} $minHeight={textBoxScrollHeight || 200}>
<DescriptionInputRoot
$mode={mode}
ref={handleSetRootRef}
$minHeight={textBoxScrollHeight || 200}
>
<CommentInput
expandOnFocus={false}
currentUser={currentUser}
Expand All @@ -86,6 +90,7 @@ export function DescriptionInput(props: ArrayFieldProps & {mode: FormMode}) {
placeholder={t('form.input.description.placeholder')}
// eslint-disable-next-line react/jsx-no-bind
onDiscardConfirm={() => null}
renderBlock={renderBlock}
/>
</DescriptionInputRoot>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {Box, Text} from '@sanity/ui'
import type * as React from 'react'
import styled from 'styled-components'

const NormalText = styled(Text)`
word-break: break-word;
`

interface NormalBlockProps {
children: React.ReactNode
}

export function DescriptionInputBlock(props: NormalBlockProps) {
const {children} = props

return (
<Box paddingTop={2} paddingBottom={3}>
<NormalText size={1}>{children}</NormalText>
</Box>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DescriptionInputBlock'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DescriptionInput'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './renderBlock'
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {type RenderBlockFunction} from '@sanity/portable-text-editor'

import {DescriptionInputBlock} from '../blocks'

export const renderBlock: RenderBlockFunction = (blockProps) => {
const {children} = blockProps

return <DescriptionInputBlock>{children}</DescriptionInputBlock>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './assignee'
export * from './DateEditFormField'
export * from './DescriptionInput'
export * from './descriptionInput'
export * from './FieldWrapper'
export * from './StatusSelector'
export * from './TargetField'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Box, rem} from '@sanity/ui'
// eslint-disable-next-line camelcase
import {getTheme_v2} from '@sanity/ui/theme'
import {motion, type Variants} from 'framer-motion'
import {useEffect, useMemo} from 'react'
import {
type CurrentUser,
Expand All @@ -20,7 +21,15 @@ import {TasksAddonWorkspaceProvider} from '../addonWorkspace/TasksAddOnWorkspace
import {getTargetValue} from '../utils'
import {useTasksFormBuilder} from './useTasksFormBuilder'

const FormBuilderRoot = styled.div((props) => {
const VARIANTS: Variants = {
hidden: {opacity: 0},
visible: {
opacity: 1,
transition: {duration: 0.2, delay: 0.2},
},
}

const FormBuilderRoot = styled(motion.div)((props) => {
const theme = getTheme_v2(props.theme)

return `
Expand Down Expand Up @@ -67,7 +76,7 @@ const TasksFormBuilderInner = ({
{formBuilderProps.loading ? (
<LoadingBlock showText />
) : (
<FormBuilderRoot id="wrapper">
<FormBuilderRoot id="wrapper" initial="hidden" animate="visible" variants={VARIANTS}>
<FormBuilder {...formBuilderProps} />
</FormBuilderRoot>
)}
Expand Down

0 comments on commit ba07e5a

Please sign in to comment.