# PickerStandalone

**Category:** Base Components/Collections/Picker

## Import

```tsx
import { PickerStandalone } from '@wix/patterns'
```

## Design

### Description

`PickerStandalone` allows rendering a Standalone [TableListItem](https://www.docs.wixdesignsystem.com/?path=/story/components-lists-table--tablelistitem), powered by Wix Patterns `CollectionState`. \
This is a component to render an item picker that adds dynamic support for:

* Setting a title from the page url using `title` query param.
* Setting a subtitle from the page url using `subtitle` query param.
* Setting the primary button text from the page url using `primaryButtonText` query param.
* The primary action can be defined as a navigation url from the `actionUrl` query param.


```tsx
import { PickerStandalone } from '@wix/patterns';
```

---

### Examples

### Basic

```tsx
import React from 'react';
import { EmptyState } from '@wix/design-system';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import {
  OffsetQuery,
  PickerStandalone,
  usePickerStandalone,
} from '@wix/patterns';
import { useHttpClient } from '@wix/fe-essentials/react';

function Basic() {
  const httpClient = useHttpClient();

  const fetchData = (query: OffsetQuery) => {
    const { limit, offset, search } = query;
    return httpClient
      .request(
        queryContacts({
          query: { paging: { limit, offset } },
          search,
        }),
      )
      .then(({ data: { contacts, pagingMetadata } }) => ({
        items: contacts || [],
        total: pagingMetadata?.total,
      }));
  };

  const state = usePickerStandalone({
    queryName: 'picker-standalone-basic',
    fetchData,
    limit: 25,
    defaultDestinationUrl: 'https://www.wix.com',
    fetchErrorMessage: () => 'Error fetching contacts',
    itemName: (contact) => contact.name as string,
  });

  return (
    <PickerStandalone
      height="666px"
      defaultTitle="Select a Contact"
      state={state}
      renderError={() => <EmptyState title="Error has occured" />}
      renderEmptyState={() => (
        <EmptyState title="You don't have any contacts that support this action." />
      )}
    />
  );
}
```

---

### Custom Empty State

```tsx
import React from 'react';
import { EmptyState } from '@wix/design-system';
import { PickerStandalone, usePickerStandalone } from '@wix/patterns';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';

function PickerStandaloneEmptyStateExample() {
  const fetchData = async () =>
    Promise.resolve({
      items: [] as Contact[],
      total: 0,
    });

  const state = usePickerStandalone({
    queryName: 'picker-standalone-empty-state',
    fetchData,
    limit: 25,
    defaultDestinationUrl: 'https://www.wix.com',
    fetchErrorMessage: () => 'Error fetching contacts',
    itemName: (contact) => contact.id as string,
  });

  return (
    <PickerStandalone
      height="666px"
      defaultTitle="Select a Contact"
      state={state}
      renderError={() => <EmptyState title="Error has occured" />}
      renderEmptyState={() => (
        <EmptyState title="You don’t have any contacts that support this action." />
      )}
    />
  );
}
```

---

### Custom Items

```tsx
import Chance from 'chance';
import React from 'react';
import { Avatar, EmptyState, Box, Text } from '@wix/design-system';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import {
  OffsetQuery,
  PickerStandalone,
  usePickerStandalone,
} from '@wix/patterns';
import { useHttpClient } from '@wix/fe-essentials/react';

function PickerStandaloneCustomItemsExample() {
  const chance = Chance();
  const httpClient = useHttpClient();

  const fetchData = (query: OffsetQuery) => {
    const { limit, offset, search } = query;
    return httpClient
      .request(
        queryContacts({
          query: { paging: { limit, offset } },
          search,
        }),
      )
      .then(({ data: { contacts, pagingMetadata } }) => ({
        items: contacts || [],
        total: pagingMetadata?.total,
      }));
  };

  const state = usePickerStandalone({
    queryName: 'picker-standalone-custom-items',
    fetchData,
    limit: 25,
    defaultDestinationUrl: 'https://www.wix.com',
    fetchErrorMessage: () => 'Error fetching contacts',
    itemName: (contact) => contact.id as string,
  });

  return (
    <PickerStandalone
      height="666px"
      defaultTitle="Select a Contact"
      state={state}
      renderItem={(contact, _index, { isMobileView }) => ({
        options: [
          {
            value: <Avatar name={contact.name} shape="square" />,
            align: 'left',
            width: 100,
          },
          {
            align: 'left',
            value: (
              <Box direction="vertical" width="300px">
                <Text size="medium" secondary weight="thin">
                  {contact.name}
                </Text>
                <Text size="small" secondary weight="thin" ellipsis>
                  Long Text: {chance.sentence({ words: 10 })}
                </Text>
                <Text size="tiny" secondary weight="thin" ellipsis>
                  {`this is rendered as ${
                    isMobileView ? 'mobile' : 'desktop'
                  } view`}
                </Text>
              </Box>
            ),
          },
        ],
      })}
      renderError={() => <EmptyState title="Error has occured" />}
      renderEmptyState={() => (
        <EmptyState title="You don’t have any contacts that support this action." />
      )}
    />
  );
}
```

---

### CreateNew

```tsx
import React from 'react';
import { EmptyState, TextButton } from '@wix/design-system';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import {
  OffsetQuery,
  PickerStandalone,
  usePickerStandalone,
} from '@wix/patterns';
import { useHttpClient } from '@wix/fe-essentials/react';

function PickerStandaloneCreateNewExample() {
  const httpClient = useHttpClient();

  const fetchData = (query: OffsetQuery) => {
    const { limit, offset, search } = query;
    return httpClient
      .request(
        queryContacts({
          query: { paging: { limit, offset } },
          search,
        }),
      )
      .then(({ data: { contacts, pagingMetadata } }) => ({
        items: contacts || [],
        total: pagingMetadata?.total,
      }));
  };

  const state = usePickerStandalone({
    queryName: 'picker-standalone-basic',
    fetchData,
    limit: 25,
    defaultDestinationUrl: 'https://www.wix.com',
    fetchErrorMessage: () => 'Error fetching contacts',
    itemName: (contact) => contact.id as string,
  });

  return (
    <PickerStandalone
      height="666px"
      defaultTitle="Select a Contact"
      state={state}
      createNewAction={
        <TextButton
          as="a"
          href="contacts"
          target="_blank"
          onClick={() => {
            const onFocus = () => {
              window.removeEventListener('focus', onFocus);
              state.picker.clearResultAndMoveToStart({ force: true });
            };
            window.addEventListener('focus', onFocus);
          }}
        >
          Create New Contact
        </TextButton>
      }
      renderError={() => <EmptyState title="Error has occured" />}
      renderEmptyState={() => (
        <EmptyState title="You don’t have any contacts that support this action." />
      )}
    />
  );
}
```

## API

### Extends

[CustomModalLayoutProps](https://www.docs.wixdesignsystem.com/?path=/story/components-overlays-modal--custommodallayout)

### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `state` | `PickerStandaloneState<T, F>` | Yes | - | A picker standalone state instance created with [`usePickerStandalone`](./?path=/story/base-components-collections-picker-hooks--usepickerstandalone) |
| `renderItem` | `((item: T, index: number, options: { isMobileView?: boolean; }) => Partial<PickerListItemProps>)` | No | - | A function that renders an item row in the `SelectorList` |
| `renderEmptyState` | `((params: { hasAvailableItems: boolean; query: ComputedQuery<F>; }) => ReactElement<any, string \| JSXElementConstructor<any>> \| null)` | No | - | A render function to be rendered when there're no items to show in the table.<br> You can use the built in [`<CollectionEmptyState />`](./?path=/story/features-display-empty-states--collectionemptystate).<br> The function accepts the following parameters * `hasAvailableItems`: Indicates whether other items might have been shown using other filtering / search * `query`: An instance of [`ComputedQuery`](./?path=/story/common-types--computedquery) that represents the query that resulted with an empty state |
| `defaultTitle` | `string` | No | - | Picker title if not provided via URL query parameter |
| `defaultSubtitle` | `string` | No | - | Picker subtitle if not provided via URL query parameter |
| `defaultPrimaryButtonText` | `string` | No | - | The text for the item primary button, if not provided via URL query parameter |
| `titleMaxLines` | `number` | No | - | Limits the number of lines for the title |
| `hideSearch` | `boolean` | No | - | Hides the search input of the picker |
| `selectorListProps` | `Partial<SelectorListContentProps>` | No | - | Additional props to pass to [SelectorList](https://www.docs.wixdesignsystem.com/?path=/story/components-lists--selectorlist), i.e `imageSize`, `imageShape` etc. |
| `primaryActionWidth` | `string` | No | - | The width of the primary action item. can be fixed or using [minmax](https://developer.mozilla.org/en-US/docs/Web/CSS/minmax()) |
| `createNewAction` | `ReactElement<TextButtonProps, string \| JSXElementConstructor<any>>` | No | - | Adds side action TextButton to the footer, with Add icon. Only `TextButton` React element is supported. |
| `mobileHeight` | `string \| number` | No | `100vh` | Height for mobile layout container |

## BI

### Picker Standalone Events

  Event   |   Description   |
--------- | --------------- |
[144:110](https://bo.wix.com/data-tools/bi-catalog-app/event/144:110) | sent when a component starts loading
[144:111](https://bo.wix.com/data-tools/bi-catalog-app/event/144:111) | sent when a component is done loading
[144:112](https://bo.wix.com/data-tools/bi-catalog-app/event/144:112) | sent when a component is done loading more items (after scrolling)
[144:113](https://bo.wix.com/data-tools/bi-catalog-app/event/144:113) | sent when a component is dismissed
[144:114](https://bo.wix.com/data-tools/bi-catalog-app/event/144:114) | sent when a user select/deselects an item(s) in a list




### Component load events
Event   |   Description   |
--------- | --------------- |
[144:110](https://bo.wix.com/data-tools/bi-catalog-app/event/144:110) | Sent when a Wix Patterns component starts loading
[144:111](https://bo.wix.com/data-tools/bi-catalog-app/event/144:111) | Sent when a Wix Patterns component is done loading


#### 🐪 Couldn't find what you need?
* Check our [BI Catalog](https://bo.wix.com/data-tools/bi-catalog-app?viewId=all-items-view&selectedColumns=src%2Cevid%2Cname%2Cowner%2Cproduct%2CuserType+false%2CdateUpdated%2CdateCreated+false%2CcreatedBy+false%2Cstatus&source=%5B%7B%22id%22%3A%22144%22%2C%22name%22%3A%22144+-+Cairo%22%7D%5D)
* Contact us on [#cairo-bi](https://wix.slack.com/archives/C03N53KURH9)


