Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DST-367]: rac SelectList component #3708

Merged
merged 37 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3d62171
Add `GridList` component
OsamaAbdellateef Feb 8, 2024
358ea71
Adding Action story
OsamaAbdellateef Feb 8, 2024
4a2c0a0
Adding base styles
OsamaAbdellateef Feb 8, 2024
17bd838
[DST-358]: remove flex from gridList
aromko Feb 8, 2024
16a6c9b
Merge branch 'main' into rac-gridlist
aromko Feb 19, 2024
39e6609
Merge branch 'main' into rac-gridlist
aromko Feb 19, 2024
5da7ed5
Merge branch 'main' into rac-gridlist
aromko Feb 23, 2024
48eaba2
Adding styles to GridList component
OsamaAbdellateef Mar 19, 2024
b0b998a
Adding context for styles
OsamaAbdellateef Mar 20, 2024
eb9e021
Adding tests 🫣
OsamaAbdellateef Mar 21, 2024
83ff5fd
Finishing tests
OsamaAbdellateef Mar 22, 2024
be637ad
Deleting unwanted files
OsamaAbdellateef Mar 22, 2024
b1c4a1c
fixing type error
OsamaAbdellateef Mar 22, 2024
573f24f
Adding docs
OsamaAbdellateef Mar 22, 2024
ec96af1
Adding demos
OsamaAbdellateef Mar 22, 2024
0c12975
Replace onSelectionChange with onChange
OsamaAbdellateef Mar 22, 2024
6c166a4
Edit example
OsamaAbdellateef Mar 25, 2024
4f88d67
edit examples
OsamaAbdellateef Mar 25, 2024
3a43089
edit docs
OsamaAbdellateef Mar 25, 2024
db18cfb
show up checkbox even in single mode
OsamaAbdellateef Mar 25, 2024
e3f734d
Creating changeset
OsamaAbdellateef Mar 25, 2024
69fa5d4
Fixing types
OsamaAbdellateef Mar 25, 2024
d119070
Fixing types
OsamaAbdellateef Mar 25, 2024
2f73722
Merge branch 'main' into rac-gridlist
OsamaAbdellateef Mar 25, 2024
de3c2ff
Adding props table for GridList.Item
OsamaAbdellateef Mar 26, 2024
0f68d01
adding more stories
OsamaAbdellateef Mar 26, 2024
1f69932
adding more changes
OsamaAbdellateef Mar 26, 2024
f957f37
Replace GridList with SelectList
OsamaAbdellateef Mar 26, 2024
0d302ec
remove radio input
OsamaAbdellateef Mar 27, 2024
c9096d8
Adding more content
OsamaAbdellateef Apr 3, 2024
5e4c9fa
Fixing checkbox in core theme
OsamaAbdellateef Apr 5, 2024
99ea9f2
Merge branch 'main' into rac-gridlist
aromko Apr 5, 2024
ad054ca
Merge branch 'main' into rac-gridlist
sarahgm Apr 5, 2024
0a4f582
Merge branch 'main' into rac-gridlist
sarahgm Apr 5, 2024
11dd46a
Edit icon color
OsamaAbdellateef Apr 5, 2024
d28a9ab
Merge branch 'rac-gridlist' of https://github.com/marigold-ui/marigol…
OsamaAbdellateef Apr 5, 2024
bf7b88a
Merge branch 'main' into rac-gridlist
sarahgm Apr 8, 2024
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
6 changes: 6 additions & 0 deletions .changeset/thirty-yaks-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@marigold/components": minor
"@marigold/docs": minor
---

Creating new component `SelectList`
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { SelectList } from '@marigold/components';

export default () => (
<SelectList aria-labelledby="SelectList" disabledKeys={['T012']}>
<SelectList.Item id="T123">Ticket 123</SelectList.Item>
<SelectList.Item id="T456">Ticket 456</SelectList.Item>
<SelectList.Item id="T789">Ticket 789</SelectList.Item>
<SelectList.Item id="T012">Ticket 012</SelectList.Item>
</SelectList>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useState } from 'react';

import { Button, SelectList } from '@marigold/components';

let pokemons = [
{ id: 'charizard', name: 'Charizard' },
{ id: 'blastoise', name: 'Blastoise' },
{ id: 'venusaur', name: 'Venusaur' },
{ id: 'pikachu', name: 'Pikachu' },
];

