@flightlesslabs/dodo-ui 0.6.6 → 0.7.1
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 +28 -7
- package/dist/index.js +12 -2
- package/dist/stories/Home.mdx +1 -1
- package/dist/stories/components/Form/Button/Button.svelte +2 -2
- package/dist/stories/components/Form/Button/Button.svelte.d.ts +8 -5
- package/dist/stories/components/Form/FormControl/FormControl.svelte +3 -0
- package/dist/stories/components/Form/FormControl/FormControl.svelte.d.ts +1 -1
- package/dist/stories/components/Form/Label/Label.svelte +5 -2
- package/dist/stories/components/Form/Label/Label.svelte.d.ts +1 -1
- package/dist/stories/components/Form/Message/Message.svelte +5 -2
- package/dist/stories/components/Form/Message/Message.svelte.d.ts +1 -1
- package/dist/stories/components/Form/PasswordInput/PasswordInput.svelte +25 -32
- package/dist/stories/components/Form/PasswordInput/PasswordInput.svelte.d.ts +5 -5
- package/dist/stories/components/Form/Select/Customize/Customize.stories.svelte +120 -0
- package/dist/stories/components/Form/Select/Customize/Customize.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/Select/Events/Events.stories.svelte +138 -0
- package/dist/stories/components/Form/Select/Options/OptionFormat.mdx +40 -0
- package/dist/stories/components/Form/Select/Roundness/Roundness.stories.svelte +28 -0
- package/dist/stories/components/Form/Select/Roundness/Roundness.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/Select/Select.stories.svelte +114 -0
- package/dist/stories/components/Form/Select/Select.stories.svelte.d.ts +22 -0
- package/dist/stories/components/Form/Select/Select.svelte +285 -0
- package/dist/stories/components/Form/Select/Select.svelte.d.ts +87 -0
- package/dist/stories/components/Form/Select/Size/Size.stories.svelte +24 -0
- package/dist/stories/components/Form/Select/Size/Size.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/Select/WithIcon/WithIcon.stories.svelte +39 -0
- package/dist/stories/components/Form/Select/WithIcon/WithIcon.stories.svelte.d.ts +18 -0
- package/dist/stories/components/Form/TextInput/TextInput.svelte +9 -28
- package/dist/stories/components/Form/TextInput/TextInput.svelte.d.ts +8 -5
- package/dist/stories/components/Layout/Menu/Menu.stories.svelte +65 -0
- package/dist/stories/components/Layout/Menu/Menu.stories.svelte.d.ts +21 -0
- package/dist/stories/components/Layout/Menu/Menu.svelte +30 -0
- package/dist/stories/components/Layout/Menu/Menu.svelte.d.ts +23 -0
- package/dist/stories/components/Layout/Menu/MenuItem/MenuItem.stories.svelte +30 -0
- package/dist/stories/components/Layout/Menu/MenuItem/MenuItem.stories.svelte.d.ts +21 -0
- package/dist/stories/components/Layout/Menu/MenuItem/MenuItem.svelte +164 -0
- package/dist/stories/components/Layout/Menu/MenuItem/MenuItem.svelte.d.ts +49 -0
- package/dist/stories/components/Layout/Menu/MenuItem/Size/Size.stories.svelte +16 -0
- package/dist/stories/components/Layout/Menu/MenuItem/Type/Type.stories.svelte +21 -0
- package/dist/stories/components/{Form/SimpleSelect/WithIcon/WithIcon.stories.svelte.d.ts → Layout/Menu/MenuItem/Type/Type.stories.svelte.d.ts} +3 -3
- package/dist/stories/components/Layout/Menu/Size/Size.stories.svelte +37 -0
- package/dist/stories/components/{Form/SimpleSelect/Roundness/Roundness.stories.svelte.d.ts → Layout/Menu/Size/Size.stories.svelte.d.ts} +3 -3
- package/dist/stories/components/Layout/Paper/Color/Color.stories.svelte +1 -1
- package/dist/stories/components/Layout/Paper/Paper.stories.svelte +1 -1
- package/dist/stories/components/Layout/Paper/Paper.svelte.d.ts +5 -5
- package/dist/stories/components/Layout/Separator/Color/Color.stories.svelte +19 -0
- package/dist/stories/components/Layout/Separator/Color/Color.stories.svelte.d.ts +26 -0
- package/dist/stories/components/Layout/Separator/Separator.stories.svelte +26 -0
- package/dist/stories/components/Layout/Separator/Separator.stories.svelte.d.ts +21 -0
- package/dist/stories/components/Layout/Separator/Separator.svelte +66 -0
- package/dist/stories/components/Layout/Separator/Separator.svelte.d.ts +22 -0
- package/dist/stories/components/Layout/Separator/utils/scss/mixins.scss +24 -0
- package/dist/stories/developer tools/components/DynamicInput/DynamicInput.stories.svelte +49 -0
- package/dist/stories/{components/Form/SimpleSelect/SimpleSelect.stories.svelte.d.ts → developer tools/components/DynamicInput/DynamicInput.stories.svelte.d.ts } +5 -7
- package/dist/stories/developer tools/components/DynamicInput/DynamicInput.svelte +92 -0
- package/dist/stories/developer tools/components/DynamicInput/DynamicInput.svelte.d.ts +60 -0
- package/dist/stories/{components/Form/SimpleSelect/Size/Size.stories.svelte → developer tools/components/DynamicInput/Size/Size.stories.svelte } +5 -8
- package/dist/stories/developer tools/components/DynamicInput/Size/Size.stories.svelte.d.ts +26 -0
- package/dist/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte +6 -2
- package/dist/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte.d.ts +1 -1
- package/dist/stories/developer tools/components/Popper/Popper.stories.svelte +119 -0
- package/dist/stories/developer tools/components/Popper/Popper.stories.svelte.d.ts +21 -0
- package/dist/stories/developer tools/components/Popper/Popper.svelte +77 -0
- package/dist/stories/developer tools/components/Popper/Popper.svelte.d.ts +50 -0
- package/dist/stories/developer tools/components/Popper/PopperPopup/PopperPopup.stories.svelte +60 -0
- package/dist/stories/developer tools/components/Popper/PopperPopup/PopperPopup.stories.svelte.d.ts +21 -0
- package/dist/stories/developer tools/components/Popper/PopperPopup/PopperPopup.svelte +66 -0
- package/dist/stories/developer tools/components/Popper/PopperPopup/PopperPopup.svelte.d.ts +34 -0
- package/dist/stories/developer tools/components/Popper/PopperPopup/utils/getPopupPosition.d.ts +21 -0
- package/dist/stories/developer tools/components/Popper/PopperPopup/utils/getPopupPosition.js +62 -0
- package/dist/stories/developer tools/components/Popper/Positions/AutoPosition/AutoPosition.stories.svelte +89 -0
- package/dist/stories/developer tools/components/Popper/Positions/AutoPosition/AutoPosition.stories.svelte.d.ts +18 -0
- package/dist/stories/developer tools/components/Popper/Positions/Positions.stories.svelte +111 -0
- package/dist/stories/developer tools/components/Popper/Positions/Positions.stories.svelte.d.ts +18 -0
- package/dist/stories/developer tools/components/UtilityButton/Size/Size.stories.svelte +3 -5
- package/dist/stories/developer tools/components/UtilityButton/UtilityButton.stories.svelte +0 -4
- package/dist/stories/developer tools/components/UtilityButton/UtilityButton.svelte +5 -2
- package/dist/stories/developer tools/components/UtilityButton/UtilityButton.svelte.d.ts +1 -1
- package/dist/stories/developer tools/directives/clickOutside/clickOutside.d.ts +3 -0
- package/dist/stories/developer tools/directives/clickOutside/clickOutside.js +14 -0
- package/dist/stories/developer tools/directives/clickOutside/index.mdx +25 -0
- package/dist/styles/_z-index.css +9 -0
- package/dist/styles/global.css +1 -0
- package/dist/types/position.d.ts +4 -0
- package/dist/types/position.js +2 -0
- package/package.json +3 -3
- package/src/lib/index.ts +50 -9
- package/src/lib/stories/components/Form/Button/Button.svelte +14 -10
- package/src/lib/stories/components/Form/FormControl/FormControl.svelte +7 -4
- package/src/lib/stories/components/Form/Label/Label.svelte +4 -2
- package/src/lib/stories/components/Form/Message/Message.svelte +4 -2
- package/src/lib/stories/components/Form/PasswordInput/PasswordInput.svelte +48 -49
- package/src/lib/stories/components/Form/Select/Select.svelte +501 -0
- package/src/lib/stories/components/Form/TextInput/TextInput.svelte +32 -59
- package/src/lib/stories/components/Layout/Menu/Menu.svelte +65 -0
- package/src/lib/stories/components/Layout/Menu/MenuItem/MenuItem.svelte +268 -0
- package/src/lib/stories/components/Layout/Paper/Paper.svelte +8 -9
- package/src/lib/stories/components/Layout/Separator/Separator.svelte +96 -0
- package/src/lib/stories/components/Layout/Separator/utils/scss/mixins.scss +24 -0
- package/src/lib/stories/developer tools/components/DynamicInput/DynamicInput.svelte +195 -0
- package/src/lib/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte +5 -2
- package/src/lib/stories/developer tools/components/Popper/Popper.svelte +159 -0
- package/src/lib/stories/developer tools/components/Popper/PopperPopup/PopperPopup.svelte +120 -0
- package/src/lib/stories/developer tools/components/Popper/PopperPopup/utils/getPopupPosition.ts +87 -0
- package/src/lib/stories/developer tools/components/UtilityButton/UtilityButton.svelte +4 -2
- package/src/lib/stories/developer tools/directives/clickOutside/clickOutside.ts +17 -0
- package/src/lib/styles/_z-index.css +9 -0
- package/src/lib/styles/global.css +1 -0
- package/src/lib/types/position.ts +5 -0
- package/dist/stories/components/Form/SimpleSelect/Events/Events.stories.svelte +0 -47
- package/dist/stories/components/Form/SimpleSelect/Roundness/Roundness.stories.svelte +0 -24
- package/dist/stories/components/Form/SimpleSelect/SimpleSelect.stories.svelte +0 -57
- package/dist/stories/components/Form/SimpleSelect/SimpleSelect.svelte +0 -69
- package/dist/stories/components/Form/SimpleSelect/SimpleSelect.svelte.d.ts +0 -51
- package/dist/stories/components/Form/SimpleSelect/WithIcon/WithIcon.stories.svelte +0 -36
- package/src/lib/stories/components/Form/SimpleSelect/SimpleSelect.svelte +0 -160
- /package/dist/stories/components/Form/{SimpleSelect → Select}/Events/Events.stories.svelte.d.ts +0 -0
- /package/dist/stories/components/{Form/SimpleSelect → Layout/Menu/MenuItem}/Size/Size.stories.svelte.d.ts +0 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { ComponentSize } from '$lib/types/size.js';
|
|
3
|
+
import type { ComponentRoundness } from '$lib/types/roundness.js';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import type {
|
|
6
|
+
ChangeEventHandler,
|
|
7
|
+
ClipboardEventHandler,
|
|
8
|
+
FocusEventHandler,
|
|
9
|
+
FormEventHandler,
|
|
10
|
+
MouseEventHandler,
|
|
11
|
+
} from 'svelte/elements';
|
|
12
|
+
|
|
13
|
+
export type SelectOption = {
|
|
14
|
+
value: string | number | boolean | null | undefined;
|
|
15
|
+
label: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface SelectProps {
|
|
20
|
+
/** How large should the button be? */
|
|
21
|
+
size?: ComponentSize;
|
|
22
|
+
/** want a searchable Select? */
|
|
23
|
+
options: SelectOption[];
|
|
24
|
+
/** want a searchable Select? */
|
|
25
|
+
searchable?: boolean;
|
|
26
|
+
/** want a clearable Select? */
|
|
27
|
+
clearable?: boolean;
|
|
28
|
+
/** onselect event handler */
|
|
29
|
+
onselect?: (val: SelectOption) => void;
|
|
30
|
+
/** onclear event handler */
|
|
31
|
+
onclear?: MouseEventHandler<HTMLButtonElement>;
|
|
32
|
+
/** Select ref */
|
|
33
|
+
ref?: HTMLInputElement | HTMLButtonElement;
|
|
34
|
+
/** How round should the border radius be? */
|
|
35
|
+
roundness?: ComponentRoundness;
|
|
36
|
+
/** Add a border around the button. Default True */
|
|
37
|
+
outline?: boolean;
|
|
38
|
+
/** Select value */
|
|
39
|
+
value: SelectOption | undefined;
|
|
40
|
+
/** How round should the border radius be? */
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
/** Placeholder if there are no options found*/
|
|
43
|
+
optionsPlaceholder?: string;
|
|
44
|
+
/** disabled state */
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
/** Read only ? */
|
|
47
|
+
readonly?: boolean;
|
|
48
|
+
/** is there any associated Error ? */
|
|
49
|
+
error?: boolean;
|
|
50
|
+
/** Name */
|
|
51
|
+
name?: string;
|
|
52
|
+
/** Id */
|
|
53
|
+
id?: string;
|
|
54
|
+
/** Icon before button content */
|
|
55
|
+
before?: Snippet;
|
|
56
|
+
/** Icon after button content */
|
|
57
|
+
after?: Snippet;
|
|
58
|
+
/** Custom css class*/
|
|
59
|
+
class?: string;
|
|
60
|
+
/** onchange event handler */
|
|
61
|
+
onchange?: ChangeEventHandler<HTMLInputElement>;
|
|
62
|
+
/** oninput event handler */
|
|
63
|
+
oninput?: FormEventHandler<HTMLInputElement>;
|
|
64
|
+
/** onblur event handler */
|
|
65
|
+
onblur?: FocusEventHandler<HTMLInputElement | HTMLButtonElement>;
|
|
66
|
+
/** onfocus event handler */
|
|
67
|
+
onfocus?: FocusEventHandler<HTMLInputElement | HTMLButtonElement>;
|
|
68
|
+
/** onpaste event handler */
|
|
69
|
+
onpaste?: ClipboardEventHandler<HTMLInputElement>;
|
|
70
|
+
/** oncopy event handler */
|
|
71
|
+
oncopy?: ClipboardEventHandler<HTMLInputElement>;
|
|
72
|
+
/** oncut event handler */
|
|
73
|
+
oncut?: ClipboardEventHandler<HTMLInputElement>;
|
|
74
|
+
/** custom Content Formatting for variant button */
|
|
75
|
+
customInputContent?: (val: SelectOption) => Snippet;
|
|
76
|
+
/** custom Content Formatting for variant button */
|
|
77
|
+
customMenuItemContent?: (val: SelectOption, selected: boolean) => Snippet;
|
|
78
|
+
/** Custom Popup Content */
|
|
79
|
+
customPopupContent?: (options: SelectOption[], selectedOption: SelectOption) => Snippet;
|
|
80
|
+
/** custom Content Formatting for variant button */
|
|
81
|
+
customPlaceholderMenuItemContent?: () => Snippet;
|
|
82
|
+
/** PopperPopup Max height. Use css compatible value */
|
|
83
|
+
popupMaxHeight?: string;
|
|
84
|
+
/** PaperProps: Paper component props for Popup */
|
|
85
|
+
paperProps?: Partial<PaperProps>;
|
|
86
|
+
/** PopperProps: Popper component props */
|
|
87
|
+
popperProps?: Partial<PopperProps>;
|
|
88
|
+
/** MenuProps: Menu component props */
|
|
89
|
+
menuProps?: Partial<MenuProps>;
|
|
90
|
+
/** MenuItem: Menu component props */
|
|
91
|
+
menuItemProps?: Partial<MenuItemProps>;
|
|
92
|
+
}
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<script lang="ts">
|
|
96
|
+
import InputEnclosure from '$lib/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte';
|
|
97
|
+
import UtilityButton from '$lib/stories/developer tools/components/UtilityButton/UtilityButton.svelte';
|
|
98
|
+
import Icon from '@iconify/svelte';
|
|
99
|
+
import {
|
|
100
|
+
DynamicInput,
|
|
101
|
+
Menu,
|
|
102
|
+
MenuItem,
|
|
103
|
+
Popper,
|
|
104
|
+
type DynamicInputFocusEvent,
|
|
105
|
+
type MenuItemProps,
|
|
106
|
+
type MenuProps,
|
|
107
|
+
type PaperProps,
|
|
108
|
+
type PopperProps,
|
|
109
|
+
} from '$lib/index.js';
|
|
110
|
+
import type { TextInputInputEvent } from '../TextInput/TextInput.svelte';
|
|
111
|
+
import type { ButtonClickEvent } from '../Button/Button.svelte';
|
|
112
|
+
|
|
113
|
+
let {
|
|
114
|
+
size = 'normal',
|
|
115
|
+
roundness = 1,
|
|
116
|
+
outline = true,
|
|
117
|
+
name,
|
|
118
|
+
id,
|
|
119
|
+
class: className = '',
|
|
120
|
+
disabled = false,
|
|
121
|
+
onchange,
|
|
122
|
+
oninput,
|
|
123
|
+
onselect,
|
|
124
|
+
onblur,
|
|
125
|
+
onfocus,
|
|
126
|
+
onpaste,
|
|
127
|
+
oncopy,
|
|
128
|
+
oncut,
|
|
129
|
+
before,
|
|
130
|
+
after,
|
|
131
|
+
error = false,
|
|
132
|
+
value,
|
|
133
|
+
placeholder,
|
|
134
|
+
ref = $bindable<HTMLInputElement | HTMLButtonElement>(),
|
|
135
|
+
readonly = false,
|
|
136
|
+
searchable = false,
|
|
137
|
+
clearable = false,
|
|
138
|
+
onclear,
|
|
139
|
+
options: optionsRaw,
|
|
140
|
+
customInputContent: customInputContentInternal,
|
|
141
|
+
customMenuItemContent: customMenuItemContentInternal,
|
|
142
|
+
customPopupContent: customPopupContentInternal,
|
|
143
|
+
customPlaceholderMenuItemContent: customPlaceholderMenuItemContentInternal,
|
|
144
|
+
popupMaxHeight = '300px',
|
|
145
|
+
paperProps,
|
|
146
|
+
popperProps,
|
|
147
|
+
menuProps,
|
|
148
|
+
menuItemProps,
|
|
149
|
+
optionsPlaceholder = 'No Options',
|
|
150
|
+
}: SelectProps = $props();
|
|
151
|
+
|
|
152
|
+
let open: boolean = $state(false);
|
|
153
|
+
let onInputStart: boolean = $state(false);
|
|
154
|
+
const selectedOption = $derived(value);
|
|
155
|
+
let searchTerm = $state(value?.label.trim() || '');
|
|
156
|
+
let options = $state(optionsRaw);
|
|
157
|
+
let menuRef = $state<HTMLUListElement | undefined>(undefined);
|
|
158
|
+
let menuItemIndex = $state(0);
|
|
159
|
+
|
|
160
|
+
$effect(() => {
|
|
161
|
+
if (!onInputStart) {
|
|
162
|
+
options = optionsRaw;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const searchTermSimplified = searchTerm.trim().toLowerCase();
|
|
167
|
+
|
|
168
|
+
if (!searchTermSimplified) {
|
|
169
|
+
options = optionsRaw;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
options = optionsRaw.filter((item) =>
|
|
174
|
+
item.label.trim().toLowerCase().includes(searchTermSimplified),
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
179
|
+
let customInputContentTyped = customInputContentInternal as any;
|
|
180
|
+
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
let customMenuItemContentTyped = customMenuItemContentInternal as any;
|
|
183
|
+
|
|
184
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
+
let customPopupContentTyped = customPopupContentInternal as any;
|
|
186
|
+
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
|
+
let customPlaceholderMenuItemContentTyped = customPlaceholderMenuItemContentInternal as any;
|
|
189
|
+
|
|
190
|
+
function closeMenu() {
|
|
191
|
+
open = false;
|
|
192
|
+
menuItemIndex = 0;
|
|
193
|
+
|
|
194
|
+
ref?.blur();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function openMenu() {
|
|
198
|
+
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
|
+
}
|
|
208
|
+
|
|
209
|
+
function onfocusMod(e: DynamicInputFocusEvent) {
|
|
210
|
+
openMenu();
|
|
211
|
+
|
|
212
|
+
if (onfocus) {
|
|
213
|
+
onfocus(e);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function onblurMod(e: DynamicInputFocusEvent) {
|
|
218
|
+
if (onblur) {
|
|
219
|
+
onblur(e);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function onClickOutside() {
|
|
224
|
+
searchTerm = selectedOption?.label || '';
|
|
225
|
+
onInputStart = false;
|
|
226
|
+
|
|
227
|
+
closeMenu();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function onselectMod(val: SelectOption) {
|
|
231
|
+
searchTerm = val.label;
|
|
232
|
+
onInputStart = false;
|
|
233
|
+
|
|
234
|
+
closeMenu();
|
|
235
|
+
|
|
236
|
+
if (onselect) {
|
|
237
|
+
onselect(val);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function oninputMod(e: TextInputInputEvent) {
|
|
242
|
+
const target = e.target as HTMLInputElement;
|
|
243
|
+
searchTerm = target.value;
|
|
244
|
+
onInputStart = true;
|
|
245
|
+
|
|
246
|
+
if (oninput) {
|
|
247
|
+
oninput(e);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function onclearMod(e: ButtonClickEvent) {
|
|
252
|
+
searchTerm = '';
|
|
253
|
+
onInputStart = false;
|
|
254
|
+
|
|
255
|
+
closeMenu();
|
|
256
|
+
|
|
257
|
+
if (onclear) {
|
|
258
|
+
onclear(e);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function onKeyBoardEnter(selectedItemIndex: number) {
|
|
263
|
+
const targetOption = options[selectedItemIndex];
|
|
264
|
+
|
|
265
|
+
if (!targetOption) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (targetOption.disabled) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
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;
|
|
341
|
+
}
|
|
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
|
+
</script>
|
|
370
|
+
|
|
371
|
+
<div class={['dodo-ui-Select', className].join(' ')}>
|
|
372
|
+
<Popper fullWidth {open} {onClickOutside} {...popperProps} {popupMaxHeight} {paperProps}>
|
|
373
|
+
<div
|
|
374
|
+
class:outline
|
|
375
|
+
class:disabled
|
|
376
|
+
class:error
|
|
377
|
+
class={[
|
|
378
|
+
'Select',
|
|
379
|
+
`size--${size}`,
|
|
380
|
+
`${open ? 'focused' : ''}`,
|
|
381
|
+
`roundness--${roundness}`,
|
|
382
|
+
className,
|
|
383
|
+
].join(' ')}
|
|
384
|
+
>
|
|
385
|
+
<InputEnclosure
|
|
386
|
+
{outline}
|
|
387
|
+
{disabled}
|
|
388
|
+
{error}
|
|
389
|
+
focused={open}
|
|
390
|
+
{size}
|
|
391
|
+
{roundness}
|
|
392
|
+
{before}
|
|
393
|
+
{after}
|
|
394
|
+
>
|
|
395
|
+
<DynamicInput
|
|
396
|
+
type="text"
|
|
397
|
+
{name}
|
|
398
|
+
{id}
|
|
399
|
+
{disabled}
|
|
400
|
+
bind:ref
|
|
401
|
+
oninput={oninputMod}
|
|
402
|
+
{onchange}
|
|
403
|
+
onfocus={onfocusMod}
|
|
404
|
+
onblur={onblurMod}
|
|
405
|
+
{onpaste}
|
|
406
|
+
{oncopy}
|
|
407
|
+
{oncut}
|
|
408
|
+
{placeholder}
|
|
409
|
+
value={searchable ? searchTerm : selectedOption?.label}
|
|
410
|
+
{readonly}
|
|
411
|
+
variant={searchable ? 'input' : 'button'}
|
|
412
|
+
>
|
|
413
|
+
{#snippet customInputContent()}
|
|
414
|
+
{#if customInputContentTyped}
|
|
415
|
+
{@render customInputContentTyped(selectedOption)}
|
|
416
|
+
{:else}
|
|
417
|
+
{selectedOption?.label || placeholder}
|
|
418
|
+
{/if}
|
|
419
|
+
{/snippet}
|
|
420
|
+
</DynamicInput>
|
|
421
|
+
|
|
422
|
+
{#if selectedOption?.label && clearable && !disabled}
|
|
423
|
+
<div class:after class="SelectClear">
|
|
424
|
+
<UtilityButton {size} title="Clear" onclick={onclearMod}>
|
|
425
|
+
<Icon icon="material-symbols:close-small" width="24" height="24" />
|
|
426
|
+
</UtilityButton>
|
|
427
|
+
</div>
|
|
428
|
+
{/if}
|
|
429
|
+
</InputEnclosure>
|
|
430
|
+
</div>
|
|
431
|
+
|
|
432
|
+
{#snippet popupChildren()}
|
|
433
|
+
{#if customPopupContentTyped}
|
|
434
|
+
{@render customPopupContentTyped(options, selectedOption)}
|
|
435
|
+
{:else}
|
|
436
|
+
<Menu bind:ref={menuRef} {...menuProps}>
|
|
437
|
+
{#if options.length}
|
|
438
|
+
{#each options as option (option.value)}
|
|
439
|
+
<MenuItem
|
|
440
|
+
onclick={() => onselectMod(option)}
|
|
441
|
+
type="button"
|
|
442
|
+
disabled={option.disabled}
|
|
443
|
+
selected={selectedOption?.value === option.value}
|
|
444
|
+
{...menuItemProps}
|
|
445
|
+
>
|
|
446
|
+
{#if customMenuItemContentTyped}
|
|
447
|
+
{@render customMenuItemContentTyped(
|
|
448
|
+
option,
|
|
449
|
+
selectedOption?.value === option.value,
|
|
450
|
+
)}
|
|
451
|
+
{:else}
|
|
452
|
+
{option.label}
|
|
453
|
+
{/if}
|
|
454
|
+
</MenuItem>
|
|
455
|
+
{/each}
|
|
456
|
+
{:else}
|
|
457
|
+
<MenuItem type="text" disabled={true} {...menuItemProps}>
|
|
458
|
+
{#if customPlaceholderMenuItemContentTyped}
|
|
459
|
+
{@render customPlaceholderMenuItemContentTyped()}
|
|
460
|
+
{:else}
|
|
461
|
+
{optionsPlaceholder}
|
|
462
|
+
{/if}
|
|
463
|
+
</MenuItem>
|
|
464
|
+
{/if}
|
|
465
|
+
</Menu>
|
|
466
|
+
{/if}
|
|
467
|
+
{/snippet}
|
|
468
|
+
</Popper>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<style lang="scss">
|
|
472
|
+
.dodo-ui-Select {
|
|
473
|
+
.Select {
|
|
474
|
+
&.size {
|
|
475
|
+
&--normal {
|
|
476
|
+
.SelectClear {
|
|
477
|
+
&.after {
|
|
478
|
+
margin-right: calc(var(--dodo-ui-space-small) * 2);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
&--small {
|
|
484
|
+
.SelectClear {
|
|
485
|
+
&.after {
|
|
486
|
+
margin-right: var(--dodo-ui-space);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
&--large {
|
|
492
|
+
.SelectClear {
|
|
493
|
+
&.after {
|
|
494
|
+
margin-right: calc(var(--dodo-ui-space) * 2);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
</style>
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
+
import type { ComponentRoundness } from '$lib/types/roundness.js';
|
|
3
|
+
import type { ComponentSize } from '$lib/types/size.js';
|
|
4
|
+
|
|
5
|
+
import type { Snippet } from 'svelte';
|
|
6
|
+
import type {
|
|
7
|
+
ChangeEventHandler,
|
|
8
|
+
ClipboardEventHandler,
|
|
9
|
+
FocusEventHandler,
|
|
10
|
+
FormEventHandler,
|
|
11
|
+
} from 'svelte/elements';
|
|
12
|
+
|
|
2
13
|
export type TextInputType = 'text' | 'tel' | 'email' | 'password' | 'url' | 'number';
|
|
3
14
|
|
|
4
15
|
export const textInputTypeArray: TextInputType[] = [
|
|
@@ -17,22 +28,12 @@
|
|
|
17
28
|
export type TextInputClipboardEvent = ClipboardEvent & {
|
|
18
29
|
currentTarget: EventTarget & HTMLInputElement;
|
|
19
30
|
};
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<script lang="ts">
|
|
23
|
-
import InputEnclosure from '$lib/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte';
|
|
24
|
-
import type { ComponentRoundness } from '$lib/types/roundness.js';
|
|
25
|
-
import type { ComponentSize } from '$lib/types/size.js';
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ClipboardEventHandler,
|
|
31
|
-
FocusEventHandler,
|
|
32
|
-
FormEventHandler,
|
|
33
|
-
} from 'svelte/elements';
|
|
32
|
+
export type TextInputInputEvent = Event & {
|
|
33
|
+
currentTarget: EventTarget & HTMLInputElement;
|
|
34
|
+
};
|
|
34
35
|
|
|
35
|
-
interface TextInputProps {
|
|
36
|
+
export interface TextInputProps {
|
|
36
37
|
/** Input type? */
|
|
37
38
|
type?: TextInputType;
|
|
38
39
|
/** Input ref */
|
|
@@ -78,6 +79,13 @@
|
|
|
78
79
|
/** oncut event handler */
|
|
79
80
|
oncut?: ClipboardEventHandler<HTMLInputElement>;
|
|
80
81
|
}
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<script lang="ts">
|
|
85
|
+
import InputEnclosure from '$lib/stories/developer tools/components/InputEnclosure/InputEnclosure.svelte';
|
|
86
|
+
import DynamicInput, {
|
|
87
|
+
type DynamicInputFocusEvent,
|
|
88
|
+
} from '$lib/stories/developer tools/components/DynamicInput/DynamicInput.svelte';
|
|
81
89
|
|
|
82
90
|
let {
|
|
83
91
|
type = 'text',
|
|
@@ -106,19 +114,21 @@
|
|
|
106
114
|
|
|
107
115
|
let focused: boolean = $state(false);
|
|
108
116
|
|
|
109
|
-
function onfocusMod(e:
|
|
117
|
+
function onfocusMod(e: DynamicInputFocusEvent) {
|
|
118
|
+
const eTyped = e as TextInputFocusEvent;
|
|
110
119
|
focused = true;
|
|
111
120
|
|
|
112
121
|
if (onfocus) {
|
|
113
|
-
onfocus(
|
|
122
|
+
onfocus(eTyped);
|
|
114
123
|
}
|
|
115
124
|
}
|
|
116
125
|
|
|
117
|
-
function onblurMod(e:
|
|
126
|
+
function onblurMod(e: DynamicInputFocusEvent) {
|
|
127
|
+
const eTyped = e as TextInputFocusEvent;
|
|
118
128
|
focused = false;
|
|
119
129
|
|
|
120
130
|
if (onblur) {
|
|
121
|
-
onblur(
|
|
131
|
+
onblur(eTyped);
|
|
122
132
|
}
|
|
123
133
|
}
|
|
124
134
|
</script>
|
|
@@ -131,11 +141,12 @@
|
|
|
131
141
|
class={['dodo-ui-TextInput', `size--${size}`, `roundness--${roundness}`, className].join(' ')}
|
|
132
142
|
>
|
|
133
143
|
<InputEnclosure {outline} {disabled} {error} {focused} {size} {roundness} {before} {after}>
|
|
134
|
-
<
|
|
144
|
+
<DynamicInput
|
|
135
145
|
{type}
|
|
136
146
|
{name}
|
|
137
147
|
{id}
|
|
138
148
|
{disabled}
|
|
149
|
+
bind:ref
|
|
139
150
|
{oninput}
|
|
140
151
|
{onchange}
|
|
141
152
|
onfocus={onfocusMod}
|
|
@@ -144,47 +155,9 @@
|
|
|
144
155
|
{oncopy}
|
|
145
156
|
{oncut}
|
|
146
157
|
{placeholder}
|
|
147
|
-
{readonly}
|
|
148
158
|
bind:value
|
|
149
|
-
|
|
159
|
+
{readonly}
|
|
160
|
+
variant="input"
|
|
150
161
|
/>
|
|
151
162
|
</InputEnclosure>
|
|
152
163
|
</div>
|
|
153
|
-
|
|
154
|
-
<style lang="scss">
|
|
155
|
-
.dodo-ui-TextInput {
|
|
156
|
-
input {
|
|
157
|
-
flex: 1;
|
|
158
|
-
border: 0;
|
|
159
|
-
outline: 0;
|
|
160
|
-
height: 100%;
|
|
161
|
-
background-color: transparent;
|
|
162
|
-
font-family: inherit;
|
|
163
|
-
color: inherit;
|
|
164
|
-
letter-spacing: 0.3px;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
&.size {
|
|
168
|
-
&--normal {
|
|
169
|
-
input {
|
|
170
|
-
font-size: 1rem;
|
|
171
|
-
padding: 0 calc(var(--dodo-ui-space-small) * 2);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
&--small {
|
|
176
|
-
input {
|
|
177
|
-
padding: 0 var(--dodo-ui-space);
|
|
178
|
-
font-size: 0.9rem;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
&--large {
|
|
183
|
-
input {
|
|
184
|
-
font-size: 1.1rem;
|
|
185
|
-
padding: 0 calc(var(--dodo-ui-space) * 2);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import { type Snippet } from 'svelte';
|
|
3
|
+
import type { ComponentSize } from '$lib/types/size.js';
|
|
4
|
+
|
|
5
|
+
export interface MenuProps {
|
|
6
|
+
/** Menu contents goes here */
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
/** Menu ref */
|
|
9
|
+
ref?: HTMLUListElement;
|
|
10
|
+
/** Custom css class */
|
|
11
|
+
class?: string;
|
|
12
|
+
/** Menu Width */
|
|
13
|
+
width?: string;
|
|
14
|
+
/** Menu Height */
|
|
15
|
+
height?: string;
|
|
16
|
+
/** How large should the Menu Items be? */
|
|
17
|
+
size?: ComponentSize;
|
|
18
|
+
/** Menu Separator */
|
|
19
|
+
separator?: boolean;
|
|
20
|
+
/** Id */
|
|
21
|
+
id?: string;
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<script lang="ts">
|
|
26
|
+
import { setContext } from 'svelte';
|
|
27
|
+
|
|
28
|
+
let {
|
|
29
|
+
children,
|
|
30
|
+
id,
|
|
31
|
+
class: className = '',
|
|
32
|
+
width,
|
|
33
|
+
height,
|
|
34
|
+
ref = $bindable<HTMLUListElement>(),
|
|
35
|
+
size,
|
|
36
|
+
separator,
|
|
37
|
+
}: MenuProps = $props();
|
|
38
|
+
|
|
39
|
+
setContext('MenuItemSize', () => size);
|
|
40
|
+
setContext('MenuItemSeparator', () => separator);
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<ul
|
|
44
|
+
class={['dodo-ui-Menu', className].join(' ')}
|
|
45
|
+
{id}
|
|
46
|
+
bind:this={ref}
|
|
47
|
+
style={`${width ? `width:${width};` : ''}
|
|
48
|
+
${height ? `height:${height};` : ''}
|
|
49
|
+
`}
|
|
50
|
+
>
|
|
51
|
+
{#if children}
|
|
52
|
+
{@render children()}
|
|
53
|
+
{/if}
|
|
54
|
+
</ul>
|
|
55
|
+
|
|
56
|
+
<style lang="scss">
|
|
57
|
+
.dodo-ui-Menu {
|
|
58
|
+
margin: 0;
|
|
59
|
+
padding: 0;
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
overflow: inherit;
|
|
63
|
+
outline: 0;
|
|
64
|
+
}
|
|
65
|
+
</style>
|