@internetarchive/collection-browser 4.8.1-webdev-9227.4 → 4.9.1-webdev-9670.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.
Files changed (105) hide show
  1. package/README.md +11 -33
  2. package/dist/src/app-root.d.ts +11 -0
  3. package/dist/src/app-root.js +95 -1
  4. package/dist/src/app-root.js.map +1 -1
  5. package/dist/src/collection-browser.d.ts +43 -2
  6. package/dist/src/collection-browser.js +221 -15
  7. package/dist/src/collection-browser.js.map +1 -1
  8. package/dist/src/collection-facets/facet-row-template.d.ts +1 -1
  9. package/dist/src/collection-facets/facet-row-template.js +7 -14
  10. package/dist/src/collection-facets/facet-row-template.js.map +1 -1
  11. package/dist/src/collection-facets/facet-row.js +1 -3
  12. package/dist/src/collection-facets/facet-row.js.map +1 -1
  13. package/dist/src/collection-facets/more-facets-content.js +5 -6
  14. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  15. package/dist/src/collection-facets/more-facets-scroller.js +2 -3
  16. package/dist/src/collection-facets/more-facets-scroller.js.map +1 -1
  17. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.js +4 -13
  18. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.js.map +1 -1
  19. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +2 -6
  20. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  21. package/dist/src/collection-facets.js +5 -6
  22. package/dist/src/collection-facets.js.map +1 -1
  23. package/dist/src/empty-placeholder.d.ts +7 -7
  24. package/dist/src/empty-placeholder.js +15 -29
  25. package/dist/src/empty-placeholder.js.map +1 -1
  26. package/dist/src/expanded-date-picker.js +2 -3
  27. package/dist/src/expanded-date-picker.js.map +1 -1
  28. package/dist/src/manage/manage-bar.d.ts +2 -3
  29. package/dist/src/manage/manage-bar.js +16 -15
  30. package/dist/src/manage/manage-bar.js.map +1 -1
  31. package/dist/src/manage/remove-items-modal-content.js +2 -3
  32. package/dist/src/manage/remove-items-modal-content.js.map +1 -1
  33. package/dist/src/mediatype/mediatype-config.js +18 -55
  34. package/dist/src/mediatype/mediatype-config.js.map +1 -1
  35. package/dist/src/models.js +40 -120
  36. package/dist/src/models.js.map +1 -1
  37. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js +2 -8
  38. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js.map +1 -1
  39. package/dist/src/sort-filter-bar/alpha-bar.js +2 -7
  40. package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
  41. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +12 -0
  42. package/dist/src/sort-filter-bar/sort-filter-bar.js +109 -28
  43. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  44. package/dist/src/tiles/grid/account-tile.js +2 -3
  45. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  46. package/dist/src/tiles/grid/collection-tile.js +11 -12
  47. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  48. package/dist/src/tiles/grid/item-tile.d.ts +4 -0
  49. package/dist/src/tiles/grid/item-tile.js +23 -8
  50. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  51. package/dist/src/tiles/grid/tile-stats.js +3 -6
  52. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  53. package/dist/src/tiles/hover/hover-pane-controller.d.ts +2 -1
  54. package/dist/src/tiles/hover/hover-pane-controller.js +1 -1
  55. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  56. package/dist/src/tiles/image-block.d.ts +5 -0
  57. package/dist/src/tiles/image-block.js +29 -0
  58. package/dist/src/tiles/image-block.js.map +1 -1
  59. package/dist/src/tiles/list/tile-list-compact-header.js +2 -3
  60. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  61. package/dist/src/tiles/list/tile-list-compact.js +1 -3
  62. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  63. package/dist/src/tiles/list/tile-list.js +5 -15
  64. package/dist/src/tiles/list/tile-list.js.map +1 -1
  65. package/dist/src/tiles/models.d.ts +2 -1
  66. package/dist/src/tiles/models.js.map +1 -1
  67. package/dist/src/tiles/overlay/text-overlay.js +1 -3
  68. package/dist/src/tiles/overlay/text-overlay.js.map +1 -1
  69. package/dist/src/tiles/preview/tile-preview-controller.d.ts +61 -0
  70. package/dist/src/tiles/preview/tile-preview-controller.js +216 -0
  71. package/dist/src/tiles/preview/tile-preview-controller.js.map +1 -0
  72. package/dist/src/tiles/preview/tile-preview-media.d.ts +44 -0
  73. package/dist/src/tiles/preview/tile-preview-media.js +151 -0
  74. package/dist/src/tiles/preview/tile-preview-media.js.map +1 -0
  75. package/dist/src/tiles/preview/tile-preview.d.ts +66 -0
  76. package/dist/src/tiles/preview/tile-preview.js +494 -0
  77. package/dist/src/tiles/preview/tile-preview.js.map +1 -0
  78. package/dist/src/tiles/review-block.js +2 -3
  79. package/dist/src/tiles/review-block.js.map +1 -1
  80. package/dist/src/tiles/tile-dispatcher.d.ts +8 -2
  81. package/dist/src/tiles/tile-dispatcher.js +36 -6
  82. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  83. package/dist/src/tiles/tile-mediatype-icon.js +1 -3
  84. package/dist/src/tiles/tile-mediatype-icon.js.map +1 -1
  85. package/dist/src/utils/format-count.d.ts +1 -3
  86. package/dist/src/utils/format-count.js +59 -19
  87. package/dist/src/utils/format-count.js.map +1 -1
  88. package/dist/src/utils/format-unit-size.d.ts +1 -1
  89. package/dist/src/utils/format-unit-size.js +18 -21
  90. package/dist/src/utils/format-unit-size.js.map +1 -1
  91. package/dist/src/utils/grid-zoom-controller.d.ts +69 -0
  92. package/dist/src/utils/grid-zoom-controller.js +261 -0
  93. package/dist/src/utils/grid-zoom-controller.js.map +1 -0
  94. package/dist/src/utils/grid-zoom.d.ts +31 -0
  95. package/dist/src/utils/grid-zoom.js +109 -0
  96. package/dist/src/utils/grid-zoom.js.map +1 -0
  97. package/package.json +2 -6
  98. package/dist/src/locales/es.d.ts +0 -200
  99. package/dist/src/locales/es.js +0 -215
  100. package/dist/src/locales/es.js.map +0 -1
  101. package/dist/src/utils/get-locale.d.ts +0 -14
  102. package/dist/src/utils/get-locale.js +0 -20
  103. package/dist/src/utils/get-locale.js.map +0 -1
  104. package/locales/es.d.ts +0 -1
  105. package/locales/es.js +0 -1
