Skip to content

Commit

Permalink
Merge branch 'prerelease/minor' of github.com:Workday/canvas-kit into…
Browse files Browse the repository at this point in the history
… feat/add-removable-support
  • Loading branch information
NicholasBoll committed Nov 6, 2024
2 parents 26b229a + b0122ce commit 5c77e25
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 79 deletions.
8 changes: 6 additions & 2 deletions modules/react/collection/lib/useOverflowListItemMeasure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,21 @@ export const useOverflowListItemMeasure = createElemPropsHook(useOverflowListMod
useMountLayout(() => {
if (localRef.current) {
const styles = getComputedStyle(localRef.current);
model.events.addItemWidth({
model.events.addItemSize({
id: name,
width:
localRef.current.offsetWidth +
parseFloat(styles.marginLeft) +
parseFloat(styles.marginRight),
height:
localRef.current.offsetHeight +
parseFloat(styles.marginTop) +
parseFloat(styles.marginBottom),
});
}

return () => {
model.events.removeItemWidth({id: name});
model.events.removeItemSize({id: name});
};
});

Expand Down
2 changes: 1 addition & 1 deletion modules/react/collection/lib/useOverflowListMeasure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const useOverflowListMeasure = createElemPropsHook(useOverflowListModel)(

useResizeObserver({
ref: localRef,
onResize: model.events.setContainerWidth,
onResize: model.events.setContainerSize,
});
useMountLayout(() => {
if (localRef.current) {
Expand Down
141 changes: 90 additions & 51 deletions modules/react/collection/lib/useOverflowListModel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import {useSelectionListModel} from './useSelectionListModel';
import {Item} from './useBaseListModel';

export function getHiddenIds(
containerWidth: number,
containerSize: number,
containerGap: number,
overflowTargetWidth: number,
itemWidthCache: Record<string, number>,
overflowTargetSize: number,
itemSizeCache: Record<string, number>,
selectedIds: string[] | 'all',
items: Item<any>[]
): string[] {
/** Allows us to prioritize showing the selected item */
let selectedKey: undefined | string;
/** Tally of combined item widths. We'll add items that fit until the container is full */
let itemWidth = 0;
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: string[] = [];
Expand All @@ -31,31 +31,31 @@ export function getHiddenIds(
}

if (
Object.keys(itemWidthCache).reduce(
(sum, key, index) => sum + itemWidthCache[key] + (index > 0 ? containerGap : 0),
Object.keys(itemSizeCache).reduce(
(sum, key, index) => sum + itemSizeCache[key] + (index > 0 ? containerGap : 0),
0
) <= containerWidth
) <= containerSize
) {
// All items fit, return empty array
return [];
} else if (selectedKey) {
if (itemWidthCache[selectedKey] + overflowTargetWidth > containerWidth) {
if (itemSizeCache[selectedKey] + overflowTargetSize > containerSize) {
// If the selected item doesn't fit, only show overflow (all items hidden)
return Object.keys(itemWidthCache);
return Object.keys(itemSizeCache);
} else {
// at least the selected item and overflow target fit. Update our itemWidth with the sum
itemWidth += itemWidthCache[selectedKey] + overflowTargetWidth;
itemSize += itemSizeCache[selectedKey] + overflowTargetSize;
shouldAddGap = true;
}
} else {
itemWidth += overflowTargetWidth;
itemSize += overflowTargetSize;
}

for (const key in itemWidthCache) {
for (const key in itemSizeCache) {
if (key !== selectedKey) {
itemWidth += itemWidthCache[key] + (shouldAddGap ? containerGap : 0);
itemSize += itemSizeCache[key] + (shouldAddGap ? containerGap : 0);
shouldAddGap = true;
if (itemWidth > containerWidth) {
if (itemSize > containerSize) {
hiddenIds.push(key);
}
}
Expand All @@ -81,13 +81,13 @@ export const useOverflowListModel = createModelHook({
const shouldCalculateOverflow =
config.shouldCalculateOverflow === undefined ? true : config.shouldCalculateOverflow;
const [hiddenIds, setHiddenIds] = React.useState(config.initialHiddenIds);
const [itemWidthCache, setItemWidthCache] = React.useState<Record<string, number>>({});
const [containerWidth, setContainerWidth] = React.useState(0);
const [itemSizeCache, setItemSizeCache] = React.useState<Record<string, number>>({});
const [containerSize, setContainerSize] = React.useState(0);
const [containerGap, setContainerGap] = React.useState(0);
const containerWidthRef = React.useRef(0);
const itemWidthCacheRef = React.useRef(itemWidthCache);
const containerSizeRef = React.useRef(0);
const itemSizeCacheRef = React.useRef(itemSizeCache);
const [overflowTargetWidth, setOverflowTargetWidth] = React.useState(0);
const overflowTargetWidthRef = React.useRef(0);
const overflowTargetSizeRef = React.useRef(0);

const internalHiddenIds = shouldCalculateOverflow ? hiddenIds : [];

Expand All @@ -103,8 +103,16 @@ export const useOverflowListModel = createModelHook({
const state = {
...model.state,
hiddenIds: internalHiddenIds,
itemWidthCache,
containerWidth,
itemSizeCache,
/**
* @deprecated Use `itemSizeCache` instead
*/
itemWidthCache: itemSizeCache,
containerSize,
/**
* @deprecated Use `containerSize` instead
*/
containerWidth: containerSize,
containerGap,
overflowTargetWidth,
};
Expand All @@ -114,80 +122,104 @@ export const useOverflowListModel = createModelHook({
select(data: Parameters<typeof model.events.select>[0]) {
const {selectedIds} = model.selection.select(data.id, state);
const ids = getHiddenIds(
containerWidthRef.current,
containerSizeRef.current,
containerGap,
overflowTargetWidthRef.current,
itemWidthCacheRef.current,
overflowTargetSizeRef.current,
itemSizeCacheRef.current,
selectedIds,
config.items
);
model.events.select(data);

setHiddenIds(ids);
},
setContainerWidth(data: {width?: number}) {
containerWidthRef.current = data.width || 0;
setContainerWidth(data.width || 0);

setContainerSize(data: {width?: number; height?: number}) {
containerSizeRef.current =
model.state.orientation === 'horizontal' ? data.width || 0 : data.height || 0;
setContainerSize(containerSizeRef.current);
const ids = getHiddenIds(
containerWidthRef.current,
containerSizeRef.current,
containerGap,
overflowTargetWidthRef.current,
itemWidthCacheRef.current,
overflowTargetSizeRef.current,
itemSizeCacheRef.current,
state.selectedIds,
config.items
);

setHiddenIds(ids);
},
/**
* @deprecated Use `setContainerSize` instead and pass both `width` and `height`
*/
setContainerWidth(data: {width?: number}) {
events.setContainerSize({width: data.width, height: 0});
},
setContainerGap(data: {size: number}) {
setContainerGap(data.size);

const ids = getHiddenIds(
containerWidthRef.current,
containerSizeRef.current,
data.size,
overflowTargetWidthRef.current,
itemWidthCacheRef.current,
overflowTargetSizeRef.current,
itemSizeCacheRef.current,
state.selectedIds,
config.items
);

setHiddenIds(ids);
},
setOverflowTargetSize(data: {width: number; height: number}) {
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: {width: number}) {
overflowTargetWidthRef.current = data.width;
setOverflowTargetWidth(data.width);
overflowTargetSizeRef.current = data.width;
events.setOverflowTargetSize({width: overflowTargetSizeRef.current, height: 0});
},

/**
*
* @deprecated `addItemWidth` is deprecated. Please use `addItemSize` and set the `width`
*/
addItemWidth(data: {id: string; width: number}) {
itemWidthCacheRef.current = {
...itemWidthCacheRef.current,
[data.id]: data.width,
events.addItemSize({id: data.id, width: data.width, height: 0});
},
addItemSize(data: {id: string; width: number; height: number}) {
itemSizeCacheRef.current = {
...itemSizeCacheRef.current,
[data.id]: model.state.orientation === 'horizontal' ? data.width : data.height,
};

setItemWidthCache(itemWidthCacheRef.current);

setItemSizeCache(itemSizeCacheRef.current);

const ids = getHiddenIds(
containerWidthRef.current,
containerSizeRef.current,
containerGap,
overflowTargetWidthRef.current,
itemWidthCacheRef.current,
overflowTargetSizeRef.current,
itemSizeCacheRef.current,
state.selectedIds,
config.items
);

setHiddenIds(ids);
},
removeItemWidth(data: {id: string}) {
const newCache = {...itemWidthCacheRef.current};
removeItemSize(data: {id: string}) {
const newCache = {...itemSizeCacheRef.current};
delete newCache[data.id];
itemWidthCacheRef.current = newCache;
setItemWidthCache(itemWidthCacheRef.current);
itemSizeCacheRef.current = newCache;
setItemSizeCache(itemSizeCacheRef.current);

const ids = getHiddenIds(
containerWidthRef.current,
containerSizeRef.current,
containerGap,
overflowTargetWidthRef.current,
itemWidthCacheRef.current,
overflowTargetSizeRef.current,
itemSizeCacheRef.current,
state.selectedIds !== 'all'
? state.selectedIds.filter(sId => data.id !== sId)
: state.selectedIds,
Expand All @@ -196,6 +228,13 @@ export const useOverflowListModel = createModelHook({

setHiddenIds(ids);
},
/**
*
* @deprecated `removeItemWidth` is deprecated. Please use `removeItemSize`.
*/
removeItemWidth(data: {id: string}) {
events.removeItemSize({id: data.id});
},
addHiddenKey(data: {id: string}) {
setHiddenIds(ids => ids.concat(data.id));
},
Expand Down
6 changes: 5 additions & 1 deletion modules/react/collection/lib/useOverflowListTarget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ export const useOverflowListTarget = createElemPropsHook(useOverflowListModel)((
if (localRef.current) {
const styles = getComputedStyle(localRef.current);

model.events.setOverflowTargetWidth({
model.events.setOverflowTargetSize({
width:
localRef.current.offsetWidth +
parseFloat(styles.marginLeft) +
parseFloat(styles.marginRight),
height:
localRef.current.offsetWidth +
parseFloat(styles.marginTop) +
parseFloat(styles.marginBottom),
});
}
});
Expand Down
Loading

0 comments on commit 5c77e25

Please sign in to comment.