Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 26 additions & 3 deletions packages/code-studio/src/styleguide/Pickers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Picker } from '@deephaven/components';
import { Item, Picker, Section } from '@deephaven/components';
import { vsPerson } from '@deephaven/icons';
import { Flex, Icon, Item, Text } from '@adobe/react-spectrum';
import { Flex, Icon, Text } from '@adobe/react-spectrum';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { sampleSectionIdAndClasses } from './utils';

Expand Down Expand Up @@ -40,9 +40,32 @@ export function Pickers(): JSX.Element {
<Item>Item Bbb</Item>
<Item textValue="Complex Ccc">
<PersonIcon />
<Text>Complex Ccc</Text>
<Text>Complex Ccc with text that should be truncated</Text>
</Item>
</Picker>

<Picker label="Sections" tooltip>
{/* eslint-disable react/jsx-curly-brace-presence */}
{'String 1'}
{'String 2'}
{'String 3'}
<Section title="Section A">
<Item>Item Aaa</Item>
<Item>Item Bbb</Item>
<Item textValue="Complex Ccc">
<PersonIcon />
<Text>Complex Ccc</Text>
</Item>
</Section>
<Section>
<Item>Item Ddd</Item>
<Item>Item Eee</Item>
<Item textValue="Complex Fff">
<PersonIcon />
<Text>Complex Fff</Text>
</Item>
</Section>
</Picker>
</Flex>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
},
"dependencies": {
"@adobe/react-spectrum": "^3.34.1",
"@react-types/shared": "^3.22.1",
"@deephaven/icons": "file:../icons",
"@deephaven/log": "file:../log",
"@deephaven/react-hooks": "file:../react-hooks",
Expand Down
13 changes: 13 additions & 0 deletions packages/components/src/spectrum/Item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Wrapping Spectrum `Item` components will break functionality due to the way
* they are consumed by collection components. They are only used to pass data
* and don't render anything on their own, so they don't need to be wrapped.
* See https://github.com/adobe/react-spectrum/blob/main/packages/%40react-stately/collections/src/Item.ts#L17
*/
import { Item } from '@adobe/react-spectrum';

export type { ItemProps } from '@react-types/shared';

export { Item };

export default Item;
13 changes: 13 additions & 0 deletions packages/components/src/spectrum/Section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Wrapping Spectrum `Section` components will break functionality due to the way
* they are consumed by collection components. They are only used to pass data
* and don't render anything on their own, so they don't need to be wrapped.
* See https://github.com/adobe/react-spectrum/blob/main/packages/%40react-stately/collections/src/Section.ts#L18
*/
import { Section } from '@adobe/react-spectrum';

export type { SectionProps } from '@react-types/shared';

export { Section };

export default Section;
2 changes: 2 additions & 0 deletions packages/components/src/spectrum/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './picker';
export * from './Item';
export * from './Section';
59 changes: 46 additions & 13 deletions packages/components/src/spectrum/picker/Picker.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { useMemo } from 'react';
import { Item, Picker as SpectrumPicker } from '@adobe/react-spectrum';
import { Key, useCallback, useMemo } from 'react';
import { Picker as SpectrumPicker } from '@adobe/react-spectrum';
import cl from 'classnames';
import { Tooltip } from '../../popper';
import {
NormalizedSpectrumPickerProps,
normalizePickerItemList,
normalizeTooltipOptions,
PickerItem,
PickerItemOrSection,
PickerItemKey,
TooltipOptions,
NormalizedPickerItem,
isNormalizedPickerSection,
} from './PickerUtils';
import { PickerItemContent } from './PickerItemContent';
import { Item } from '../Item';
import { Section } from '../Section';

export type PickerProps = {
children: PickerItem | PickerItem[];
children: PickerItemOrSection | PickerItemOrSection[];
/** Can be set to true or a TooltipOptions to enable item tooltips */
tooltip?: boolean | TooltipOptions;
/** The currently selected key in the collection (controlled). */
Expand Down Expand Up @@ -54,11 +59,13 @@ export type PickerProps = {
*/
export function Picker({
children,
tooltip,
tooltip = true,
defaultSelectedKey,
selectedKey,
onChange,
onSelectionChange,
// eslint-disable-next-line camelcase
UNSAFE_className,
...spectrumPickerProps
}: PickerProps): JSX.Element {
const normalizedItems = useMemo(
Expand All @@ -71,10 +78,29 @@ export function Picker({
[tooltip]
);

const renderItem = useCallback(
({ key, content, textValue }: NormalizedPickerItem) => (
// The `textValue` prop gets used to provide the content of `<option>`
// elements that back the Spectrum Picker. These are not visible in the UI,
// but are used for accessibility purposes, so we set to an arbitrary
// 'Empty' value so that they are not empty strings.
<Item key={key as Key} textValue={textValue === '' ? 'Empty' : textValue}>
<PickerItemContent>{content}</PickerItemContent>
{tooltipOptions == null || content === '' ? null : (
<Tooltip options={tooltipOptions}>
{typeof content === 'boolean' ? String(content) : content}
</Tooltip>
)}
</Item>
),
[tooltipOptions]
);

return (
<SpectrumPicker
// eslint-disable-next-line react/jsx-props-no-spreading
{...spectrumPickerProps}
UNSAFE_className={cl('dh-picker', UNSAFE_className)}
items={normalizedItems}
// Type assertions are necessary for `selectedKey`, `defaultSelectedKey`,
// and `onSelectionChange` due to Spectrum types not accounting for
Expand All @@ -89,14 +115,21 @@ export function Picker({
onSelectionChange) as NormalizedSpectrumPickerProps['onSelectionChange']
}
>
{({ content, textValue }) => (
<Item textValue={textValue === '' ? 'Empty' : textValue}>
<PickerItemContent>{content}</PickerItemContent>
{tooltipOptions == null || content === '' ? null : (
<Tooltip options={tooltipOptions}>{content}</Tooltip>
)}
</Item>
)}
{itemOrSection => {
if (isNormalizedPickerSection(itemOrSection)) {
return (
<Section
key={itemOrSection.key}
title={itemOrSection.title}
items={itemOrSection.items}
>
{renderItem}
</Section>
);
}

return renderItem(itemOrSection);
}}
</SpectrumPicker>
);
}
Expand Down
6 changes: 6 additions & 0 deletions packages/components/src/spectrum/picker/PickerItemContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export function PickerItemContent({
content = <>&nbsp;</>;
}

if (typeof content === 'boolean') {
// Boolean values need to be stringified to render
// eslint-disable-next-line no-param-reassign
content = String(content);
}

return (
<Text UNSAFE_className={stylesCommon.spectrumEllipsis}>{content}</Text>
);
Expand Down
Loading