-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathselect-alignment.stories.tsx
More file actions
100 lines (92 loc) · 3.23 KB
/
select-alignment.stories.tsx
File metadata and controls
100 lines (92 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import type { Meta, StoryObj } from '@storybook/react-vite';
import { expect, userEvent, waitFor, within } from '@storybook/test';
import { useState } from 'react';
import { Select } from '@lambdacurry/forms/ui/select';
const meta = {
title: 'UI/Select/Alignment',
component: Select,
parameters: {
layout: 'centered',
docs: {
description: {
story:
'Use `contentProps` to align the popover with right-aligned triggers, such as when a Select sits near the edge of a container.',
},
},
},
tags: ['autodocs'],
} satisfies Meta<typeof Select>;
export default meta;
type Story = StoryObj<typeof meta>;
const fruits = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Cherry', value: 'cherry' },
];
const RightAlignedSelectExample = () => {
const [value, setValue] = useState('');
return (
<div className="w-full max-w-md space-y-3">
<div className="rounded-lg border border-border bg-card p-6">
<div className="flex justify-end">
<div className="w-44">
<Select
aria-label="Favorite fruit"
placeholder="Select a fruit"
options={fruits}
value={value}
onValueChange={setValue}
contentProps={{ align: 'end' }}
/>
</div>
</div>
</div>
<p className="text-sm text-muted-foreground">
Right-align the popover when the trigger is flush with the container edge to avoid clipping and keep the
dropdown visible.
</p>
</div>
);
};
export const RightAligned: Story = {
render: () => <RightAlignedSelectExample />,
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
const trigger = canvas.getByRole('combobox', { name: 'Favorite fruit' });
await step('Open the select', async () => {
await userEvent.click(trigger);
await waitFor(() => {
const popover = document.querySelector('[data-slot="popover-content"]');
expect(popover).not.toBeNull();
expect(popover).toHaveAttribute('data-align', 'end');
});
});
await step('Navigate and select via keyboard', async () => {
await waitFor(() => {
const commandRoot = document.querySelector('[cmdk-root]');
expect(commandRoot).not.toBeNull();
});
const listbox = document.querySelector('[role="listbox"]') as HTMLElement;
listbox.focus();
await waitFor(() => {
expect(document.activeElement).toBe(listbox);
});
await userEvent.keyboard('{ArrowDown}', { focusTrap: false });
await waitFor(() => {
const activeItem = document.querySelector('[cmdk-item][aria-selected="true"]');
expect(activeItem).not.toBeNull();
});
const activeItem = document.querySelector('[cmdk-item][aria-selected="true"]') as HTMLElement;
activeItem.dispatchEvent(
new CustomEvent('cmdk-item-select', {
detail: activeItem.getAttribute('data-value'),
bubbles: true,
}),
);
await waitFor(() => {
expect(document.querySelector('[data-slot="popover-content"]')).toBeNull();
expect(trigger).toHaveAttribute('aria-expanded', 'false');
});
});
},
};