Skip to content

Commit 36fe15d

Browse files
committed
Section heights in scroll position (#1935)
1 parent f541b3e commit 36fe15d

5 files changed

Lines changed: 95 additions & 15 deletions

File tree

packages/code-studio/src/styleguide/Pickers.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,19 @@ import { Icon } from '@adobe/react-spectrum';
1313
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
1414
import { getPositionOfSelectedItem } from '@deephaven/react-hooks';
1515
import { PICKER_ITEM_HEIGHTS, PICKER_TOP_OFFSET } from '@deephaven/utils';
16-
import { generateNormalizedItems, sampleSectionIdAndClasses } from './utils';
16+
import {
17+
generateItemElements,
18+
generateNormalizedItems,
19+
sampleSectionIdAndClasses,
20+
} from './utils';
1721

1822
// Generate enough items to require scrolling
1923
const items = [...generateNormalizedItems(52)];
24+
const itemElementsA = [...generateItemElements(0, 51)];
25+
const itemElementsB = [...generateItemElements(52, 103)];
26+
const itemElementsC = [...generateItemElements(104, 155)];
27+
const itemElementsD = [...generateItemElements(156, 207)];
28+
const itemElementsE = [...generateItemElements(208, 259)];
2029

2130
function PersonIcon(): JSX.Element {
2231
return (
@@ -79,7 +88,7 @@ export function Pickers(): JSX.Element {
7988
{'String 1'}
8089
{'String 2'}
8190
{'String 3'}
82-
<Section title="Section A">
91+
<Section title="Section">
8392
<Item textValue="Item Aaa">Item Aaa</Item>
8493
<Item textValue="Item Bbb">Item Bbb</Item>
8594
<Item textValue="Complex Ccc">
@@ -105,6 +114,11 @@ export function Pickers(): JSX.Element {
105114
<Text slot="description">Description that causes overflow</Text>
106115
</Item>
107116
</Section>
117+
<Section title="Section A">{itemElementsA}</Section>
118+
<Section title="Section B">{itemElementsB}</Section>
119+
<Section key="Section C">{itemElementsC}</Section>
120+
<Section key="Section D">{itemElementsD}</Section>
121+
<Section title="Section E">{itemElementsE}</Section>
108122
</Picker>
109123

110124
<PickerNormalized

packages/code-studio/src/styleguide/utils.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
import cl from 'classnames';
2-
import { useCallback, useState } from 'react';
3-
import { NormalizedItem } from '@deephaven/components';
2+
import { createElement, useCallback, useState } from 'react';
3+
import { Item, ItemElement, NormalizedItem } from '@deephaven/components';
44

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

8+
/**
9+
* Generate a given number of `Item` elements.
10+
*/
11+
export function* generateItemElements(
12+
start: number,
13+
end: number
14+
): Generator<ItemElement> {
15+
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
16+
const len = letters.length;
17+
18+
for (let i = start; i <= end; i += 1) {
19+
const charI = i % len;
20+
let suffix = String(Math.floor(i / len));
21+
if (suffix === '0') {
22+
suffix = '';
23+
}
24+
const letter = letters[charI];
25+
const key = `${letter}${suffix}`;
26+
const content = `${letter}${letter}${letter}${suffix}`;
27+
28+
// eslint-disable-next-line react/no-children-prop
29+
yield createElement(Item, {
30+
key,
31+
textValue: content,
32+
children: content,
33+
});
34+
}
35+
}
36+
837
/**
938
* Generate a given number of NormalizedItems.
1039
* @param count The number of items to generate

packages/components/src/spectrum/picker/Picker.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import cl from 'classnames';
55
import {
66
EMPTY_FUNCTION,
77
PICKER_ITEM_HEIGHTS,
8+
PICKER_SECTION_HEIGHTS,
89
PICKER_TOP_OFFSET,
910
} from '@deephaven/utils';
1011
import {
@@ -92,9 +93,11 @@ export function Picker({
9293
const getInitialScrollPosition = useCallback(
9394
async () =>
9495
getPositionOfSelectedItemElement({
95-
children: wrappedItems,
96+
itemsOrSections: wrappedItems,
9697
itemHeight: PICKER_ITEM_HEIGHTS.noDescription,
9798
itemHeightWithDescription: PICKER_ITEM_HEIGHTS.withDescription,
99+
sectionTitleHeight: PICKER_SECTION_HEIGHTS.title,
100+
sectionEmptyTitleHeight: PICKER_SECTION_HEIGHTS.emptyTitle,
98101
selectedKey: isUncontrolled ? uncontrolledSelectedKey : selectedKey,
99102
topOffset: PICKER_TOP_OFFSET,
100103
}),

packages/components/src/spectrum/utils/itemUtils.ts

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,37 +101,67 @@ export function getItemKey<
101101
return (item?.item?.key ?? item?.key) as TKey;
102102
}
103103

104+
/**
105+
* Get the position of the item with the given selected key in a list of items.
106+
*/
104107
export async function getPositionOfSelectedItemElement<
105108
TKey extends string | number | boolean | undefined,
106109
>({
107-
children,
110+
itemsOrSections,
108111
itemHeight,
109112
itemHeightWithDescription,
113+
sectionTitleHeight,
114+
sectionEmptyTitleHeight,
110115
selectedKey,
111116
topOffset,
112117
}: {
113-
children: (ItemElement | SectionElement)[];
118+
itemsOrSections: (ItemElement | SectionElement)[];
114119
selectedKey: TKey | null | undefined;
115120
itemHeight: number;
116121
itemHeightWithDescription: number;
122+
sectionTitleHeight: number;
123+
sectionEmptyTitleHeight: number;
117124
topOffset: number;
118125
}): Promise<number> {
119-
let position = 0;
126+
let position = topOffset;
127+
128+
if (selectedKey == null) {
129+
return position;
130+
}
131+
132+
const getItemHeight = (item: ItemElement) =>
133+
isItemElementWithDescription(item) ? itemHeightWithDescription : itemHeight;
120134

121135
// eslint-disable-next-line no-restricted-syntax
122-
for (const child of children) {
123-
if (child.key === selectedKey) {
124-
break;
136+
for (const itemOrSection of itemsOrSections) {
137+
if (itemOrSection.key === selectedKey) {
138+
return position;
125139
}
126140

127-
if (isItemElementWithDescription(child)) {
128-
position += itemHeightWithDescription;
141+
if (isSectionElement(itemOrSection)) {
142+
position +=
143+
(itemOrSection.props.title ?? '') === ''
144+
? sectionEmptyTitleHeight
145+
: sectionTitleHeight;
146+
147+
const childItems = Array.isArray(itemOrSection.props.children)
148+
? itemOrSection.props.children
149+
: [itemOrSection.props.children];
150+
151+
// eslint-disable-next-line no-restricted-syntax
152+
for (const childItem of childItems) {
153+
if (childItem.key === selectedKey) {
154+
return position;
155+
}
156+
157+
position += getItemHeight(childItem);
158+
}
129159
} else {
130-
position += itemHeight;
160+
position += getItemHeight(itemOrSection);
131161
}
132162
}
133163

134-
return position + topOffset;
164+
return topOffset;
135165
}
136166

137167
/**

packages/utils/src/UIConstants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ export const PICKER_ITEM_HEIGHTS = {
66
noDescription: 32,
77
withDescription: 48,
88
} as const;
9+
export const PICKER_SECTION_HEIGHTS = {
10+
title: 33,
11+
emptyTitle: 5,
12+
};
913
export const PICKER_TOP_OFFSET = 4;
1014
export const TABLE_ROW_HEIGHT = 33;
1115
export const SCROLL_DEBOUNCE_MS = 150;

0 commit comments

Comments
 (0)