Skip to content

Commit

Permalink
Section heights in scroll position (#1935)
Browse files Browse the repository at this point in the history
  • Loading branch information
bmingles committed Apr 18, 2024
1 parent f541b3e commit 36fe15d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 15 deletions.
18 changes: 16 additions & 2 deletions packages/code-studio/src/styleguide/Pickers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,19 @@ import { Icon } from '@adobe/react-spectrum';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { getPositionOfSelectedItem } from '@deephaven/react-hooks';
import { PICKER_ITEM_HEIGHTS, PICKER_TOP_OFFSET } from '@deephaven/utils';
import { generateNormalizedItems, sampleSectionIdAndClasses } from './utils';
import {
generateItemElements,
generateNormalizedItems,
sampleSectionIdAndClasses,
} from './utils';

// Generate enough items to require scrolling
const items = [...generateNormalizedItems(52)];
const itemElementsA = [...generateItemElements(0, 51)];
const itemElementsB = [...generateItemElements(52, 103)];
const itemElementsC = [...generateItemElements(104, 155)];
const itemElementsD = [...generateItemElements(156, 207)];
const itemElementsE = [...generateItemElements(208, 259)];

function PersonIcon(): JSX.Element {
return (
Expand Down Expand Up @@ -79,7 +88,7 @@ export function Pickers(): JSX.Element {
{'String 1'}
{'String 2'}
{'String 3'}
<Section title="Section A">
<Section title="Section">
<Item textValue="Item Aaa">Item Aaa</Item>
<Item textValue="Item Bbb">Item Bbb</Item>
<Item textValue="Complex Ccc">
Expand All @@ -105,6 +114,11 @@ export function Pickers(): JSX.Element {
<Text slot="description">Description that causes overflow</Text>
</Item>
</Section>
<Section title="Section A">{itemElementsA}</Section>
<Section title="Section B">{itemElementsB}</Section>
<Section key="Section C">{itemElementsC}</Section>
<Section key="Section D">{itemElementsD}</Section>
<Section title="Section E">{itemElementsE}</Section>
</Picker>

<PickerNormalized
Expand Down
33 changes: 31 additions & 2 deletions packages/code-studio/src/styleguide/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
import cl from 'classnames';
import { useCallback, useState } from 'react';
import { NormalizedItem } from '@deephaven/components';
import { createElement, useCallback, useState } from 'react';
import { Item, ItemElement, NormalizedItem } from '@deephaven/components';

export const HIDE_FROM_E2E_TESTS_CLASS = 'hide-from-e2e-tests';
export const SAMPLE_SECTION_CLASS = 'sample-section';

/**
* Generate a given number of `Item` elements.
*/
export function* generateItemElements(
start: number,
end: number
): Generator<ItemElement> {
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const len = letters.length;

for (let i = start; i <= end; i += 1) {
const charI = i % len;
let suffix = String(Math.floor(i / len));
if (suffix === '0') {
suffix = '';
}
const letter = letters[charI];
const key = `${letter}${suffix}`;
const content = `${letter}${letter}${letter}${suffix}`;

// eslint-disable-next-line react/no-children-prop
yield createElement(Item, {
key,
textValue: content,
children: content,
});
}
}

/**
* Generate a given number of NormalizedItems.
* @param count The number of items to generate
Expand Down
5 changes: 4 additions & 1 deletion packages/components/src/spectrum/picker/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import cl from 'classnames';
import {
EMPTY_FUNCTION,
PICKER_ITEM_HEIGHTS,
PICKER_SECTION_HEIGHTS,
PICKER_TOP_OFFSET,
} from '@deephaven/utils';
import {
Expand Down Expand Up @@ -92,9 +93,11 @@ export function Picker({
const getInitialScrollPosition = useCallback(
async () =>
getPositionOfSelectedItemElement({
children: wrappedItems,
itemsOrSections: wrappedItems,
itemHeight: PICKER_ITEM_HEIGHTS.noDescription,
itemHeightWithDescription: PICKER_ITEM_HEIGHTS.withDescription,
sectionTitleHeight: PICKER_SECTION_HEIGHTS.title,
sectionEmptyTitleHeight: PICKER_SECTION_HEIGHTS.emptyTitle,
selectedKey: isUncontrolled ? uncontrolledSelectedKey : selectedKey,
topOffset: PICKER_TOP_OFFSET,
}),
Expand Down
50 changes: 40 additions & 10 deletions packages/components/src/spectrum/utils/itemUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,37 +101,67 @@ export function getItemKey<
return (item?.item?.key ?? item?.key) as TKey;
}

/**
* Get the position of the item with the given selected key in a list of items.
*/
export async function getPositionOfSelectedItemElement<
TKey extends string | number | boolean | undefined,
>({
children,
itemsOrSections,
itemHeight,
itemHeightWithDescription,
sectionTitleHeight,
sectionEmptyTitleHeight,
selectedKey,
topOffset,
}: {
children: (ItemElement | SectionElement)[];
itemsOrSections: (ItemElement | SectionElement)[];
selectedKey: TKey | null | undefined;
itemHeight: number;
itemHeightWithDescription: number;
sectionTitleHeight: number;
sectionEmptyTitleHeight: number;
topOffset: number;
}): Promise<number> {
let position = 0;
let position = topOffset;

if (selectedKey == null) {
return position;
}

const getItemHeight = (item: ItemElement) =>
isItemElementWithDescription(item) ? itemHeightWithDescription : itemHeight;

// eslint-disable-next-line no-restricted-syntax
for (const child of children) {
if (child.key === selectedKey) {
break;
for (const itemOrSection of itemsOrSections) {
if (itemOrSection.key === selectedKey) {
return position;
}

if (isItemElementWithDescription(child)) {
position += itemHeightWithDescription;
if (isSectionElement(itemOrSection)) {
position +=
(itemOrSection.props.title ?? '') === ''
? sectionEmptyTitleHeight
: sectionTitleHeight;

const childItems = Array.isArray(itemOrSection.props.children)
? itemOrSection.props.children
: [itemOrSection.props.children];

// eslint-disable-next-line no-restricted-syntax
for (const childItem of childItems) {
if (childItem.key === selectedKey) {
return position;
}

position += getItemHeight(childItem);
}
} else {
position += itemHeight;
position += getItemHeight(itemOrSection);
}
}

return position + topOffset;
return topOffset;
}

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/utils/src/UIConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export const PICKER_ITEM_HEIGHTS = {
noDescription: 32,
withDescription: 48,
} as const;
export const PICKER_SECTION_HEIGHTS = {
title: 33,
emptyTitle: 5,
};
export const PICKER_TOP_OFFSET = 4;
export const TABLE_ROW_HEIGHT = 33;
export const SCROLL_DEBOUNCE_MS = 150;
Expand Down

0 comments on commit 36fe15d

Please sign in to comment.