Files
o11y-components/apps/docs/stories/select-simple.stories.tsx
zeekay 464e1eece0 State a version once
A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.

Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
2026-09-15 11:45:32 -07:00

325 lines
7.3 KiB
TypeScript

import { Code, Database, GitBranch, Terminal } from '@signozhq/icons';
import { SelectSimple } from '@signozhq/ui';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { useState } from 'react';
const meta: Meta<typeof SelectSimple> = {
title: 'Composed Components/Select/SelectSimple',
component: SelectSimple,
argTypes: {
items: {
control: 'object',
description: 'List of items to display (flat). Ignored when groups is provided.',
table: { category: 'Content', type: { summary: 'SelectSimpleItem[]' } },
},
groups: {
control: false,
description: 'Grouped items with optional headings. When provided, items is ignored.',
table: { category: 'Content', type: { summary: 'SelectSimpleGroup[]' } },
},
placeholder: {
control: 'text',
description: 'Placeholder text when no value is selected.',
table: { category: 'Content', type: { summary: 'string' } },
},
value: {
control: 'text',
description: 'Controlled selected value.',
table: { category: 'State', type: { summary: 'string | string[]' } },
},
defaultValue: {
control: 'text',
description: 'Initial value when uncontrolled.',
table: { category: 'State', type: { summary: 'string | string[]' } },
},
disabled: {
control: 'boolean',
description: 'Whether the select is disabled.',
table: {
category: 'State',
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
multiple: {
control: 'boolean',
description: 'Enable multi-select mode.',
table: {
category: 'Behavior',
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
withPortal: {
control: 'boolean',
description: 'Whether to render dropdown in a portal.',
table: {
category: 'Behavior',
type: { summary: 'boolean' },
defaultValue: { summary: 'true' },
},
},
defaultOpen: {
control: 'boolean',
description: 'Initial open state when uncontrolled.',
table: {
category: 'Behavior',
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
onChange: {
control: false,
description: 'Callback when selection changes.',
table: { category: 'Events', type: { summary: '(value: string | string[]) => void' } },
},
displayValue: {
control: false,
description: 'Customize what is shown in the trigger for selected items.',
table: {
category: 'Styling',
type: { summary: '(selectedItems: SelectSimpleItem[]) => React.ReactNode' },
},
},
loading: {
control: 'boolean',
description: 'Show loading spinner on trigger.',
table: {
category: 'State',
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
},
},
loadingPlaceholder: {
control: 'text',
description: 'Content shown in dropdown while loading. Can be string or ReactNode.',
table: {
category: 'Content',
type: { summary: 'ReactNode' },
defaultValue: { summary: "'Loading...'" },
},
},
},
parameters: {
layout: 'fullscreen',
},
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof SelectSimple>;
const defaultItems = [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
];
export const Default: Story = {
args: {
items: defaultItems,
placeholder: 'Select a framework...',
},
render: (args) => (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} />
</div>
),
};
export const Controlled: Story = {
args: {
items: defaultItems,
placeholder: 'Select a framework...',
},
render: (args) => {
const [value, setValue] = useState('');
return (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} value={value} onChange={(v) => setValue(v as string)} />
<p
style={{
marginTop: 16,
fontSize: 14,
lineHeight: 1.42857,
color: 'var(--muted-foreground)',
}}
>
Selected: {value || 'none'}
</p>
</div>
);
},
};
export const WithDefaultValue: Story = {
args: {
items: defaultItems,
placeholder: 'Select a framework...',
defaultValue: 'react',
},
render: (args) => (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} />
</div>
),
};
const groups = [
{
heading: 'Frameworks',
items: [
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
],
},
{
heading: 'Languages',
items: [
{ value: 'javascript', label: 'JavaScript' },
{ value: 'typescript', label: 'TypeScript' },
{ value: 'python', label: 'Python' },
{ value: 'go', label: 'Go' },
{ value: 'rust', label: 'Rust' },
],
},
];
export const WithGroups: Story = {
args: {
groups,
placeholder: 'Select a technology...',
},
render: (args) => (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} />
</div>
),
};
const itemsWithIcons = [
{
value: 'react',
label: (
<>
<Code style={{ marginRight: 8, height: 16, width: 16 }} />
React
</>
),
displayValue: 'React',
},
{
value: 'nodejs',
label: (
<>
<Terminal style={{ marginRight: 8, height: 16, width: 16 }} />
Node.js
</>
),
displayValue: 'Node.js',
},
{
value: 'postgres',
label: (
<>
<Database style={{ marginRight: 8, height: 16, width: 16 }} />
PostgreSQL
</>
),
displayValue: 'PostgreSQL',
},
{
value: 'git',
label: (
<>
<GitBranch style={{ marginRight: 8, height: 16, width: 16 }} />
Git
</>
),
displayValue: 'Git',
},
];
export const WithIcons: Story = {
args: {
items: itemsWithIcons,
placeholder: 'Select a tool...',
},
render: (args) => (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} />
</div>
),
};
export const MultiSelect: Story = {
args: {
items: defaultItems,
placeholder: 'Select frameworks...',
multiple: true,
},
render: (args) => {
const [values, setValues] = useState<string[]>([]);
return (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} value={values} onChange={(v) => setValues(v as string[])} />
<p
style={{
marginTop: 16,
fontSize: 14,
lineHeight: 1.42857,
color: 'var(--muted-foreground)',
}}
>
Selected: {values.length > 0 ? values.join(', ') : 'none'}
</p>
</div>
);
},
};
export const MultiSelectWithIcons: Story = {
args: {
items: itemsWithIcons,
placeholder: 'Select tools...',
multiple: true,
},
render: (args) => {
const [values, setValues] = useState<string[]>([]);
return (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} value={values} onChange={(v) => setValues(v as string[])} />
<p
style={{
marginTop: 16,
fontSize: 14,
lineHeight: 1.42857,
color: 'var(--muted-foreground)',
}}
>
Selected: {values.length > 0 ? values.join(', ') : 'none'}
</p>
</div>
);
},
};
export const Disabled: Story = {
args: {
items: defaultItems,
placeholder: 'Select a framework...',
disabled: true,
},
render: (args) => (
<div style={{ padding: 32, width: '100%', maxWidth: 384 }}>
<SelectSimple {...args} />
</div>
),
};