Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

feat: Add onBeforeStart and onBeforeUpdate handlers to the render function #1

Closed
wants to merge 1 commit into from

Conversation

rfgamaral
Copy link
Member

@rfgamaral rfgamaral commented Mar 11, 2022

This simple change provides onBefore* handlers to the render function, allowing one to start rendering a loading spinner, for instance, while waiting for async items to be received from a backend service.

A working demo can be found here:

P.S: This PR is not meant to be merged to our fork, it serves only as a code review platform before opening a PR against the upstream repository.


With this change, the meaning of each handler now becomes:

  • onBeforeStart: Invoked once as soon as the user types the suggestion trigger character
    • Async: This is where a dropdown would be first rendered with a loading spinner
    • Not-async: There's no use for this handler in this situation (can be omitted)
  • onStart: Invoked once as soon as the first results from the async call are received
    • Async: This is where a dropdown would be updated with the first results (replacing the loading spinner)
    • Not-async: This is where a dropdown would be first rendered with the first results
  • onBeforeUpdate: Invoked every time for each character pressed, and as soon as it's pressed
    • Async: This is where a dropdown would be updated with a loading spinner
    • Not-async: There's no use for this handler in this situation (can be omitted)
  • onUpdate: Invoked every time for each character pressed, and as soon as the filtered results from the async call are received
    • Async: This is where a dropdown would be updated with the filtered results (replacing the loading spinner)
    • Not-async: This is where a dropdown would be rendered again with the filtered results

Here's how a render function could look like (unoptimized code, some duplication can probably be avoided):

render: () => {
    let reactRenderer
    let dropdown

    return {
        onBeforeStart: (props) => {
            reactRenderer = new ReactRenderer(MentionList, {
                props: {
                    ...props,
                    items: null, // represents loading state
                },
                editor: props.editor,
            })

            if (props.decorationNode) {
                dropdown = tippy(props.decorationNode, {
                    getReferenceClientRect: props.clientRect,
                    appendTo: () => document.body,
                    content: reactRenderer.element,
                    duration: [150, 200],
                    interactive: true,
                    placement: 'bottom-start',
                    showOnCreate: true,
                    trigger: 'manual',
                })
            }
        },
        onStart(props) {
            reactRenderer.updateProps(props)

            dropdown.setProps({
                getReferenceClientRect: props.clientRect,
            })
        },
        onBeforeUpdate(props) {
            reactRenderer.updateProps({
                ...props,
                items: null, // represents loading state
            })

            dropdown.setProps({
                getReferenceClientRect: props.clientRect,
            })
        },
        onUpdate(props) {
            reactRenderer.updateProps(props)

            dropdown.setProps({
                getReferenceClientRect: props.clientRect,
            })
        },
        onKeyDown(props) {
            if (props.event.key === 'Escape') {
                dropdown.hide()
                return true
            }

            return Boolean(reactRenderer.ref?.onKeyDown(props))
        },
        onExit() {
            dropdown.destroy()
            reactRenderer.destroy()
        },
    }
}

@rfgamaral rfgamaral self-assigned this Mar 11, 2022
Copy link
Member

@frankieyan frankieyan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new hooks make a lot of sense, @rfgamaral! Let's submit the change upstream and see if we can get it merged 👍

@rfgamaral
Copy link
Member Author

Opened upstream PR: ueberdosis#2628

@rfgamaral rfgamaral closed this Mar 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
2 participants