Skip to content

Commit

Permalink
create reusable component
Browse files Browse the repository at this point in the history
  • Loading branch information
mxkae committed Sep 18, 2024
1 parent 1097e04 commit 0dfe241
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 176 deletions.
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,4 @@ export { default as ColumnsWidthMultiControl } from './columns-width-multi-contr
export { default as Popover } from './popover'
export { default as HelpTooltip } from './help-tooltip'
export { default as RichText } from './rich-text'
export { default as SortablePicker } from './sortable-picker'
225 changes: 225 additions & 0 deletions src/components/sortable-picker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/**
* External dependencies
*/
import classnames from 'classnames'
import { Button } from '~stackable/components'
import {
sortableContainer, sortableElement, sortableHandle,
} from 'react-sortable-hoc'

/**
* WordPress dependencies
*/
import {
ColorPicker,
BaseControl,
ColorIndicator,
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalHStack as HStack,
Dashicon,
Dropdown,
} from '@wordpress/components'
import { useState } from '@wordpress/element'
import { __ } from '@wordpress/i18n'
import { applyFilters } from '@wordpress/hooks'

const popoverProps = {
placement: 'left-start',
offset: 36,
shift: true,
}

// We need to define these because 13 (return key) is not included in the
// default keyCodes to initiate a drag.
const DRAG_KEYCODES = {
lift: [ 32, 13 ],
drop: [ 32, 13 ],
cancel: [ 27 ],
up: [ 38, 37 ],
down: [ 40, 39 ],
}

const SortablePicker = props => {
const {
items,
itemType,
dropdownOnAdd = false,
onChangeItem,
onDeleteItem,
handleAddItem,
onSortEnd,
AddItemPopover = null,
ref,
} = props
const [ isSorting, setIsSorting ] = useState( false )

const classNames = classnames(
'ugb-global-settings-color-picker',
'components-circular-option-picker',
'editor-color-palette-control__color-palette',
props.className
)

return (
<BaseControl className={ classNames } label={ props.label }>
<Dropdown
renderToggle={ ( { onToggle, isOpen } ) => (
<Button
className="ugb-global-settings-color-picker__add-button"
onClick={ dropdownOnAdd ? onToggle : handleAddItem }
icon="plus-alt2"
aria-expanded={ isOpen }
/>
) }
renderContent={ ( { onClose } ) => (
<AddItemPopover onClose={ onClose } onChange={ handleAddItem } />
) }
/>
<div
ref={ ref }
className={ classnames(
'ugb-global-settings-color-picker__color-indicators',
{ 'is-sorting': isSorting }
) }
>
<SortableContainer
items={ items }
onSortStart={ () => setIsSorting( true ) }
onSortEnd={ ( { oldIndex, newIndex } ) => onSortEnd( {
oldIndex, newIndex, setIsSorting,
} ) }
axis="y"
useDragHandle
keyCodes={ DRAG_KEYCODES }
>
{ items.map( ( item, i ) => (
<SortableItem
key={ i }
index={ i }
item={ item }
onDelete={ () => onDeleteItem( item ) }
onChange={ item => onChangeItem( item ) }
itemType={ itemType }
/> ) ) }
</SortableContainer>
</div>
</BaseControl>
)
}

SortablePicker.defaultProps = {
className: '',
label: '',
onReset: () => {},
}

export default SortablePicker

const SortableItem = sortableElement( props => <LabeledItemIndicator { ...props } /> )

const SortableContainer = sortableContainer( ( { children } ) => {
return <div>{ children }</div>
} )

const DragHandle = sortableHandle( () => <Dashicon
icon="menu"
size="16"
tabIndex="0"
/> )

const LabeledItemIndicator = props => {
const {
item,
onDelete,
onChange,
itemType,
} = props

const [ isFocused, setIsFocused ] = useState( false )

return (
<HStack justify="space-between" className="stk-global-settings-color-picker__color-indicator-wrapper">
<Dropdown
popoverProps={ popoverProps }
// This is so that when we click on the label to edit it, the input doesn't lose focus.
focusOnMount={ ! isFocused ? 'firstElement' : false }
renderToggle={ ( { onToggle, isOpen } ) => {
return (
<Button
className="block-editor-panel-color-gradient-settings__dropdown"
onClick={ () => {
if ( ! isFocused ) {
onToggle()
}
} }
isPressed={ isOpen }
>
<HStack justify="flex-start">
{ itemType === 'color' &&
<ColorIndicator
className="stk-color-indicator block-editor-panel-color-gradient-settings__color-indicator"
colorValue={ item.color }
/> }
{ itemType === 'icon' && <p> Icon </p> }
<input
className="components-input-control__input"
value={ item.name }
onChange={ ev => {
onChange( {
...item,
name: ev.target.value,
} )
} }
onFocus={ () => setIsFocused( true ) }
onBlur={ ev => {
setIsFocused( false )
if ( isOpen && ! ev.relatedTarget?.closest( '.components-popover' ) ) {
onToggle()
}
} }
onClick={ () => {
if ( ! isOpen ) {
onToggle()
}
} }
onKeyDown={ ev => {
// On enter, blur the input.
if ( ev.keyCode === 13 ) {
ev.target.blur()
}
} }
/>
<DragHandle />
</HStack>
</Button>
)
} }
renderContent={ () => (
<div className="stk-color-palette-control__popover-content">
{ itemType === 'color' &&
<ColorPicker
onChange={ value => onChange( {
...item,
color: value,
} ) }
color={ item.color }
enableAlpha={ true }
/>
}
{ itemType === 'icon' && <>
<p>hello</p>
{ applyFilters( 'stackable.global-settings.inspector.icon-library.icon-picker', null ) }
</> }
</div>
) }
/>
<Button
className="stk-global-settings-color-picker__delete-button"
icon="trash"
isSmall
isTertiary
onClick={ onDelete }
/>
</HStack>
)
}
Loading

0 comments on commit 0dfe241

Please sign in to comment.