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

Add menu/select items stories and add player.shortcuts #452

Merged
merged 8 commits into from
Nov 29, 2024
5 changes: 5 additions & 0 deletions src/assets/icons/arrow-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions src/stories/dotsMenu/dotsmenuitem.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { Meta, StoryObj } from "@storybook/react";
import { StatusRunningIcon } from "../icons";

import { DotsMenu } from ".";

type Args = React.ComponentProps<typeof DotsMenu.Item> & {
contentType?: string;
};

const meta = {
title: "Atoms/DotsMenuItem",
component: DotsMenu.Item,

parameters: {
docs: {
description: {
component: "Available only inside a `DotsMenu` component.",
},
},
},
argTypes: {
contentType: {
options: ["simple", "withMeta"],
control: {
type: "select",
},
},
},

decorators: [
(Story) => (
<DotsMenu isExpanded={true}>
<Story />
</DotsMenu>
),
],

render: ({ contentType, ...args }) => {
return (
<DotsMenu.Item {...args}>
{contentType === "simple" && "Acacia"}
{contentType === "withMeta" && (
<>
Acacia
<DotsMenu.Item.Meta>Daisy</DotsMenu.Item.Meta>
</>
)}
</DotsMenu.Item>
);
},
args: {
contentType: "simple",
value: "acacia",
},
} satisfies Meta<Args>;

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

export const Default: Story = {
args: {},
};

export const WithMeta: Story = {
args: {
contentType: "withMeta",
},
};

export const Disabled: Story = {
args: {
isDisabled: true,
},
};

export const WithIcon: Story = {
args: {
icon: <StatusRunningIcon />,
},
};
29 changes: 15 additions & 14 deletions src/stories/dropdowns/autocomplete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import {
IComboboxProps,
IOptGroupProps,
IOptionProps,
Option,
OptionValue,
} from "@zendeskgarden/react-dropdowns.next";
import { useCallback, useEffect, useMemo, useState } from "react";
import useDebounce from "../../../hooks/useDebounce";
import { SelectOption } from "../../selectOption";
import { OptGroup } from "../optGroup";

export interface OnOptionClickArgs {
Expand Down Expand Up @@ -100,13 +100,13 @@ const Autocomplete = ({
isHidden: isHidden(opt, debouncedInputValue),
};
}),
[_options, debouncedInputValue]
[_options, debouncedInputValue],
);

// check if there are visible options
const thereAreVisibleOptions = useMemo(
() => flatOptions(matchingOptions).some((opt) => opt.isHidden !== true),
[matchingOptions]
[matchingOptions],
);

