@flightlesslabs/dodo-ui 0.7.1 → 0.8.0
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/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/stories/components/Form/Select/Customize/Customize.stories.svelte +16 -1
- package/dist/stories/components/Form/Select/DropDownArrow/DropDownArrow.stories.svelte +59 -0
- package/dist/stories/components/Form/Select/DropDownArrow/DropDownArrow.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/Select/Positions/AutoPosition/AutoPosition.stories.svelte +54 -0
- package/dist/stories/components/Form/Select/Positions/AutoPosition/AutoPosition.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/Select/Positions/Positions.stories.svelte +83 -0
- package/dist/stories/components/Form/Select/Positions/Positions.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/Select/Select.svelte +107 -123
- package/dist/stories/components/Form/Select/Select.svelte.d.ts +15 -2
- package/dist/stories/components/Layout/Menu/DynamicMenu/Customize/Customize.stories.svelte +28 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/Customize/Customize.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.stories.svelte +51 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.stories.svelte.d.ts +22 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.svelte +129 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.svelte.d.ts +81 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/Events/Events.stories.svelte +46 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/Events/Events.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/KeybaordNavigation/KeybaordNavigation.stories.svelte +27 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/KeybaordNavigation/KeybaordNavigation.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Layout/Menu/DynamicMenu/Options/OptionFormat.mdx +72 -0
- package/dist/stories/components/Layout/Menu/MenuItem/MenuItem.svelte.d.ts +1 -1
- package/dist/stories/developer tools/components/DynamicInput/DynamicInput.svelte +1 -0
- package/package.json +17 -18
- package/src/lib/index.ts +13 -0
- package/src/lib/stories/Home.mdx +59 -0
- package/src/lib/stories/assets/dark-theme-toggle.png +0 -0
- package/src/lib/stories/components/Form/Button/Button.stories.svelte +61 -0
- package/src/lib/stories/components/Form/Button/Color/Color.stories.svelte +43 -0
- package/src/lib/stories/components/Form/Button/Events/Events.stories.svelte +36 -0
- package/src/lib/stories/components/Form/Button/IconButton/IconButton.stories.svelte +43 -0
- package/src/lib/stories/components/Form/Button/Roundness/Roundness.stories.svelte +23 -0
- package/src/lib/stories/components/Form/Button/Size/Size.stories.svelte +16 -0
- package/src/lib/stories/components/Form/Button/Variant/Variant.stories.svelte +18 -0
- package/src/lib/stories/components/Form/FormControl/FormControl.stories.svelte +28 -0
- package/src/lib/stories/components/Form/Label/Label.stories.svelte +13 -0
- package/src/lib/stories/components/Form/Message/Color/Color.stories.svelte +36 -0
- package/src/lib/stories/components/Form/Message/Message.stories.svelte +27 -0
- package/src/lib/stories/components/Form/Message/Size/Size.stories.svelte +22 -0
- package/src/lib/stories/components/Form/PasswordInput/Events/Events.stories.svelte +110 -0
- package/src/lib/stories/components/Form/PasswordInput/PasswordInput.stories.svelte +59 -0
- package/src/lib/stories/components/Form/PasswordInput/Roundness/Roundness.stories.svelte +20 -0
- package/src/lib/stories/components/Form/PasswordInput/Size/Size.stories.svelte +16 -0
- package/src/lib/stories/components/Form/PasswordInput/WithIcon/WithIcon.stories.svelte +31 -0
- package/src/lib/stories/components/Form/Select/Customize/Customize.stories.svelte +139 -0
- package/src/lib/stories/components/Form/Select/DropDownArrow/DropDownArrow.stories.svelte +63 -0
- package/src/lib/stories/components/Form/Select/Events/Events.stories.svelte +144 -0
- package/src/lib/stories/components/Form/Select/Options/OptionFormat.mdx +40 -0
- package/src/lib/stories/components/Form/Select/Positions/AutoPosition/AutoPosition.stories.svelte +58 -0
- package/src/lib/stories/components/Form/Select/Positions/Positions.stories.svelte +87 -0
- package/src/lib/stories/components/Form/Select/Roundness/Roundness.stories.svelte +32 -0
- package/src/lib/stories/components/Form/Select/Select.stories.svelte +121 -0
- package/src/lib/stories/components/Form/Select/Select.svelte +153 -146
- package/src/lib/stories/components/Form/Select/Size/Size.stories.svelte +28 -0
- package/src/lib/stories/components/Form/Select/WithIcon/WithIcon.stories.svelte +43 -0
- package/src/lib/stories/components/Form/TextInput/Events/Events.stories.svelte +97 -0
- package/src/lib/stories/components/Form/TextInput/Roundness/Roundness.stories.svelte +21 -0
- package/src/lib/stories/components/Form/TextInput/Size/Size.stories.svelte +17 -0
- package/src/lib/stories/components/Form/TextInput/TextInput.stories.svelte +43 -0
- package/src/lib/stories/components/Form/TextInput/WithIcon/WithIcon.stories.svelte +47 -0
- package/src/lib/stories/components/Layout/Menu/DynamicMenu/Customize/Customize.stories.svelte +30 -0
- package/src/lib/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.stories.svelte +56 -0
- package/src/lib/stories/components/Layout/Menu/DynamicMenu/DynamicMenu.svelte +262 -0
- package/src/lib/stories/components/Layout/Menu/DynamicMenu/Events/Events.stories.svelte +48 -0
- package/src/lib/stories/components/Layout/Menu/DynamicMenu/KeybaordNavigation/KeybaordNavigation.stories.svelte +29 -0
- package/src/lib/stories/components/Layout/Menu/DynamicMenu/Options/OptionFormat.mdx +72 -0
- package/src/lib/stories/components/Layout/Menu/Menu.stories.svelte +69 -0
- package/src/lib/stories/components/Layout/Menu/MenuItem/MenuItem.stories.svelte +34 -0
- package/src/lib/stories/components/Layout/Menu/MenuItem/MenuItem.svelte +1 -1
- package/src/lib/stories/components/Layout/Menu/MenuItem/Size/Size.stories.svelte +16 -0
- package/src/lib/stories/components/Layout/Menu/MenuItem/Type/Type.stories.svelte +21 -0
- package/src/lib/stories/components/Layout/Menu/Size/Size.stories.svelte +37 -0
- package/src/lib/stories/components/Layout/Paper/Color/Color.stories.svelte +63 -0
- package/src/lib/stories/components/Layout/Paper/Paper.stories.svelte +50 -0
- package/src/lib/stories/components/Layout/Paper/Roundness/Roundness.stories.svelte +25 -0
- package/src/lib/stories/components/Layout/Paper/Shadow/Shadow.stories.svelte +24 -0
- package/src/lib/stories/components/Layout/Separator/Color/Color.stories.svelte +19 -0
- package/src/lib/stories/components/Layout/Separator/Separator.stories.svelte +30 -0
- package/src/lib/stories/developer tools/Intro.mdx +9 -0
- package/src/lib/stories/developer tools/components/DynamicInput/DynamicInput.stories.svelte +53 -0
- package/src/lib/stories/developer tools/components/DynamicInput/DynamicInput.svelte +1 -0
- package/src/lib/stories/developer tools/components/DynamicInput/Size/Size.stories.svelte +17 -0
- package/src/lib/stories/developer tools/components/InputEnclosure/InputEnclosure.stories.svelte +38 -0
- package/src/lib/stories/developer tools/components/InputEnclosure/Roundness/Roundness.stories.svelte +20 -0
- package/src/lib/stories/developer tools/components/InputEnclosure/Size/Size.stories.svelte +16 -0
- package/src/lib/stories/developer tools/components/InputEnclosure/WithIcon/WithIcon.stories.svelte +47 -0
- package/src/lib/stories/developer tools/components/Popper/Popper.stories.svelte +124 -0
- package/src/lib/stories/developer tools/components/Popper/PopperPopup/PopperPopup.stories.svelte +64 -0
- package/src/lib/stories/developer tools/components/Popper/Positions/AutoPosition/AutoPosition.stories.svelte +92 -0
- package/src/lib/stories/developer tools/components/Popper/Positions/Positions.stories.svelte +114 -0
- package/src/lib/stories/developer tools/components/UtilityButton/Size/Size.stories.svelte +25 -0
- package/src/lib/stories/developer tools/components/UtilityButton/UtilityButton.stories.svelte +30 -0
- package/src/lib/stories/developer tools/directives/clickOutside/index.mdx +25 -0
- package/src/lib/stories/developer tools/philosophy/Colors/Colors.mdx +43 -0
- package/src/lib/stories/developer tools/philosophy/Colors/Colors.stories.svelte +22 -0
- package/src/lib/stories/developer tools/philosophy/Colors/Opacity.stories.svelte +11 -0
- package/src/lib/stories/developer tools/philosophy/Themes.mdx +23 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import Select, { type SelectOption } from './Select.svelte';
|
|
4
|
+
import type { StoryBookArgTypes } from '$lib/storybook-types.js';
|
|
5
|
+
import { componentRoundnessArray } from '$lib/types/roundness.js';
|
|
6
|
+
import { componentSizeArray } from '$lib/types/size.js';
|
|
7
|
+
|
|
8
|
+
export const storySelectArgTypes: StoryBookArgTypes = {
|
|
9
|
+
roundness: {
|
|
10
|
+
control: { type: 'select' },
|
|
11
|
+
options: componentRoundnessArray,
|
|
12
|
+
},
|
|
13
|
+
size: {
|
|
14
|
+
control: { type: 'select' },
|
|
15
|
+
options: componentSizeArray,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
20
|
+
const { Story } = defineMeta({
|
|
21
|
+
component: Select,
|
|
22
|
+
tags: ['autodocs'],
|
|
23
|
+
argTypes: storySelectArgTypes,
|
|
24
|
+
parameters: {
|
|
25
|
+
docs: {
|
|
26
|
+
story: {
|
|
27
|
+
height: '400px',
|
|
28
|
+
inline: false,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const selectOptions: SelectOption[] = [
|
|
35
|
+
{
|
|
36
|
+
value: 1,
|
|
37
|
+
label: 'One',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: 2,
|
|
41
|
+
label: 'Two',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
value: 3,
|
|
45
|
+
label: 'Three',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
value: 4,
|
|
49
|
+
label: 'Four',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
value: 5,
|
|
53
|
+
label: 'Five',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
value: 6,
|
|
57
|
+
label: 'Six',
|
|
58
|
+
disabled: true,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
value: 7,
|
|
62
|
+
label: 'Seven',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
value: 8,
|
|
66
|
+
label: 'Eight',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
value: 9,
|
|
70
|
+
label: 'Nine',
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const options = selectOptions;
|
|
75
|
+
|
|
76
|
+
let value = $state<SelectOption | undefined>(options[0]);
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<!-- Select with default style -->
|
|
80
|
+
<Story name="Default" asChild>
|
|
81
|
+
<Select {options} {value} onselect={(val: SelectOption) => (value = val)} />
|
|
82
|
+
</Story>
|
|
83
|
+
|
|
84
|
+
<Story name="Searchable" asChild>
|
|
85
|
+
<Select
|
|
86
|
+
{options}
|
|
87
|
+
{value}
|
|
88
|
+
searchable
|
|
89
|
+
optionsPlaceholder="No results"
|
|
90
|
+
onselect={(val: SelectOption) => (value = val)}
|
|
91
|
+
/>
|
|
92
|
+
</Story>
|
|
93
|
+
|
|
94
|
+
<Story name="Clearable" asChild>
|
|
95
|
+
<Select
|
|
96
|
+
{options}
|
|
97
|
+
{value}
|
|
98
|
+
clearable
|
|
99
|
+
onselect={(val: SelectOption) => (value = val)}
|
|
100
|
+
onclear={() => (value = undefined)}
|
|
101
|
+
placeholder="Select option"
|
|
102
|
+
/>
|
|
103
|
+
</Story>
|
|
104
|
+
|
|
105
|
+
<Story name="PopupMaxHeight" asChild>
|
|
106
|
+
<Select
|
|
107
|
+
{options}
|
|
108
|
+
{value}
|
|
109
|
+
onselect={(val: SelectOption) => (value = val)}
|
|
110
|
+
popupMaxHeight="200px"
|
|
111
|
+
/>
|
|
112
|
+
</Story>
|
|
113
|
+
|
|
114
|
+
<!-- Format look and feel of input content. [More Customizations](?path=/docs/components-form-select-customize--docs) -->
|
|
115
|
+
<Story name="CustomInputContent" asChild>
|
|
116
|
+
<Select {options} {value} onselect={(val: SelectOption) => (value = val)}>
|
|
117
|
+
{#snippet customInputContent(selectedOption)}
|
|
118
|
+
{selectedOption.label} 💯💯💯
|
|
119
|
+
{/snippet}
|
|
120
|
+
</Select>
|
|
121
|
+
</Story>
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
disabled?: boolean;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
export type SelectDropdownArrowPosition = false | 'before' | 'after';
|
|
20
|
+
|
|
19
21
|
export interface SelectProps {
|
|
20
22
|
/** How large should the button be? */
|
|
21
23
|
size?: ComponentSize;
|
|
@@ -76,7 +78,11 @@
|
|
|
76
78
|
/** custom Content Formatting for variant button */
|
|
77
79
|
customMenuItemContent?: (val: SelectOption, selected: boolean) => Snippet;
|
|
78
80
|
/** Custom Popup Content */
|
|
79
|
-
customPopupContent?: (
|
|
81
|
+
customPopupContent?: (
|
|
82
|
+
options: SelectOption[],
|
|
83
|
+
selectedOption: SelectOption,
|
|
84
|
+
onselect: (val: SelectOption) => void,
|
|
85
|
+
) => Snippet;
|
|
80
86
|
/** custom Content Formatting for variant button */
|
|
81
87
|
customPlaceholderMenuItemContent?: () => Snippet;
|
|
82
88
|
/** PopperPopup Max height. Use css compatible value */
|
|
@@ -89,6 +95,18 @@
|
|
|
89
95
|
menuProps?: Partial<MenuProps>;
|
|
90
96
|
/** MenuItem: Menu component props */
|
|
91
97
|
menuItemProps?: Partial<MenuItemProps>;
|
|
98
|
+
/** Dropdown Arrow Icon */
|
|
99
|
+
customDropdownArrowIcon?: (open: boolean) => Snippet;
|
|
100
|
+
/** Select Dropdown Arrow Position */
|
|
101
|
+
dropdownArrowPosition?: SelectDropdownArrowPosition;
|
|
102
|
+
/** Popup stick horizontally */
|
|
103
|
+
popupPositionX?: PositionX;
|
|
104
|
+
/** Popup stick vertically */
|
|
105
|
+
popupPositionY?: PositionY;
|
|
106
|
+
/** Lock positions, disable auto top, bottom position based */
|
|
107
|
+
lockPoistions?: boolean;
|
|
108
|
+
/** Popper Height For Vertical Position, default 300 */
|
|
109
|
+
popperHeightForVerticalPosition?: number;
|
|
92
110
|
}
|
|
93
111
|
</script>
|
|
94
112
|
|
|
@@ -98,14 +116,16 @@
|
|
|
98
116
|
import Icon from '@iconify/svelte';
|
|
99
117
|
import {
|
|
100
118
|
DynamicInput,
|
|
101
|
-
|
|
102
|
-
MenuItem,
|
|
119
|
+
DynamicMenu,
|
|
103
120
|
Popper,
|
|
104
121
|
type DynamicInputFocusEvent,
|
|
122
|
+
type DynamicMenuItemOption,
|
|
105
123
|
type MenuItemProps,
|
|
106
124
|
type MenuProps,
|
|
107
125
|
type PaperProps,
|
|
108
126
|
type PopperProps,
|
|
127
|
+
type PositionX,
|
|
128
|
+
type PositionY,
|
|
109
129
|
} from '$lib/index.js';
|
|
110
130
|
import type { TextInputInputEvent } from '../TextInput/TextInput.svelte';
|
|
111
131
|
import type { ButtonClickEvent } from '../Button/Button.svelte';
|
|
@@ -141,37 +161,56 @@
|
|
|
141
161
|
customMenuItemContent: customMenuItemContentInternal,
|
|
142
162
|
customPopupContent: customPopupContentInternal,
|
|
143
163
|
customPlaceholderMenuItemContent: customPlaceholderMenuItemContentInternal,
|
|
164
|
+
customDropdownArrowIcon: customDropdownArrowIconInternal,
|
|
144
165
|
popupMaxHeight = '300px',
|
|
145
166
|
paperProps,
|
|
146
167
|
popperProps,
|
|
147
168
|
menuProps,
|
|
148
169
|
menuItemProps,
|
|
149
170
|
optionsPlaceholder = 'No Options',
|
|
171
|
+
dropdownArrowPosition = 'after',
|
|
172
|
+
popupPositionX,
|
|
173
|
+
popupPositionY,
|
|
174
|
+
lockPoistions,
|
|
175
|
+
popperHeightForVerticalPosition,
|
|
150
176
|
}: SelectProps = $props();
|
|
151
177
|
|
|
178
|
+
function convertOptionsToDynamicMenuItemOptions(
|
|
179
|
+
options: SelectOption[],
|
|
180
|
+
): DynamicMenuItemOption<SelectOption>[] {
|
|
181
|
+
const newOptions: DynamicMenuItemOption<SelectOption>[] = options.map((option) => ({
|
|
182
|
+
id: `opt-${option.value}`,
|
|
183
|
+
disabled: option.disabled,
|
|
184
|
+
label: option.label,
|
|
185
|
+
meta: option,
|
|
186
|
+
type: 'button',
|
|
187
|
+
}));
|
|
188
|
+
|
|
189
|
+
return newOptions;
|
|
190
|
+
}
|
|
191
|
+
|
|
152
192
|
let open: boolean = $state(false);
|
|
153
193
|
let onInputStart: boolean = $state(false);
|
|
154
194
|
const selectedOption = $derived(value);
|
|
155
195
|
let searchTerm = $state(value?.label.trim() || '');
|
|
156
|
-
let options = $state(optionsRaw);
|
|
196
|
+
let options = $state(convertOptionsToDynamicMenuItemOptions(optionsRaw));
|
|
157
197
|
let menuRef = $state<HTMLUListElement | undefined>(undefined);
|
|
158
|
-
let menuItemIndex = $state(0);
|
|
159
198
|
|
|
160
199
|
$effect(() => {
|
|
161
200
|
if (!onInputStart) {
|
|
162
|
-
options = optionsRaw;
|
|
201
|
+
options = convertOptionsToDynamicMenuItemOptions(optionsRaw);
|
|
163
202
|
return;
|
|
164
203
|
}
|
|
165
204
|
|
|
166
205
|
const searchTermSimplified = searchTerm.trim().toLowerCase();
|
|
167
206
|
|
|
168
207
|
if (!searchTermSimplified) {
|
|
169
|
-
options = optionsRaw;
|
|
208
|
+
options = convertOptionsToDynamicMenuItemOptions(optionsRaw);
|
|
170
209
|
return;
|
|
171
210
|
}
|
|
172
211
|
|
|
173
|
-
options = optionsRaw.filter((item) =>
|
|
174
|
-
item
|
|
212
|
+
options = convertOptionsToDynamicMenuItemOptions(optionsRaw).filter((item) =>
|
|
213
|
+
item?.meta?.label.trim().toLowerCase().includes(searchTermSimplified),
|
|
175
214
|
);
|
|
176
215
|
});
|
|
177
216
|
|
|
@@ -187,23 +226,17 @@
|
|
|
187
226
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
227
|
let customPlaceholderMenuItemContentTyped = customPlaceholderMenuItemContentInternal as any;
|
|
189
228
|
|
|
229
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
230
|
+
let customDropdownArrowIconTyped = customDropdownArrowIconInternal as any;
|
|
231
|
+
|
|
190
232
|
function closeMenu() {
|
|
191
233
|
open = false;
|
|
192
|
-
menuItemIndex = 0;
|
|
193
234
|
|
|
194
235
|
ref?.blur();
|
|
195
236
|
}
|
|
196
237
|
|
|
197
238
|
function openMenu() {
|
|
198
239
|
open = true;
|
|
199
|
-
|
|
200
|
-
const menuItemIndexNew = options.findIndex((item) => item.value === selectedOption?.value);
|
|
201
|
-
|
|
202
|
-
if (menuItemIndexNew < 0) {
|
|
203
|
-
menuItemIndex = 0;
|
|
204
|
-
} else {
|
|
205
|
-
menuItemIndex = menuItemIndexNew;
|
|
206
|
-
}
|
|
207
240
|
}
|
|
208
241
|
|
|
209
242
|
function onfocusMod(e: DynamicInputFocusEvent) {
|
|
@@ -259,7 +292,9 @@
|
|
|
259
292
|
}
|
|
260
293
|
}
|
|
261
294
|
|
|
262
|
-
function onKeyBoardEnter(selectedItemIndex: number) {
|
|
295
|
+
function onKeyBoardEnter(e: KeyboardEvent, selectedItemIndex: number) {
|
|
296
|
+
e.preventDefault();
|
|
297
|
+
|
|
263
298
|
const targetOption = options[selectedItemIndex];
|
|
264
299
|
|
|
265
300
|
if (!targetOption) {
|
|
@@ -270,106 +305,35 @@
|
|
|
270
305
|
return;
|
|
271
306
|
}
|
|
272
307
|
|
|
273
|
-
onselectMod(targetOption);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function onKeyboardNavigation(e: KeyboardEvent) {
|
|
277
|
-
let keyHit: string | undefined = undefined;
|
|
278
|
-
|
|
279
|
-
if (!menuRef) {
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (!open) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
switch (e.key) {
|
|
288
|
-
case 'ArrowDown':
|
|
289
|
-
case 'ArrowUp':
|
|
290
|
-
case 'Enter':
|
|
291
|
-
keyHit = e.key;
|
|
292
|
-
e.preventDefault();
|
|
293
|
-
break;
|
|
294
|
-
default:
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (!keyHit) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const listItems = menuRef.querySelectorAll(':scope > li.dodo-ui-MenuItem');
|
|
303
|
-
|
|
304
|
-
if (!listItems.length) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
for (let index = 0; index < listItems.length; index++) {
|
|
309
|
-
const element = listItems[index];
|
|
310
|
-
|
|
311
|
-
element.classList.remove('hover');
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
let newMenuItemIndex = menuItemIndex;
|
|
315
|
-
|
|
316
|
-
if (keyHit === 'ArrowDown') {
|
|
317
|
-
if (listItems[newMenuItemIndex + 1]) {
|
|
318
|
-
newMenuItemIndex = newMenuItemIndex + 1;
|
|
319
|
-
} else {
|
|
320
|
-
newMenuItemIndex = 0;
|
|
321
|
-
}
|
|
322
|
-
} else if (keyHit === 'ArrowUp') {
|
|
323
|
-
if (listItems[newMenuItemIndex - 1]) {
|
|
324
|
-
newMenuItemIndex = newMenuItemIndex - 1;
|
|
325
|
-
} else {
|
|
326
|
-
newMenuItemIndex = listItems.length - 1;
|
|
327
|
-
}
|
|
328
|
-
} else if (keyHit === 'Enter') {
|
|
329
|
-
onKeyBoardEnter(newMenuItemIndex);
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const targetItem = listItems[newMenuItemIndex] as HTMLLIElement;
|
|
334
|
-
|
|
335
|
-
targetItem.classList.add('hover');
|
|
336
|
-
|
|
337
|
-
targetItem.focus();
|
|
338
|
-
targetItem.scrollIntoView({ block: 'nearest' });
|
|
339
|
-
|
|
340
|
-
menuItemIndex = newMenuItemIndex;
|
|
308
|
+
onselectMod(targetOption.meta as SelectOption);
|
|
341
309
|
}
|
|
342
|
-
|
|
343
|
-
$effect(() => {
|
|
344
|
-
if (!menuRef) {
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (!open) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const targetItem = menuRef.querySelector(':scope > li.dodo-ui-MenuItem.selected') as
|
|
353
|
-
| HTMLLIElement
|
|
354
|
-
| undefined;
|
|
355
|
-
|
|
356
|
-
if (targetItem) {
|
|
357
|
-
targetItem.classList.add('hover');
|
|
358
|
-
|
|
359
|
-
targetItem.focus();
|
|
360
|
-
targetItem.scrollIntoView({ block: 'nearest' });
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
window.addEventListener('keydown', onKeyboardNavigation);
|
|
364
|
-
|
|
365
|
-
return () => {
|
|
366
|
-
window.removeEventListener('keydown', onKeyboardNavigation);
|
|
367
|
-
};
|
|
368
|
-
});
|
|
369
310
|
</script>
|
|
370
311
|
|
|
312
|
+
{#snippet selectDropdownArrowIcon()}
|
|
313
|
+
<UtilityButton {size} title="Dropdown" onclick={onfocusMod}>
|
|
314
|
+
{#if customDropdownArrowIconTyped}
|
|
315
|
+
{@render customDropdownArrowIconTyped(open)}
|
|
316
|
+
{:else if open}
|
|
317
|
+
<Icon icon="material-symbols:arrow-drop-up-rounded" width="28" height="28" />
|
|
318
|
+
{:else}
|
|
319
|
+
<Icon icon="material-symbols:arrow-drop-down-rounded" width="28" height="28" />
|
|
320
|
+
{/if}
|
|
321
|
+
</UtilityButton>
|
|
322
|
+
{/snippet}
|
|
323
|
+
|
|
371
324
|
<div class={['dodo-ui-Select', className].join(' ')}>
|
|
372
|
-
<Popper
|
|
325
|
+
<Popper
|
|
326
|
+
fullWidth
|
|
327
|
+
{open}
|
|
328
|
+
{onClickOutside}
|
|
329
|
+
{...popperProps}
|
|
330
|
+
{popupMaxHeight}
|
|
331
|
+
{popupPositionX}
|
|
332
|
+
{popupPositionY}
|
|
333
|
+
{paperProps}
|
|
334
|
+
{lockPoistions}
|
|
335
|
+
{popperHeightForVerticalPosition}
|
|
336
|
+
>
|
|
373
337
|
<div
|
|
374
338
|
class:outline
|
|
375
339
|
class:disabled
|
|
@@ -392,6 +356,12 @@
|
|
|
392
356
|
{before}
|
|
393
357
|
{after}
|
|
394
358
|
>
|
|
359
|
+
{#if dropdownArrowPosition === 'before'}
|
|
360
|
+
<div class:before class:open class="DropdownArrow">
|
|
361
|
+
{@render selectDropdownArrowIcon()}
|
|
362
|
+
</div>
|
|
363
|
+
{/if}
|
|
364
|
+
|
|
395
365
|
<DynamicInput
|
|
396
366
|
type="text"
|
|
397
367
|
{name}
|
|
@@ -426,43 +396,50 @@
|
|
|
426
396
|
</UtilityButton>
|
|
427
397
|
</div>
|
|
428
398
|
{/if}
|
|
399
|
+
|
|
400
|
+
{#if dropdownArrowPosition === 'after'}
|
|
401
|
+
<div class:after class:open class="DropdownArrow">
|
|
402
|
+
{@render selectDropdownArrowIcon()}
|
|
403
|
+
</div>
|
|
404
|
+
{/if}
|
|
429
405
|
</InputEnclosure>
|
|
430
406
|
</div>
|
|
431
407
|
|
|
432
408
|
{#snippet popupChildren()}
|
|
433
409
|
{#if customPopupContentTyped}
|
|
434
|
-
{@render customPopupContentTyped(
|
|
410
|
+
{@render customPopupContentTyped(optionsRaw, selectedOption, onselectMod)}
|
|
435
411
|
{:else}
|
|
436
|
-
<
|
|
437
|
-
{
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
412
|
+
<DynamicMenu
|
|
413
|
+
bind:ref={menuRef}
|
|
414
|
+
{menuItemProps}
|
|
415
|
+
{options}
|
|
416
|
+
keyboardNavigation
|
|
417
|
+
onEnter={onKeyBoardEnter}
|
|
418
|
+
selectedOption={options.find((item) => item.meta?.value === selectedOption?.value)}
|
|
419
|
+
onclick={(_e, option: DynamicMenuItemOption) => onselectMod(option.meta as SelectOption)}
|
|
420
|
+
showOptionsPlaceholder
|
|
421
|
+
{...menuProps}
|
|
422
|
+
>
|
|
423
|
+
{#snippet customMenuItemContent(option, selectedOption)}
|
|
424
|
+
{#if customMenuItemContentTyped}
|
|
425
|
+
{@render customMenuItemContentTyped(
|
|
426
|
+
option?.meta as SelectOption,
|
|
427
|
+
(selectedOption?.meta as SelectOption).value ===
|
|
428
|
+
(option?.meta as SelectOption).value,
|
|
429
|
+
)}
|
|
430
|
+
{:else}
|
|
431
|
+
{(option?.meta as SelectOption).label}
|
|
432
|
+
{/if}
|
|
433
|
+
{/snippet}
|
|
434
|
+
|
|
435
|
+
{#snippet customPlaceholderMenuItemContent()}
|
|
436
|
+
{#if customPlaceholderMenuItemContentTyped}
|
|
437
|
+
{@render customPlaceholderMenuItemContentTyped()}
|
|
438
|
+
{:else}
|
|
439
|
+
{optionsPlaceholder}
|
|
440
|
+
{/if}
|
|
441
|
+
{/snippet}
|
|
442
|
+
</DynamicMenu>
|
|
466
443
|
{/if}
|
|
467
444
|
{/snippet}
|
|
468
445
|
</Popper>
|
|
@@ -478,6 +455,16 @@
|
|
|
478
455
|
margin-right: calc(var(--dodo-ui-space-small) * 2);
|
|
479
456
|
}
|
|
480
457
|
}
|
|
458
|
+
|
|
459
|
+
.DropdownArrow {
|
|
460
|
+
&.after {
|
|
461
|
+
margin-right: calc(var(--dodo-ui-space-small) * 2);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
&.before {
|
|
465
|
+
margin-right: calc(var(--dodo-ui-space-small) * 2);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
481
468
|
}
|
|
482
469
|
|
|
483
470
|
&--small {
|
|
@@ -486,6 +473,16 @@
|
|
|
486
473
|
margin-right: var(--dodo-ui-space);
|
|
487
474
|
}
|
|
488
475
|
}
|
|
476
|
+
|
|
477
|
+
.DropdownArrow {
|
|
478
|
+
&.after {
|
|
479
|
+
margin-right: var(--dodo-ui-space);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
&.before {
|
|
483
|
+
margin-right: var(--dodo-ui-space);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
489
486
|
}
|
|
490
487
|
|
|
491
488
|
&--large {
|
|
@@ -494,6 +491,16 @@
|
|
|
494
491
|
margin-right: calc(var(--dodo-ui-space) * 2);
|
|
495
492
|
}
|
|
496
493
|
}
|
|
494
|
+
|
|
495
|
+
.DropdownArrow {
|
|
496
|
+
&.after {
|
|
497
|
+
margin-right: calc(var(--dodo-ui-space) * 2);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
&.before {
|
|
501
|
+
margin-right: calc(var(--dodo-ui-space) * 2);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
497
504
|
}
|
|
498
505
|
}
|
|
499
506
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import Select, { type SelectOption } from '../Select.svelte';
|
|
4
|
+
import { selectOptions, storySelectArgTypes } from '../Select.stories.svelte';
|
|
5
|
+
|
|
6
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
7
|
+
const { Story } = defineMeta({
|
|
8
|
+
component: Select,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
argTypes: storySelectArgTypes,
|
|
11
|
+
parameters: {
|
|
12
|
+
docs: {
|
|
13
|
+
story: {
|
|
14
|
+
height: '400px',
|
|
15
|
+
inline: false,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const options = selectOptions;
|
|
22
|
+
|
|
23
|
+
let value = $state<SelectOption>(options[0]);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<Story name="Normal" args={{ options, value }} />
|
|
27
|
+
<Story name="Small" args={{ options, value, size: 'small' }} />
|
|
28
|
+
<Story name="Large" args={{ options, value, size: 'large' }} />
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import Select, { type SelectOption } from '../Select.svelte';
|
|
4
|
+
import { selectOptions, storySelectArgTypes } from '../Select.stories.svelte';
|
|
5
|
+
import Icon from '@iconify/svelte';
|
|
6
|
+
|
|
7
|
+
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
|
|
8
|
+
const { Story } = defineMeta({
|
|
9
|
+
component: Select,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
argTypes: storySelectArgTypes,
|
|
12
|
+
parameters: {
|
|
13
|
+
docs: {
|
|
14
|
+
story: {
|
|
15
|
+
height: '400px',
|
|
16
|
+
inline: false,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const options = selectOptions;
|
|
23
|
+
|
|
24
|
+
let value = $state<SelectOption>(options[0]);
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<!-- Select icon in front. -->
|
|
28
|
+
<Story name="Icon Before" asChild>
|
|
29
|
+
<Select {value} {options}>
|
|
30
|
+
{#snippet before()}
|
|
31
|
+
<Icon icon="material-symbols:content-copy" />
|
|
32
|
+
{/snippet}
|
|
33
|
+
</Select>
|
|
34
|
+
</Story>
|
|
35
|
+
|
|
36
|
+
<!-- Select icon in front. -->
|
|
37
|
+
<Story name="Icon After" asChild>
|
|
38
|
+
<Select {value} {options}>
|
|
39
|
+
{#snippet after()}
|
|
40
|
+
<Icon icon="material-symbols:download-2" />
|
|
41
|
+
{/snippet}
|
|
42
|
+
</Select>
|
|
43
|
+
</Story>
|