Skip to content

Commit

Permalink
[AlphaPicker] Add logic for multiple select (#11819)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyledurand committed Apr 2, 2024
1 parent d0039a5 commit 35eb10c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 59 deletions.
5 changes: 5 additions & 0 deletions .changeset/wise-teachers-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': patch
---

Added multi select functionality to AlphaPicker
109 changes: 69 additions & 40 deletions polaris-react/playground/DetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
FooterHelp,
Link,
AlphaPicker,
BlockStack,
} from '../src';
import type {DropZoneProps, PageProps} from '../src';

Expand All @@ -56,10 +57,6 @@ export function DetailsPage() {
nameFieldValue: 'Jaded Pixel',
});
const [query, setQuery] = useState('');
const [vendors, setVendors] = useState([
{value: 'The North Face', children: 'The North Face'},
{value: 'Patagonia', children: 'Patagonia'},
]);
const skipToContentRef = useRef<HTMLAnchorElement>(null);
const [toastActive, setToastActive] = useState(false);
const [isLoading, setIsLoading] = useState(false);
Expand All @@ -85,16 +82,6 @@ export function DetailsPage() {
const [supportSubject, setSupportSubject] = useState('');
const [supportMessage, setSupportMessage] = useState('');

const handleSelect = (selected: string) => {
setQuery('');
if (vendors.some((vendor) => vendor.children === selected)) return;

setVendors((vendors) => [
...vendors,
{value: selected, children: selected},
]);
};

const handleDiscard = useCallback(() => {
setEmailFieldValue(defaultState.current.emailFieldValue);
setNameFieldValue(defaultState.current.nameFieldValue);
Expand Down Expand Up @@ -644,32 +631,74 @@ export function DetailsPage() {
<Layout.Section variant="oneThird">
<LegacyCard title="Organization">
<LegacyCard.Section>
<Select
label="Product type"
options={options}
onChange={setSelected}
value={selected}
/>
<br />
<AlphaPicker
onSelect={handleSelect}
activator={{
label: 'Vendor',
placeholder: 'None selected',
}}
searchField={{
label: 'Search vendors',
placeholder: 'Search or add new vendor',
autoComplete: 'off',
value: query,
onChange: (value) => setQuery(value),
}}
options={vendors}
addAction={{
value: query,
children: `Add ${query}`,
}}
/>
<BlockStack gap="200">
<Select
label="Product type"
options={options}
onChange={setSelected}
value={selected}
/>

<AlphaPicker
allowMultiple
activator={{
label: 'Tags',
placeholder: 'None selected',
}}
searchField={{
label: 'Search tags',
placeholder: 'Search or add new tags',
autoComplete: 'off',
value: query,
onChange: (value) => setQuery(value),
}}
options={[
{value: 'Outdoors', children: 'Outdoors'},
{value: 'Adventure', children: 'Adventure'},
{value: 'Hiking', children: 'Hiking'},
{value: 'Camping', children: 'Camping'},
{value: 'Backpacking', children: 'Backpacking'},
{value: 'Mountaineering', children: 'Mountaineering'},
{value: 'Skiing', children: 'Skiing'},
{value: 'Snowboarding', children: 'Snowboarding'},
]}
addAction={{
value: query,
children: `Add ${query}`,
}}
/>

<AlphaPicker
activator={{
label: 'Vendor',
placeholder: 'None selected',
}}
searchField={{
label: 'Search vendors',
placeholder: 'Search or add new vendor',
autoComplete: 'off',
value: query,
onChange: (value) => setQuery(value),
}}
options={[
{value: 'The North Face', children: 'The North Face'},
{value: 'Patagonia', children: 'Patagonia'},
{value: 'Arc’teryx', children: 'Arc’teryx'},
{value: 'Marmot', children: 'Marmot'},
{value: 'Black Diamond', children: 'Black Diamond'},
{value: 'Mountain Hardwear', children: 'Mountain Hardwear'},
{value: 'Columbia', children: 'Columbia'},
{value: 'Canada Goose', children: 'Canada Goose'},
{value: 'Merrell', children: 'Merrell'},
{value: 'Salomon', children: 'Salomon'},
{value: 'Burton', children: 'Burton'},
]}
addAction={{
value: query,
children: `Add ${query}`,
}}
/>
</BlockStack>
</LegacyCard.Section>
<LegacyCard.Section title="Collections" />
<LegacyCard.Section title="Tags" />
Expand Down
48 changes: 29 additions & 19 deletions polaris-react/src/components/Picker/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function Picker({
...listboxProps
}: PickerProps) {
const activatorRef = React.createRef<HTMLButtonElement>();
const [activeItem, setActiveItem] = useState<string>();
const [activeItems, setActiveItems] = useState<string[]>([]);
const [popoverActive, setPopoverActive] = useState(false);
const [activeOptionId, setActiveOptionId] = useState<string>();
const [textFieldLabelId, setTextFieldLabelId] = useState<string>();
Expand Down Expand Up @@ -164,14 +164,36 @@ export function Picker({
[options],
);

const firstSelectedOption = reactChildrenText(
options.find((option) => option.value === activeItem)?.children,
const handleSelect = useCallback(
(selected: string) => {
setQuery('');
updateText('');
listboxProps.onSelect?.(selected);

if (!allowMultiple) {
handleClose();
setActiveItems([selected]);
return;
}

setActiveItems((selectedOptions) => {
return activeItems.includes(selected)
? selectedOptions.filter((option) => option !== selected)
: [...selectedOptions, selected];
});
},
[updateText, listboxProps, allowMultiple, activeItems, handleClose],
);

const queryMatchesExistingOption = options.some((option) =>
QUERY_REGEX(query).exec(reactChildrenText(option.children)),
const firstSelectedOption = reactChildrenText(
options.find((option) => option.value === activeItems?.[0])?.children,
);

const queryMatchesExistingOption = options.some((option) => {
const matcher = QUERY_REGEX(query);
return reactChildrenText(option.children).match(matcher);
});

return (
<Popover
activator={
Expand Down Expand Up @@ -219,23 +241,11 @@ export function Picker({
value={listboxOptionContextValue}
>
<Box paddingBlock="200">
<Listbox
{...listboxProps}
onSelect={(selected: string) => {
setQuery('');
updateText('');
setActiveItem(selected);
listboxProps.onSelect?.(selected);

if (!allowMultiple) {
handleClose();
}
}}
>
<Listbox {...listboxProps} onSelect={handleSelect}>
{filteredOptions?.map((option) => (
<Listbox.Option
key={option.value}
selected={option.value === activeItem}
selected={activeItems.some((item) => item === option.value)}
{...option}
/>
))}
Expand Down

0 comments on commit 35eb10c

Please sign in to comment.