const handleChange = useCallback<NonNullable<IComboboxProps["onChange"]>>(
Expand All @@ -118,16 +118,17 @@ const Autocomplete = ({
if (event.type === "input:change" && event.inputValue !== undefined) {
const sanitizedInputValue = event.inputValue.replace(
/[.*+?^${}()|[\]\\]/giu,
"\\$&"
"\\$&",
);
setInputValue(sanitizedInputValue);
if (typeof onInputChange === "function")
onInputChange(sanitizedInputValue);
}
if (
(event.type === "option:click" || event.type === "input:keyDown:Enter")
&& typeof onOptionClick === "function"
&& event.selectionValue // address the issue of clicking enter on an empty input
(event.type === "option:click" ||
event.type === "input:keyDown:Enter") &&
typeof onOptionClick === "function" &&
event.selectionValue // address the issue of clicking enter on an empty input
) {
setInputValue(undefined);
onOptionClick({
Expand All @@ -136,7 +137,7 @@ const Autocomplete = ({
});
}
},
[]
[],
);

return (
Expand All @@ -146,20 +147,20 @@ const Autocomplete = ({
return (
<OptGroup key={option.id} {...option}>
{option.options.map((opt) => (
<Option key={opt.id} {...opt} />
<SelectOption key={opt.id} {...opt} />
))}
</OptGroup>
);
}
return <Option key={index} {...option} />;
return <SelectOption key={index} {...option} />;
})}
{!thereAreVisibleOptions && (
<Option value="" isDisabled>
<SelectOption value="" isDisabled>
No results found
</Option>
</SelectOption>
)}
{isCreatable && debouncedInputValue && (
<Option
<SelectOption
type="add"
value={debouncedInputValue}
title={debouncedInputValue}
Expand All @@ -171,7 +172,7 @@ const Autocomplete = ({
}}
>
{`Add "${debouncedInputValue}"`}
</Option>
</SelectOption>
)}
</Combobox>
);
Expand Down
26 changes: 11 additions & 15 deletions src/stories/dropdowns/countermultiselect/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import {
Combobox,
Field,
Label,
Option,
} from "@zendeskgarden/react-dropdowns.next";
import { Combobox, Field, Label } from "@zendeskgarden/react-dropdowns.next";
import { useEffect, useState } from "react";
import styled from "styled-components";
import { SelectOption } from "../../selectOption";
import { CounterMultiselectArgs } from "./_types";

const StyledComboBox = styled(Combobox)<{ isPrimary?: boolean }>`
Expand Down Expand Up @@ -36,7 +32,7 @@ const CounterMultiselect = ({
isCompact,
}: CounterMultiselectArgs) => {
const [selectedItems, setSelectedItems] = useState(
options.filter((o) => o.selected)
options.filter((o) => o.selected),
);
const [inputValue, setInputValue] = useState("");
const [matchingOptions, setMatchingOptions] = useState(options);
Expand All @@ -48,8 +44,8 @@ const CounterMultiselect = ({
option.label
.trim()
.toLowerCase()
.indexOf(inputValue.trim().toLowerCase()) !== -1
)
.indexOf(inputValue.trim().toLowerCase()) !== -1,
),
);
}, [inputValue, options]);

Expand All @@ -74,7 +70,7 @@ const CounterMultiselect = ({
? i18n?.counterText
? i18n.counterText(selectedItems.length)
: `Items (${selectedItems.length})`
: i18n?.noItems ?? "No items";
: (i18n?.noItems ?? "No items");
}}
isMultiselectable
onChange={({ type, selectionValue, inputValue }) => {
Expand All @@ -85,7 +81,7 @@ const CounterMultiselect = ({
onChange
) {
const newOptions = options.filter((o) =>
selectionValue.includes(o.itemId.toString())
selectionValue.includes(o.itemId.toString()),
);
onChange(newOptions);
setSelectedItems(newOptions);
Expand All @@ -97,7 +93,7 @@ const CounterMultiselect = ({
}}
>
{options.map((option) => (
<Option
<SelectOption
key={option.itemId}
value={option.itemId.toString()}
label={option.label}
Expand All @@ -106,16 +102,16 @@ const CounterMultiselect = ({
}}
isHidden={
!matchingOptions.some(
(matchingOption) => matchingOption.itemId === option.itemId
(matchingOption) => matchingOption.itemId === option.itemId,
)
}
isSelected={selectedItems.some(
(selectedItem) => selectedItem.itemId === option.itemId
(selectedItem) => selectedItem.itemId === option.itemId,
)}
/>
))}
{matchingOptions.length === 0 && (
<Option
<SelectOption
isDisabled
value=""
label={i18n?.noMatches ?? "No matches found"}
Expand Down
7 changes: 4 additions & 3 deletions src/stories/dropdowns/select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "@zendeskgarden/react-dropdowns.next";
import { ComponentProps } from "react";
import styled from "styled-components";
import { SelectOption } from "../../selectOption";
import { SelectArgs } from "./_types";

const StyledComboBox = styled(Combobox)<{ isPrimary?: boolean }>`
Expand Down Expand Up @@ -46,7 +47,7 @@ const Select = ({
onChange={(changeEvent) => {
if (
["input:keyDown:Enter", "option:click"].includes(
changeEvent.type
changeEvent.type,
) &&
changeEvent.selectionValue &&
onSelect
Expand All @@ -62,7 +63,7 @@ const Select = ({
);
};

Select.Option = Option;
Select.Option = SelectOption;

const StyledMenuOption = styled(Option)`
padding-left: ${({ theme }) => theme.space.sm};
Expand All @@ -80,7 +81,7 @@ const StyledMenuOption = styled(Option)`
`;

Select.MenuOption = (
props: Omit<ComponentProps<typeof Select.Option>, "isDisabled">
props: Omit<ComponentProps<typeof Select.Option>, "isDisabled">,
) => {
return <StyledMenuOption {...props} isDisabled />;
};
Expand Down
24 changes: 11 additions & 13 deletions src/stories/multiselect/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import {
Combobox,
Field,
Label,
Option,
} from "@zendeskgarden/react-dropdowns.next";
import { Combobox, Field, Label } from "@zendeskgarden/react-dropdowns.next";
import { useEffect, useState } from "react";
import { ReactComponent as GridAddIcon } from "../../assets/icons/plus.svg";
import { Separator } from "../dropdowns/menu";
import { SelectOption } from "../selectOption";
import { theme } from "../theme";
import { MultiSelectProps } from "./_types";

Expand All @@ -27,7 +23,7 @@ export const MultiSelect = ({
option.label
.trim()
.toLowerCase()
.indexOf(inputValue.trim().toLowerCase()) !== -1
.indexOf(inputValue.trim().toLowerCase()) !== -1,
);

setMatchingOptions(matchedOptions);
Expand Down Expand Up @@ -76,7 +72,9 @@ export const MultiSelect = ({
}
if (
onChange &&
(type === "fn:setSelectionValue" || type === "option:click" || type === "input:keyDown:Enter") &&
(type === "fn:setSelectionValue" ||
type === "option:click" ||
type === "input:keyDown:Enter") &&
Array.isArray(selectionValue)
) {
const ss = selectionValue.map((s) => {
Expand All @@ -100,13 +98,13 @@ export const MultiSelect = ({
...o,
selected: selectedOptions.some((i) => i.id === o.id),
})),
newOption ? newOption : undefined
newOption ? newOption : undefined,
).then(() => setInputValue(""));
}
}}
>
{options.map((option) => (
<Option
<SelectOption
isHidden={!matchingOptions.some((o) => o.id === option.id)}
key={option.id}
value={option.id.toString()}
Expand All @@ -118,7 +116,7 @@ export const MultiSelect = ({
/>
))}
{matchingOptions.length === 0 && !creatable && (
<Option
<SelectOption
isDisabled
value=""
label={i18n?.noMatches ?? "No matches found"}
Expand All @@ -127,11 +125,11 @@ export const MultiSelect = ({
{creatable &&
inputValue.length > 0 &&
!matchingOptions.find(
(item) => item.label.toLowerCase() === inputValue.toLowerCase()
(item) => item.label.toLowerCase() === inputValue.toLowerCase(),
) ? (
<>
<Separator />
<Option
<SelectOption
tagProps={{ isPill: true }}
value={inputValue}
icon={<GridAddIcon />}
Expand Down
5 changes: 5 additions & 0 deletions src/stories/player/_types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export interface PlayerArgs extends HTMLAttributes<HTMLVideoElement> {
export interface PlayerI18n {
beforeHighlight?: string;
onHighlight?: string;
playpause?: string;
mute?: string;
observations?: string;
forward?: string;
backward?: string;
}

export interface IBookmark {
Expand Down
Loading
Loading