export default () => {
const [selectedPokemons, setSelectedPokemons] = useState(['charizard']);
return (
<>
<SelectList
aria-label="Favorite pokemon"
selectionMode="multiple"
items={pokemons}
selectedKeys={selectedPokemons}
onChange={setSelectedPokemons}
>
{(item: { id: any; name: string }) => (
<SelectList.Item id={item.id}>
{item.name}
<Button
aria-label="Info"
onPress={() => alert(`Info for ${item.name}...`)}
className="ml-auto"
>
sarahgm marked this conversation as resolved.
Show resolved Hide resolved
</Button>
</SelectList.Item>
)}
</SelectList>
{selectedPokemons}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useState } from 'react';

import { SelectList } from '@marigold/components';

export default () => {
const [paymentMethod, setPaymentMethod] = useState(new Set(['bankTransfer']));
return (
<>
<SelectList
selectionMode="single"
aria-labelledby="PaymentMethodSelectList"
onChange={setPaymentMethod}
selectedKeys={paymentMethod}
>
<SelectList.Item id="creditCard">Credit Card</SelectList.Item>
<SelectList.Item id="debitCard">Debit Card</SelectList.Item>
<SelectList.Item id="bankTransfer">Bank Transfer</SelectList.Item>
<SelectList.Item id="paypal">PayPal</SelectList.Item>
</SelectList>
Current Payment is: {paymentMethod}
</>
);
};
180 changes: 180 additions & 0 deletions docs/content/components/collection/gridlist/selectlist.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
---
title: SelectList
caption: A component for displaying a list of interactive items, with support for keyboard navigation, single or multiple selection, and row actions.
badge: new
---

A `SelectList` consists of a container element, with rows of data inside. The rows within a list may contain focusable elements or plain text content. If the list supports row selection, each row includes a selection checkbox.
OsamaAbdellateef marked this conversation as resolved.
Show resolved Hide resolved

## Usage

### Import

To import the component you just have to use this code below.

```tsx
import { SelectList } from '@marigold/components';
```

### Props

<PropsTable
props={[
{
property: 'download',
type: 'string | boolean | undefined',
description:
'Causes the browser to download the linked URL. A string may be provided to suggest a file name.',
default: 'none',
},
{
property: 'href',
type: 'string | undefined',
description: 'A URL to link to.',
default: 'none',
},
{
property: 'ping',
type: 'string | undefined',
description:
'A space-separated list of URLs to ping when the link is followed.',
default: 'none',
},

{
property: 'textValue',
type: 'string | undefined',
description:
"A string representation of the item's contents, used for features like typeahead.",
default: 'none',
},
{
property: 'onScroll',
type: '(e: React.UIEvent<HTMLDivElement, UIEvent>) => void',
description: 'Handler that is called when a user scrolls.',
default: 'none',
},
{
property: 'renderEmptyState',
type: '(props: GridListRenderProps) => React.ReactNode',
description:
'Provides content to display when there are no items in the list.',
default: 'none',
},

]}
/>

### Item props

<PropsTable
props={[
{
property: 'dependencies',
type: 'any[] | undefined',
description:
'Values that should invalidate the item cache when using dynamic collections.',
default: 'none',
},
{
property: 'disabledBehavior',
type: 'DisabledBehavior | undefined',
description:
'Whether disabledKeys applies to all interactions, or only selection.',
default: 'none',
},
{
property: 'disallowEmptySelection',
type: 'boolean | undefined',
description: 'Whether the collection allows empty selection.',
default: 'false',
},
{
property: 'dragAndDropHooks',
type: 'DragAndDropHooks | undefined',
description:
'The drag and drop hooks returned by useDragAndDrop used to enable drag and drop behavior for the GridList.',
default: 'none',
},
{
property: 'items',
type: 'Iterable<object> | undefined',
description: 'Item objects in the collection.',
default: 'none',
},
{
property: 'selectedKeys',
type: '"all" | Iterable<Key> | undefined',
description:
'The currently selected keys in the collection (controlled).',
default: 'none',
},
{
property: 'selectionMode',
type: '"multiple" | "none" | "single" | undefined',
description: 'The type of selection that is allowed in the collection.',
default: 'none',
},
{
property: 'selectionBehavior',
type: '"replace" | "toggle" | undefined',
description: 'How multiple selection should behave in the collection.',
default: 'none',
},
{
property: 'slot',
type: 'string | null | undefined',
description:
'A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.',
default: 'none',
},
{
property: 'ref',
type: 'Ref<HTMLUListElement> | undefined',
description: `Allows getting a ref to the component instance. Once the component unmounts, React will set ref.current to null (or call the ref with null if you passed a callback ref).`,
default: 'full',
},
{
property: 'onAction',
type: '(key: Key) => void',
description:
"Handler that is called when a user performs an action on an item. The exact user event depends on the collection's selectionBehavior prop and the interaction modality.",
default: 'none',
},
{
property: 'onSelectionChange',
type: '(key: Key) => any',
description: 'Handler that is called when the selection changes.',
default: 'none',
},
{
property: 'onScroll',
type: '(e: React.UIEvent<HTMLDivElement, UIEvent>) => void',
description: 'Handler that is called when a user scrolls.',
default: 'none',
},
{
property: 'renderEmptyState',
type: '(props: GridListRenderProps) => React.ReactNode',
description:
'Provides content to display when there are no items in the list.',
default: 'none',
},
]}
/>

## Examples

### Standard SelectList

This example shows the standard appearance for `SelectList` component.

<ComponentDemo file="./selectlist-basic.demo.tsx" />

### SelectList with single selection mode

<ComponentDemo file="./selectlist-single-selection.demo.tsx" />

### SelectList with multiple selection mode

<ComponentDemo file="./selectlist-multiple-selection.demo.tsx" />
10 changes: 10 additions & 0 deletions packages/components/src/SelectList/Context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createContext, useContext } from 'react';

