|
1 | 1 | <script>
|
2 | 2 | import { beforeUpdate, createEventDispatcher, onMount, tick } from 'svelte';
|
3 | 3 | import isOutOfViewport from './isOutOfViewport';
|
| 4 | + import clickOutside from './clickOutside'; |
4 | 5 |
|
5 | 6 | const dispatch = createEventDispatcher();
|
6 | 7 |
|
|
34 | 35 |
|
35 | 36 | onMount(() => {
|
36 | 37 | if (items.length > 0 && !isMulti && value) {
|
37 |
| - const _hoverItemIndex = items.findIndex( |
38 |
| - (item) => item[optionIdentifier] === value[optionIdentifier] |
39 |
| - ); |
| 38 | + const _hoverItemIndex = items.findIndex((item) => item[optionIdentifier] === value[optionIdentifier]); |
40 | 39 |
|
41 | 40 | if (_hoverItemIndex) {
|
42 | 41 | hoverItemIndex = _hoverItemIndex;
|
|
79 | 78 |
|
80 | 79 | function handleClick(args) {
|
81 | 80 | const { item, i, event } = args;
|
82 |
| - event.stopPropagation(); |
| 81 | + // event.stopPropagation(); |
83 | 82 |
|
84 |
| - if ( |
85 |
| - value && |
86 |
| - !isMulti && |
87 |
| - value[optionIdentifier] === item[optionIdentifier] |
88 |
| - ) |
89 |
| - return closeList(); |
| 83 | + if (value && !isMulti && value[optionIdentifier] === item[optionIdentifier]) return closeList(); |
90 | 84 |
|
91 | 85 | if (item.isCreator) {
|
92 | 86 | dispatch('itemCreated', filterText);
|
|
97 | 91 | }
|
98 | 92 | }
|
99 | 93 |
|
100 |
| - function closeList() { |
101 |
| - dispatch('closeList'); |
| 94 | + function closeList(args) { |
| 95 | + dispatch('closeList', args); |
102 | 96 | }
|
103 | 97 |
|
104 | 98 | async function updateHoverItem(increment) {
|
|
141 | 135 | e.preventDefault();
|
142 | 136 | if (items.length === 0) break;
|
143 | 137 | const hoverItem = items[hoverItemIndex];
|
144 |
| - if ( |
145 |
| - value && |
146 |
| - !isMulti && |
147 |
| - value[optionIdentifier] === hoverItem[optionIdentifier] |
148 |
| - ) { |
| 138 | + if (value && !isMulti && value[optionIdentifier] === hoverItem[optionIdentifier]) { |
149 | 139 | closeList();
|
150 | 140 | break;
|
151 | 141 | }
|
|
161 | 151 | if (items.length === 0) {
|
162 | 152 | return closeList();
|
163 | 153 | }
|
164 |
| - if ( |
165 |
| - value && |
166 |
| - value[optionIdentifier] === |
167 |
| - items[hoverItemIndex][optionIdentifier] |
168 |
| - ) |
169 |
| - return closeList(); |
| 154 | + if (value && value[optionIdentifier] === items[hoverItemIndex][optionIdentifier]) return closeList(); |
170 | 155 | activeItemIndex = hoverItemIndex;
|
171 | 156 | handleSelect(items[hoverItemIndex]);
|
172 | 157 | break;
|
|
177 | 162 | if (VirtualList || !container) return;
|
178 | 163 |
|
179 | 164 | let offsetBounding;
|
180 |
| - const focusedElemBounding = container.querySelector( |
181 |
| - `.list-item .${className}` |
182 |
| - ); |
| 165 | + const focusedElemBounding = container.querySelector(`.list-item .${className}`); |
183 | 166 |
|
184 | 167 | if (focusedElemBounding) {
|
185 |
| - offsetBounding = |
186 |
| - container.getBoundingClientRect().bottom - |
187 |
| - focusedElemBounding.getBoundingClientRect().bottom; |
| 168 | + offsetBounding = container.getBoundingClientRect().bottom - focusedElemBounding.getBoundingClientRect().bottom; |
188 | 169 | }
|
189 | 170 |
|
190 | 171 | container.scrollTop -= offsetBounding;
|
|
199 | 180 | }
|
200 | 181 |
|
201 | 182 | function isItemHover(hoverItemIndex, item, itemIndex, items) {
|
202 |
| - return ( |
203 |
| - isItemSelectable(item) && |
204 |
| - (hoverItemIndex === itemIndex || items.length === 1) |
205 |
| - ); |
| 183 | + return isItemSelectable(item) && (hoverItemIndex === itemIndex || items.length === 1); |
206 | 184 | }
|
207 | 185 |
|
208 | 186 | function isItemSelectable(item) {
|
209 |
| - return ( |
210 |
| - (item.isGroupHeader && item.isSelectable) || |
211 |
| - item.selectable || |
212 |
| - !item.hasOwnProperty('selectable') |
213 |
| - ); |
| 187 | + return (item.isGroupHeader && item.isSelectable) || item.selectable || !item.hasOwnProperty('selectable'); |
| 188 | + } |
| 189 | +
|
| 190 | + function handleClickOutside() { |
| 191 | + closeList({ isOutside: true }); |
214 | 192 | }
|
215 | 193 |
|
216 | 194 | let listStyle;
|
217 | 195 | function computePlacement() {
|
218 | 196 | const { top, height, width } = parent.getBoundingClientRect();
|
219 | 197 |
|
220 | 198 | listStyle = '';
|
221 |
| - listStyle += `min-width:${width}px;width:${ |
222 |
| - listAutoWidth ? 'auto' : '100%' |
223 |
| - };`; |
224 |
| -
|
225 |
| - if ( |
226 |
| - listPlacement === 'top' || |
227 |
| - (listPlacement === 'auto' && isOutOfViewport(parent).bottom) |
228 |
| - ) { |
| 199 | + listStyle += `min-width:${width}px;width:${listAutoWidth ? 'auto' : '100%'};`; |
| 200 | +
|
| 201 | + if (listPlacement === 'top' || (listPlacement === 'auto' && isOutOfViewport(parent).bottom)) { |
229 | 202 | listStyle += `bottom:${height + listOffset}px;`;
|
230 | 203 | } else {
|
231 | 204 | listStyle += `top:${height + listOffset}px;`;
|
|
235 | 208 | $: {
|
236 | 209 | if (parent && container) computePlacement();
|
237 | 210 | }
|
| 211 | +
|
| 212 | + |
238 | 213 | </script>
|
239 | 214 |
|
240 | 215 | <svelte:window on:keydown={handleKeyDown} on:resize={computePlacement} />
|
241 | 216 |
|
242 |
| -<div |
243 |
| - class={listClass} |
244 |
| - class:virtual-list={VirtualList} |
245 |
| - bind:this={container} |
246 |
| - style={listStyle}> |
| 217 | +<div use:clickOutside={parent} on:clickOutside={handleClickOutside} class={listClass} class:virtual-list={VirtualList} bind:this={container} style={listStyle}> |
247 | 218 | {#if VirtualList}
|
248 |
| - <svelte:component |
249 |
| - this={VirtualList} |
250 |
| - {items} |
251 |
| - {itemHeight} |
252 |
| - let:item |
253 |
| - let:i> |
254 |
| - <div |
255 |
| - on:mouseover={() => handleHover(i)} |
256 |
| - on:focus={() => handleHover(i)} |
257 |
| - on:click={(event) => handleClick({ item, i, event })} |
258 |
| - class="list-item" |
259 |
| - tabindex="-1"> |
| 219 | + <svelte:component this={VirtualList} {items} {itemHeight} let:item let:i> |
| 220 | + <div on:mouseover={() => handleHover(i)} on:focus={() => handleHover(i)} on:click={(event) => handleClick({ item, i, event })} class="list-item" tabindex="-1"> |
260 | 221 | <svelte:component
|
261 | 222 | this={Item}
|
262 | 223 | {item}
|
|
274 | 235 | {#if item.isGroupHeader && !item.isSelectable}
|
275 | 236 | <div class="list-group-title">{getGroupHeaderLabel(item)}</div>
|
276 | 237 | {:else}
|
277 |
| - <div |
278 |
| - on:mouseover={() => handleHover(i)} |
279 |
| - on:focus={() => handleHover(i)} |
280 |
| - on:click={(event) => handleClick({ item, i, event })} |
281 |
| - class="list-item" |
282 |
| - tabindex="-1"> |
| 238 | + <div on:mouseover={() => handleHover(i)} on:focus={() => handleHover(i)} on:click={(event) => handleClick({ item, i, event })} class="list-item" tabindex="-1"> |
283 | 239 | <svelte:component
|
284 | 240 | this={Item}
|
285 | 241 | {item}
|
|
0 commit comments