@altimateai/ui-components 0.0.37-beta.1 → 0.0.37-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CoachForm.css +1 -1
- package/dist/CoachForm.js +10471 -10409
- package/dist/Form.js +2288 -1905
- package/dist/Stack.js +1146 -1140
- package/dist/assets/icons/index.js +1 -1
- package/dist/chatbotV2/index.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index2.js +14 -14
- package/dist/lineage/index.js +1 -1
- package/dist/main.js +75 -75
- package/dist/shadcn/index.d.ts +36 -30
- package/dist/shadcn/index.js +2070 -2293
- package/dist/storybook/Combobox.stories.tsx +650 -0
- package/dist/storybook/Select.stories.tsx +0 -318
- package/dist/storybook/Tabs.stories.tsx +7 -7
- package/dist/{types-Bot4W1-C.d.ts → types-COyBAkqH.d.ts} +4 -0
- package/package.json +2 -2
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
import { Meta, StoryFn } from "@storybook/react";
|
|
2
|
+
import { Combobox } from "../shadcn";
|
|
3
|
+
import { Button } from "../button";
|
|
4
|
+
import { DatabaseIcon } from "@ac-assets/icons";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "Shadcn/Components/Combobox",
|
|
9
|
+
component: Combobox,
|
|
10
|
+
} as Meta;
|
|
11
|
+
|
|
12
|
+
export const ComboboxExample: StoryFn = () => {
|
|
13
|
+
const options = [
|
|
14
|
+
{ value: "react", label: "React" },
|
|
15
|
+
{ value: "vue", label: "Vue" },
|
|
16
|
+
{ value: "angular", label: "Angular" },
|
|
17
|
+
{ value: "svelte", label: "Svelte" },
|
|
18
|
+
{ value: "nextjs", label: "Next.js" },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const [value, setValue] = useState("");
|
|
22
|
+
|
|
23
|
+
const handleChange = (newValue: string) => {
|
|
24
|
+
setValue(newValue);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className="al-flex al-flex-col al-gap-4 al-justify-start al-items-start">
|
|
29
|
+
<h3 className="al-text-lg al-font-medium">Single Select</h3>
|
|
30
|
+
<Combobox
|
|
31
|
+
options={options}
|
|
32
|
+
value={value}
|
|
33
|
+
onChange={handleChange}
|
|
34
|
+
placeholder="Select framework..."
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
<Combobox
|
|
38
|
+
options={options}
|
|
39
|
+
value={value}
|
|
40
|
+
onChange={handleChange}
|
|
41
|
+
placeholder="Custom width..."
|
|
42
|
+
buttonProps={{ className: "al-w-[300px]" }}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<Combobox
|
|
46
|
+
options={options}
|
|
47
|
+
value={value}
|
|
48
|
+
onChange={handleChange}
|
|
49
|
+
placeholder="With icon..."
|
|
50
|
+
icon={<DatabaseIcon className="al-mr-2" />}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const ComboboxMultiSelectExample: StoryFn = () => {
|
|
57
|
+
const options = [
|
|
58
|
+
{ value: "react", label: "React" },
|
|
59
|
+
{ value: "vue", label: "Vue" },
|
|
60
|
+
{ value: "angular", label: "Angular" },
|
|
61
|
+
{ value: "svelte", label: "Svelte" },
|
|
62
|
+
{ value: "nextjs", label: "Next.js" },
|
|
63
|
+
{ value: "remix", label: "Remix" },
|
|
64
|
+
{ value: "gatsby", label: "Gatsby" },
|
|
65
|
+
{ value: "ember", label: "Ember.js" },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
|
69
|
+
const [selectedValuesWithApply, setSelectedValuesWithApply] = useState<string[]>([
|
|
70
|
+
"react",
|
|
71
|
+
"vue",
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
const handleMultiSelectChange = (newValue: string[]) => {
|
|
75
|
+
setSelectedValues(Array.isArray(newValue) ? newValue : []);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const handleMultiSelectWithApplyChange = (newValue: string | string[]) => {
|
|
79
|
+
setSelectedValuesWithApply(Array.isArray(newValue) ? newValue : []);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className="al-flex al-flex-col al-gap-8 al-justify-start al-items-start">
|
|
84
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
85
|
+
<h3 className="al-text-lg al-font-medium">Multi-Select (Auto-Apply)</h3>
|
|
86
|
+
<p className="al-text-sm al-text-muted-foreground">
|
|
87
|
+
Changes are applied immediately when selecting/deselecting options
|
|
88
|
+
</p>
|
|
89
|
+
<Combobox
|
|
90
|
+
options={options}
|
|
91
|
+
value={selectedValues}
|
|
92
|
+
placeholder="Select frameworks..."
|
|
93
|
+
multiSelect={true}
|
|
94
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
95
|
+
onChange={handleMultiSelectChange}
|
|
96
|
+
/>
|
|
97
|
+
<div className="al-text-sm">
|
|
98
|
+
Selected: {selectedValues.length > 0 ? selectedValues.join(", ") : "None"}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
103
|
+
<h3 className="al-text-lg al-font-medium">Multi-Select with Apply Button</h3>
|
|
104
|
+
<p className="al-text-sm al-text-muted-foreground">
|
|
105
|
+
Changes are only applied when clicking the Apply button
|
|
106
|
+
</p>
|
|
107
|
+
<Combobox
|
|
108
|
+
options={options}
|
|
109
|
+
value={selectedValuesWithApply}
|
|
110
|
+
onChange={handleMultiSelectWithApplyChange}
|
|
111
|
+
placeholder="Select frameworks..."
|
|
112
|
+
multiSelect={true}
|
|
113
|
+
showApplyButton={true}
|
|
114
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
115
|
+
/>
|
|
116
|
+
<div className="al-text-sm">
|
|
117
|
+
Selected:{" "}
|
|
118
|
+
{selectedValuesWithApply.length > 0 ? selectedValuesWithApply.join(", ") : "None"}
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
123
|
+
<h3 className="al-text-lg al-font-medium">Columns Selector Example</h3>
|
|
124
|
+
<p className="al-text-sm al-text-muted-foreground">
|
|
125
|
+
Similar to the UI shown in the screenshot
|
|
126
|
+
</p>
|
|
127
|
+
<ComboboxColumnsExample />
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const ComboboxColumnsExample = () => {
|
|
134
|
+
const options = [
|
|
135
|
+
{ value: "est_cost", label: "Est. Cost" },
|
|
136
|
+
{ value: "exec_time", label: "Exec. Time" },
|
|
137
|
+
{ value: "insights", label: "Insights" },
|
|
138
|
+
{ value: "query_hash", label: "Query Hash" },
|
|
139
|
+
{ value: "query_text", label: "Query Text" },
|
|
140
|
+
{ value: "query_type", label: "Query Type" },
|
|
141
|
+
{ value: "timestamp", label: "Timestamp" },
|
|
142
|
+
{ value: "user", label: "User" },
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
const [selectedColumns, setSelectedColumns] = useState<string[]>([
|
|
146
|
+
"est_cost",
|
|
147
|
+
"exec_time",
|
|
148
|
+
"insights",
|
|
149
|
+
"query_hash",
|
|
150
|
+
"query_text",
|
|
151
|
+
"query_type",
|
|
152
|
+
"timestamp",
|
|
153
|
+
"user",
|
|
154
|
+
]);
|
|
155
|
+
|
|
156
|
+
const handleColumnsChange = (newValue: string | string[]) => {
|
|
157
|
+
setSelectedColumns(Array.isArray(newValue) ? newValue : []);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<Combobox
|
|
162
|
+
options={options}
|
|
163
|
+
value={selectedColumns}
|
|
164
|
+
onChange={handleColumnsChange}
|
|
165
|
+
placeholder="Columns"
|
|
166
|
+
multiSelect={true}
|
|
167
|
+
showApplyButton={true}
|
|
168
|
+
buttonProps={{ className: "al-w-[200px]" }}
|
|
169
|
+
/>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export const ComboboxAdvancedExample: StoryFn = () => {
|
|
174
|
+
const options = [
|
|
175
|
+
{ value: "react", label: "React" },
|
|
176
|
+
{ value: "vue", label: "Vue" },
|
|
177
|
+
{ value: "angular", label: "Angular" },
|
|
178
|
+
{ value: "svelte", label: "Svelte" },
|
|
179
|
+
{ value: "nextjs", label: "Next.js" },
|
|
180
|
+
{ value: "remix", label: "Remix" },
|
|
181
|
+
{ value: "gatsby", label: "Gatsby" },
|
|
182
|
+
{ value: "ember", label: "Ember.js" },
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
const [singleValue, setSingleValue] = useState("");
|
|
186
|
+
const [multiValue, setMultiValue] = useState<string[]>(["react", "vue"]);
|
|
187
|
+
const [clearableValue, setClearableValue] = useState("angular");
|
|
188
|
+
const [multiClearableValue, setMultiClearableValue] = useState<string[]>(["nextjs", "remix"]);
|
|
189
|
+
const [multiApplyValue, setMultiApplyValue] = useState<string[]>(["gatsby", "ember"]);
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<div className="al-flex al-flex-col al-gap-8 al-justify-start al-items-start">
|
|
193
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
194
|
+
<h3 className="al-text-lg al-font-medium">Search Placeholders</h3>
|
|
195
|
+
<p className="al-text-sm al-text-muted-foreground">Different search placeholder examples</p>
|
|
196
|
+
|
|
197
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
198
|
+
<label className="al-text-sm al-font-medium">Default Search Placeholder</label>
|
|
199
|
+
<Combobox
|
|
200
|
+
options={options}
|
|
201
|
+
value={singleValue}
|
|
202
|
+
onChange={value => setSingleValue(value as string)}
|
|
203
|
+
placeholder="Select framework..."
|
|
204
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
205
|
+
/>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
209
|
+
<label className="al-text-sm al-font-medium">Custom Search Placeholder</label>
|
|
210
|
+
<Combobox
|
|
211
|
+
options={options}
|
|
212
|
+
value={singleValue}
|
|
213
|
+
onChange={value => setSingleValue(value as string)}
|
|
214
|
+
placeholder="Select framework..."
|
|
215
|
+
searchPlaceholder="Type to find frameworks..."
|
|
216
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
217
|
+
/>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
221
|
+
<label className="al-text-sm al-font-medium">Empty Search Placeholder</label>
|
|
222
|
+
<Combobox
|
|
223
|
+
options={options}
|
|
224
|
+
value={singleValue}
|
|
225
|
+
onChange={value => setSingleValue(value as string)}
|
|
226
|
+
placeholder="Select framework..."
|
|
227
|
+
searchPlaceholder=""
|
|
228
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
234
|
+
<h3 className="al-text-lg al-font-medium">Clear Button Examples</h3>
|
|
235
|
+
<p className="al-text-sm al-text-muted-foreground">
|
|
236
|
+
Demonstrating showClearButton prop with different configurations
|
|
237
|
+
</p>
|
|
238
|
+
|
|
239
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
240
|
+
<label className="al-text-sm al-font-medium">
|
|
241
|
+
Single Select - No Clear Button (Default)
|
|
242
|
+
</label>
|
|
243
|
+
<Combobox
|
|
244
|
+
options={options}
|
|
245
|
+
value={clearableValue}
|
|
246
|
+
onChange={value => setClearableValue(value as string)}
|
|
247
|
+
placeholder="Select framework..."
|
|
248
|
+
searchPlaceholder="Search frameworks..."
|
|
249
|
+
showClearButton={false}
|
|
250
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
251
|
+
/>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
255
|
+
<label className="al-text-sm al-font-medium">Single Select - With Clear Button</label>
|
|
256
|
+
<Combobox
|
|
257
|
+
options={options}
|
|
258
|
+
value={clearableValue}
|
|
259
|
+
onChange={value => setClearableValue(value as string)}
|
|
260
|
+
placeholder="Select framework..."
|
|
261
|
+
searchPlaceholder="Search frameworks..."
|
|
262
|
+
showClearButton={true}
|
|
263
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
264
|
+
/>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
268
|
+
<label className="al-text-sm al-font-medium">Multi Select - No Clear Button</label>
|
|
269
|
+
<Combobox
|
|
270
|
+
options={options}
|
|
271
|
+
value={multiValue}
|
|
272
|
+
onChange={value => setMultiValue(value as string[])}
|
|
273
|
+
placeholder="Select frameworks..."
|
|
274
|
+
searchPlaceholder="Find your frameworks..."
|
|
275
|
+
multiSelect={true}
|
|
276
|
+
showClearButton={false}
|
|
277
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
278
|
+
/>
|
|
279
|
+
<div className="al-text-sm">
|
|
280
|
+
Selected: {multiValue.length > 0 ? multiValue.join(", ") : "None"}
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
285
|
+
<label className="al-text-sm al-font-medium">Multi Select - With Clear Button</label>
|
|
286
|
+
<Combobox
|
|
287
|
+
options={options}
|
|
288
|
+
value={multiClearableValue}
|
|
289
|
+
onChange={value => setMultiClearableValue(value as string[])}
|
|
290
|
+
placeholder="Select frameworks..."
|
|
291
|
+
searchPlaceholder="Find your frameworks..."
|
|
292
|
+
multiSelect={true}
|
|
293
|
+
showClearButton={true}
|
|
294
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
295
|
+
/>
|
|
296
|
+
<div className="al-text-sm">
|
|
297
|
+
Selected: {multiClearableValue.length > 0 ? multiClearableValue.join(", ") : "None"}
|
|
298
|
+
</div>
|
|
299
|
+
</div>
|
|
300
|
+
|
|
301
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
302
|
+
<label className="al-text-sm al-font-medium">
|
|
303
|
+
Multi Select - With Apply Button & Clear Button
|
|
304
|
+
</label>
|
|
305
|
+
<Combobox
|
|
306
|
+
options={options}
|
|
307
|
+
value={multiApplyValue}
|
|
308
|
+
onChange={value => setMultiApplyValue(value as string[])}
|
|
309
|
+
placeholder="Select frameworks..."
|
|
310
|
+
searchPlaceholder="Filter options..."
|
|
311
|
+
multiSelect={true}
|
|
312
|
+
showApplyButton={true}
|
|
313
|
+
showClearButton={true}
|
|
314
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
315
|
+
/>
|
|
316
|
+
<div className="al-text-sm">
|
|
317
|
+
Selected: {multiApplyValue.length > 0 ? multiApplyValue.join(", ") : "None"}
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
export const ComboboxInfiniteScrollExample: StoryFn = () => {
|
|
326
|
+
const [allOptions] = useState(() => {
|
|
327
|
+
// Generate a large dataset for demonstration
|
|
328
|
+
return Array.from({ length: 1000 }, (_, i) => ({
|
|
329
|
+
value: `option-${i + 1}`,
|
|
330
|
+
label: `Option ${i + 1}`,
|
|
331
|
+
}));
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const [displayedOptions, setDisplayedOptions] = useState(() => allOptions.slice(0, 20));
|
|
335
|
+
const [hasMore, setHasMore] = useState(true);
|
|
336
|
+
const [selectedValue, setSelectedValue] = useState("option-500"); // Pre-select a value not in initial load
|
|
337
|
+
const [multiSelectedValue, setMultiSelectedValue] = useState<string[]>([
|
|
338
|
+
"option-100",
|
|
339
|
+
"option-200",
|
|
340
|
+
]); // Pre-select values not in initial load
|
|
341
|
+
|
|
342
|
+
const loadMore = async () => {
|
|
343
|
+
if (!hasMore) return;
|
|
344
|
+
|
|
345
|
+
// Simulate API call delay
|
|
346
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
347
|
+
|
|
348
|
+
const currentLength = displayedOptions.length;
|
|
349
|
+
const nextBatch = allOptions.slice(currentLength, currentLength + 20);
|
|
350
|
+
|
|
351
|
+
if (nextBatch.length === 0) {
|
|
352
|
+
setHasMore(false);
|
|
353
|
+
} else {
|
|
354
|
+
setDisplayedOptions(prev => [...prev, ...nextBatch]);
|
|
355
|
+
setHasMore(currentLength + nextBatch.length < allOptions.length);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const resetData = () => {
|
|
360
|
+
setDisplayedOptions(allOptions.slice(0, 20));
|
|
361
|
+
setHasMore(true);
|
|
362
|
+
setSelectedValue("");
|
|
363
|
+
setMultiSelectedValue([]);
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
return (
|
|
367
|
+
<div className="al-flex al-flex-col al-gap-6 al-justify-start al-items-start">
|
|
368
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
369
|
+
<div className="al-flex al-gap-4 al-items-center">
|
|
370
|
+
<h3 className="al-text-lg al-font-medium">Infinite Scroll Examples</h3>
|
|
371
|
+
<Button onClick={resetData} size="sm" variant="outline">
|
|
372
|
+
Reset Data
|
|
373
|
+
</Button>
|
|
374
|
+
</div>
|
|
375
|
+
<p className="al-text-sm al-text-muted-foreground">
|
|
376
|
+
Notice how pre-selected values (Option 500, Option 100, Option 200) show proper labels
|
|
377
|
+
even though they're not in the initial 20 options. This demonstrates the valueLabels
|
|
378
|
+
prop functionality.
|
|
379
|
+
</p>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
383
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
384
|
+
<label className="al-text-sm al-font-medium">Single Select with Infinite Scroll</label>
|
|
385
|
+
<p className="al-text-xs al-text-muted-foreground">
|
|
386
|
+
Showing {displayedOptions.length} of {allOptions.length} options
|
|
387
|
+
</p>
|
|
388
|
+
<Combobox
|
|
389
|
+
options={displayedOptions}
|
|
390
|
+
value={selectedValue}
|
|
391
|
+
onChange={value => setSelectedValue(value as string)}
|
|
392
|
+
placeholder="Select an option..."
|
|
393
|
+
onLoadMore={loadMore}
|
|
394
|
+
hasMore={hasMore}
|
|
395
|
+
valueLabels={{
|
|
396
|
+
"option-500": "Option 500",
|
|
397
|
+
}}
|
|
398
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
399
|
+
/>
|
|
400
|
+
</div>
|
|
401
|
+
|
|
402
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
403
|
+
<label className="al-text-sm al-font-medium">Multi-Select with Infinite Scroll</label>
|
|
404
|
+
<p className="al-text-xs al-text-muted-foreground">
|
|
405
|
+
Selected: {multiSelectedValue.length} items
|
|
406
|
+
</p>
|
|
407
|
+
<Combobox
|
|
408
|
+
options={displayedOptions}
|
|
409
|
+
value={multiSelectedValue}
|
|
410
|
+
onChange={value => setMultiSelectedValue(value as string[])}
|
|
411
|
+
placeholder="Select multiple options..."
|
|
412
|
+
multiSelect={true}
|
|
413
|
+
onLoadMore={loadMore}
|
|
414
|
+
hasMore={hasMore}
|
|
415
|
+
valueLabels={{
|
|
416
|
+
"option-100": "Option 100",
|
|
417
|
+
"option-200": "Option 200",
|
|
418
|
+
}}
|
|
419
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
420
|
+
/>
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
424
|
+
<label className="al-text-sm al-font-medium">
|
|
425
|
+
Standard Combobox (No Infinite Scroll)
|
|
426
|
+
</label>
|
|
427
|
+
<Combobox
|
|
428
|
+
options={displayedOptions.slice(0, 10)}
|
|
429
|
+
value="option-5" // Use a value that exists in the first 10 options
|
|
430
|
+
onChange={value => setSelectedValue(value as string)}
|
|
431
|
+
placeholder="Standard combobox..."
|
|
432
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
433
|
+
/>
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
</div>
|
|
437
|
+
);
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
export const ComboboxSearchExample: StoryFn = () => {
|
|
441
|
+
const [options] = useState([
|
|
442
|
+
{ value: "react", label: "React" },
|
|
443
|
+
{ value: "vue", label: "Vue" },
|
|
444
|
+
{ value: "angular", label: "Angular" },
|
|
445
|
+
{ value: "svelte", label: "Svelte" },
|
|
446
|
+
{ value: "nextjs", label: "Next.js" },
|
|
447
|
+
]);
|
|
448
|
+
|
|
449
|
+
const [selectedValue, setSelectedValue] = useState("");
|
|
450
|
+
const [searchValue, setSearchValue] = useState("");
|
|
451
|
+
const [searchHistory, setSearchHistory] = useState<string[]>([]);
|
|
452
|
+
|
|
453
|
+
const handleSearch = (searchTerm: string) => {
|
|
454
|
+
setSearchValue(searchTerm);
|
|
455
|
+
if (searchTerm.trim() && !searchHistory.includes(searchTerm.trim())) {
|
|
456
|
+
setSearchHistory(prev => [searchTerm.trim(), ...prev.slice(0, 4)]); // Keep last 5 searches
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const clearHistory = () => {
|
|
461
|
+
setSearchHistory([]);
|
|
462
|
+
setSearchValue("");
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
return (
|
|
466
|
+
<div className="al-flex al-flex-col al-gap-6 al-justify-start al-items-start">
|
|
467
|
+
<div className="al-flex al-gap-4 al-items-center">
|
|
468
|
+
<h3 className="al-text-lg al-font-medium">Search Callback Example</h3>
|
|
469
|
+
<Button onClick={clearHistory} size="sm" variant="outline">
|
|
470
|
+
Clear History
|
|
471
|
+
</Button>
|
|
472
|
+
</div>
|
|
473
|
+
|
|
474
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
475
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
476
|
+
<label className="al-text-sm al-font-medium">Combobox with Search Callback</label>
|
|
477
|
+
<p className="al-text-xs al-text-muted-foreground">
|
|
478
|
+
Type in the search box to see the search values being emitted
|
|
479
|
+
</p>
|
|
480
|
+
<Combobox
|
|
481
|
+
options={options}
|
|
482
|
+
value={selectedValue}
|
|
483
|
+
onChange={value => setSelectedValue(value as string)}
|
|
484
|
+
placeholder="Search frameworks..."
|
|
485
|
+
searchPlaceholder="Type to search..."
|
|
486
|
+
onSearch={handleSearch}
|
|
487
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
488
|
+
/>
|
|
489
|
+
</div>
|
|
490
|
+
|
|
491
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
492
|
+
<label className="al-text-sm al-font-medium">Current Search Value:</label>
|
|
493
|
+
<code className="al-text-sm al-bg-muted al-p-2 al-rounded">
|
|
494
|
+
{searchValue || "No search performed yet"}
|
|
495
|
+
</code>
|
|
496
|
+
</div>
|
|
497
|
+
|
|
498
|
+
{searchHistory.length > 0 && (
|
|
499
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
500
|
+
<label className="al-text-sm al-font-medium">Search History:</label>
|
|
501
|
+
<ul className="al-text-sm al-bg-muted al-p-2 al-rounded al-space-y-1">
|
|
502
|
+
{searchHistory.map((search, index) => (
|
|
503
|
+
<li key={index} className="al-font-mono">
|
|
504
|
+
{index + 1}. "{search}"
|
|
505
|
+
</li>
|
|
506
|
+
))}
|
|
507
|
+
</ul>
|
|
508
|
+
</div>
|
|
509
|
+
)}
|
|
510
|
+
</div>
|
|
511
|
+
</div>
|
|
512
|
+
);
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
export const ComboboxCallbacksExample: StoryFn = () => {
|
|
516
|
+
const options = [
|
|
517
|
+
{ value: "react", label: "React" },
|
|
518
|
+
{ value: "vue", label: "Vue" },
|
|
519
|
+
{ value: "angular", label: "Angular" },
|
|
520
|
+
{ value: "svelte", label: "Svelte" },
|
|
521
|
+
{ value: "nextjs", label: "Next.js" },
|
|
522
|
+
];
|
|
523
|
+
|
|
524
|
+
const [selectedValue, setSelectedValue] = useState("");
|
|
525
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
526
|
+
const [openHistory, setOpenHistory] = useState<string[]>([]);
|
|
527
|
+
|
|
528
|
+
const handleOpenChange = (open: boolean) => {
|
|
529
|
+
setIsOpen(open);
|
|
530
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
531
|
+
setOpenHistory(prev => [`${timestamp}: ${open ? "opened" : "closed"}`, ...prev.slice(0, 4)]);
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
const clearHistory = () => {
|
|
535
|
+
setOpenHistory([]);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
return (
|
|
539
|
+
<div className="al-flex al-flex-col al-gap-6 al-justify-start al-items-start">
|
|
540
|
+
<div className="al-flex al-gap-4 al-items-center">
|
|
541
|
+
<h3 className="al-text-lg al-font-medium">Open/Close Callback Example</h3>
|
|
542
|
+
<Button onClick={clearHistory} size="sm" variant="outline">
|
|
543
|
+
Clear History
|
|
544
|
+
</Button>
|
|
545
|
+
</div>
|
|
546
|
+
|
|
547
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
548
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
549
|
+
<label className="al-text-sm al-font-medium">Combobox with onOpenChange Callback</label>
|
|
550
|
+
<p className="al-text-xs al-text-muted-foreground">
|
|
551
|
+
Open and close the combobox to see the callback events
|
|
552
|
+
</p>
|
|
553
|
+
<Combobox
|
|
554
|
+
options={options}
|
|
555
|
+
value={selectedValue}
|
|
556
|
+
onChange={value => setSelectedValue(value as string)}
|
|
557
|
+
placeholder="Select framework..."
|
|
558
|
+
onOpenChange={handleOpenChange}
|
|
559
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
560
|
+
/>
|
|
561
|
+
</div>
|
|
562
|
+
|
|
563
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
564
|
+
<label className="al-text-sm al-font-medium">Current State:</label>
|
|
565
|
+
<code className="al-text-sm al-bg-muted al-p-2 al-rounded">
|
|
566
|
+
Popover is {isOpen ? "open" : "closed"}
|
|
567
|
+
</code>
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
{openHistory.length > 0 && (
|
|
571
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
572
|
+
<label className="al-text-sm al-font-medium">Open/Close History:</label>
|
|
573
|
+
<ul className="al-text-sm al-bg-muted al-p-2 al-rounded al-space-y-1">
|
|
574
|
+
{openHistory.map((event, index) => (
|
|
575
|
+
<li key={index} className="al-font-mono">
|
|
576
|
+
{event}
|
|
577
|
+
</li>
|
|
578
|
+
))}
|
|
579
|
+
</ul>
|
|
580
|
+
</div>
|
|
581
|
+
)}
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
);
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
export const ComboboxPopoverCustomizationExample: StoryFn = () => {
|
|
588
|
+
const options = [
|
|
589
|
+
{ value: "react", label: "React" },
|
|
590
|
+
{ value: "vue", label: "Vue" },
|
|
591
|
+
{ value: "angular", label: "Angular" },
|
|
592
|
+
{ value: "svelte", label: "Svelte" },
|
|
593
|
+
{ value: "nextjs", label: "Next.js" },
|
|
594
|
+
];
|
|
595
|
+
|
|
596
|
+
const [selectedValue1, setSelectedValue1] = useState("");
|
|
597
|
+
const [selectedValue2, setSelectedValue2] = useState("");
|
|
598
|
+
const [selectedValue3, setSelectedValue3] = useState("");
|
|
599
|
+
|
|
600
|
+
return (
|
|
601
|
+
<div className="al-flex al-flex-col al-gap-6 al-justify-start al-items-start">
|
|
602
|
+
<h3 className="al-text-lg al-font-medium">Popover Customization Examples</h3>
|
|
603
|
+
|
|
604
|
+
<div className="al-flex al-flex-col al-gap-4">
|
|
605
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
606
|
+
<label className="al-text-sm al-font-medium">Default Popover (Bottom)</label>
|
|
607
|
+
<Combobox
|
|
608
|
+
options={options}
|
|
609
|
+
value={selectedValue1}
|
|
610
|
+
onChange={value => setSelectedValue1(value as string)}
|
|
611
|
+
placeholder="Default positioning..."
|
|
612
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
613
|
+
/>
|
|
614
|
+
</div>
|
|
615
|
+
|
|
616
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
617
|
+
<label className="al-text-sm al-font-medium">
|
|
618
|
+
Right Side Popover (with right chevron)
|
|
619
|
+
</label>
|
|
620
|
+
<Combobox
|
|
621
|
+
options={options}
|
|
622
|
+
value={selectedValue2}
|
|
623
|
+
onChange={value => setSelectedValue2(value as string)}
|
|
624
|
+
placeholder="Right side popover..."
|
|
625
|
+
popoverContentProps={{ side: "right" }}
|
|
626
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
627
|
+
/>
|
|
628
|
+
</div>
|
|
629
|
+
|
|
630
|
+
<div className="al-flex al-flex-col al-gap-2">
|
|
631
|
+
<label className="al-text-sm al-font-medium">Custom Styled Popover</label>
|
|
632
|
+
<p className="al-text-xs al-text-muted-foreground">
|
|
633
|
+
Popover with custom styling and wider width
|
|
634
|
+
</p>
|
|
635
|
+
<Combobox
|
|
636
|
+
options={options}
|
|
637
|
+
value={selectedValue3}
|
|
638
|
+
onChange={value => setSelectedValue3(value as string)}
|
|
639
|
+
placeholder="Custom styled popover..."
|
|
640
|
+
popoverContentProps={{
|
|
641
|
+
className: "al-w-[350px] al-border-2 al-border-blue-200",
|
|
642
|
+
side: "top",
|
|
643
|
+
}}
|
|
644
|
+
buttonProps={{ className: "al-w-[250px]" }}
|
|
645
|
+
/>
|
|
646
|
+
</div>
|
|
647
|
+
</div>
|
|
648
|
+
</div>
|
|
649
|
+
);
|
|
650
|
+
};
|