|
275 | 275 | let sortedItems = sort(); |
276 | 276 |
|
277 | 277 | $: menuId = `menu-${id}`; |
| 278 | + $: comboId = `combo-${id}`; |
278 | 279 | $: inline = type === "inline"; |
279 | 280 | $: ariaLabel = $$props["aria-label"] || "Choose an item"; |
280 | 281 | $: if ( |
|
324 | 325 | {/if} |
325 | 326 | <ListBox |
326 | 327 | role={undefined} |
| 328 | + id={comboId} |
| 329 | + aria-label={ariaLabel} |
327 | 330 | {disabled} |
328 | 331 | {invalid} |
329 | 332 | {invalidText} |
|
347 | 350 | class="bx--list-box__invalid-icon bx--list-box__invalid-icon--warning" |
348 | 351 | /> |
349 | 352 | {/if} |
350 | | - <ListBoxField |
351 | | - role="button" |
352 | | - tabindex="0" |
353 | | - aria-expanded={open} |
354 | | - on:click={() => { |
355 | | - if (disabled) return; |
356 | | - if (filterable) { |
357 | | - open = true; |
358 | | - inputRef.focus(); |
359 | | - } else { |
360 | | - open = !open; |
361 | | - } |
362 | | - }} |
363 | | - on:keydown={(e) => { |
364 | | - if (filterable) { |
365 | | - return; |
366 | | - } |
367 | | - const key = e.key; |
368 | | - if ([" ", "ArrowUp", "ArrowDown"].includes(key)) { |
369 | | - e.preventDefault(); |
370 | | - } |
371 | | - if (key === " ") { |
372 | | - open = !open; |
373 | | - } else if (key === "Tab") { |
374 | | - if (selectionRef && checked.length > 0) { |
375 | | - selectionRef.focus(); |
376 | | - } else { |
377 | | - open = false; |
378 | | - } |
379 | | - } else if (key === "ArrowDown") { |
380 | | - change(1); |
381 | | - } else if (key === "ArrowUp") { |
382 | | - change(-1); |
383 | | - } else if (key === "Enter") { |
384 | | - if (highlightedIndex > -1) { |
385 | | - sortedItems = sortedItems.map((item, i) => { |
386 | | - if (i !== highlightedIndex) return item; |
387 | | - return { ...item, checked: !item.checked }; |
388 | | - }); |
389 | | - } |
390 | | - } else if (key === "Escape") { |
391 | | - open = false; |
392 | | - } |
393 | | - }} |
394 | | - on:focus={() => { |
395 | | - if (filterable) { |
396 | | - open = true; |
397 | | - if (inputRef) inputRef.focus(); |
398 | | - } |
399 | | - }} |
400 | | - on:blur={(e) => { |
401 | | - if (!filterable) dispatch("blur", e); |
402 | | - }} |
403 | | - {id} |
404 | | - {disabled} |
405 | | - {translateWithId} |
406 | | - > |
407 | | - {#if checked.length > 0} |
408 | | - <ListBoxSelection |
409 | | - selectionCount={checked.length} |
410 | | - on:clear |
411 | | - on:clear={() => { |
412 | | - selectedIds = []; |
413 | | - sortedItems = sortedItems.map((item) => ({ |
414 | | - ...item, |
415 | | - checked: false, |
416 | | - })); |
417 | | - }} |
418 | | - translateWithId={translateWithIdSelection} |
419 | | - {disabled} |
420 | | - /> |
421 | | - {/if} |
422 | | - {#if filterable} |
| 353 | + {#if filterable} |
| 354 | + <div class:bx--list-box__field={true}> |
| 355 | + {#if checked.length > 0} |
| 356 | + <ListBoxSelection |
| 357 | + selectionCount={checked.length} |
| 358 | + on:clear |
| 359 | + on:clear={() => { |
| 360 | + selectedIds = []; |
| 361 | + sortedItems = sortedItems.map((item) => ({ |
| 362 | + ...item, |
| 363 | + checked: false, |
| 364 | + })); |
| 365 | + }} |
| 366 | + translateWithId={translateWithIdSelection} |
| 367 | + {disabled} |
| 368 | + /> |
| 369 | + {/if} |
423 | 370 | <input |
424 | 371 | bind:this={inputRef} |
425 | 372 | bind:value |
|
430 | 377 | aria-autocomplete="list" |
431 | 378 | aria-expanded={open} |
432 | 379 | aria-activedescendant={highlightedId} |
| 380 | + aria-labelledby={comboId} |
433 | 381 | aria-disabled={disabled} |
434 | | - aria-controls={menuId} |
| 382 | + aria-controls={open ? menuId : undefined} |
| 383 | + aria-owns={open ? menuId : undefined} |
435 | 384 | class:bx--text-input={true} |
436 | 385 | class:bx--text-input--empty={value === ""} |
437 | 386 | class:bx--text-input--light={light} |
| 387 | + on:click={() => { |
| 388 | + if (disabled) return; |
| 389 | + open = true; |
| 390 | + }} |
438 | 391 | on:keydown |
439 | 392 | on:keydown|stopPropagation={({ key }) => { |
440 | 393 | if (key === "Enter") { |
|
472 | 425 | {#if invalid} |
473 | 426 | <WarningFilled class="bx--list-box__invalid-icon" /> |
474 | 427 | {/if} |
| 428 | + {#if !invalid && warn} |
| 429 | + <WarningAltFilled |
| 430 | + class="bx--list-box__invalid-icon bx--list-box__invalid-icon--warning" |
| 431 | + /> |
| 432 | + {/if} |
475 | 433 | {#if value} |
476 | 434 | <ListBoxSelection |
477 | 435 | on:clear={() => { |
|
484 | 442 | /> |
485 | 443 | {/if} |
486 | 444 | <ListBoxMenuIcon |
487 | | - style="pointer-events: {open ? 'auto' : 'none'}" |
488 | 445 | on:click={(e) => { |
| 446 | + if (disabled) return; |
489 | 447 | e.stopPropagation(); |
490 | 448 | open = !open; |
491 | 449 | }} |
492 | 450 | {translateWithId} |
493 | 451 | {open} |
494 | 452 | /> |
495 | | - {/if} |
496 | | - {#if !filterable} |
| 453 | + </div> |
| 454 | + {:else} |
| 455 | + <ListBoxField |
| 456 | + role="combobox" |
| 457 | + tabindex="0" |
| 458 | + aria-expanded={open} |
| 459 | + aria-activedescendant={highlightedId} |
| 460 | + aria-controls={open ? menuId : undefined} |
| 461 | + aria-owns={open ? menuId : undefined} |
| 462 | + on:click={() => { |
| 463 | + if (disabled) return; |
| 464 | + open = !open; |
| 465 | + }} |
| 466 | + on:keydown={(e) => { |
| 467 | + const key = e.key; |
| 468 | + if ([" ", "ArrowUp", "ArrowDown"].includes(key)) { |
| 469 | + e.preventDefault(); |
| 470 | + } |
| 471 | + if (key === " ") { |
| 472 | + open = !open; |
| 473 | + } else if (key === "Tab") { |
| 474 | + if (selectionRef && checked.length > 0) { |
| 475 | + selectionRef.focus(); |
| 476 | + } else { |
| 477 | + open = false; |
| 478 | + } |
| 479 | + } else if (key === "ArrowDown") { |
| 480 | + change(1); |
| 481 | + } else if (key === "ArrowUp") { |
| 482 | + change(-1); |
| 483 | + } else if (key === "Enter") { |
| 484 | + if (highlightedIndex > -1) { |
| 485 | + sortedItems = sortedItems.map((item, i) => { |
| 486 | + if (i !== highlightedIndex) return item; |
| 487 | + return { ...item, checked: !item.checked }; |
| 488 | + }); |
| 489 | + } |
| 490 | + } else if (key === "Escape") { |
| 491 | + open = false; |
| 492 | + } |
| 493 | + }} |
| 494 | + on:blur={(e) => { |
| 495 | + dispatch("blur", e); |
| 496 | + }} |
| 497 | + {id} |
| 498 | + {disabled} |
| 499 | + {translateWithId} |
| 500 | + > |
| 501 | + {#if checked.length > 0} |
| 502 | + <ListBoxSelection |
| 503 | + selectionCount={checked.length} |
| 504 | + on:clear |
| 505 | + on:clear={() => { |
| 506 | + selectedIds = []; |
| 507 | + sortedItems = sortedItems.map((item) => ({ |
| 508 | + ...item, |
| 509 | + checked: false, |
| 510 | + })); |
| 511 | + }} |
| 512 | + translateWithId={translateWithIdSelection} |
| 513 | + {disabled} |
| 514 | + /> |
| 515 | + {/if} |
497 | 516 | <span class:bx--list-box__label={true}>{label}</span> |
498 | 517 | <ListBoxMenuIcon {open} {translateWithId} /> |
499 | | - {/if} |
500 | | - </ListBoxField> |
| 518 | + </ListBoxField> |
| 519 | + {/if} |
501 | 520 | <div style:display={open ? "block" : "none"}> |
502 | 521 | <ListBoxMenu aria-label={ariaLabel} {id} aria-multiselectable="true"> |
503 | 522 | {#each filterable ? filteredItems : sortedItems as item, i (item.id)} |
|
0 commit comments