Skip to content

Commit

Permalink
Merge pull request #424 from AppQuality/new-select
Browse files Browse the repository at this point in the history
feat: Add new select
  • Loading branch information
d-beezee authored Oct 14, 2024
2 parents 98094b6 + 80fc148 commit a8b338d
Show file tree
Hide file tree
Showing 5 changed files with 390 additions and 88 deletions.
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export * from "./stories/dropdowns/item-content";
export * from "./stories/dropdowns/menu";
export * from "./stories/dropdowns/menuheader";
export * from "./stories/dropdowns/select";
export * from "./stories/dropdowns/selectNew";

// --- Editor ---
export * from "./stories/editor";
Expand Down
12 changes: 12 additions & 0 deletions src/stories/dropdowns/selectNew/_types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { IComboboxProps } from "@zendeskgarden/react-dropdowns.next";

export interface SelectArgs extends Omit<IComboboxProps, "onSelect"> {
/** The label*/
label?: React.ReactNode;
className?: string;
/** Sets the style of dropdown item*/
isPrimary?: boolean;
children?: React.ReactNode;
onSelect?: (value: string) => Promise<void> | void;
isDisabled?: boolean;
}
165 changes: 165 additions & 0 deletions src/stories/dropdowns/selectNew/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { Meta as ComponentMeta, StoryFn as Story } from "@storybook/react";
import { useState } from "react";
import { SelectNew as Select } from ".";
import { SelectArgs } from "./_types";

type ISingleItem = {
label: string;
value: string;
};

type IGroup = {
label?: string;
items: Array<ISingleItem>;
};

type IItem = ISingleItem | IGroup;

interface MenuStoryArgs extends SelectArgs {
items: Array<IItem>;
menuOption?: {
label: string;
onClick: () => void;
};
}

const items = [
{ label: "Ferdinand ThreeMelons", value: "item-1" },
{ label: "Giommo Cornelio", value: "item-2" },
{ label: "Rubber tree", value: "item-3" },
];

const Template: Story<MenuStoryArgs> = ({ items, ...args }) => {
function getSelectedValue() {
if ("items" in items[0]) return items[0].items[0].value;
return items[0].value;
}
const [selectedItem, setSelectedItem] = useState(getSelectedValue());
function getItems() {
return items.map((item) => {
if ("items" in item) {
return (
<Select.OptionGroup label={item.label}>
{item.items.map((singleItem) => (
<Select.Option
value={singleItem.value}
label={singleItem.label}
/>
))}
</Select.OptionGroup>
);
} else {
return <Select.Option value={item.value} label={item.label} />;
}
});
}
function getItemByValue(value: string) {
const allItems = items
.map((item) => {
if ("items" in item) {
return item.items;
}
return item;
})
.flat();
return allItems.find((item) => item.value === value);
}
return (
<div style={{ width: "300px" }}>
<Select
{...args}
inputValue={selectedItem}
selectionValue={selectedItem}
renderValue={(value) => getItemByValue(value.inputValue || "")?.label}
onSelect={(value) => {
setSelectedItem(value);
args.onSelect?.(value);
}}
validation={args?.validation}
label="Food Manager"
>
{getItems()}
{args.menuOption && (
<Select.MenuOption
label={args.menuOption.label}
value="menu-option"
onClick={args.menuOption.onClick}
/>
)}
</Select>
</div>
);
};

export const Default = Template.bind({});
Default.args = {
items: items,
onSelect: (item: string) => {
console.log(item);
alert("Selected: " + item);
},
isCompact: false,
isBare: false,
isDisabled: false,
isPrimary: false,
};

export const Validation = Template.bind({});
Validation.args = {
items: items,
onSelect: (item: string) => {
console.log(item);
alert("Selected: " + item);
},
isCompact: false,
isBare: false,
isDisabled: false,
isPrimary: false,

validation: "warning",
};

