|
|
|
@ -1,10 +1,10 @@
|
|
|
|
|
import { Spinner, DeferredRender, Icon, FilterInput, HelpMessage, __TabBar, StickyElement } from '@vizality/components';
|
|
|
|
|
import { useForceUpdate, usePreviousProps, useFilter } from '@vizality/hooks';
|
|
|
|
|
import { Spinner, DeferredRender, Icon, FilterInput, HelpMessage, __TabBar, StickyElement, Popout } from '@vizality/components';
|
|
|
|
|
import { useForceUpdate, usePreviousProps, useFilter, useToggle } from '@vizality/hooks';
|
|
|
|
|
import { toPlural, toTitleCase } from '@vizality/util/string';
|
|
|
|
|
import React, { memo, useState, useEffect } from 'react';
|
|
|
|
|
import { unstable_batchedUpdates } from 'react-dom';
|
|
|
|
|
import { joinClassNames } from '@vizality/util/dom';
|
|
|
|
|
import { getModule } from '@vizality/webpack';
|
|
|
|
|
import { getModule, getModuleByDisplayName } from '@vizality/webpack';
|
|
|
|
|
import { error } from '@vizality/util/logger';
|
|
|
|
|
import { Events } from '@vizality/constants';
|
|
|
|
|
import { useRouteMatch } from 'react-router';
|
|
|
|
@ -122,7 +122,10 @@ const ContentBody = memo(({ community, display, filteredResults, type, limit, re
|
|
|
|
|
*/
|
|
|
|
|
const StickyBar = memo(({ query, type, tab, resetSearchOptions, handleTabChange, display, handleQueryChange, handleDisplayChange }) => {
|
|
|
|
|
const [ sticky, setSticky ] = useState(false);
|
|
|
|
|
const PopoutDispatcher = getModule('openPopout');
|
|
|
|
|
const [ showSortFilterMenu, toggleSortFilterMenu ] = useToggle(false);
|
|
|
|
|
const [ showTagsMenu, toggleTagsMenu ] = useToggle(false);
|
|
|
|
|
const [ showDisplayMenu, toggleDisplayMenu ] = useToggle(false);
|
|
|
|
|
const [ showOverflowMenu, toggleOverflowMenu ] = useToggle(false);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Formats a display type string into one matching its corresponding icon name.
|
|
|
|
@ -137,68 +140,8 @@ const StickyBar = memo(({ query, type, tab, resetSearchOptions, handleTabChange,
|
|
|
|
|
* Configuration for the popouts used in this component.
|
|
|
|
|
*/
|
|
|
|
|
const popoutConfig = {
|
|
|
|
|
animationType: 0,
|
|
|
|
|
closeOnScroll: false,
|
|
|
|
|
shadow: false,
|
|
|
|
|
position: 'bottom'
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders the Sort and Filter context menu / popout.
|
|
|
|
|
* @param {document#event:mousedown} evt Mousedown event
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const renderSortFilterMenu = evt => {
|
|
|
|
|
PopoutDispatcher.openPopout(evt.target, {
|
|
|
|
|
'vz-popout': 'vz-addons-list-sort-filter-menu',
|
|
|
|
|
render: ({ onClose }) => <SortFilterMenu onClose={onClose} />,
|
|
|
|
|
...popoutConfig
|
|
|
|
|
}, 'vz-addons-list-sort-filter-menu');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders the Tags context menu / popout.
|
|
|
|
|
* @param {document#event:mousedown} evt Mousedown event
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const renderTagsMenu = evt => {
|
|
|
|
|
PopoutDispatcher.openPopout(evt.target, {
|
|
|
|
|
'vz-popout': 'vz-addons-list-tags-menu',
|
|
|
|
|
render: ({ onClose }) => <TagsMenu onClose={onClose} type={type} />,
|
|
|
|
|
...popoutConfig
|
|
|
|
|
}, 'vz-addons-list-tags-menu');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders the Display options context menu / popout.
|
|
|
|
|
* @param {document#event:mousedown} evt Mousedown event
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const renderDisplayMenu = evt => {
|
|
|
|
|
PopoutDispatcher.openPopout(evt.target, {
|
|
|
|
|
'vz-popout': 'vz-addons-list-display-menu',
|
|
|
|
|
render: ({ onClose }) => (
|
|
|
|
|
<DisplayMenu
|
|
|
|
|
onClose={onClose}
|
|
|
|
|
handleDisplayChange={handleDisplayChange}
|
|
|
|
|
display={display}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
...popoutConfig
|
|
|
|
|
}, 'vz-addons-list-display-menu');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Renders the More context menu / popout.
|
|
|
|
|
* @param {document#event:mousedown} evt Mousedown event
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const renderOverflowMenu = evt => {
|
|
|
|
|
PopoutDispatcher.openPopout(evt.target, {
|
|
|
|
|
'vz-popout': 'vz-addons-list-overflow-menu',
|
|
|
|
|
render: ({ onClose }) => <OverflowMenu onClose={onClose} type={type} resetSearchOptions={resetSearchOptions} />,
|
|
|
|
|
...popoutConfig
|
|
|
|
|
}, 'vz-addons-list-overflow-menu');
|
|
|
|
|
position: 'left',
|
|
|
|
|
animation: '2'
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
@ -235,37 +178,57 @@ const StickyBar = memo(({ query, type, tab, resetSearchOptions, handleTabChange,
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='vz-addons-list-filter-button vz-addons-list-search-options-button'>
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip={`Sort & Filter`}
|
|
|
|
|
size='20'
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
name='FilterAlt'
|
|
|
|
|
onClick={renderSortFilterMenu}
|
|
|
|
|
/>
|
|
|
|
|
<Popout renderPopout={props => <SortFilterMenu {...props} />} {...popoutConfig} shouldShow={showSortFilterMenu} onRequestClose={toggleSortFilterMenu}>
|
|
|
|
|
{props => (
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip={`Sort & Filter`}
|
|
|
|
|
size='20'
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
name='FilterAlt'
|
|
|
|
|
onClick={toggleSortFilterMenu}
|
|
|
|
|
popoutProps={props}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Popout>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='vz-addons-list-tags-button vz-addons-list-search-options-button'>
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip='Tags'
|
|
|
|
|
name='StoreTag'
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
onClick={renderTagsMenu}
|
|
|
|
|
/>
|
|
|
|
|
<Popout renderPopout={props => <TagsMenu type={type} {...props} />} {...popoutConfig} shouldShow={showTagsMenu} onRequestClose={toggleTagsMenu}>
|
|
|
|
|
{props => (
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip='Tags'
|
|
|
|
|
name='StoreTag'
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
onClick={toggleTagsMenu}
|
|
|
|
|
popoutProps={props}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Popout>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='vz-addons-list-display-button vz-addons-list-search-options-button'>
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip='Display'
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
name={formatDisplayIconName(display)}
|
|
|
|
|
onClick={renderDisplayMenu}
|
|
|
|
|
/>
|
|
|
|
|
<Popout renderPopout={props => <DisplayMenu handleDisplayChange={handleDisplayChange} display={display} {...props} />} {...popoutConfig} shouldShow={showDisplayMenu} onRequestClose={toggleDisplayMenu}>
|
|
|
|
|
{props => (
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip='Display'
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
name={formatDisplayIconName(display)}
|
|
|
|
|
onClick={toggleDisplayMenu}
|
|
|
|
|
popoutProps={props}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Popout>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='vz-addons-list-more-button vz-addons-list-search-options-button'>
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip={Messages.MORE}
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
name='OverflowMenu'
|
|
|
|
|
onClick={renderOverflowMenu}
|
|
|
|
|
/>
|
|
|
|
|
<Popout renderPopout={props => <OverflowMenu type={type} resetSearchOptions={resetSearchOptions} {...props} />} {...popoutConfig} shouldShow={showOverflowMenu} onRequestClose={toggleOverflowMenu}>
|
|
|
|
|
{props => (
|
|
|
|
|
<Icon
|
|
|
|
|
tooltip={Messages.MORE}
|
|
|
|
|
tooltipPosition={sticky ? 'bottom' : 'top'}
|
|
|
|
|
name='OverflowMenu'
|
|
|
|
|
onClick={toggleOverflowMenu}
|
|
|
|
|
popoutProps={props}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Popout>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</StickyElement>
|
|
|
|
@ -335,6 +298,7 @@ export default memo(({ source, type, tab, search, display, limit, className, com
|
|
|
|
|
*
|
|
|
|
|
* Handles tab changes.
|
|
|
|
|
* @param {string} tab Content tab
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const handleTabChange = tab => unstable_batchedUpdates(() => {
|
|
|
|
|
try {
|
|
|
|
@ -349,9 +313,10 @@ export default memo(({ source, type, tab, search, display, limit, className, com
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
/**
|
|
|
|
|
* Including these in this component so we can forceUpdate the switches.
|
|
|
|
|
* There's probably a better way to do it.
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
const resetSearchOptions = () => {
|
|
|
|
|
return setQuery('');
|
|
|
|
|