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
Development

Successfully merging this pull request may close these issues.

2 participants