UNPKG

@workday/canvas-kit-react

Version:

The parent module that contains all Workday Canvas Kit React components

185 lines (184 loc) • 8.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useOverflowListModel = exports.getHiddenIds = void 0; const react_1 = __importDefault(require("react")); const common_1 = require("@workday/canvas-kit-react/common"); const useSelectionListModel_1 = require("./useSelectionListModel"); function getHiddenIds(containerSize, containerGap, overflowTargetSize, itemSizeCache, selectedIds, items) { /** Allows us to prioritize showing the selected item */ let selectedKey; /** Tally of combined item widths. We'll add items that fit until the container is full */ let itemSize = 0; /** Tally ids that won't fit inside the container. These will be used by components to hide * elements that won't fit in the container */ const hiddenIds = []; /** Track if gap should be calculated since gap doesn't apply to the width of the first item, only * consecutive items */ let shouldAddGap = false; if (selectedIds !== 'all' && selectedIds.length) { if (items.length) { // If selectedIds[0] is not in items, use the first id from items selectedKey = items.find(item => item.id === selectedIds[0]) ? selectedIds[0] : items[0].id; } } if (Object.keys(itemSizeCache).reduce((sum, key, index) => sum + itemSizeCache[key] + (index > 0 ? containerGap : 0), 0) <= containerSize) { // All items fit, return empty array return []; } else if (selectedKey) { if (itemSizeCache[selectedKey] + overflowTargetSize > containerSize) { // If the selected item doesn't fit, only show overflow (all items hidden) return Object.keys(itemSizeCache); } else { // at least the selected item and overflow target fit. Update our itemWidth with the sum itemSize += itemSizeCache[selectedKey] + overflowTargetSize; shouldAddGap = true; } } else { itemSize += overflowTargetSize; } for (const key in itemSizeCache) { if (key !== selectedKey) { itemSize += itemSizeCache[key] + (shouldAddGap ? containerGap : 0); shouldAddGap = true; if (itemSize > containerSize) { hiddenIds.push(key); } } } return hiddenIds; } exports.getHiddenIds = getHiddenIds; exports.useOverflowListModel = (0, common_1.createModelHook)({ defaultConfig: { ...useSelectionListModel_1.useSelectionListModel.defaultConfig, initialHiddenIds: [], containerWidth: 0, /** * Determines if overflow should actually occur. For example, touch devices are better at * side-scrolling than mouse devices. In these cases, it makes sense to disable overflowing. * @default true */ shouldCalculateOverflow: true, }, requiredConfig: useSelectionListModel_1.useSelectionListModel.requiredConfig, contextOverride: useSelectionListModel_1.useSelectionListModel.Context, })(config => { const shouldCalculateOverflow = config.shouldCalculateOverflow === undefined ? true : config.shouldCalculateOverflow; const [hiddenIds, setHiddenIds] = react_1.default.useState(config.initialHiddenIds); const [itemSizeCache, setItemSizeCache] = react_1.default.useState({}); const [containerSize, setContainerSize] = react_1.default.useState(0); const [containerGap, setContainerGap] = react_1.default.useState(0); const containerSizeRef = react_1.default.useRef(0); const itemSizeCacheRef = react_1.default.useRef(itemSizeCache); const [overflowTargetWidth, setOverflowTargetWidth] = react_1.default.useState(0); const overflowTargetSizeRef = react_1.default.useRef(0); const internalHiddenIds = shouldCalculateOverflow ? hiddenIds : []; // Cursors skip over disabled ids, but know nothing of hidden ids. We'll go ahead and disable // hidden ids as well const nonInteractiveIds = (config.nonInteractiveIds || []).concat(internalHiddenIds); const model = (0, useSelectionListModel_1.useSelectionListModel)({ ...config, nonInteractiveIds, }); const state = { ...model.state, hiddenIds: internalHiddenIds, itemSizeCache, /** * @deprecated Use `itemSizeCache` instead */ itemWidthCache: itemSizeCache, containerSize, /** * @deprecated Use `containerSize` instead */ containerWidth: containerSize, containerGap, overflowTargetWidth, }; const events = { ...model.events, select(data) { const { selectedIds } = model.selection.select(data.id, state); const ids = getHiddenIds(containerSizeRef.current, containerGap, overflowTargetSizeRef.current, itemSizeCacheRef.current, selectedIds, config.items); model.events.select(data); setHiddenIds(ids); }, setContainerSize(data) { containerSizeRef.current = model.state.orientation === 'horizontal' ? data.width || 0 : data.height || 0; setContainerSize(containerSizeRef.current); const ids = getHiddenIds(containerSizeRef.current, containerGap, overflowTargetSizeRef.current, itemSizeCacheRef.current, state.selectedIds, config.items); setHiddenIds(ids); }, /** * @deprecated Use `setContainerSize` instead and pass both `width` and `height` */ setContainerWidth(data) { events.setContainerSize({ width: data.width, height: 0 }); }, setContainerGap(data) { setContainerGap(data.size); const ids = getHiddenIds(containerSizeRef.current, data.size, overflowTargetSizeRef.current, itemSizeCacheRef.current, state.selectedIds, config.items); setHiddenIds(ids); }, setOverflowTargetSize(data) { overflowTargetSizeRef.current = model.state.orientation === 'horizontal' ? data.width || 0 : data.height || 0; setOverflowTargetWidth(overflowTargetSizeRef.current); }, /** * * @deprecated `setOverflowTargetWidth` is deprecated. Please use `setOverflowTargetSize` and pass in the `width` and set `height` to `0`. */ setOverflowTargetWidth(data) { overflowTargetSizeRef.current = data.width; events.setOverflowTargetSize({ width: overflowTargetSizeRef.current, height: 0 }); }, /** * * @deprecated `addItemWidth` is deprecated. Please use `addItemSize` and set the `width` */ addItemWidth(data) { events.addItemSize({ id: data.id, width: data.width, height: 0 }); }, addItemSize(data) { itemSizeCacheRef.current = { ...itemSizeCacheRef.current, [data.id]: model.state.orientation === 'horizontal' ? data.width : data.height, }; setItemSizeCache(itemSizeCacheRef.current); const ids = getHiddenIds(containerSizeRef.current, containerGap, overflowTargetSizeRef.current, itemSizeCacheRef.current, state.selectedIds, config.items); setHiddenIds(ids); }, removeItemSize(data) { const newCache = { ...itemSizeCacheRef.current }; delete newCache[data.id]; itemSizeCacheRef.current = newCache; setItemSizeCache(itemSizeCacheRef.current); const ids = getHiddenIds(containerSizeRef.current, containerGap, overflowTargetSizeRef.current, itemSizeCacheRef.current, state.selectedIds !== 'all' ? state.selectedIds.filter(sId => data.id !== sId) : state.selectedIds, config.items); setHiddenIds(ids); }, /** * * @deprecated `removeItemWidth` is deprecated. Please use `removeItemSize`. */ removeItemWidth(data) { events.removeItemSize({ id: data.id }); }, addHiddenKey(data) { setHiddenIds(ids => ids.concat(data.id)); }, removeHiddenKey(data) { setHiddenIds(ids => ids.filter(key => key !== data.id)); }, }; return { ...model, state, events }; });