@internetarchive/collection-browser 4.9.0 → 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.
- package/README.md +11 -0
- package/dist/src/app-root.d.ts +11 -0
- package/dist/src/app-root.js +95 -1
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.d.ts +42 -0
- package/dist/src/collection-browser.js +186 -2
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +12 -0
- package/dist/src/sort-filter-bar/sort-filter-bar.js +64 -0
- package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
- package/dist/src/tiles/grid/collection-tile.js +5 -0
- package/dist/src/tiles/grid/collection-tile.js.map +1 -1
- package/dist/src/tiles/grid/item-tile.d.ts +4 -0
- package/dist/src/tiles/grid/item-tile.js +16 -0
- package/dist/src/tiles/grid/item-tile.js.map +1 -1
- package/dist/src/tiles/hover/hover-pane-controller.d.ts +2 -1
- package/dist/src/tiles/hover/hover-pane-controller.js +1 -1
- package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
- package/dist/src/tiles/image-block.d.ts +5 -0
- package/dist/src/tiles/image-block.js +29 -0
- package/dist/src/tiles/image-block.js.map +1 -1
- package/dist/src/tiles/models.d.ts +2 -1
- package/dist/src/tiles/models.js.map +1 -1
- package/dist/src/tiles/preview/tile-preview-controller.d.ts +61 -0
- package/dist/src/tiles/preview/tile-preview-controller.js +216 -0
- package/dist/src/tiles/preview/tile-preview-controller.js.map +1 -0
- package/dist/src/tiles/preview/tile-preview-media.d.ts +44 -0
- package/dist/src/tiles/preview/tile-preview-media.js +151 -0
- package/dist/src/tiles/preview/tile-preview-media.js.map +1 -0
- package/dist/src/tiles/preview/tile-preview.d.ts +66 -0
- package/dist/src/tiles/preview/tile-preview.js +494 -0
- package/dist/src/tiles/preview/tile-preview.js.map +1 -0
- package/dist/src/tiles/tile-dispatcher.d.ts +7 -0
- package/dist/src/tiles/tile-dispatcher.js +31 -0
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/src/utils/grid-zoom-controller.d.ts +69 -0
- package/dist/src/utils/grid-zoom-controller.js +261 -0
- package/dist/src/utils/grid-zoom-controller.js.map +1 -0
- package/dist/src/utils/grid-zoom.d.ts +31 -0
- package/dist/src/utils/grid-zoom.js +109 -0
- package/dist/src/utils/grid-zoom.js.map +1 -0
- package/dist/src/utils/log.d.ts +1 -4
- package/package.json +5 -1
|
@@ -3,6 +3,7 @@ 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 { styleMap } from 'lit/directives/style-map.js';
|
|
6
7
|
import { msg } from '@lit/localize';
|
|
7
8
|
import { SearchType, } from '@internetarchive/search-service';
|
|
8
9
|
import '@internetarchive/infinite-scroller';
|
|
@@ -10,6 +11,8 @@ import { SortField, getDefaultSelectedFacets, sortOptionFromAPIString, SORT_OPTI
|
|
|
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';
|
|
@@ -24,11 +27,22 @@ import './manage/manage-bar';
|
|
|
24
27
|
import './collection-facets';
|
|
25
28
|
import './circular-activity-indicator';
|
|
26
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;
|
|
27
34
|
let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
28
35
|
static { CollectionBrowser_1 = this; }
|
|
29
36
|
constructor() {
|
|
30
37
|
super();
|
|
31
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 = {};
|
|
32
46
|
/**
|
|
33
47
|
* Which backend should be targeted by searches (e.g., metadata or FTS)
|
|
34
48
|
*/
|
|
@@ -131,6 +145,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
131
145
|
* `LayoutType` for available options. Has no effect on list display modes.
|
|
132
146
|
*/
|
|
133
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;
|
|
134
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;
|
|
@@ -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.
|
|
@@ -673,6 +703,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
673
703
|
itemCount=${this.placeholderType ? 0 : nothing}
|
|
674
704
|
ariaLandmarkLabel="Search results"
|
|
675
705
|
.estimatedCellHeight=${this.estimatedTileHeight}
|
|
706
|
+
style=${styleMap(this.gridZoomStyles)}
|
|
676
707
|
.minBufferMarginCells=${this.pageSize}
|
|
677
708
|
.cellProvider=${this}
|
|
678
709
|
.placeholderCellTemplate=${this.placeholderCellTemplate}
|
|
@@ -683,6 +714,127 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
683
714
|
: nothing}
|
|
684
715
|
</infinite-scroller>`;
|
|
685
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
|
+
}
|
|
686
838
|
/**
|
|
687
839
|
* Produces a `classMap` indicating which classes the infinite scroller should have
|
|
688
840
|
* given the current display mode & placeholder case.
|
|
@@ -745,6 +897,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
745
897
|
.prefixFilterCountMap=${this.dataSource.prefixFilterCountMap}
|
|
746
898
|
.enableSortOptionsSlot=${this.enableSortOptionsSlot}
|
|
747
899
|
.suppressDisplayModes=${this.suppressDisplayModes}
|
|
900
|
+
.showGridZoomSlider=${this.pinchZoomActive}
|
|
901
|
+
.gridZoomLevel=${this.effectiveGridZoomLevel}
|
|
902
|
+
@gridZoomLevelChanged=${this.gridZoomSliderChanged}
|
|
748
903
|
@sortChanged=${this.userChangedSort}
|
|
749
904
|
@displayModeChanged=${this.displayModeChanged}
|
|
750
905
|
@titleLetterChanged=${this.titleLetterSelected}
|
|
@@ -1420,9 +1575,18 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1420
1575
|
changed.has('baseImageUrl') ||
|
|
1421
1576
|
changed.has('loggedIn') ||
|
|
1422
1577
|
changed.has('tileActions') ||
|
|
1423
|
-
changed.has('tileLayoutType')
|
|
1578
|
+
changed.has('tileLayoutType') ||
|
|
1579
|
+
changed.has('gridZoomLevel') ||
|
|
1580
|
+
changed.has('enableTilePreviews') ||
|
|
1581
|
+
changed.has('tilePreviewOptions')) {
|
|
1424
1582
|
this.infiniteScroller?.reload();
|
|
1425
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
|
+
}
|
|
1426
1590
|
if (changed.has('profileElement')) {
|
|
1427
1591
|
this.applyDefaultProfileSort();
|
|
1428
1592
|
}
|
|
@@ -1523,8 +1687,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
1523
1687
|
super.connectedCallback?.();
|
|
1524
1688
|
this.setupStateRestorationObserver();
|
|
1525
1689
|
this.setupResizeObserver();
|
|
1690
|
+
if (this.hasUpdated)
|
|
1691
|
+
this.updateGridZoom(new Map());
|
|
1526
1692
|
}
|
|
1527
1693
|
disconnectedCallback() {
|
|
1694
|
+
this.gridZoomController.disconnect();
|
|
1528
1695
|
if (this.resizeObserver) {
|
|
1529
1696
|
this.disconnectResizeObserver(this.resizeObserver);
|
|
1530
1697
|
}
|
|
@@ -2075,9 +2242,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
|
|
|
2075
2242
|
.suppressBlurring=${this.shouldSuppressTileBlurring}
|
|
2076
2243
|
.isManageView=${this.isManageView}
|
|
2077
2244
|
.tileActions=${this.tileActions}
|
|
2078
|
-
.layoutType=${this.
|
|
2245
|
+
.layoutType=${this.effectiveTileLayoutType}
|
|
2079
2246
|
?showTvClips=${isTVSearch || isTVCollection}
|
|
2080
2247
|
?enableHoverPane=${true}
|
|
2248
|
+
?enableTilePreview=${this.enableTilePreviews}
|
|
2249
|
+
.tilePreviewOptions=${this.tilePreviewOptions}
|
|
2081
2250
|
?useLocalTime=${shouldUseLocalTime}
|
|
2082
2251
|
@resultSelected=${(e) => this.resultSelected(e)}
|
|
2083
2252
|
>
|
|
@@ -2616,6 +2785,12 @@ __decorate([
|
|
|
2616
2785
|
__decorate([
|
|
2617
2786
|
property({ type: String })
|
|
2618
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);
|
|
2619
2794
|
__decorate([
|
|
2620
2795
|
property({ type: Object })
|
|
2621
2796
|
], CollectionBrowser.prototype, "searchService", void 0);
|
|
@@ -2760,6 +2935,9 @@ __decorate([
|
|
|
2760
2935
|
__decorate([
|
|
2761
2936
|
property({ type: String })
|
|
2762
2937
|
], CollectionBrowser.prototype, "tileLayoutType", void 0);
|
|
2938
|
+
__decorate([
|
|
2939
|
+
property({ type: Boolean, attribute: 'enable-pinch-zoom' })
|
|
2940
|
+
], CollectionBrowser.prototype, "enablePinchZoom", void 0);
|
|
2763
2941
|
__decorate([
|
|
2764
2942
|
property({ type: String })
|
|
2765
2943
|
], CollectionBrowser.prototype, "manageViewLabel", void 0);
|
|
@@ -2790,6 +2968,12 @@ __decorate([
|
|
|
2790
2968
|
__decorate([
|
|
2791
2969
|
state()
|
|
2792
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);
|
|
2793
2977
|
__decorate([
|
|
2794
2978
|
state()
|
|
2795
2979
|
], CollectionBrowser.prototype, "tileBlurOverrideState", void 0);
|