Skip to content

Commit

Permalink
Merge pull request #6938 from Sage/FE-6776
Browse files Browse the repository at this point in the history
docs(duelling-picklist): fix storybook docs page not displaying in production
  • Loading branch information
nuria1110 committed Sep 20, 2024
2 parents 67f225c + 9728dde commit 600ac5f
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 11 deletions.
3 changes: 1 addition & 2 deletions src/components/duelling-picklist/duelling-picklist.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Meta, ArgTypes, Canvas } from "@storybook/blocks";

import { Default } from "./duelling-picklist-test.stories";
import * as PickListStories from "./picklist/picklist.stories";
import * as PicklistItemStories from "./picklist-item/picklist-item.stories";
import * as PicklistPlaceholderStories from "./picklist-placeholder/picklist-placeholder.stories";
Expand Down Expand Up @@ -55,7 +54,7 @@ import {

Example of composed Duelling Picklist components with order preservation and search implemented.

<Canvas of={Default} />
<Canvas of={DuellingPicklistStories.Default} />

### Alternative search placement

Expand Down
163 changes: 154 additions & 9 deletions src/components/duelling-picklist/duelling-picklist.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ import { Checkbox } from "../checkbox";
import Box from "../box";
import Button from "../button";
import Typography from "../typography";
import { Default } from "./duelling-picklist-test.stories";
import generateStyledSystemProps from "../../../.storybook/utils/styled-system-props";
import isChromatic from "../../../.storybook/isChromatic";

const styledSystemProps = generateStyledSystemProps({
margin: true,
});

const defaultOpenState = isChromatic();

const meta: Meta<typeof DuellingPicklist> = {
title: "Duelling Picklist",
component: DuellingPicklist,
Expand All @@ -38,6 +40,154 @@ type Story = StoryObj<typeof DuellingPicklist>;
type Item = { key: string; title: string; description: string };
type AllItems = { [key: string]: Item };

export const Default = () => {
const mockData: Item[] = useMemo(() => {
const arr = [];
for (let i = 0; i < 20; i++) {
const data = {
key: i.toString(),
title: `Content ${i + 1}`,
description: `Description ${i + 1}`,
};
arr.push(data);
}
return arr;
}, []);

const allItems = useMemo(() => {
return mockData.reduce((obj, item) => {
obj[item.key] = item;
return obj;
}, {} as { [key: string]: Item });
}, [mockData]);

const [isEachItemSelected, setIsEachItemSelected] = useState(false);
const [order] = useState(mockData.map(({ key }) => key));
const [notSelectedItems, setNotSelectedItems] = useState<AllItems>(allItems);
const [notSelectedSearch, setNotSelectedSearch] = useState<AllItems>({});
const [selectedItems, setSelectedItems] = useState<AllItems>({});
const [searchQuery, setSearchQuery] = useState("");
const isSearchMode = Boolean(searchQuery.length);

const onAdd = useCallback(
(item) => {
const { [item.key]: removed, ...rest } = notSelectedItems;
setNotSelectedItems(rest);
setSelectedItems({ ...selectedItems, [item.key]: item });
const { [item.key]: removed2, ...rest2 } = notSelectedSearch;
setNotSelectedSearch(rest2);
},
[notSelectedItems, notSelectedSearch, selectedItems]
);

const onRemove = useCallback(
(item) => {
const { [item.key]: removed, ...rest } = selectedItems;
setSelectedItems(rest);
setNotSelectedItems({ ...notSelectedItems, [item.key]: item });
if (isSearchMode && item.title.includes(searchQuery)) {
setNotSelectedSearch({ ...notSelectedSearch, [item.key]: item });
}
},
[
isSearchMode,
notSelectedItems,
notSelectedSearch,
searchQuery,
selectedItems,
]
);

const handleSearch = useCallback(
(ev) => {
setSearchQuery(ev.target.value);
const tempNotSelectedItems = Object.keys(notSelectedItems).reduce(
(items, key) => {
const item = notSelectedItems[key];
if (item.title.includes(ev.target.value)) {
items[item.key] = item;
}
return items;
},
{} as AllItems
);
setNotSelectedSearch(tempNotSelectedItems);
},
[notSelectedItems]
);

const renderItems = (
list: AllItems,
type: PicklistItemProps["type"],
handler: PicklistItemProps["onChange"]
) =>
order.reduce((items, key) => {
const item = list[key];
if (item) {
items.push(
<PicklistItem key={key} type={type} item={item} onChange={handler}>
<div style={{ display: "flex", width: "100%" }}>
<div style={{ width: "50%" }}>
<p style={{ fontWeight: 700, margin: 0, marginLeft: 24 }}>
{item.title}
</p>
</div>
<div style={{ width: "50%" }}>
<p style={{ margin: 0 }}>{item.description}</p>
</div>
</div>
</PicklistItem>
);
}
return items;
}, [] as JSX.Element[]);

return (
<>
<Checkbox
onChange={() => setIsEachItemSelected(!isEachItemSelected)}
checked={isEachItemSelected}
label="Example checkbox"
/>
<DuellingPicklist
leftLabel={`List 1 (${Object.keys(notSelectedItems).length})`}
rightLabel={`List 2 (${Object.keys(selectedItems).length})`}
leftControls={
<Search
tabIndex={isEachItemSelected ? -1 : 0}
placeholder="Search"
name="search_name"
onChange={handleSearch}
value={searchQuery}
id="search_id"
/>
}
disabled={isEachItemSelected}
>
<Picklist
disabled={isEachItemSelected}
placeholder={<div>Your own placeholder</div>}
>
{renderItems(
isSearchMode ? notSelectedSearch : notSelectedItems,
"add",
onAdd
)}
</Picklist>
<PicklistDivider />
<Picklist
disabled={isEachItemSelected}
placeholder={<PicklistPlaceholder text="Nothing to see here" />}
>
{renderItems(selectedItems, "remove", onRemove)}
</Picklist>
</DuellingPicklist>
</>
);
};

Default.storyName = "Default";

export const AlternativeSearch: Story = () => {
const mockData = useMemo(() => {
const arr = [];
Expand Down Expand Up @@ -323,9 +473,9 @@ export const Grouped: Story = () => {
Grouped.storyName = "Grouped";

export const InDialog: Story = () => {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isDialogOpen, setIsDialogOpen] = useState(defaultOpenState);
return (
<>
<Box {...(defaultOpenState ? { height: 900 } : {})}>
<Button onClick={() => setIsDialogOpen(true)}>
Open Duelling Picklist
</Button>
Expand All @@ -337,15 +487,10 @@ export const InDialog: Story = () => {
>
<Default />
</Dialog>
</>
</Box>
);
};
InDialog.storyName = "In Dialog";
InDialog.parameters = {
chromatic: {
disableSnapshot: true,
},
};

export const AddItem: Story = () => (
<ul>
Expand Down

0 comments on commit 600ac5f

Please sign in to comment.