main

mattermost/focalboard

Last updated at: 28/12/2023 01:42

checkboxElement.tsx

TLDR

This file, checkboxElement.tsx, is part of the Demo Projects project. It contains the implementation of a React component called CheckboxElement. The component renders a checkbox input element along with an editable title. It allows users to toggle the checkbox state and modify the title. The component also registers itself as a content type with the contentRegistry module.

Methods

There are no methods defined in this file.

Classes

CheckboxElement

The CheckboxElement class is a React component that renders a checkbox input element along with an editable title. It has the following props:

  • block: The ContentBlock object associated with the element.
  • readonly: A boolean indicating whether the element is in read-only mode.
  • onAddElement (optional): A callback function called when a new element is added.
  • onDeleteElement (optional): A callback function called when the element is deleted.

The CheckboxElement component maintains its own state for the active state of the checkbox and the current title. It uses the useIntl hook for internationalization and the useCardDetailContext hook to access the card detail context.

The component updates its state and triggers the necessary mutations when the checkbox is toggled or the title is modified. It also supports focusing on the title input field when a new element is added.

The CheckboxElement component is exported as the default export of the file and wrapped in the React.memo higher-order component.

contentRegistry

The contentRegistry object is imported from the ./contentRegistry module. The CheckboxElement component is registered as a content type with the contentRegistry using the registerContentType method. The content type registration specifies the text to be displayed for the content type, the icon to be used, and the functions to create a new block and create a component for rendering the block.

END

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useEffect, useRef, useState} from 'react'
import {useIntl} from 'react-intl'

import {createCheckboxBlock} from '../../blocks/checkboxBlock'
import {ContentBlock} from '../../blocks/contentBlock'
import CheckIcon from '../../widgets/icons/check'
import mutator from '../../mutator'
import Editable, {Focusable} from '../../widgets/editable'
import {useCardDetailContext} from '../cardDetail/cardDetailContext'

import './checkboxElement.scss'

import {contentRegistry} from './contentRegistry'

type Props = {
    block: ContentBlock
    readonly: boolean
    onAddElement?: () => void
    onDeleteElement?: () => void
}

const CheckboxElement = (props: Props) => {
    const {block, readonly} = props
    const intl = useIntl()
    const titleRef = useRef<Focusable>(null)
    const cardDetail = useCardDetailContext()
    const [addedBlockId, setAddedBlockId] = useState(cardDetail.lastAddedBlock.id)
    const [active, setActive] = useState(Boolean(block.fields.value))
    const [title, setTitle] = useState(block.title)

    useEffect(() => {
        if (block.id === addedBlockId) {
            titleRef.current?.focus()
            setAddedBlockId('')
        }
    }, [block, addedBlockId, titleRef])

    useEffect(() => {
        setActive(Boolean(block.fields.value))
    }, [Boolean(block.fields.value)])

    return (
        <div className='CheckboxElement'>
            <input
                type='checkbox'
                id={`checkbox-${block.id}`}
                disabled={readonly}
                checked={active}
                value={active ? 'on' : 'off'}
                onChange={(e) => {
                    e.preventDefault()
                    const newBlock = createCheckboxBlock(block)
                    newBlock.fields.value = !active
                    newBlock.title = title
                    setActive(newBlock.fields.value)
                    mutator.updateBlock(block.boardId, newBlock, block, intl.formatMessage({id: 'ContentBlock.editCardCheckbox', defaultMessage: 'toggled-checkbox'}))
                }}
            />
            <Editable
                ref={titleRef}
                value={title}
                placeholderText={intl.formatMessage({id: 'ContentBlock.editText', defaultMessage: 'Edit text...'})}
                onChange={setTitle}
                saveOnEsc={true}
                onSave={async (saveType) => {
                    const {lastAddedBlock} = cardDetail
                    if (title === '' && block.id === lastAddedBlock.id && lastAddedBlock.autoAdded && props.onDeleteElement) {
                        props.onDeleteElement()
                        return
                    }

                    if (block.title !== title) {
                        await mutator.changeBlockTitle(block.boardId, block.id, block.title, title, intl.formatMessage({id: 'ContentBlock.editCardCheckboxText', defaultMessage: 'edit card text'}))
                        if (saveType === 'onEnter' && title !== '' && props.onAddElement) {
                            // Wait for the change to happen
                            setTimeout(props.onAddElement, 100)
                        }
                        return
                    }

                    if (saveType === 'onEnter' && title !== '' && props.onAddElement) {
                        props.onAddElement()
                    }
                }}
                readonly={readonly}
                spellCheck={true}
            />
        </div>
    )
}

contentRegistry.registerContentType({
    type: 'checkbox',
    getDisplayText: (intl) => intl.formatMessage({id: 'ContentBlock.checkbox', defaultMessage: 'checkbox'}),
    getIcon: () => <CheckIcon/>,
    createBlock: async () => {
        return createCheckboxBlock()
    },
    createComponent: (block, readonly, onAddElement, onDeleteElement) => {
        return (
            <CheckboxElement
                block={block}
                readonly={readonly}
                onAddElement={onAddElement}
                onDeleteElement={onDeleteElement}
            />
        )
    },
})

export default React.memo(CheckboxElement)