Skip to content

Commit

Permalink
Add affordance to icon selector in docs and fix selection state (#6877)
Browse files Browse the repository at this point in the history
  • Loading branch information
evansjohnson authored Jun 28, 2024
1 parent 7d776d4 commit 855a067
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 24 deletions.
7 changes: 3 additions & 4 deletions packages/core/src/components/menu/menuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,9 @@ export interface MenuItemProps
popoverProps?: Partial<Omit<PopoverProps, "content" | "minimal">>;

/**
* Whether this item should appear selected.
* Defining this will set the `aria-selected` attribute and apply a
* "check" or "blank" icon on the item (unless the `icon` prop is set,
* which always takes precedence).
* Whether this item should appear selected - `roleStructure` must be `"listoption"` for this to be
* applied. Defining this will set the `aria-selected` attribute and apply a small tick icon if `true`,
* and empty space for a small tick icon if `false` or `undefined`.
*
* @default undefined
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,10 @@

import { type IconName, IconNames } from "@blueprintjs/icons";

export const NONE = "(none)";
export type IconNameOrNone = IconName | typeof NONE;

export function getIconNames(): IconNameOrNone[] {
const iconNames = new Set<IconNameOrNone>();
export function getIconNames(): IconName[] {
const iconNames = new Set<IconName>();
for (const [, name] of Object.entries(IconNames)) {
iconNames.add(name);
}
iconNames.add(NONE);
return Array.from(iconNames.values());
}
28 changes: 15 additions & 13 deletions packages/docs-app/src/examples/core-examples/common/iconSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { Alignment, Button, Classes, MenuItem } from "@blueprintjs/core";
import type { IconName } from "@blueprintjs/icons";
import { type ItemRenderer, Select } from "@blueprintjs/select";

import { getIconNames, type IconNameOrNone, NONE } from "./iconNames";
import { getIconNames } from "./iconNames";

const ICON_NAMES = getIconNames();

Expand All @@ -35,39 +35,42 @@ export class IconSelect extends React.PureComponent<IconSelectProps> {
public render() {
const { disabled, iconName } = this.props;
return (
<label className={classNames(Classes.LABEL, { [Classes.DISABLED]: disabled })}>
<label className={classNames("icon-select", Classes.LABEL, { [Classes.DISABLED]: disabled })}>
Icon
<Select<IconNameOrNone>
<Select<IconName>
disabled={disabled}
items={ICON_NAMES}
itemPredicate={this.filterIconName}
itemRenderer={this.renderIconItem}
noResults={<MenuItem disabled={true} text="No results" />}
placeholder="Start typing to search…"
onItemSelect={this.handleIconChange}
popoverProps={{ minimal: true }}
>
<Button
alignText={Alignment.LEFT}
className={Classes.TEXT_OVERFLOW_ELLIPSIS}
textClassName={Classes.TEXT_OVERFLOW_ELLIPSIS}
disabled={disabled}
fill={true}
icon={iconName}
text={iconName || NONE}
text={iconName || "None"}
rightIcon="caret-down"
/>
</Select>
</label>
);
}

private renderIconItem: ItemRenderer<IconName | typeof NONE> = (icon, { handleClick, handleFocus, modifiers }) => {
private renderIconItem: ItemRenderer<IconName | undefined> = (icon, { handleClick, handleFocus, modifiers }) => {
if (!modifiers.matchesPredicate) {
return null;
}
return (
<MenuItem
selected={modifiers.active}
icon={icon === NONE ? undefined : icon}
roleStructure="listoption"
active={modifiers.active}
selected={this.props.iconName === icon}
icon={icon}
key={icon}
onClick={handleClick}
onFocus={handleFocus}
Expand All @@ -76,15 +79,14 @@ export class IconSelect extends React.PureComponent<IconSelectProps> {
);
};

private filterIconName = (query: string, iconName: IconName | typeof NONE) => {
if (iconName === NONE) {
return true;
}
private filterIconName = (query: string, iconName: IconName | undefined) => {
if (query === "") {
return iconName === this.props.iconName;
}
return iconName.toLowerCase().indexOf(query.toLowerCase()) >= 0;
};

private handleIconChange = (icon: IconNameOrNone) => this.props.onChange(icon === NONE ? undefined : icon);
private handleIconChange = (icon: IconName) => {
this.props.onChange(icon === this.props.iconName ? undefined : icon);
};
}
4 changes: 4 additions & 0 deletions packages/docs-app/src/styles/_examples.scss
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,10 @@ $docs-hotkey-piano-height: 510px;
flex-direction: row;
}

.icon-select {
width: 170px;
}

//
// DATETIME2
//
Expand Down
11 changes: 10 additions & 1 deletion packages/select/src/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ export interface SelectProps<T> extends ListItemsProps<T>, SelectPopoverProps {
*/
menuProps?: React.HTMLAttributes<HTMLUListElement>;

/**
* A placeholder string passed to the filter text input.
* Applicable only when `filterable` is `true`.
*
* @default "Filter..."
*/
placeholder?: string;

/**
* Whether the active item should be reset to the first matching item _when
* the popover closes_. The query will also be reset to the empty string.
Expand Down Expand Up @@ -159,6 +167,7 @@ export class Select<T> extends AbstractPureComponent<SelectProps<T>, SelectState
filterable = true,
disabled = false,
inputProps = {},
placeholder = "Filter...",
popoverContentProps = {},
popoverProps = {},
popoverRef,
Expand All @@ -168,7 +177,7 @@ export class Select<T> extends AbstractPureComponent<SelectProps<T>, SelectState
<InputGroup
aria-autocomplete="list"
leftIcon={<Search />}
placeholder="Filter..."
placeholder={placeholder}
rightElement={this.maybeRenderClearButton(listProps.query)}
{...inputProps}
inputRef={this.handleInputRef}
Expand Down

1 comment on commit 855a067

@svc-palantir-github
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add affordance to icon selector in docs and fix selection state (#6877)

Build artifact links for this commit: documentation | landing | table | demo

This is an automated comment from the deploy-preview CircleCI job.

Please sign in to comment.