List.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import Element from './Element';
  2. import Item from './List/Item';
  3. import supportsFocusWithin from '../supportsFocusWithin';
  4. export default class List extends Element {
  5. #collection;
  6. #items;
  7. constructor() {
  8. super('<ul class="loading"></ul>');
  9. this.bindEvents();
  10. }
  11. bindEvents() {
  12. this.on('list:update:request', () => this.loading());
  13. this.on('list:update:success', (collection) => this.update(collection));
  14. this.on('list:update:failed', () => this.loading(false));
  15. this.on('collection:update', (collection) => {
  16. if (collection === this.#collection) {
  17. this.update();
  18. }
  19. });
  20. this.on('entry:update', (entry) => {
  21. if (entry.collection === this.#collection) {
  22. this.update();
  23. }
  24. });
  25. const arrowHandler = (event) => {
  26. if (!['ArrowUp', 'ArrowDown'].includes(event.key)) {
  27. return;
  28. }
  29. event.preventDefault();
  30. event.stopPropagation();
  31. const current = this.element.querySelector(
  32. `li:focus${supportsFocusWithin ? ', li:focus-within' : ''}`
  33. ),
  34. next = current
  35. ? current.nextSibling
  36. : this.element.querySelector('li:first-child'),
  37. previous = current ? current.previousSibling : null;
  38. if (event.key === 'ArrowUp' && previous) {
  39. previous.focus();
  40. } else if (event.key === 'ArrowDown' && next) {
  41. next.focus();
  42. }
  43. };
  44. document.addEventListener('keydown', arrowHandler);
  45. this.element.addEventListener('keydown', arrowHandler);
  46. }
  47. loading(loading = true) {
  48. if (loading) {
  49. return this.element.classList.add('loading');
  50. }
  51. this.element.classList.remove('loading');
  52. }
  53. update(collection = this.#collection) {
  54. this.emptyNode();
  55. this.#items = collection.map((entry) => new Item(entry));
  56. [...this.#items.map((item) => item.element)].forEach((element) =>
  57. this.element.appendChild(element)
  58. );
  59. this.loading(false);
  60. this.#collection = collection;
  61. }
  62. }