Files
Verso/services/web/frontend/stories/shared/autocomplete.stories.tsx
T
Alf EatonandCopybot ce4ca192ee Upgrade Storybook to v10 (#30442)
GitOrigin-RevId: 9f51624bc2b34b6746d1854969173b44c9c9cf9a
2026-04-22 08:06:26 +00:00

337 lines
9.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Meta, StoryObj } from '@storybook/react-webpack5'
import { useState } from 'react'
import OLAutocomplete from '@/shared/components/ol/ol-autocomplete'
type Args = React.ComponentProps<typeof OLAutocomplete>
const sampleItems = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
{ value: 'ember', label: 'Ember' },
{ value: 'backbone', label: 'Backbone' },
{ value: 'preact', label: 'Preact' },
{ value: 'nextjs', label: 'Next.js' },
{ value: 'nuxtjs', label: 'Nuxt.js' },
{ value: 'gatsby', label: 'Gatsby' },
]
const programmingLanguages = [
{ value: 'javascript', label: 'JavaScript' },
{ value: 'typescript', label: 'TypeScript' },
{ value: 'python', label: 'Python' },
{ value: 'java', label: 'Java' },
{ value: 'cpp', label: 'C++' },
{ value: 'csharp', label: 'C#' },
{ value: 'go', label: 'Go' },
{ value: 'rust', label: 'Rust' },
{ value: 'ruby', label: 'Ruby' },
{ value: 'php', label: 'PHP' },
{ value: 'swift', label: 'Swift' },
{ value: 'kotlin', label: 'Kotlin' },
{ value: 'dart', label: 'Dart' },
]
const countries = [
{ value: 'us', label: 'United States' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'ca', label: 'Canada' },
{ value: 'au', label: 'Australia' },
{ value: 'de', label: 'Germany' },
{ value: 'fr', label: 'France' },
{ value: 'es', label: 'Spain' },
{ value: 'it', label: 'Italy' },
{ value: 'nl', label: 'Netherlands' },
{ value: 'be', label: 'Belgium' },
]
const entryTypeItems = [
{ value: 'article', label: 'Article', group: 'Most common' },
{ value: 'review', label: 'Review', group: 'Most common' },
{ value: 'book', label: 'Book', group: 'Most common' },
{ value: 'conference', label: 'Conference paper', group: 'Most common' },
{ value: 'thesis', label: 'Thesis', group: 'Most common' },
{ value: 'mastersthesis', label: "Master's thesis", group: 'Most common' },
{ value: 'phdthesis', label: 'PhD thesis', group: 'Most common' },
{ value: 'bookchapter', label: 'Book chapter', group: 'Book types' },
{ value: 'booksection', label: 'Book section', group: 'Book types' },
{ value: 'bookpart', label: 'Book part', group: 'Book types' },
{ value: 'editedbook', label: 'Edited book', group: 'Book types' },
{ value: 'referencebook', label: 'Reference book', group: 'Book types' },
{ value: 'proceedings', label: 'Conference proceedings', group: 'Other' },
{ value: 'journalarticle', label: 'Journal article', group: 'Other' },
{ value: 'techreport', label: 'Technical report', group: 'Other' },
{ value: 'preprint', label: 'Preprint', group: 'Other' },
{ value: 'patent', label: 'Patent', group: 'Other' },
{ value: 'manuscript', label: 'Manuscript', group: 'Other' },
{ value: 'unpublished', label: 'Unpublished', group: 'Other' },
]
function InteractiveAutocomplete(args: Args) {
const [value, setValue] = useState('')
return (
<div style={{ maxWidth: '400px' }}>
<OLAutocomplete {...args} onChange={setValue} />
<div style={{ marginTop: '1rem' }}>
<strong>Current value:</strong> {value || '(empty)'}
</div>
</div>
)
}
export const Default: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: sampleItems,
label: 'Select a framework',
placeholder: 'Type to search...',
showLabel: true,
allowCreate: true,
},
}
export const WithoutCreateOption: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: programmingLanguages,
label: 'Programming language',
placeholder: 'Choose a language',
showLabel: true,
allowCreate: false,
},
}
export const AllowCreatePredicate: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: programmingLanguages,
label: 'Programming language (custom rule)',
placeholder: 'Try typing java or script',
showLabel: true,
allowCreate: value => {
const normalized = value.trim().toLowerCase()
return (
normalized.length >= 4 &&
!normalized.includes('script') &&
normalized !== 'java'
)
},
},
}
export const HiddenLabel: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: countries,
label: 'Country',
placeholder: 'Select your country',
showLabel: false,
allowCreate: true,
},
}
export const CustomCreatePrefix: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: [
{ value: 'alpha', label: 'Project Alpha' },
{ value: 'beta', label: 'Project Beta' },
{ value: 'gamma', label: 'Project Gamma' },
],
label: 'Project name',
placeholder: 'Select or create a project',
showLabel: true,
allowCreate: true,
createOptionPrefix: ' Create new project:',
},
}
export const Disabled: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: sampleItems,
label: 'Framework (disabled)',
placeholder: 'Cannot interact',
showLabel: true,
disabled: true,
},
}
export const SmallList: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
{ value: 'option3', label: 'Option 3' },
],
label: 'Choose an option',
placeholder: 'Type or select...',
showLabel: true,
allowCreate: true,
},
}
export const GroupedItems: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: entryTypeItems,
label: 'Entry type',
placeholder: 'Enter entry type',
showLabel: true,
allowCreate: true,
},
}
export const GroupedWithoutCreate: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: [
{ value: 'react', label: 'React', group: 'Frontend' },
{ value: 'vue', label: 'Vue', group: 'Frontend' },
{ value: 'angular', label: 'Angular', group: 'Frontend' },
{ value: 'svelte', label: 'Svelte', group: 'Frontend' },
{ value: 'nodejs', label: 'Node.js', group: 'Backend' },
{ value: 'django', label: 'Django', group: 'Backend' },
{ value: 'rails', label: 'Ruby on Rails', group: 'Backend' },
{ value: 'spring', label: 'Spring Boot', group: 'Backend' },
{ value: 'reactnative', label: 'React Native', group: 'Mobile' },
{ value: 'flutter', label: 'Flutter', group: 'Mobile' },
{ value: 'swift', label: 'Swift', group: 'Mobile' },
{ value: 'kotlin', label: 'Kotlin', group: 'Mobile' },
],
label: 'Technology',
placeholder: 'Search technologies...',
showLabel: true,
allowCreate: false,
},
}
export const FuzzySearch: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: [
{ value: 'javascript', label: 'JavaScript' },
{ value: 'typescript', label: 'TypeScript' },
{ value: 'python', label: 'Python' },
{ value: 'rust', label: 'Rust' },
{ value: 'golang', label: 'Go' },
],
label: 'Language (fuzzy search)',
placeholder: 'Try typo searches, e.g. javasript or pyton',
showLabel: true,
allowCreate: true,
useFuzzySearch: true,
},
}
export const GroupedFuzzySearch: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: entryTypeItems,
label: 'Grouped entry type (fuzzy search)',
placeholder: 'Try typo searches, e.g. confernce or theis',
showLabel: true,
allowCreate: true,
useFuzzySearch: true,
},
}
export const ExpandUp: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: sampleItems,
label: 'Framework (expand up)',
placeholder: 'Dropdown expands upward',
showLabel: true,
allowCreate: true,
expandUp: true,
},
}
export const ExpandUpGrouped: StoryObj<Args> = {
render: args => <InteractiveAutocomplete {...args} />,
args: {
items: entryTypeItems,
label: 'Entry type (expand up)',
placeholder: 'Grouped items expanding upward',
showLabel: true,
allowCreate: true,
expandUp: true,
},
}
const meta: Meta<typeof OLAutocomplete> = {
title: 'Shared / Components / Autocomplete',
component: OLAutocomplete,
tags: ['autodocs'],
parameters: {
controls: {
include: [
'items',
'label',
'placeholder',
'showLabel',
'allowCreate',
'disabled',
'createOptionPrefix',
'useFuzzySearch',
'expandUp',
],
},
},
argTypes: {
items: {
control: 'object',
description:
'Array of available options; use the optional group property for grouped sections',
},
onChange: {
description: 'Callback when value changes',
},
label: {
control: 'text',
description: 'Label for the input',
},
placeholder: {
control: 'text',
description: 'Placeholder text',
},
showLabel: {
control: 'boolean',
description: 'Show or hide the label visually',
},
allowCreate: {
control: 'boolean',
description:
'Allow creating custom values, or provide a predicate function `(value) => boolean` to conditionally allow create per input value',
table: {
type: {
summary: 'boolean | ((value: string) => boolean)',
},
},
},
disabled: {
control: 'boolean',
description: 'Disable the input',
},
createOptionPrefix: {
control: 'text',
description: 'Text prefix for the create option',
},
useFuzzySearch: {
control: 'boolean',
description: 'Enable fuzzy search matching for suggestions',
},
expandUp: {
control: 'boolean',
description:
'When true, the dropdown expands upward and the search bar appears below the results list',
},
},
}
export default meta