@@ -12,6 +12,7 @@ import { RestorationStateHandlerInterface } from './restoration-state-handler';
12
12
  import type { CollectionBrowserQueryState, CollectionBrowserSearchInterface } from './data-source/collection-browser-query-state';
13
13
  import type { CollectionBrowserDataSourceInterface } from './data-source/collection-browser-data-source-interface';
14
14
  import type { LayoutType, TileAction } from './tiles/models';
15
+ import type { TilePreviewOptions } from './tiles/preview/tile-preview-media';
15
16
  import '@internetarchive/elements/ia-combo-box/ia-combo-box';
16
17
  import './empty-placeholder';
17
18
  import './tiles/tile-dispatcher';
@@ -24,6 +25,13 @@ import './collection-facets/smart-facets/smart-facet-bar';
24
25
  export declare class CollectionBrowser extends LitElement implements InfiniteScrollerCellProviderInterface, SharedResizeObserverResizeHandlerInterface, CollectionBrowserSearchInterface {
25
26
  baseNavigationUrl?: string;
26
27
  baseImageUrl: string;
28
+ /**
29
+ * Prototype: show a live preview of an item when its tile is hovered,
30
+ * focused with the keyboard or long-pressed. Off by default.
31
+ */
32
+ enableTilePreviews: boolean;
33
+ /** Prototype: what tile previews may fetch and play (video clips, audio sound). */
34
+ tilePreviewOptions: TilePreviewOptions;
27
35
  searchService?: SearchServiceInterface;
28
36
  /**
29
37
  * Which backend should be targeted by searches (e.g., metadata or FTS)
@@ -172,8 +180,12 @@ export declare class CollectionBrowser extends LitElement implements InfiniteScr
172
180
  * `LayoutType` for available options. Has no effect on list display modes.
173
181
  */
174
182
  tileLayoutType: LayoutType;
175
- /** Label for the manage bar. Defaults to the manage bar's own localized label. */
176
- manageViewLabel?: string;
183
+ /**
184
+ * Prototype: lets viewers zoom the tile grid with a pinch, ctrl/cmd +/-,
185
+ * or a slider next to the display mode buttons. Off by default.
186
+ */
187
+ enablePinchZoom: boolean;
188
+ manageViewLabel: string;
177
189
  /** Whether to replace the default sort options with a slot for customization (default: false) */
178
190
  enableSortOptionsSlot: boolean;
179
191
  /** Whether to expose a slot for a smart results carousel above the full results */
@@ -209,6 +221,13 @@ export declare class CollectionBrowser extends LitElement implements InfiniteScr
209
221
  private facetsLoading;
210
222
  private totalResults?;
211
223
  private mobileView;
224
+ /** The zoom level the viewer has chosen, if any (an index into `GRID_ZOOM_COLUMNS`). */
225
+ private gridZoomLevel?;
226
+ /** The zoom level closest to the layout the grid has when no zoom level is chosen. */
227
+ private defaultGridZoomLevel;
228
+ /** Identifies the latest zoom, so that an earlier one stops lining up its tile. */
229
+ private gridZoomAlignment;
230
+ private gridZoomController;
212
231
  /**
213
232
  * Any temporarily overridden `on`/`off` state for the user's tile blurring preference if they
214
233
  * have chosen to override it, or `no-override` if they have not.
@@ -388,6 +407,28 @@ export declare class CollectionBrowser extends LitElement implements InfiniteScr
388
407
  * Template for the infinite scroller widget that contains the result tiles.
389
408
  */
390
409
  private get infiniteScrollerTemplate();
410
+ /** Whether the grid zoom prototype is on and applies to what's showing. */
411
+ private get pinchZoomActive();
412
+ private get effectiveGridZoomLevel();
413
+ /** Inline CSS variables for the chosen zoom level, if the viewer has chosen one. */
414
+ private get gridZoomStyles();
415
+ private get effectiveTileLayoutType();
416
+ /** How many columns the scroller's grid currently has. */
417
+ private measureGridColumns;
418
+ /** Connects/disconnects the gesture handling and tracks the default zoom level. */
419
+ private updateGridZoom;
420
+ private gridZoomSliderChanged;
421
+ /**
422
+ * Switches the grid to `level`, then scrolls so that the tile that was under
423
+ * `focal` (viewport coordinates) is still under it.
424
+ */
425
+ private commitGridZoomLevel;
426
+ /** Keeps `anchor`'s tile lined up with `focal` for `duration` ms. */
427
+ private alignTile;
428
+ /** Scrolls the nearest scrolling ancestor of `el` (or the page) by `delta` px. */
429
+ private scrollByWithin;
430
+ /** Finds the tile under a viewport point and where in the tile the point falls. */
431
+ private tileAtPoint;
391
432
  /**
392
433
  * Produces a `classMap` indicating which classes the infinite scroller should have
393
434
  * given the current display mode & placeholder case.
@@ -3,19 +3,21 @@ import { __decorate } from "tslib";
3
3
  import { html, css, LitElement, nothing, } from 'lit';
4
4
  import { customElement, property, query, state } from 'lit/decorators.js';
5
5
  import { classMap } from 'lit/directives/class-map.js';
6
- import { localized, msg } from '@lit/localize';
6
+ import { styleMap } from 'lit/directives/style-map.js';
7
+ import { msg } from '@lit/localize';
7
8
  import { SearchType, } from '@internetarchive/search-service';
8
9
  import '@internetarchive/infinite-scroller';
9
10
  import { SortField, getDefaultSelectedFacets, sortOptionFromAPIString, SORT_OPTIONS, defaultProfileElementSorts, defaultFacetDisplayOrder, tvFacetDisplayOrder, defaultSortAvailability, favoritesSortAvailability, tvSortAvailability, } from './models';
10
11
  import { RestorationStateHandler, } from './restoration-state-handler';
11
12
  import { CollectionBrowserDataSource } from './data-source/collection-browser-data-source';
12
13
  import { FACETLESS_PAGE_ELEMENTS } from './data-source/models';
14
+ import { GRID_ZOOM_COLUMNS, loadStoredZoomLevel, nearestZoomLevel, storeZoomLevel, zoomLayoutType, zoomLevelStyles, } from './utils/grid-zoom';
15
+ import { GridZoomController } from './utils/grid-zoom-controller';
13
16
  import { analyticsActions, analyticsCategories, } from './utils/analytics-events';
14
17
  import { updateSelectedFacetBucket } from './utils/facet-utils';
15
18
  import chevronIcon from './assets/img/icons/chevron';
16
19
  import { srOnlyStyle } from './styles/sr-only';
17
20
  import { sha1 } from './utils/sha1';
18
- import { getLocale } from './utils/get-locale';
19
21
  import '@internetarchive/elements/ia-combo-box/ia-combo-box';
20
22
  import './empty-placeholder';
21
23
  import './tiles/tile-dispatcher';
@@ -25,11 +27,22 @@ import './manage/manage-bar';
25
27
  import './collection-facets';
26
28
  import './circular-activity-indicator';
27
29
  import './collection-facets/smart-facets/smart-facet-bar';
30
+ /** How long to keep a zoomed tile lined up with the focal point after a layout change. */
31
+ const GRID_ZOOM_SETTLE_MS = 600;
32
+ /** How long the grid stays hidden while the tile is lined up after a layout change. */
33
+ const GRID_ZOOM_HIDDEN_MS = 250;
28
34
  let CollectionBrowser = class CollectionBrowser extends LitElement {
29
35
  static { CollectionBrowser_1 = this; }
30
36
  constructor() {
31
37
  super();
32
38
  this.baseImageUrl = 'https://archive.org';
39
+ /**
40
+ * Prototype: show a live preview of an item when its tile is hovered,
41
+ * focused with the keyboard or long-pressed. Off by default.
42
+ */
43
+ this.enableTilePreviews = false;
44
+ /** Prototype: what tile previews may fetch and play (video clips, audio sound). */
45
+ this.tilePreviewOptions = {};
33
46
  /**
34
47
  * Which backend should be targeted by searches (e.g., metadata or FTS)
35
48
  */
@@ -132,6 +145,12 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
132
145
  * `LayoutType` for available options. Has no effect on list display modes.
133
146
  */
134
147
  this.tileLayoutType = 'default';
148
+ /**
149
+ * Prototype: lets viewers zoom the tile grid with a pinch, ctrl/cmd +/-,
150
+ * or a slider next to the display mode buttons. Off by default.
151
+ */
152
+ this.enablePinchZoom = false;
153
+ this.manageViewLabel = 'Select items to remove';
135
154
  /** Whether to replace the default sort options with a slot for customization (default: false) */
136
155
  this.enableSortOptionsSlot = false;
137
156
  /** Whether to expose a slot for a smart results carousel above the full results */
@@ -166,6 +185,17 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
166
185
  this.searchResultsLoading = false;
167
186
  this.facetsLoading = false;
168
187
  this.mobileView = false;
188
+ /** The zoom level closest to the layout the grid has when no zoom level is chosen. */
189
+ this.defaultGridZoomLevel = nearestZoomLevel(4);
190
+ /** Identifies the latest zoom, so that an earlier one stops lining up its tile. */
191
+ this.gridZoomAlignment = 0;
192
+ this.gridZoomController = new GridZoomController({
193
+ getSurface: () => this.infiniteScroller,
194
+ getColumns: () => this.measureGridColumns(),
195
+ getLevel: () => this.effectiveGridZoomLevel,
196
+ captureAnchor: focal => this.tileAtPoint(focal),
197
+ commitLevel: (level, focal, anchor) => this.commitGridZoomLevel(level, focal, anchor),
198
+ });
169
199
  /**
170
200
  * Any temporarily overridden `on`/`off` state for the user's tile blurring preference if they
171
201
  * have chosen to override it, or `no-override` if they have not.
@@ -609,15 +639,13 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
609
639
  return nothing;
610
640
  const shouldShowSearching = this.searchResultsLoading || this.totalResults === undefined;
611
641
  const classes = classMap({ filtered: this.hasActiveFilters });
612
- const resultsCount = this.totalResults === undefined
613
- ? undefined
614
- : new Intl.NumberFormat(getLocale()).format(this.totalResults);
615
- const resultsLabel = this.totalResults === 1 ? msg('Result') : msg('Results');
642
+ const resultsCount = this.totalResults?.toLocaleString();
643
+ const resultsLabel = this.totalResults === 1 ? 'Result' : 'Results';
616
644
  // Added data-testid for Playwright testing
617
645
  return html `
618
646
  <div id="results-total" class=${classes} data-testid="results-total">
619
647
  <span id="big-results-count">
620
- ${shouldShowSearching ? msg('Searching…') : resultsCount}
648
+ ${shouldShowSearching ? html `Searching&hellip;` : resultsCount}
621
649
  </span>
622
650
  <span id="big-results-label">
623
651
  ${shouldShowSearching ? nothing : resultsLabel}
@@ -651,10 +679,17 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
651
679
  ? this.manageBarTemplate
652
680
  : this.sortFilterBarTemplate}
653
681
  <slot name="cb-results"></slot>
654
- ${this.displayMode === `list-compact` && this.totalResults
682
+ <div id="results-body">
683
+ <slot name="results-aside"></slot>
684
+ <div id="results-main">
685
+ ${this.displayMode === `list-compact` && this.totalResults
655
686
  ? this.listHeaderTemplate
656
687
  : nothing}
657
- ${this.suppressResultTiles ? nothing : this.infiniteScrollerTemplate}
688
+ ${this.suppressResultTiles
689
+ ? nothing
690
+ : this.infiniteScrollerTemplate}
691
+ </div>
692
+ </div>
658
693
  </section>
659
694
  </div>
660
695
  `;
@@ -666,8 +701,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
666
701
  return html `<infinite-scroller
667
702
  class=${this.infiniteScrollerClasses}
668
703
  itemCount=${this.placeholderType ? 0 : nothing}
669
- ariaLandmarkLabel=${msg('Search results')}
704
+ ariaLandmarkLabel="Search results"
670
705
  .estimatedCellHeight=${this.estimatedTileHeight}
706
+ style=${styleMap(this.gridZoomStyles)}
671
707
  .minBufferMarginCells=${this.pageSize}
672
708
  .cellProvider=${this}
673
709
  .placeholderCellTemplate=${this.placeholderCellTemplate}
@@ -678,6 +714,127 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
678
714
  : nothing}
679
715
  </infinite-scroller>`;
680
716
  }
717
+ /** Whether the grid zoom prototype is on and applies to what's showing. */
718
+ get pinchZoomActive() {
719
+ return this.enablePinchZoom && this.displayMode === 'grid';
720
+ }
721
+ get effectiveGridZoomLevel() {
722
+ return this.gridZoomLevel ?? this.defaultGridZoomLevel;
723
+ }
724
+ /** Inline CSS variables for the chosen zoom level, if the viewer has chosen one. */
725
+ get gridZoomStyles() {
726
+ if (!this.pinchZoomActive || this.gridZoomLevel === undefined)
727
+ return {};
728
+ return zoomLevelStyles(this.gridZoomLevel, this.infiniteScroller?.clientWidth ?? 0);
729
+ }
730
+ get effectiveTileLayoutType() {
731
+ if (!this.pinchZoomActive || this.gridZoomLevel === undefined) {
732
+ return this.tileLayoutType;
733
+ }
734
+ return zoomLayoutType(this.gridZoomLevel) ?? this.tileLayoutType;
735
+ }
736
+ /** How many columns the scroller's grid currently has. */
737
+ measureGridColumns() {
738
+ const cells = this.infiniteScroller?.shadowRoot?.querySelectorAll('.cell-container');
739
+ if (!cells?.length)
740
+ return GRID_ZOOM_COLUMNS[this.effectiveGridZoomLevel];
741
+ const firstTop = cells[0].getBoundingClientRect().top;
742
+ let columns = 0;
743
+ for (const cell of cells) {
744
+ if (cell.getBoundingClientRect().top !== firstTop)
745
+ break;
746
+ columns += 1;
747
+ }
748
+ return columns;
749
+ }
750
+ /** Connects/disconnects the gesture handling and tracks the default zoom level. */
751
+ updateGridZoom(changed) {
752
+ if (changed.has('enablePinchZoom') && this.enablePinchZoom) {
753
+ this.gridZoomLevel ??= loadStoredZoomLevel();
754
+ }
755
+ if (this.pinchZoomActive && this.infiniteScroller) {
756
+ this.gridZoomController.connect();
757
+ if (this.gridZoomLevel === undefined) {
758
+ this.defaultGridZoomLevel = nearestZoomLevel(this.measureGridColumns());
759
+ }
760
+ }
761
+ else {
762
+ this.gridZoomAlignment += 1;
763
+ this.gridZoomController.disconnect();
764
+ }
765
+ }
766
+ gridZoomSliderChanged(e) {
767
+ this.gridZoomController.zoomToLevel(e.detail.level);
768
+ }
769
+ /**
770
+ * Switches the grid to `level`, then scrolls so that the tile that was under
771
+ * `focal` (viewport coordinates) is still under it.
772
+ */
773
+ async commitGridZoomLevel(level, focal, anchor) {
774
+ const scroller = this.infiniteScroller;
775
+ if (!scroller)
776
+ return;
777
+ this.gridZoomLevel = level;
778
+ storeZoomLevel(level);
779
+ await this.updateComplete;
780
+ await scroller.bufferStabilized;
781
+ if (!anchor)
782
+ return;
783
+ // The scroller keeps re-measuring rows for a moment after a layout change.
784
+ // The grid stays hidden for the first part of that, and the rest is corrected
785
+ // in the background.
786
+ this.gridZoomAlignment += 1;
787
+ const alignment = this.gridZoomAlignment;
788
+ await this.alignTile(scroller, anchor, focal, GRID_ZOOM_HIDDEN_MS, alignment);
789
+ this.alignTile(scroller, anchor, focal, GRID_ZOOM_SETTLE_MS, alignment).catch(() => { });
790
+ }
791
+ /** Keeps `anchor`'s tile lined up with `focal` for `duration` ms. */
792
+ async alignTile(scroller, anchor, focal, duration, alignment) {
793
+ const deadline = performance.now() + duration;
794
+ while (performance.now() < deadline &&
795
+ alignment === this.gridZoomAlignment) {
796
+ const cell = scroller.shadowRoot?.querySelector(`[data-cell-index="${anchor.index}"]`);
797
+ if (cell) {
798
+ const rect = cell.getBoundingClientRect();
799
+ const delta = rect.top + rect.height * anchor.fractionY - focal.y;
800
+ if (Math.abs(delta) > 1)
801
+ this.scrollByWithin(scroller, delta);
802
+ }
803
+ else {
804
+ await scroller.scrollToCell(anchor.index, false);
805
+ }
806
+ await new Promise(requestAnimationFrame);
807
+ }
808
+ }
809
+ /** Scrolls the nearest scrolling ancestor of `el` (or the page) by `delta` px. */
810
+ scrollByWithin(el, delta) {
811
+ let node = el;
812
+ while (node) {
813
+ const parent = node.parentElement ?? node.getRootNode().host ?? null;
814
+ if (!parent)
815
+ break;
816
+ const { overflowY } = getComputedStyle(parent);
817
+ if (overflowY === 'auto' || overflowY === 'scroll') {
818
+ parent.scrollTop += delta;
819
+ return;
820
+ }
821
+ node = parent;
822
+ }
823
+ window.scrollBy(0, delta);
824
+ }
825
+ /** Finds the tile under a viewport point and where in the tile the point falls. */
826
+ tileAtPoint(point) {
827
+ const cell = this.infiniteScroller?.shadowRoot
828
+ ?.elementsFromPoint(point.x, point.y)
829
+ .find(el => el.classList.contains('cell-container'));
830
+ if (!cell)
831
+ return undefined;
832
+ const rect = cell.getBoundingClientRect();
833
+ return {
834
+ index: Number(cell.dataset.cellIndex),
835
+ fractionY: (point.y - rect.top) / rect.height,
836
+ };
837
+ }
681
838
  /**
682
839
  * Produces a `classMap` indicating which classes the infinite scroller should have
683
840
  * given the current display mode & placeholder case.
@@ -740,6 +897,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
740
897
  .prefixFilterCountMap=${this.dataSource.prefixFilterCountMap}
741
898
  .enableSortOptionsSlot=${this.enableSortOptionsSlot}
742
899
  .suppressDisplayModes=${this.suppressDisplayModes}
900
+ .showGridZoomSlider=${this.pinchZoomActive}
901
+ .gridZoomLevel=${this.effectiveGridZoomLevel}
902
+ @gridZoomLevelChanged=${this.gridZoomSliderChanged}
743
903
  @sortChanged=${this.userChangedSort}
744
904
  @displayModeChanged=${this.displayModeChanged}
745
905
  @titleLetterChanged=${this.titleLetterSelected}
@@ -749,6 +909,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
749
909
  <slot name="sort-options-left" slot="sort-options-left"></slot>
750
910
  <slot name="sort-options" slot="sort-options"></slot>
751
911
  <slot name="sort-options-right" slot="sort-options-right"></slot>
912
+ <slot name="sort-bar-end" slot="sort-bar-end"></slot>
752
913
  </sort-filter-bar>
753
914
  `;
754
915
  }
@@ -1272,7 +1433,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1272
1433
  'clear-filters-btn': true,
1273
1434
  mobile,
1274
1435
  });
1275
- const buttonText = mobile ? msg('Clear all') : msg('Clear all filters');
1436
+ const buttonText = mobile ? 'Clear all' : 'Clear all filters';
1276
1437
  return html `
1277
1438
  <div class="clear-filters-btn-row">
1278
1439
  ${mobile
@@ -1414,9 +1575,18 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1414
1575
  changed.has('baseImageUrl') ||
1415
1576
  changed.has('loggedIn') ||
1416
1577
  changed.has('tileActions') ||
1417
- changed.has('tileLayoutType')) {
1578
+ changed.has('tileLayoutType') ||
1579
+ changed.has('gridZoomLevel') ||
1580
+ changed.has('enableTilePreviews') ||
1581
+ changed.has('tilePreviewOptions')) {
1418
1582
  this.infiniteScroller?.reload();
1419
1583
  }
1584
+ this.updateGridZoom(changed);
1585
+ if (changed.has('contentWidth') &&
1586
+ this.gridZoomStyles['--imgBlockHeight']) {
1587
+ // Thumbnail sizes come from the scroller's width, which has only just changed.
1588
+ requestAnimationFrame(() => this.requestUpdate());
1589
+ }
1420
1590
  if (changed.has('profileElement')) {
1421
1591
  this.applyDefaultProfileSort();
1422
1592
  }
@@ -1517,8 +1687,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1517
1687
  super.connectedCallback?.();
1518
1688
  this.setupStateRestorationObserver();
1519
1689
  this.setupResizeObserver();
1690
+ if (this.hasUpdated)
1691
+ this.updateGridZoom(new Map());
1520
1692
  }
1521
1693
  disconnectedCallback() {
1694
+ this.gridZoomController.disconnect();
1522
1695
  if (this.resizeObserver) {
1523
1696
  this.disconnectResizeObserver(this.resizeObserver);
1524
1697
  }
@@ -2069,9 +2242,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
2069
2242
  .suppressBlurring=${this.shouldSuppressTileBlurring}
2070
2243
  .isManageView=${this.isManageView}
2071
2244
  .tileActions=${this.tileActions}
2072
- .layoutType=${this.tileLayoutType}
2245
+ .layoutType=${this.effectiveTileLayoutType}
2073
2246
  ?showTvClips=${isTVSearch || isTVCollection}
2074
2247
  ?enableHoverPane=${true}
2248
+ ?enableTilePreview=${this.enableTilePreviews}
2249
+ .tilePreviewOptions=${this.tilePreviewOptions}
2075
2250
  ?useLocalTime=${shouldUseLocalTime}
2076
2251
  @resultSelected=${(e) => this.resultSelected(e)}
2077
2252
  >
@@ -2221,6 +2396,23 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
2221
2396
  padding: 5px 5px 0;
2222
2397
  }
2223
2398
 
2399
+ /*
2400
+ * The results sit in a row with the optional results-aside slot, which
2401
+ * lays out beside them as a flex item and takes its own width and spacing.
2402
+ * The aside comes first in the DOM so keyboard and screen reader users
2403
+ * reach it before the infinitely scrolling tiles, but it shows on the right.
2404
+ */
2405
+ #results-body {
2406
+ display: flex;
2407
+ align-items: flex-start;
2408
+ }
2409
+
2410
+ #results-main {
2411
+ order: -1;
2412
+ flex: 1;
2413
+ min-width: 0;
2414
+ }
2415
+
2224
2416
  #left-column {
2225
2417
  width: var(--leftColumnWidth, 18rem);
2226
2418
  /* Prevents Safari from shrinking col at first draw */
@@ -2593,6 +2785,12 @@ __decorate([
2593
2785
  __decorate([
2594
2786
  property({ type: String })
2595
2787
  ], CollectionBrowser.prototype, "baseImageUrl", void 0);
2788
+ __decorate([
2789
+ property({ type: Boolean })
2790
+ ], CollectionBrowser.prototype, "enableTilePreviews", void 0);
2791
+ __decorate([
2792
+ property({ type: Object })
2793
+ ], CollectionBrowser.prototype, "tilePreviewOptions", void 0);
2596
2794
  __decorate([
2597
2795
  property({ type: Object })
2598
2796
  ], CollectionBrowser.prototype, "searchService", void 0);
@@ -2737,6 +2935,9 @@ __decorate([
2737
2935
  __decorate([
2738
2936
  property({ type: String })
2739
2937
  ], CollectionBrowser.prototype, "tileLayoutType", void 0);
2938
+ __decorate([
2939
+ property({ type: Boolean, attribute: 'enable-pinch-zoom' })
2940
+ ], CollectionBrowser.prototype, "enablePinchZoom", void 0);
2740
2941
  __decorate([
2741
2942
  property({ type: String })
2742
2943
  ], CollectionBrowser.prototype, "manageViewLabel", void 0);
@@ -2767,6 +2968,12 @@ __decorate([
2767
2968
  __decorate([
2768
2969
  state()
2769
2970
  ], CollectionBrowser.prototype, "mobileView", void 0);
2971
+ __decorate([
2972
+ state()
2973
+ ], CollectionBrowser.prototype, "gridZoomLevel", void 0);
2974
+ __decorate([
2975
+ state()
2976
+ ], CollectionBrowser.prototype, "defaultGridZoomLevel", void 0);
2770
2977
  __decorate([
2771
2978
  state()
2772
2979
  ], CollectionBrowser.prototype, "tileBlurOverrideState", void 0);
@@ -2822,8 +3029,7 @@ __decorate([
2822
3029
  query('infinite-scroller')
2823
3030
  ], CollectionBrowser.prototype, "infiniteScroller", void 0);
2824
3031
  CollectionBrowser = CollectionBrowser_1 = __decorate([
2825
- customElement('collection-browser'),
2826
- localized()
3032
+ customElement('collection-browser')
2827
3033
  ], CollectionBrowser);
2828
3034
  export { CollectionBrowser };
2829
3035
  //# sourceMappingURL=collection-browser.js.map