export const WithMenuOption = Template.bind({});
WithMenuOption.args = {
items: items,
onSelect: (item: string) => {
console.log(item);
alert("Selected: " + item);
},
isCompact: false,
isBare: false,
isDisabled: false,
isPrimary: false,
menuOption: {
label: "Add new",
onClick: () => {
alert("Add new clicked");
},
},
};

export const WithGroups = Template.bind({});
WithGroups.args = {
items: [
{ label: "Giommis", items: items },
{ label: "Others", items: [{ label: "Non Giommis", value: "item-99" }] },
{ items: [{ label: "Ungrouped", value: "item-1000" }] },
],
onSelect: (item: string) => {
console.log(item);
alert("Selected: " + item);
},
isCompact: false,
isBare: false,
isDisabled: false,
isPrimary: false,
};

export default {
title: "Molecules/Dropdown/SelectNew",
component: Select,
parameters: {
// Sets a delay for the component's stories
chromatic: { delay: 300 },
},
} as ComponentMeta<typeof Select>;
106 changes: 106 additions & 0 deletions src/stories/dropdowns/selectNew/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
Combobox,
Field,
Label,
OptGroup,
Option,
} from "@zendeskgarden/react-dropdowns.next";
import { ComponentProps } from "react";
import styled from "styled-components";
import { SelectArgs } from "./_types";

const StyledComboBox = styled(Combobox)<{ isPrimary?: boolean }>`
[data-garden-container-id="containers.combobox.option"] {
display: flex;
gap: ${({ theme }) => theme.space.sm};
align-items: center;
}
${(props) =>
props.isPrimary &&
`
[data-garden-container-id="containers.combobox"] {
background-color: ${props.theme.palette.blue[600]};
color: white;
svg[data-garden-id="dropdowns.combobox.input_icon"] {
color: white;
}
}
`}
`;

const SelectNew = ({
label,
className,
children,
onSelect,
...props
}: SelectArgs) => {
return (
<div className={className}>
<Field>
{label ? <Label>{label}</Label> : null}
<StyledComboBox
{...props}
isEditable={false}
onChange={(changeEvent) => {
if (
["input:keyDown:Enter", "option:click"].includes(
changeEvent.type
) &&
changeEvent.selectionValue &&
onSelect
) {
onSelect(changeEvent.selectionValue.toString());
}
}}
>
{children}
</StyledComboBox>
</Field>
</div>
);
};

SelectNew.Option = Option;

const StyledMenuOption = styled(Option)`
padding-left: ${({ theme }) => theme.space.sm};
padding-right: ${({ theme }) => theme.space.sm};
&[aria-disabled="true"] {
color: ${({ theme }) => theme.palette.blue[600]};
font-weight: ${({ theme }) => theme.fontWeights.semibold};
cursor: pointer;
&:hover {
border-radius: 0 !important;
box-shadow: inset 3px 0 ${({ theme }) => theme.palette.blue[600]};
background-color: ${({ theme }) => theme.palette.blue[600]}14;
}
}
`;

SelectNew.MenuOption = (
props: Omit<ComponentProps<typeof SelectNew.Option>, "isDisabled">
) => {
return <StyledMenuOption {...props} isDisabled />;
};

const OptionGroup = styled(OptGroup)`
[data-garden-id="dropdowns.combobox.option.content"]
> [data-garden-id="dropdowns.combobox.option"] {
padding-left: ${({ theme }) => theme.space.sm};
padding-right: ${({ theme }) => theme.space.sm};
}
`;

SelectNew.OptionGroup = OptionGroup;

const OptionTitle = styled.div`
padding: ${({ theme }) => theme.space.xxs} ${({ theme }) => theme.space.sm};
color: ${({ theme }) => theme.palette.grey[800]};
font-weight: ${({ theme }) => theme.fontWeights.semibold};
`;

SelectNew.OptionTitle = OptionTitle;

export { SelectNew };
Loading

0 comments on commit a8b338d

Please sign in to comment.