diff --git a/packages/core/src/components/Dropdown/components/Trigger/SingleSelectTrigger.tsx b/packages/core/src/components/Dropdown/components/Trigger/SingleSelectTrigger.tsx index 87941c5b22..c947f091c2 100644 --- a/packages/core/src/components/Dropdown/components/Trigger/SingleSelectTrigger.tsx +++ b/packages/core/src/components/Dropdown/components/Trigger/SingleSelectTrigger.tsx @@ -8,6 +8,7 @@ import { Flex } from "@vibe/layout"; import TriggerActions from "./TriggerActions"; import { getStyle } from "@vibe/shared"; +// Renders the trigger for single-select dropdowns (searchable and non-searchable). const SingleSelectTrigger = () => { const { inputValue, diff --git a/packages/docs/src/pages/components/Dropdown/DropdownSearchableSingleSelect.mdx b/packages/docs/src/pages/components/Dropdown/DropdownSearchableSingleSelect.mdx new file mode 100644 index 0000000000..3e73fb2e5e --- /dev/null +++ b/packages/docs/src/pages/components/Dropdown/DropdownSearchableSingleSelect.mdx @@ -0,0 +1,32 @@ +import { Meta, Canvas } from "@storybook/blocks"; +import * as DropdownSearchableSingleSelectStories from "./DropdownSearchableSingleSelect.stories"; + + + +# Searchable single select — Accessibility + +### Import + +```js +import { Dropdown } from "@vibe/core"; +``` + +## Overview + + + +## Default value + + + +## With icons and avatars + + + +## With end elements + + + +## With valueRenderer + + diff --git a/packages/docs/src/pages/components/Dropdown/DropdownSearchableSingleSelect.stories.tsx b/packages/docs/src/pages/components/Dropdown/DropdownSearchableSingleSelect.stories.tsx new file mode 100644 index 0000000000..bfacd79188 --- /dev/null +++ b/packages/docs/src/pages/components/Dropdown/DropdownSearchableSingleSelect.stories.tsx @@ -0,0 +1,230 @@ +import React, { useMemo } from "react"; +import { type Meta, type StoryObj } from "@storybook/react"; +import { createStoryMetaSettingsDecorator } from "../../../utils/createStoryMetaSettingsDecorator"; +import person1 from "../Avatar/assets/person1.png"; +import person2 from "../Avatar/assets/person2.png"; +import person3 from "../Avatar/assets/person3.png"; +import { Attach, Email } from "@vibe/icons"; +import { Dropdown, type BaseDropdownProps, type DropdownOption, Flex, Text } from "@vibe/core"; + +type Story = StoryObj; + +const metaSettings = createStoryMetaSettingsDecorator({ + component: Dropdown, + actionPropsArray: [ + "onMenuOpen", + "onMenuClose", + "onFocus", + "onBlur", + "onChange", + "openMenuOnFocus", + "onOptionSelect", + "onClear", + "onInputChange", + "onKeyDown" + ] +}); + +const meta: Meta = { + title: "Components/Dropdown/Searchable single select", + component: Dropdown, + argTypes: metaSettings.argTypes, + decorators: metaSettings.decorators +}; + +export default meta; + +const basicOptions = [ + { value: "marketing", label: "Marketing" }, + { value: "design", label: "Design" }, + { value: "engineering", label: "Engineering" }, + { value: "product", label: "Product" }, + { value: "sales", label: "Sales" } +]; + +const dropdownTemplate = (props: BaseDropdownProps) => { + const options = useMemo(() => basicOptions, []); + + return ( +
+ +
+ ); +}; + +export const Overview: Story = { + render: dropdownTemplate.bind({}), + args: { + id: "searchable-single-overview", + "aria-label": "Searchable single select", + placeholder: "Search a team", + clearAriaLabel: "Clear" + }, + parameters: { + docs: { + liveEdit: { + isEnabled: false + } + } + } +}; + +export const WithDefaultValue: Story = { + render: () => { + const options = useMemo(() => basicOptions, []); + return ( +
+ +
+ ); + } +}; + +export const WithIconsAndAvatars: Story = { + render: () => { + const iconOptions = useMemo( + () => [ + { value: "email", label: "Email", startElement: { type: "icon", value: Email } }, + { value: "attach", label: "Attach", startElement: { type: "icon", value: Attach } } + ], + [] + ); + const avatarOptions = useMemo( + () => [ + { value: "julia", label: "Julia Martinez", startElement: { type: "avatar", value: person1 } }, + { value: "sophia", label: "Sophia Johnson", startElement: { type: "avatar", value: person2 } }, + { value: "marco", label: "Marco DiAngelo", startElement: { type: "avatar", value: person3 } } + ], + [] + ); + + return ( + +
+ +
+
+ +
+
+ ); + }, + parameters: { + docs: { + liveEdit: { + scope: { person1, person2, person3 } + } + } + } +}; + +export const WithEndElements: Story = { + render: () => { + const endIconOptions = useMemo( + () => [ + { value: "email", label: "Email", endElement: { type: "icon", value: Email } }, + { value: "attach", label: "Attach", endElement: { type: "icon", value: Attach } } + ], + [] + ); + const suffixOptions = useMemo( + () => [ + { value: "copy", label: "Copy", endElement: { type: "suffix", value: "⌘C" } }, + { value: "paste", label: "Paste", endElement: { type: "suffix", value: "⌘V" } } + ], + [] + ); + + return ( + +
+ +
+
+ +
+
+ ); + } +}; + +export const WithValueRenderer: Story = { + render: () => { + const options = useMemo( + () => [ + { value: "julia", label: "Julia Martinez", startElement: { type: "avatar", value: person1 } }, + { value: "sophia", label: "Sophia Johnson", startElement: { type: "avatar", value: person2 } } + ], + [] + ); + + const valueRenderer = (option: DropdownOption) => ( + + + Custom: {option.label} + + ); + + return ( +
+ +
+ ); + }, + parameters: { + docs: { + liveEdit: { + scope: { person1, person2 } + } + } + } +};