Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

Commit

Permalink
- fixed bug with dropdown not being deleted from editor;
Browse files Browse the repository at this point in the history
- fixed bug with text not being inserted when dropdown is closed;
- small refactoring of CustomPortal -> PortalAtCursorPosition
  • Loading branch information
bmdalex committed Feb 21, 2019
1 parent efb1490 commit 8ab6fa2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 29 deletions.
42 changes: 24 additions & 18 deletions docs/src/prototypes/dropdowns/MentionsWithDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import * as _ from 'lodash'
import keyboardKey from 'keyboard-key'
import { Dropdown, DropdownProps } from '@stardust-ui/react'

import { atMentionItems, AtMentionItem } from './dataMocks'
import { atMentionItems } from './dataMocks'
import { insertTextAtCursorPosition } from './utils'
import { CustomPortal } from './CustomPortal'
import { PortalAtCursorPosition } from './PortalAtCursorPosition'

interface MentionsWithDropdownState {
dropdownOpen?: boolean
Expand Down Expand Up @@ -40,7 +40,7 @@ class MentionsWithDropdown extends React.Component<{}, MentionsWithDropdownState
onKeyUp={this.handleEditorKeyUp}
style={editorStyle}
/>
<CustomPortal mountNodeId="dropdown-mount-node" open={dropdownOpen}>
<PortalAtCursorPosition open={dropdownOpen}>
<Dropdown
defaultOpen={true}
inline
Expand All @@ -51,32 +51,25 @@ class MentionsWithDropdown extends React.Component<{}, MentionsWithDropdownState
input: { autoFocus: true, size: searchQuery.length + 1 },
onInputKeyDown: this.handleInputKeyDown,
}}
onSelectedChange={this.handleSelectedChange}
onOpenChange={this.handleOpenChange}
onSearchQueryChange={this.handleSearchQueryChange}
noResultsMessage="We couldn't find any matches."
/>
</CustomPortal>
</PortalAtCursorPosition>
</>
)
}

private hideDropdownAndRestoreEditor = (cb?: () => void) => {
this.setState(this.initialState, () => {
this.tryFocusEditor()
cb && cb()
})
}

private handleEditorKeyUp = (e: React.KeyboardEvent) => {
if (!this.state.dropdownOpen && keyboardKey.getCode(e) === keyboardKey.AtSign) {
this.setState({ dropdownOpen: true })
}
}

private handleSelectedChange = (e: React.SyntheticEvent, { value }: DropdownProps) => {
this.hideDropdownAndRestoreEditor(() => {
insertTextAtCursorPosition((value as AtMentionItem).header)
})
private handleOpenChange = (e: React.SyntheticEvent, { open }: DropdownProps) => {
if (!open) {
this.resetStateAndUpdateEditor()
}
}

private handleSearchQueryChange = (e: React.SyntheticEvent, { searchQuery }: DropdownProps) => {
Expand All @@ -88,15 +81,28 @@ class MentionsWithDropdown extends React.Component<{}, MentionsWithDropdownState
switch (keyCode) {
case keyboardKey.Backspace: // 8
if (this.state.searchQuery === '') {
this.hideDropdownAndRestoreEditor()
this.resetStateAndUpdateEditor()
}
break
case keyboardKey.Escape: // 27
this.hideDropdownAndRestoreEditor()
this.resetStateAndUpdateEditor()
break
}
}

private resetStateAndUpdateEditor = () => {
const { searchQuery, dropdownOpen } = this.state

if (dropdownOpen) {
this.setState(this.initialState, () => {
this.tryFocusEditor()

// after the dropdown is closed the value of the search query is inserted in the editor at cursor position
insertTextAtCursorPosition(searchQuery)
})
}
}

private tryFocusEditor = () => _.invoke(this.contendEditableRef.current, 'focus')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@ import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { insertSpanAtCursorPosition, removeElement } from './utils'

export interface CustomPortalProps {
export interface PortalAtCursorPositionProps {
mountNodeId: string
open?: boolean
}

export class CustomPortal extends React.Component<CustomPortalProps, {}> {
export class PortalAtCursorPosition extends React.Component<PortalAtCursorPositionProps> {
private mountNodeInstance: HTMLElement = null

public render() {
this.setupMountNode()
return this.props.open && this.mountNodeInstance
? ReactDOM.createPortal(this.props.children, this.mountNodeInstance)
: null
static defaultProps = {
mountNodeId: 'portal-at-cursor-position',
}

public componentWillUnmount() {
this.removeMountNode()
}

public render() {
const { children, open } = this.props

this.setupMountNode()
return open && this.mountNodeInstance
? ReactDOM.createPortal(children, this.mountNodeInstance)
: null
}

private setupMountNode = () => {
if (this.props.open) {
this.mountNodeInstance =
this.mountNodeInstance || insertSpanAtCursorPosition(this.props.mountNodeId)
const { mountNodeId, open } = this.props

if (open) {
this.mountNodeInstance = this.mountNodeInstance || insertSpanAtCursorPosition(mountNodeId)
} else {
this.removeMountNode()
}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/prototypes/dropdowns/dataMocks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as _ from 'lodash'
import { name, internet } from 'faker'

export interface AtMentionItem {
interface AtMentionItem {
header: string
image: string
content: string
Expand Down

0 comments on commit 8ab6fa2

Please sign in to comment.