export interface SelectListContextProps {
classNames: any;
}

export const SelectListContext = createContext<SelectListContextProps>(
{} as any
);
export const useSelectListContext = () => useContext(SelectListContext);
94 changes: 94 additions & 0 deletions packages/components/src/SelectList/SelectList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';

import { Button } from '../Button';
import { SelectList } from './SelectList';

const meta = {
title: 'Components/SelectList',
argTypes: {
selectionMode: {
control: {
type: 'select',
},
options: ['single', 'multiple'],
table: {
type: { summary: 'select' },
defaultValue: { summary: 'single' },
},
description: 'Set selection mode of the select list',
defaultValue: false,
},
},
} satisfies Meta<typeof SelectList>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Basic: Story = {
render: args => (
<SelectList
aria-labelledby="SelectList"
defaultSelectedKeys={['one']}
disabledKeys={['four']}
{...args}
>
<SelectList.Item id="one">one</SelectList.Item>
<SelectList.Item id="two">Two</SelectList.Item>
<SelectList.Item id="three">Three</SelectList.Item>
<SelectList.Item id="four">Four</SelectList.Item>
</SelectList>
),
};

export const WithSingleSelection: Story = {
render: args => (
<SelectList aria-labelledby="SelectList" selectionMode="single" {...args}>
<SelectList.Item id="one">one</SelectList.Item>
<SelectList.Item id="two">Two</SelectList.Item>
<SelectList.Item id="three">Three</SelectList.Item>
<SelectList.Item id="four">Four</SelectList.Item>
</SelectList>
),
};

export const WithMultiSelection: Story = {
render: args => (
<SelectList aria-labelledby="SelectList" selectionMode="multiple" {...args}>
<SelectList.Item id="charizard">Charizard</SelectList.Item>
<SelectList.Item id="blastoise">Blastoise</SelectList.Item>
<SelectList.Item id="venusaur">Venusaur</SelectList.Item>
<SelectList.Item id="pikachu">Pikachu</SelectList.Item>
</SelectList>
),
};

let rows = [
{ id: 1, name: 'Games' },
{ id: 2, name: 'Program Files' },
{ id: 3, name: 'bootmgr' },
{ id: 4, name: 'log.txt' },
];
export const Action: Story = {
render: args => (
<SelectList
aria-labelledby="SelectList"
selectionMode="multiple"
{...args}
items={rows}
>
{(item: { id: number; name: string }) => (
<SelectList.Item textValue={item.name}>
{item.name}
<Button
aria-label="Info"
onPress={() => alert(`Info for ${item.name}...`)}
className="ml-auto"
>
</Button>
</SelectList.Item>
)}
</SelectList>
),
};
Loading
Loading