import React, { ReactElement, useEffect, useLayoutEffect, useMemo, useState, } from 'react'; import { Box, DropdownProps, TabsProps } from '@wix/design-system'; import { Filter } from '@wix/bex-core'; import { runInAction } from 'mobx'; import { FilterContextProvider } from '../FilterContext'; import { observer } from 'mobx-react-lite'; import { TabTitle } from './TabTitle'; import { useToolbarCollectionContext } from '../ToolbarCollectionContext'; import { TabsFilterState } from './TabsFilterState'; import { TabsDropdown } from './TabsDropdown'; import { ALL_TAB_ITEM_ID, TabsFilterItemBase } from './types'; import { TabsDefault } from './TabsDefault'; import { useFilterValueTotalState } from '../TabTotal/useFilterValueTotalState'; import type { TabCounterBadgeProps } from '../TabTotal/TabTotalCounterBadge'; import type { TabTotalParensProps } from '../TabTotal/TabTotalParens'; /** Type alias for TabTotalCounterBadge component element */ type TabTotalCounterBadge = ReactElement< TabCounterBadgeProps >; /** Type alias for TabTotalParens component element */ type TabTotalParens = ReactElement>; export interface TabsFilterProps { /** * List of tabs. * @external */ data: V[]; /** * Defines the selected filter. *

* Must be an [arrayFilter](./?path=/story/features-filter-factories--arrayfilter) object. * @external */ filter: Filter; /** * Display name of the tab that indicates that all items are included. *
* Changes the value of `filter` to an empty array. * @external */ all?: string | null | false; /** * Renders a counter badge next to the tabs' texts. *

* See different examples of this implementation in the [Overview](./?path=/story/features-filter-components--tabsfilter) tab. * @external */ counterBadge?: ( value: V | null | undefined, ) => TabTotalCounterBadge | TabTotalParens | null | undefined; onChange?: (value: V | null | undefined) => unknown; /** * Tabs layout type. *

* If this prop is omitted, the width depends on the label width. The total width of all the tabs cannot exceed 80% of the toolbar. *

* Supported values:
* - `uniformFull`: Tabs are spread out uniformly. * @external */ type?: Extract; placeAllTabLast?: boolean; /** * Custom popover props for the mobile dropdown menu. On mobile devices, tabs are displayed as a dropdown menu. * @external */ mobilePopoverProps?: DropdownProps['popoverProps']; } function _TabsFilter(props: TabsFilterProps) { const { type, filter, data: dataProp, all, counterBadge, placeAllTabLast, onChange, mobilePopoverProps, } = props; const { itemKey, itemName } = filter; const table = useToolbarCollectionContext(); const filterAllValueTotal = useFilterValueTotalState({ ...props, value: undefined, }); const container = React.useRef(); const [state] = useState( () => (table.tabs ??= new TabsFilterState({ table, })), ); useLayoutEffect(() => { runInAction(() => { if (filter.persistent == null) { filter.persistent = true; } }); }, []); const { responsive } = state; const isAllCounterBadgeLoading = useMemo(() => { const allStatus = filterAllValueTotal.totalsCollection.initTask.status; const { isLoading, isIdle } = allStatus; return isLoading || isIdle; }, [filterAllValueTotal.totalsCollection.initTask.status]); const isTableLoading = useMemo(() => { const { isLoading, isIdle } = table.initTask.status; return isLoading || isIdle; }, [table.initTask.status]); const hideCounterBadge = isTableLoading || isAllCounterBadgeLoading; const selectedId = filter.isEmpty ? ALL_TAB_ITEM_ID : itemKey(filter.value[0]); const items = useMemo(() => { const _mergedItems = dataProp.map((value, index) => { const id = itemKey(value); return { id, name: itemName(value), title: ( ), value, }; }); if (!all) { return _mergedItems.map((item, index) => ({ ...item, index, minWidth: responsive.itemsMinWidths[index], maxWidth: responsive.itemMaxWidth, })); } const allTabItem = { id: ALL_TAB_ITEM_ID, name: all, title: ( ), }; return ( placeAllTabLast ? [..._mergedItems, allTabItem] : [allTabItem, ..._mergedItems] ).map((item, index) => ({ ...item, minWidth: responsive.itemsMinWidths[index], index, })); }, [ dataProp, all, counterBadge, responsive.panelMinWidth, hideCounterBadge, selectedId, ]); useEffect( () => state.init({ container: container.current, itemsCount: items.length, }), [container, state], ); return ( { if (node) { container.current = node; } }} dataHook="collection-tabs-filter" width="100%" height={60} direction="vertical" verticalAlign="middle" flexGrow={1} > {responsive.mode === 'tabs' ? ( ) : ( )} ); } export const TabsFilter = observer(_TabsFilter); TabsFilter.displayName = 'TabsFilter';