@internetarchive/collection-browser 3.0.0 → 3.0.1

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 (60) hide show
  1. package/dist/src/collection-browser.js +680 -680
  2. package/dist/src/collection-browser.js.map +1 -1
  3. package/dist/src/collection-facets/facet-row.js +130 -130
  4. package/dist/src/collection-facets/facet-row.js.map +1 -1
  5. package/dist/src/collection-facets/models.d.ts +9 -0
  6. package/dist/src/collection-facets/models.js +10 -0
  7. package/dist/src/collection-facets/models.js.map +1 -0
  8. package/dist/src/collection-facets/more-facets-content.js +121 -120
  9. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  10. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +75 -75
  11. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  12. package/dist/src/collection-facets.js +263 -263
  13. package/dist/src/collection-facets.js.map +1 -1
  14. package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
  15. package/dist/src/data-source/collection-browser-query-state.js.map +1 -1
  16. package/dist/src/data-source/models.js.map +1 -1
  17. package/dist/src/models.js.map +1 -1
  18. package/dist/src/restoration-state-handler.js.map +1 -1
  19. package/dist/src/tiles/base-tile-component.js.map +1 -1
  20. package/dist/src/tiles/grid/item-tile.js +139 -139
  21. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  22. package/dist/src/tiles/hover/hover-pane-controller.js +21 -21
  23. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  24. package/dist/src/tiles/hover/tile-hover-pane.js +108 -108
  25. package/dist/src/tiles/hover/tile-hover-pane.js.map +1 -1
  26. package/dist/src/tiles/list/tile-list-compact-header.js +45 -45
  27. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  28. package/dist/src/tiles/list/tile-list-compact.js +97 -97
  29. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  30. package/dist/src/tiles/list/tile-list.js +289 -289
  31. package/dist/src/tiles/list/tile-list.js.map +1 -1
  32. package/dist/src/tiles/tile-dispatcher.js +200 -200
  33. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  34. package/dist/src/tiles/tile-display-value-provider.js.map +1 -1
  35. package/dist/test/collection-browser.test.js +183 -183
  36. package/dist/test/collection-browser.test.js.map +1 -1
  37. package/dist/test/restoration-state-handler.test.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/collection-browser.ts +2775 -2775
  40. package/src/collection-facets/facet-row.ts +282 -282
  41. package/src/collection-facets/models.ts +10 -0
  42. package/src/collection-facets/more-facets-content.ts +636 -632
  43. package/src/collection-facets/smart-facets/smart-facet-bar.ts +437 -437
  44. package/src/collection-facets.ts +990 -990
  45. package/src/data-source/collection-browser-data-source.ts +1390 -1390
  46. package/src/data-source/collection-browser-query-state.ts +63 -63
  47. package/src/data-source/models.ts +43 -43
  48. package/src/models.ts +870 -870
  49. package/src/restoration-state-handler.ts +544 -544
  50. package/src/tiles/base-tile-component.ts +53 -53
  51. package/src/tiles/grid/item-tile.ts +339 -339
  52. package/src/tiles/hover/hover-pane-controller.ts +517 -517
  53. package/src/tiles/hover/tile-hover-pane.ts +180 -180
  54. package/src/tiles/list/tile-list-compact-header.ts +86 -86
  55. package/src/tiles/list/tile-list-compact.ts +236 -236
  56. package/src/tiles/list/tile-list.ts +688 -688
  57. package/src/tiles/tile-dispatcher.ts +486 -486
  58. package/src/tiles/tile-display-value-provider.ts +124 -124
  59. package/test/collection-browser.test.ts +2340 -2340
  60. package/test/restoration-state-handler.test.ts +510 -510
@@ -46,30 +46,30 @@ let ItemTile = class ItemTile extends BaseTileComponent {
46
46
  'stats-only': this.simpleLayoutType === 'stats-only',
47
47
  'snippets-only': this.simpleLayoutType === 'snippets-only',
48
48
  });
49
- return html `
50
- <div class=${containerClasses}>
51
- ${this.infoButtonTemplate}
52
- <div class="tile-details">
53
- <div class="item-info">
54
- ${this.imageBlockTemplate}
55
-
56
- <div id="title">
57
- <h4 class="truncated" title=${ifDefined(itemTitle)}>
58
- ${itemTitle}
59
- </h4>
60
- </div>
61
-
62
- ${this.volumeIssueTemplate}
49
+ return html `
50
+ <div class=${containerClasses}>
51
+ ${this.infoButtonTemplate}
52
+ <div class="tile-details">
53
+ <div class="item-info">
54
+ ${this.imageBlockTemplate}
55
+
56
+ <div id="title">
57
+ <h4 class="truncated" title=${ifDefined(itemTitle)}>
58
+ ${itemTitle}
59
+ </h4>
60
+ </div>
61
+
62
+ ${this.volumeIssueTemplate}
63
63
  ${this.isSortedByDate
64
64
  ? this.sortedDateInfoTemplate
65
- : this.creatorTemplate}
66
- ${this.webArchivesCaptureDatesTemplate} ${this.textSnippetsTemplate}
67
- ${this.reviewBlockTemplate}
68
- </div>
69
-
70
- ${this.tileStatsTemplate}
71
- </div>
72
- </div>
65
+ : this.creatorTemplate}
66
+ ${this.webArchivesCaptureDatesTemplate} ${this.textSnippetsTemplate}
67
+ ${this.reviewBlockTemplate}
68
+ </div>
69
+
70
+ ${this.tileStatsTemplate}
71
+ </div>
72
+ </div>
73
73
  `;
74
74
  }
75
75
  /**
@@ -79,26 +79,26 @@ let ItemTile = class ItemTile extends BaseTileComponent {
79
79
  const displayedCreator = this.displayValueProvider.firstCreatorMatchingFilter;
80
80
  if (!displayedCreator)
81
81
  return nothing;
82
- return html `
83
- <div class="created-by">
84
- <span class="truncated" title=${displayedCreator}>
85
- by&nbsp;${displayedCreator}
86
- </span>
87
- </div>
82
+ return html `
83
+ <div class="created-by">
84
+ <span class="truncated" title=${displayedCreator}>
85
+ by&nbsp;${displayedCreator}
86
+ </span>
87
+ </div>
88
88
  `;
89
89
  }
90
90
  get imageBlockTemplate() {
91
- return html `
92
- <image-block
93
- .model=${this.model}
94
- .baseImageUrl=${this.baseImageUrl}
95
- .loggedIn=${this.loggedIn}
96
- .suppressBlurring=${this.suppressBlurring}
97
- .isCompactTile=${false}
98
- .isListTile=${false}
99
- .viewSize=${'grid'}
100
- >
101
- </image-block>
91
+ return html `
92
+ <image-block
93
+ .model=${this.model}
94
+ .baseImageUrl=${this.baseImageUrl}
95
+ .loggedIn=${this.loggedIn}
96
+ .suppressBlurring=${this.suppressBlurring}
97
+ .isCompactTile=${false}
98
+ .isListTile=${false}
99
+ .viewSize=${'grid'}
100
+ >
101
+ </image-block>
102
102
  `;
103
103
  }
104
104
  get sortedDateInfoTemplate() {
@@ -129,20 +129,20 @@ let ItemTile = class ItemTile extends BaseTileComponent {
129
129
  if (!(sortedValue === null || sortedValue === void 0 ? void 0 : sortedValue.value)) {
130
130
  return nothing;
131
131
  }
132
- return html `
133
- <div class="date-sorted-by truncated">
134
- <span>
135
- ${sortedValue === null || sortedValue === void 0 ? void 0 : sortedValue.field} ${formatDate(sortedValue === null || sortedValue === void 0 ? void 0 : sortedValue.value, format)}
136
- </span>
137
- </div>
132
+ return html `
133
+ <div class="date-sorted-by truncated">
134
+ <span>
135
+ ${sortedValue === null || sortedValue === void 0 ? void 0 : sortedValue.field} ${formatDate(sortedValue === null || sortedValue === void 0 ? void 0 : sortedValue.value, format)}
136
+ </span>
137
+ </div>
138
138
  `;
139
139
  }
140
140
  get infoButtonTemplate() {
141
141
  // &#9432; is an information icon
142
142
  return this.showInfoButton
143
- ? html `<button class="info-button" @click=${this.infoButtonPressed}>
144
- &#9432;
145
- <span class="sr-only">${msg('More info')}</span>
143
+ ? html `<button class="info-button" @click=${this.infoButtonPressed}>
144
+ &#9432;
145
+ <span class="sr-only">${msg('More info')}</span>
146
146
  </button>`
147
147
  : nothing;
148
148
  }
@@ -151,47 +151,47 @@ let ItemTile = class ItemTile extends BaseTileComponent {
151
151
  if (!((_a = this.model) === null || _a === void 0 ? void 0 : _a.review))
152
152
  return nothing;
153
153
  const { reviewtitle, reviewbody, stars } = this.model.review;
154
- return html `
155
- <review-block
156
- viewsize="grid"
157
- title=${ifDefined(reviewtitle)}
158
- body=${ifDefined(reviewbody)}
159
- starRating=${ifDefined(stars)}
160
- >
161
- </review-block>
154
+ return html `
155
+ <review-block
156
+ viewsize="grid"
157
+ title=${ifDefined(reviewtitle)}
158
+ body=${ifDefined(reviewbody)}
159
+ starRating=${ifDefined(stars)}
160
+ >
161
+ </review-block>
162
162
  `;
163
163
  }
164
164
  get textSnippetsTemplate() {
165
165
  var _a;
166
166
  if (!this.hasSnippets || this.simpleLayoutType === 'stats-only')
167
167
  return nothing;
168
- return html `
169
- <text-snippet-block viewsize="grid" .snippets=${(_a = this.model) === null || _a === void 0 ? void 0 : _a.snippets}>
170
- </text-snippet-block>
168
+ return html `
169
+ <text-snippet-block viewsize="grid" .snippets=${(_a = this.model) === null || _a === void 0 ? void 0 : _a.snippets}>
170
+ </text-snippet-block>
171
171
  `;
172
172
  }
173
173
  get volumeIssueTemplate() {
174
174
  var _a, _b, _c, _d;
175
175
  if (!((_a = this.model) === null || _a === void 0 ? void 0 : _a.volume) || !((_b = this.model) === null || _b === void 0 ? void 0 : _b.issue))
176
176
  return nothing;
177
- return html `
178
- <div class="volume-issue">
179
- <span class="truncated" title="volume|issue">
180
- Volume&nbsp;${(_c = this.model) === null || _c === void 0 ? void 0 : _c.volume}, Issue&nbsp;${(_d = this.model) === null || _d === void 0 ? void 0 : _d.issue}
181
- </span>
182
- </div>
177
+ return html `
178
+ <div class="volume-issue">
179
+ <span class="truncated" title="volume|issue">
180
+ Volume&nbsp;${(_c = this.model) === null || _c === void 0 ? void 0 : _c.volume}, Issue&nbsp;${(_d = this.model) === null || _d === void 0 ? void 0 : _d.issue}
181
+ </span>
182
+ </div>
183
183
  `;
184
184
  }
185
185
  get webArchivesCaptureDatesTemplate() {
186
186
  var _a;
187
187
  if (!((_a = this.model) === null || _a === void 0 ? void 0 : _a.captureDates) || !this.model.title)
188
188
  return nothing;
189
- return html `
190
- <ul class="capture-dates">
191
- ${map(this.model.captureDates, date => html `<li>
192
- ${this.displayValueProvider.webArchivesCaptureLink(this.model.title, date)}
193
- </li>`)}
194
- </ul>
189
+ return html `
190
+ <ul class="capture-dates">
191
+ ${map(this.model.captureDates, date => html `<li>
192
+ ${this.displayValueProvider.webArchivesCaptureLink(this.model.title, date)}
193
+ </li>`)}
194
+ </ul>
195
195
  `;
196
196
  }
197
197
  /**
@@ -205,18 +205,18 @@ let ItemTile = class ItemTile extends BaseTileComponent {
205
205
  const [viewCount, viewLabel] = (effectiveSort === null || effectiveSort === void 0 ? void 0 : effectiveSort.field) === 'week'
206
206
  ? [(_b = this.model) === null || _b === void 0 ? void 0 : _b.weeklyViewCount, 'weekly views']
207
207
  : [(_c = this.model) === null || _c === void 0 ? void 0 : _c.viewCount, 'all-time views'];
208
- return html `
209
- <tile-stats
210
- .model=${this.model}
211
- .mediatype=${(_d = this.model) === null || _d === void 0 ? void 0 : _d.mediatype}
212
- .viewCount=${viewCount}
213
- .viewLabel=${viewLabel}
214
- .favCount=${(_e = this.model) === null || _e === void 0 ? void 0 : _e.favCount}
215
- .commentCount=${(_f = this.model) === null || _f === void 0 ? void 0 : _f.commentCount}
216
- .tvClipCount=${(_g = this.model) === null || _g === void 0 ? void 0 : _g.tvClipCount}
217
- .showTvClips=${this.showTvClips}
218
- >
219
- </tile-stats>
208
+ return html `
209
+ <tile-stats
210
+ .model=${this.model}
211
+ .mediatype=${(_d = this.model) === null || _d === void 0 ? void 0 : _d.mediatype}
212
+ .viewCount=${viewCount}
213
+ .viewLabel=${viewLabel}
214
+ .favCount=${(_e = this.model) === null || _e === void 0 ? void 0 : _e.favCount}
215
+ .commentCount=${(_f = this.model) === null || _f === void 0 ? void 0 : _f.commentCount}
216
+ .tvClipCount=${(_g = this.model) === null || _g === void 0 ? void 0 : _g.tvClipCount}
217
+ .showTvClips=${this.showTvClips}
218
+ >
219
+ </tile-stats>
220
220
  `;
221
221
  }
222
222
  get isSortedByDate() {
@@ -246,62 +246,62 @@ let ItemTile = class ItemTile extends BaseTileComponent {
246
246
  const tileBorderColor = css `var(--tileBorderColor, #dddddd)`;
247
247
  return [
248
248
  baseTileStyles,
249
- css `
250
- a:link {
251
- text-decoration: none;
252
- color: var(--ia-theme-link-color, #4b64ff);
253
- }
254
- a:hover {
255
- text-decoration: underline;
256
- }
257
-
258
- .container {
259
- border: 1px solid ${tileBorderColor};
260
- }
261
-
262
- .simple #title > .truncated {
263
- -webkit-line-clamp: 2;
264
- }
265
-
266
- .simple .created-by > .truncated,
267
- .simple .date-sorted-by > .truncated,
268
- .simple .volume-issue > .truncated {
269
- -webkit-line-clamp: 1;
270
- }
271
-
272
- .simple.snippets-only .item-info {
273
- padding-bottom: 5px;
274
- }
275
-
276
- .simple.snippets-only text-snippet-block {
277
- margin-top: auto; /* Force the snippets to the bottom of the tile */
278
- }
279
-
280
- .capture-dates {
281
- margin: 0;
282
- padding: 0 5px;
283
- list-style-type: none;
284
- }
285
-
286
- review-block,
287
- text-snippet-block {
288
- --containerLeftMargin: 5px;
289
- --containerTopMargin: 5px;
290
- }
291
-
292
- /**
293
- * iOS Safari long-press on tiles (to bring up hover pane)
294
- * gets messy without this
295
- */
296
- @media screen and (pointer: coarse) and (hover: none) {
297
- .container {
298
- -webkit-touch-callout: none;
299
- }
300
-
301
- .truncated {
302
- -webkit-touch-callout: default;
303
- }
304
- }
249
+ css `
250
+ a:link {
251
+ text-decoration: none;
252
+ color: var(--ia-theme-link-color, #4b64ff);
253
+ }
254
+ a:hover {
255
+ text-decoration: underline;
256
+ }
257
+
258
+ .container {
259
+ border: 1px solid ${tileBorderColor};
260
+ }
261
+
262
+ .simple #title > .truncated {
263
+ -webkit-line-clamp: 2;
264
+ }
265
+
266
+ .simple .created-by > .truncated,
267
+ .simple .date-sorted-by > .truncated,
268
+ .simple .volume-issue > .truncated {
269
+ -webkit-line-clamp: 1;
270
+ }
271
+
272
+ .simple.snippets-only .item-info {
273
+ padding-bottom: 5px;
274
+ }
275
+
276
+ .simple.snippets-only text-snippet-block {
277
+ margin-top: auto; /* Force the snippets to the bottom of the tile */
278
+ }
279
+
280
+ .capture-dates {
281
+ margin: 0;
282
+ padding: 0 5px;
283
+ list-style-type: none;
284
+ }
285
+
286
+ review-block,
287
+ text-snippet-block {
288
+ --containerLeftMargin: 5px;
289
+ --containerTopMargin: 5px;
290
+ }
291
+
292
+ /**
293
+ * iOS Safari long-press on tiles (to bring up hover pane)
294
+ * gets messy without this
295
+ */
296
+ @media screen and (pointer: coarse) and (hover: none) {
297
+ .container {
298
+ -webkit-touch-callout: none;
299
+ }
300
+
301
+ .truncated {
302
+ -webkit-touch-callout: default;
303
+ }
304
+ }
305
305
  `,
306
306
  ];
307
307
  }
@@ -1 +1 @@
1
- {"version":3,"file":"item-tile.js","sourceRoot":"","sources":["../../../../src/tiles/grid/item-tile.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, CSSResultGroup, html, nothing, TemplateResult } from 'lit';\r\nimport { customElement, property } from 'lit/decorators.js';\r\nimport { ifDefined } from 'lit/directives/if-defined.js';\r\nimport { map } from 'lit/directives/map.js';\r\nimport { classMap } from 'lit/directives/class-map.js';\r\nimport { msg } from '@lit/localize';\r\n\r\nimport type { SortParam } from '@internetarchive/search-service';\r\nimport { DateFormat, formatDate } from '../../utils/format-date';\r\nimport { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';\r\nimport { BaseTileComponent } from '../base-tile-component';\r\nimport { baseTileStyles } from './styles/tile-grid-shared-styles';\r\n\r\nimport '../image-block';\r\nimport '../review-block';\r\nimport '../text-snippet-block';\r\nimport '../item-image';\r\nimport '../tile-mediatype-icon';\r\nimport './tile-stats';\r\nimport { SimpleLayoutType } from '../models';\r\n\r\n@customElement('item-tile')\r\nexport class ItemTile extends BaseTileComponent {\r\n /*\r\n * Reactive properties inherited from BaseTileComponent:\r\n * - model?: TileModel;\r\n * - currentWidth?: number;\r\n * - currentHeight?: number;\r\n * - baseNavigationUrl?: string;\r\n * - baseImageUrl?: string;\r\n * - collectionPagePath?: string;\r\n * - sortParam: SortParam | null = null;\r\n * - defaultSortParam: SortParam | null = null;\r\n * - creatorFilter?: string;\r\n * - mobileBreakpoint?: number;\r\n * - loggedIn = false;\r\n * - suppressBlurring = false;\r\n */\r\n\r\n @property({ type: Boolean }) showInfoButton = false;\r\n\r\n @property({ type: Boolean }) showTvClips = false;\r\n\r\n @property({ type: String }) simpleLayoutType: SimpleLayoutType = 'none';\r\n\r\n render() {\r\n const itemTitle = this.model?.title;\r\n const containerClasses = classMap({\r\n container: true,\r\n simple: this.simpleLayoutType !== 'none',\r\n 'stats-only': this.simpleLayoutType === 'stats-only',\r\n 'snippets-only': this.simpleLayoutType === 'snippets-only',\r\n });\r\n\r\n return html`\r\n <div class=${containerClasses}>\r\n ${this.infoButtonTemplate}\r\n <div class=\"tile-details\">\r\n <div class=\"item-info\">\r\n ${this.imageBlockTemplate}\r\n\r\n <div id=\"title\">\r\n <h4 class=\"truncated\" title=${ifDefined(itemTitle)}>\r\n ${itemTitle}\r\n </h4>\r\n </div>\r\n\r\n ${this.volumeIssueTemplate}\r\n ${this.isSortedByDate\r\n ? this.sortedDateInfoTemplate\r\n : this.creatorTemplate}\r\n ${this.webArchivesCaptureDatesTemplate} ${this.textSnippetsTemplate}\r\n ${this.reviewBlockTemplate}\r\n </div>\r\n\r\n ${this.tileStatsTemplate}\r\n </div>\r\n </div>\r\n `;\r\n }\r\n\r\n /**\r\n * Templates\r\n */\r\n private get creatorTemplate(): TemplateResult | typeof nothing {\r\n const displayedCreator =\r\n this.displayValueProvider.firstCreatorMatchingFilter;\r\n if (!displayedCreator) return nothing;\r\n\r\n return html`\r\n <div class=\"created-by\">\r\n <span class=\"truncated\" title=${displayedCreator}>\r\n by&nbsp;${displayedCreator}\r\n </span>\r\n </div>\r\n `;\r\n }\r\n\r\n private get imageBlockTemplate(): TemplateResult {\r\n return html`\r\n <image-block\r\n .model=${this.model}\r\n .baseImageUrl=${this.baseImageUrl}\r\n .loggedIn=${this.loggedIn}\r\n .suppressBlurring=${this.suppressBlurring}\r\n .isCompactTile=${false}\r\n .isListTile=${false}\r\n .viewSize=${'grid'}\r\n >\r\n </image-block>\r\n `;\r\n }\r\n\r\n private get sortedDateInfoTemplate() {\r\n let sortedValue;\r\n let format: DateFormat = 'long';\r\n switch (this.effectiveSort?.field) {\r\n case 'date': {\r\n const datePublished = this.model?.datePublished;\r\n sortedValue = { field: 'published', value: datePublished };\r\n if (isFirstMillisecondOfUTCYear(datePublished)) {\r\n format = 'year-only';\r\n }\r\n break;\r\n }\r\n case 'reviewdate':\r\n sortedValue = { field: 'reviewed', value: this.model?.dateReviewed };\r\n break;\r\n case 'addeddate':\r\n sortedValue = { field: 'added', value: this.model?.dateAdded };\r\n break;\r\n case 'publicdate':\r\n sortedValue = { field: 'archived', value: this.model?.dateArchived };\r\n break;\r\n default:\r\n break;\r\n }\r\n\r\n if (!sortedValue?.value) {\r\n return nothing;\r\n }\r\n return html`\r\n <div class=\"date-sorted-by truncated\">\r\n <span>\r\n ${sortedValue?.field} ${formatDate(sortedValue?.value, format)}\r\n </span>\r\n </div>\r\n `;\r\n }\r\n\r\n private get infoButtonTemplate(): TemplateResult | typeof nothing {\r\n // &#9432; is an information icon\r\n return this.showInfoButton\r\n ? html`<button class=\"info-button\" @click=${this.infoButtonPressed}>\r\n &#9432;\r\n <span class=\"sr-only\">${msg('More info')}</span>\r\n </button>`\r\n : nothing;\r\n }\r\n\r\n private get reviewBlockTemplate(): TemplateResult | typeof nothing {\r\n if (!this.model?.review) return nothing;\r\n\r\n const { reviewtitle, reviewbody, stars } = this.model.review;\r\n return html`\r\n <review-block\r\n viewsize=\"grid\"\r\n title=${ifDefined(reviewtitle)}\r\n body=${ifDefined(reviewbody)}\r\n starRating=${ifDefined(stars)}\r\n >\r\n </review-block>\r\n `;\r\n }\r\n\r\n private get textSnippetsTemplate(): TemplateResult | typeof nothing {\r\n if (!this.hasSnippets || this.simpleLayoutType === 'stats-only')\r\n return nothing;\r\n\r\n return html`\r\n <text-snippet-block viewsize=\"grid\" .snippets=${this.model?.snippets}>\r\n </text-snippet-block>\r\n `;\r\n }\r\n\r\n private get volumeIssueTemplate(): TemplateResult | typeof nothing {\r\n if (!this.model?.volume || !this.model?.issue) return nothing;\r\n\r\n return html`\r\n <div class=\"volume-issue\">\r\n <span class=\"truncated\" title=\"volume|issue\">\r\n Volume&nbsp;${this.model?.volume}, Issue&nbsp;${this.model?.issue}\r\n </span>\r\n </div>\r\n `;\r\n }\r\n\r\n private get webArchivesCaptureDatesTemplate():\r\n | TemplateResult\r\n | typeof nothing {\r\n if (!this.model?.captureDates || !this.model.title) return nothing;\r\n\r\n return html`\r\n <ul class=\"capture-dates\">\r\n ${map(\r\n this.model.captureDates,\r\n date =>\r\n html`<li>\r\n ${this.displayValueProvider.webArchivesCaptureLink(\r\n this.model!.title,\r\n date,\r\n )}\r\n </li>`,\r\n )}\r\n </ul>\r\n `;\r\n }\r\n\r\n /**\r\n * Template for the stats row along the bottom of the tile.\r\n */\r\n private get tileStatsTemplate(): TemplateResult | typeof nothing {\r\n if (this.simpleLayoutType === 'snippets-only') return nothing;\r\n\r\n const effectiveSort = this.sortParam ?? this.defaultSortParam;\r\n const [viewCount, viewLabel] =\r\n effectiveSort?.field === 'week'\r\n ? [this.model?.weeklyViewCount, 'weekly views']\r\n : [this.model?.viewCount, 'all-time views'];\r\n\r\n return html`\r\n <tile-stats\r\n .model=${this.model}\r\n .mediatype=${this.model?.mediatype}\r\n .viewCount=${viewCount}\r\n .viewLabel=${viewLabel}\r\n .favCount=${this.model?.favCount}\r\n .commentCount=${this.model?.commentCount}\r\n .tvClipCount=${this.model?.tvClipCount}\r\n .showTvClips=${this.showTvClips}\r\n >\r\n </tile-stats>\r\n `;\r\n }\r\n\r\n private get isSortedByDate(): boolean {\r\n return ['date', 'reviewdate', 'addeddate', 'publicdate'].includes(\r\n this.effectiveSort?.field as string,\r\n );\r\n }\r\n\r\n /**\r\n * Returns the active sort param if one is set, or the default sort param otherwise.\r\n */\r\n private get effectiveSort(): SortParam | null {\r\n return this.sortParam ?? this.defaultSortParam;\r\n }\r\n\r\n private get hasSnippets(): boolean {\r\n return !!this.model?.snippets?.length;\r\n }\r\n\r\n private infoButtonPressed(e: PointerEvent): void {\r\n e.preventDefault();\r\n const event = new CustomEvent<{ x: number; y: number }>(\r\n 'infoButtonPressed',\r\n { detail: { x: e.clientX, y: e.clientY } },\r\n );\r\n this.dispatchEvent(event);\r\n }\r\n\r\n /**\r\n * CSS\r\n */\r\n static get styles(): CSSResultGroup {\r\n const tileBorderColor = css`var(--tileBorderColor, #dddddd)`;\r\n\r\n return [\r\n baseTileStyles,\r\n css`\r\n a:link {\r\n text-decoration: none;\r\n color: var(--ia-theme-link-color, #4b64ff);\r\n }\r\n a:hover {\r\n text-decoration: underline;\r\n }\r\n\r\n .container {\r\n border: 1px solid ${tileBorderColor};\r\n }\r\n\r\n .simple #title > .truncated {\r\n -webkit-line-clamp: 2;\r\n }\r\n\r\n .simple .created-by > .truncated,\r\n .simple .date-sorted-by > .truncated,\r\n .simple .volume-issue > .truncated {\r\n -webkit-line-clamp: 1;\r\n }\r\n\r\n .simple.snippets-only .item-info {\r\n padding-bottom: 5px;\r\n }\r\n\r\n .simple.snippets-only text-snippet-block {\r\n margin-top: auto; /* Force the snippets to the bottom of the tile */\r\n }\r\n\r\n .capture-dates {\r\n margin: 0;\r\n padding: 0 5px;\r\n list-style-type: none;\r\n }\r\n\r\n review-block,\r\n text-snippet-block {\r\n --containerLeftMargin: 5px;\r\n --containerTopMargin: 5px;\r\n }\r\n\r\n /**\r\n * iOS Safari long-press on tiles (to bring up hover pane)\r\n * gets messy without this\r\n */\r\n @media screen and (pointer: coarse) and (hover: none) {\r\n .container {\r\n -webkit-touch-callout: none;\r\n }\r\n\r\n .truncated {\r\n -webkit-touch-callout: default;\r\n }\r\n }\r\n `,\r\n ];\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"item-tile.js","sourceRoot":"","sources":["../../../../src/tiles/grid/item-tile.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, CSSResultGroup, html, nothing, TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { map } from 'lit/directives/map.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { msg } from '@lit/localize';\n\nimport type { SortParam } from '@internetarchive/search-service';\nimport { DateFormat, formatDate } from '../../utils/format-date';\nimport { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';\nimport { BaseTileComponent } from '../base-tile-component';\nimport { baseTileStyles } from './styles/tile-grid-shared-styles';\n\nimport '../image-block';\nimport '../review-block';\nimport '../text-snippet-block';\nimport '../item-image';\nimport '../tile-mediatype-icon';\nimport './tile-stats';\nimport { SimpleLayoutType } from '../models';\n\n@customElement('item-tile')\nexport class ItemTile extends BaseTileComponent {\n /*\n * Reactive properties inherited from BaseTileComponent:\n * - model?: TileModel;\n * - currentWidth?: number;\n * - currentHeight?: number;\n * - baseNavigationUrl?: string;\n * - baseImageUrl?: string;\n * - collectionPagePath?: string;\n * - sortParam: SortParam | null = null;\n * - defaultSortParam: SortParam | null = null;\n * - creatorFilter?: string;\n * - mobileBreakpoint?: number;\n * - loggedIn = false;\n * - suppressBlurring = false;\n */\n\n @property({ type: Boolean }) showInfoButton = false;\n\n @property({ type: Boolean }) showTvClips = false;\n\n @property({ type: String }) simpleLayoutType: SimpleLayoutType = 'none';\n\n render() {\n const itemTitle = this.model?.title;\n const containerClasses = classMap({\n container: true,\n simple: this.simpleLayoutType !== 'none',\n 'stats-only': this.simpleLayoutType === 'stats-only',\n 'snippets-only': this.simpleLayoutType === 'snippets-only',\n });\n\n return html`\n <div class=${containerClasses}>\n ${this.infoButtonTemplate}\n <div class=\"tile-details\">\n <div class=\"item-info\">\n ${this.imageBlockTemplate}\n\n <div id=\"title\">\n <h4 class=\"truncated\" title=${ifDefined(itemTitle)}>\n ${itemTitle}\n </h4>\n </div>\n\n ${this.volumeIssueTemplate}\n ${this.isSortedByDate\n ? this.sortedDateInfoTemplate\n : this.creatorTemplate}\n ${this.webArchivesCaptureDatesTemplate} ${this.textSnippetsTemplate}\n ${this.reviewBlockTemplate}\n </div>\n\n ${this.tileStatsTemplate}\n </div>\n </div>\n `;\n }\n\n /**\n * Templates\n */\n private get creatorTemplate(): TemplateResult | typeof nothing {\n const displayedCreator =\n this.displayValueProvider.firstCreatorMatchingFilter;\n if (!displayedCreator) return nothing;\n\n return html`\n <div class=\"created-by\">\n <span class=\"truncated\" title=${displayedCreator}>\n by&nbsp;${displayedCreator}\n </span>\n </div>\n `;\n }\n\n private get imageBlockTemplate(): TemplateResult {\n return html`\n <image-block\n .model=${this.model}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n .isCompactTile=${false}\n .isListTile=${false}\n .viewSize=${'grid'}\n >\n </image-block>\n `;\n }\n\n private get sortedDateInfoTemplate() {\n let sortedValue;\n let format: DateFormat = 'long';\n switch (this.effectiveSort?.field) {\n case 'date': {\n const datePublished = this.model?.datePublished;\n sortedValue = { field: 'published', value: datePublished };\n if (isFirstMillisecondOfUTCYear(datePublished)) {\n format = 'year-only';\n }\n break;\n }\n case 'reviewdate':\n sortedValue = { field: 'reviewed', value: this.model?.dateReviewed };\n break;\n case 'addeddate':\n sortedValue = { field: 'added', value: this.model?.dateAdded };\n break;\n case 'publicdate':\n sortedValue = { field: 'archived', value: this.model?.dateArchived };\n break;\n default:\n break;\n }\n\n if (!sortedValue?.value) {\n return nothing;\n }\n return html`\n <div class=\"date-sorted-by truncated\">\n <span>\n ${sortedValue?.field} ${formatDate(sortedValue?.value, format)}\n </span>\n </div>\n `;\n }\n\n private get infoButtonTemplate(): TemplateResult | typeof nothing {\n // &#9432; is an information icon\n return this.showInfoButton\n ? html`<button class=\"info-button\" @click=${this.infoButtonPressed}>\n &#9432;\n <span class=\"sr-only\">${msg('More info')}</span>\n </button>`\n : nothing;\n }\n\n private get reviewBlockTemplate(): TemplateResult | typeof nothing {\n if (!this.model?.review) return nothing;\n\n const { reviewtitle, reviewbody, stars } = this.model.review;\n return html`\n <review-block\n viewsize=\"grid\"\n title=${ifDefined(reviewtitle)}\n body=${ifDefined(reviewbody)}\n starRating=${ifDefined(stars)}\n >\n </review-block>\n `;\n }\n\n private get textSnippetsTemplate(): TemplateResult | typeof nothing {\n if (!this.hasSnippets || this.simpleLayoutType === 'stats-only')\n return nothing;\n\n return html`\n <text-snippet-block viewsize=\"grid\" .snippets=${this.model?.snippets}>\n </text-snippet-block>\n `;\n }\n\n private get volumeIssueTemplate(): TemplateResult | typeof nothing {\n if (!this.model?.volume || !this.model?.issue) return nothing;\n\n return html`\n <div class=\"volume-issue\">\n <span class=\"truncated\" title=\"volume|issue\">\n Volume&nbsp;${this.model?.volume}, Issue&nbsp;${this.model?.issue}\n </span>\n </div>\n `;\n }\n\n private get webArchivesCaptureDatesTemplate():\n | TemplateResult\n | typeof nothing {\n if (!this.model?.captureDates || !this.model.title) return nothing;\n\n return html`\n <ul class=\"capture-dates\">\n ${map(\n this.model.captureDates,\n date =>\n html`<li>\n ${this.displayValueProvider.webArchivesCaptureLink(\n this.model!.title,\n date,\n )}\n </li>`,\n )}\n </ul>\n `;\n }\n\n /**\n * Template for the stats row along the bottom of the tile.\n */\n private get tileStatsTemplate(): TemplateResult | typeof nothing {\n if (this.simpleLayoutType === 'snippets-only') return nothing;\n\n const effectiveSort = this.sortParam ?? this.defaultSortParam;\n const [viewCount, viewLabel] =\n effectiveSort?.field === 'week'\n ? [this.model?.weeklyViewCount, 'weekly views']\n : [this.model?.viewCount, 'all-time views'];\n\n return html`\n <tile-stats\n .model=${this.model}\n .mediatype=${this.model?.mediatype}\n .viewCount=${viewCount}\n .viewLabel=${viewLabel}\n .favCount=${this.model?.favCount}\n .commentCount=${this.model?.commentCount}\n .tvClipCount=${this.model?.tvClipCount}\n .showTvClips=${this.showTvClips}\n >\n </tile-stats>\n `;\n }\n\n private get isSortedByDate(): boolean {\n return ['date', 'reviewdate', 'addeddate', 'publicdate'].includes(\n this.effectiveSort?.field as string,\n );\n }\n\n /**\n * Returns the active sort param if one is set, or the default sort param otherwise.\n */\n private get effectiveSort(): SortParam | null {\n return this.sortParam ?? this.defaultSortParam;\n }\n\n private get hasSnippets(): boolean {\n return !!this.model?.snippets?.length;\n }\n\n private infoButtonPressed(e: PointerEvent): void {\n e.preventDefault();\n const event = new CustomEvent<{ x: number; y: number }>(\n 'infoButtonPressed',\n { detail: { x: e.clientX, y: e.clientY } },\n );\n this.dispatchEvent(event);\n }\n\n /**\n * CSS\n */\n static get styles(): CSSResultGroup {\n const tileBorderColor = css`var(--tileBorderColor, #dddddd)`;\n\n return [\n baseTileStyles,\n css`\n a:link {\n text-decoration: none;\n color: var(--ia-theme-link-color, #4b64ff);\n }\n a:hover {\n text-decoration: underline;\n }\n\n .container {\n border: 1px solid ${tileBorderColor};\n }\n\n .simple #title > .truncated {\n -webkit-line-clamp: 2;\n }\n\n .simple .created-by > .truncated,\n .simple .date-sorted-by > .truncated,\n .simple .volume-issue > .truncated {\n -webkit-line-clamp: 1;\n }\n\n .simple.snippets-only .item-info {\n padding-bottom: 5px;\n }\n\n .simple.snippets-only text-snippet-block {\n margin-top: auto; /* Force the snippets to the bottom of the tile */\n }\n\n .capture-dates {\n margin: 0;\n padding: 0 5px;\n list-style-type: none;\n }\n\n review-block,\n text-snippet-block {\n --containerLeftMargin: 5px;\n --containerTopMargin: 5px;\n }\n\n /**\n * iOS Safari long-press on tiles (to bring up hover pane)\n * gets messy without this\n */\n @media screen and (pointer: coarse) and (hover: none) {\n .container {\n -webkit-touch-callout: none;\n }\n\n .truncated {\n -webkit-touch-callout: default;\n }\n }\n `,\n ];\n }\n}\n"]}
@@ -171,18 +171,18 @@ export class HoverPaneController {
171
171
  var _a, _b, _c, _d, _e, _f, _g;
172
172
  this.hoverPaneProps = this.host.getHoverPaneProps();
173
173
  return this.shouldRenderHoverPane
174
- ? html ` ${this.touchBackdropTemplate}
175
- <tile-hover-pane
176
- popover
177
- .model=${(_a = this.hoverPaneProps) === null || _a === void 0 ? void 0 : _a.model}
178
- .baseNavigationUrl=${(_b = this.hoverPaneProps) === null || _b === void 0 ? void 0 : _b.baseNavigationUrl}
179
- .baseImageUrl=${(_c = this.hoverPaneProps) === null || _c === void 0 ? void 0 : _c.baseImageUrl}
180
- .loggedIn=${(_d = this.hoverPaneProps) === null || _d === void 0 ? void 0 : _d.loggedIn}
181
- .suppressBlurring=${(_e = this.hoverPaneProps) === null || _e === void 0 ? void 0 : _e.suppressBlurring}
182
- .sortParam=${(_f = this.hoverPaneProps) === null || _f === void 0 ? void 0 : _f.sortParam}
183
- .collectionTitles=${(_g = this.hoverPaneProps) === null || _g === void 0 ? void 0 : _g.collectionTitles}
184
- .mobileBreakpoint=${this.mobileBreakpoint}
185
- .currentWidth=${window.innerWidth}
174
+ ? html ` ${this.touchBackdropTemplate}
175
+ <tile-hover-pane
176
+ popover
177
+ .model=${(_a = this.hoverPaneProps) === null || _a === void 0 ? void 0 : _a.model}
178
+ .baseNavigationUrl=${(_b = this.hoverPaneProps) === null || _b === void 0 ? void 0 : _b.baseNavigationUrl}
179
+ .baseImageUrl=${(_c = this.hoverPaneProps) === null || _c === void 0 ? void 0 : _c.baseImageUrl}
180
+ .loggedIn=${(_d = this.hoverPaneProps) === null || _d === void 0 ? void 0 : _d.loggedIn}
181
+ .suppressBlurring=${(_e = this.hoverPaneProps) === null || _e === void 0 ? void 0 : _e.suppressBlurring}
182
+ .sortParam=${(_f = this.hoverPaneProps) === null || _f === void 0 ? void 0 : _f.sortParam}
183
+ .collectionTitles=${(_g = this.hoverPaneProps) === null || _g === void 0 ? void 0 : _g.collectionTitles}
184
+ .mobileBreakpoint=${this.mobileBreakpoint}
185
+ .currentWidth=${window.innerWidth}
186
186
  ></tile-hover-pane>`
187
187
  : nothing;
188
188
  }
@@ -208,15 +208,15 @@ export class HoverPaneController {
208
208
  */
209
209
  get touchBackdropTemplate() {
210
210
  return this.showTouchBackdrop
211
- ? html `<div
212
- id="touch-backdrop"
213
- @touchstart=${this.handleBackdropInteraction}
214
- @touchmove=${this.handleBackdropInteraction}
215
- @touchend=${this.handleBackdropInteraction}
216
- @touchcancel=${this.handleBackdropInteraction}
217
- @mouseenter=${(e) => e.stopPropagation()}
218
- @mousemove=${(e) => e.stopPropagation()}
219
- @mouseleave=${(e) => e.stopPropagation()}
211
+ ? html `<div
212
+ id="touch-backdrop"
213
+ @touchstart=${this.handleBackdropInteraction}
214
+ @touchmove=${this.handleBackdropInteraction}
215
+ @touchend=${this.handleBackdropInteraction}
216
+ @touchcancel=${this.handleBackdropInteraction}
217
+ @mouseenter=${(e) => e.stopPropagation()}
218
+ @mousemove=${(e) => e.stopPropagation()}
219
+ @mouseleave=${(e) => e.stopPropagation()}
220
220
  ></div>`
221
221
  : nothing;
222
222
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hover-pane-controller.js","sourceRoot":"","sources":["../../../../src/tiles/hover/hover-pane-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SortParam } from '@internetarchive/search-service';\r\nimport {\r\n html,\r\n HTMLTemplateResult,\r\n nothing,\r\n ReactiveController,\r\n ReactiveControllerHost,\r\n} from 'lit';\r\nimport type { TileModel } from '../../models';\r\nimport type { CollectionTitles } from '../../data-source/models';\r\n\r\ntype HoverPaneState = 'hidden' | 'shown' | 'fading-out';\r\n\r\nexport interface HoverPaneProperties {\r\n model?: TileModel;\r\n baseNavigationUrl?: string;\r\n baseImageUrl?: string;\r\n loggedIn: boolean;\r\n suppressBlurring: boolean;\r\n sortParam: SortParam | null;\r\n collectionTitles?: CollectionTitles;\r\n}\r\n\r\nexport interface HoverPaneControllerOptions {\r\n offsetX?: number;\r\n offsetY?: number;\r\n enableLongPress?: boolean;\r\n showDelay?: number;\r\n hideDelay?: number;\r\n longPressDelay?: number;\r\n mobileBreakpoint?: number;\r\n}\r\n\r\n/** A common interface for providing a hover pane element. */\r\nexport interface HoverPaneProviderInterface {\r\n /** Returns the provider's currently rendered hover pane element. */\r\n getHoverPane(): HTMLElement | undefined;\r\n /** Returns properties that should be passed to the hover pane. */\r\n getHoverPaneProps(): HoverPaneProperties;\r\n}\r\n\r\nexport interface ToggleHoverPaneOptions {\r\n coords: { x: number; y: number };\r\n enableTouchBackdrop?: boolean;\r\n}\r\n\r\n/**\r\n * An interface for interacting with hover pane controllers (e.g.,\r\n * to retrieve their current hover pane template).\r\n */\r\nexport interface HoverPaneControllerInterface extends ReactiveController {\r\n /**\r\n * Returns the hover pane template to render based on this controller's\r\n * current state. The returned template may be `nothing` if the hover\r\n * pane should not currently be rendered.\r\n */\r\n getTemplate(): HTMLTemplateResult | typeof nothing;\r\n\r\n /**\r\n * Requests to manually toggle the state of the hover pane.\r\n * If the hover pane is already shown, it will begin fading out and then\r\n * subsequently be hidden and removed. If the hover pane is already fading\r\n * out or hidden, it will fade back in and be shown.\r\n */\r\n toggleHoverPane(options: ToggleHoverPaneOptions): void;\r\n}\r\n\r\nconst clamp = (val: number, min = -Infinity, max = Infinity) =>\r\n Math.max(min, Math.min(val, max));\r\n\r\nexport class HoverPaneController implements HoverPaneControllerInterface {\r\n /**\r\n * The hover pane element attached to this controller's host.\r\n */\r\n private hoverPane?: HTMLElement;\r\n\r\n /**\r\n * The properties to be passed to the hover pane element\r\n */\r\n private hoverPaneProps?: HoverPaneProperties;\r\n\r\n /**\r\n * The breakpoint (in pixels) below which the mobile interface should be used.\r\n */\r\n private mobileBreakpoint?: number = 600;\r\n\r\n /**\r\n * The number of horizontal pixels the hover pane should be offset from the\r\n * pointer position.\r\n */\r\n private offsetX: number = -10;\r\n\r\n /**\r\n * The number of vertical pixels the hover pane should be offset from the\r\n * pointer position.\r\n */\r\n private offsetY: number = 15;\r\n\r\n /**\r\n * The delay between the mouse idling within the host element and when the hover\r\n * pane should begin fading in (in milliseconds).\r\n */\r\n private showDelay: number = 300;\r\n\r\n /**\r\n * The delay between when the mouse leaves the host element and when the hover\r\n * pane should begin fading out (in milliseconds).\r\n */\r\n private hideDelay: number = 100;\r\n\r\n /**\r\n * The delay between when a touch event begins on the host element and when the\r\n * hover pane should begin fading in (in milliseconds).\r\n */\r\n private longPressDelay: number = 600;\r\n\r\n /**\r\n * Whether long press interactions should cause the hover pane to appear (when\r\n * below the mobile breakpoint).\r\n */\r\n private enableLongPress: boolean = false;\r\n\r\n /**\r\n * Used to control the current state of this provider's hover pane.\r\n * - `'hidden'` => The hover pane is not present at all.\r\n * - `'shown'` => The hover pane is either fading in or fully visible.\r\n * - `'fading-out'` => The hover pane is fading out and about to be removed.\r\n */\r\n private hoverPaneState: HoverPaneState = 'hidden';\r\n\r\n /** The timer ID for showing the hover pane */\r\n private showTimer?: number;\r\n\r\n /** The timer ID for hiding the hover pane */\r\n private hideTimer?: number;\r\n\r\n /** The timer ID for recognizing a long press event */\r\n private longPressTimer?: number;\r\n\r\n /**\r\n * Whether the touch backdrop should currently be rendered irrespective of other touch\r\n * interactions being enabled.\r\n */\r\n private forceTouchBackdrop: boolean = false;\r\n\r\n /** A record of the last mouse position on the host element, for positioning the hover pane */\r\n private lastPointerClientPos = { x: 0, y: 0 };\r\n\r\n constructor(\r\n /** The host element to which this controller should attach listeners */\r\n private readonly host: ReactiveControllerHost &\r\n HoverPaneProviderInterface &\r\n HTMLElement,\r\n /** Options for adjusting the hover pane behavior (offsets, delays, etc.) */\r\n options: HoverPaneControllerOptions = {},\r\n ) {\r\n this.mobileBreakpoint = options.mobileBreakpoint ?? this.mobileBreakpoint;\r\n this.offsetX = options.offsetX ?? this.offsetX;\r\n this.offsetY = options.offsetY ?? this.offsetY;\r\n this.showDelay = options.showDelay ?? this.showDelay;\r\n this.hideDelay = options.hideDelay ?? this.hideDelay;\r\n this.longPressDelay = options.longPressDelay ?? this.longPressDelay;\r\n this.enableLongPress = options.enableLongPress ?? this.enableLongPress;\r\n\r\n this.host.addController(this);\r\n }\r\n\r\n hostConnected(): void {\r\n this.attachListeners();\r\n }\r\n\r\n hostDisconnected(): void {\r\n this.detachListeners();\r\n }\r\n\r\n hostUpdated(): void {\r\n this.hoverPane = this.host.getHoverPane();\r\n this.hoverPaneProps = this.host.getHoverPaneProps();\r\n }\r\n\r\n /** @inheritdoc */\r\n getTemplate(): HTMLTemplateResult | typeof nothing {\r\n this.hoverPaneProps = this.host.getHoverPaneProps();\r\n\r\n return this.shouldRenderHoverPane\r\n ? html` ${this.touchBackdropTemplate}\r\n <tile-hover-pane\r\n popover\r\n .model=${this.hoverPaneProps?.model}\r\n .baseNavigationUrl=${this.hoverPaneProps?.baseNavigationUrl}\r\n .baseImageUrl=${this.hoverPaneProps?.baseImageUrl}\r\n .loggedIn=${this.hoverPaneProps?.loggedIn}\r\n .suppressBlurring=${this.hoverPaneProps?.suppressBlurring}\r\n .sortParam=${this.hoverPaneProps?.sortParam}\r\n .collectionTitles=${this.hoverPaneProps?.collectionTitles}\r\n .mobileBreakpoint=${this.mobileBreakpoint}\r\n .currentWidth=${window.innerWidth}\r\n ></tile-hover-pane>`\r\n : nothing;\r\n }\r\n\r\n /** @inheritdoc */\r\n toggleHoverPane(options: ToggleHoverPaneOptions): void {\r\n if (this.hoverPaneState === 'shown') {\r\n this.fadeOutHoverPane();\r\n this.forceTouchBackdrop = false;\r\n } else {\r\n this.lastPointerClientPos = options.coords;\r\n this.forceTouchBackdrop = options.enableTouchBackdrop ?? false;\r\n this.showHoverPane();\r\n }\r\n }\r\n\r\n /**\r\n * Produces a template for the invisible touch capture backdrop that\r\n * is used to cancel the hover pane on touch devices. We want any\r\n * touch interaction on the backdrop to remove the hover pane, and\r\n * we don't want to bubble up mouse events that would otherwise\r\n * affect the state of the hover pane (e.g., fading it back in).\r\n */\r\n private get touchBackdropTemplate(): HTMLTemplateResult | typeof nothing {\r\n return this.showTouchBackdrop\r\n ? html`<div\r\n id=\"touch-backdrop\"\r\n @touchstart=${this.handleBackdropInteraction}\r\n @touchmove=${this.handleBackdropInteraction}\r\n @touchend=${this.handleBackdropInteraction}\r\n @touchcancel=${this.handleBackdropInteraction}\r\n @mouseenter=${(e: MouseEvent) => e.stopPropagation()}\r\n @mousemove=${(e: MouseEvent) => e.stopPropagation()}\r\n @mouseleave=${(e: MouseEvent) => e.stopPropagation()}\r\n ></div>`\r\n : nothing;\r\n }\r\n\r\n private get showTouchBackdrop(): boolean {\r\n return (\r\n (this.isTouchEnabled && this.enableLongPress) || this.forceTouchBackdrop\r\n );\r\n }\r\n\r\n /** Whether to use the mobile layout */\r\n private get isMobileView(): boolean {\r\n return !!this.mobileBreakpoint && window.innerWidth < this.mobileBreakpoint;\r\n }\r\n\r\n private get isHoverEnabled(): boolean {\r\n return window.matchMedia('(hover: hover)').matches;\r\n }\r\n\r\n private get isTouchEnabled(): boolean {\r\n return (\r\n 'ontouchstart' in window &&\r\n window.matchMedia('(any-pointer: coarse)').matches\r\n );\r\n }\r\n\r\n /** Whether this controller should currently render its hover pane. */\r\n private get shouldRenderHoverPane(): boolean {\r\n return this.hoverPaneState !== 'hidden';\r\n }\r\n\r\n /**\r\n * Returns the desired top/left offsets (in pixels) for this tile's hover pane.\r\n * The desired offsets balance positioning the hover pane under the primary pointer\r\n * while preventing it from flowing outside the viewport. The returned offsets are\r\n * relative to the viewport, intended to position the pane as a popover element.\r\n *\r\n * These offsets are only valid if the hover pane is already rendered with its\r\n * correct width and height. If the hover pane is not present, the returned offsets\r\n * will simply represent the current pointer position.\r\n */\r\n private get hoverPaneDesiredOffsets(): { top: number; left: number } {\r\n // Try to find offsets for the hover pane that:\r\n // (a) cause it to lie entirely within the viewport, and\r\n // (b) to the extent possible, minimize the distance between the\r\n // nearest corner of the hover pane and the mouse position\r\n // (with some additional offsets applied after the fact).\r\n\r\n let [left, top] = [\r\n this.lastPointerClientPos.x,\r\n this.lastPointerClientPos.y,\r\n ];\r\n\r\n // Flip the hover pane according to which quadrant of the viewport the mouse is in.\r\n // (Similar to how Wikipedia's link hover panes work)\r\n const flipHorizontal = this.lastPointerClientPos.x > window.innerWidth / 2;\r\n const flipVertical = this.lastPointerClientPos.y > window.innerHeight / 2;\r\n\r\n const hoverPaneRect = this.hoverPane?.getBoundingClientRect();\r\n if (hoverPaneRect) {\r\n // If we need to flip the hover pane, do so by subtracting its width/height from left/top\r\n if (flipHorizontal) {\r\n left -= hoverPaneRect.width;\r\n }\r\n if (flipVertical) {\r\n top -= hoverPaneRect.height;\r\n }\r\n\r\n // Apply desired offsets from the mouse position\r\n left += (flipHorizontal ? -1 : 1) * this.offsetX;\r\n top += (flipVertical ? -1 : 1) * this.offsetY;\r\n\r\n // On mobile view, shunt the hover pane to avoid overflowing the viewport\r\n if (this.isMobileView) {\r\n left = clamp(left, 20, window.innerWidth - hoverPaneRect.width - 20);\r\n top = clamp(top, 20, window.innerHeight - hoverPaneRect.height - 20);\r\n }\r\n }\r\n\r\n left += window.scrollX;\r\n top += window.scrollY;\r\n\r\n return { left, top };\r\n }\r\n\r\n /**\r\n * Adds to the host element all the listeners necessary to make the\r\n * hover pane functional.\r\n */\r\n private attachListeners(): void {\r\n if (this.isHoverEnabled) {\r\n this.host.addEventListener('mouseenter', this.handleMouseEnter);\r\n this.host.addEventListener('mousemove', this.handleMouseMove);\r\n this.host.addEventListener('mouseleave', this.handleMouseLeave);\r\n }\r\n\r\n if (this.isTouchEnabled && this.enableLongPress) {\r\n this.host.addEventListener('touchstart', this.handleTouchStart);\r\n this.host.addEventListener('touchmove', this.handleLongPressCancel);\r\n this.host.addEventListener('touchend', this.handleLongPressCancel);\r\n this.host.addEventListener('touchcancel', this.handleLongPressCancel);\r\n this.host.addEventListener('contextmenu', this.handleContextMenu);\r\n }\r\n }\r\n\r\n /**\r\n * Removes all the hover pane listeners from the host element.\r\n */\r\n private detachListeners(): void {\r\n this.host.removeEventListener('mouseenter', this.handleMouseEnter);\r\n this.host.removeEventListener('mousemove', this.handleMouseMove);\r\n this.host.removeEventListener('mouseleave', this.handleMouseLeave);\r\n this.host.removeEventListener('touchstart', this.handleTouchStart);\r\n this.host.removeEventListener('touchmove', this.handleLongPressCancel);\r\n this.host.removeEventListener('touchend', this.handleLongPressCancel);\r\n this.host.removeEventListener('touchcancel', this.handleLongPressCancel);\r\n this.host.removeEventListener('contextmenu', this.handleContextMenu);\r\n }\r\n\r\n /**\r\n * Handler for the mouseenter event on the host element.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleMouseEnter = (e: MouseEvent): void => {\r\n // Delegate to the mousemove handler, as they are currently processed identically\r\n this.handleMouseMove(e);\r\n };\r\n\r\n /**\r\n * Handler for the mousemove event on the host element.\r\n * Aborts any pending hide/fade-out for the hover pane, and restarts the\r\n * timer to show it.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleMouseMove = (e: MouseEvent): void => {\r\n // The mouse is within the tile, so abort any pending removal of the hover pane\r\n clearTimeout(this.hideTimer);\r\n\r\n // If the hover pane is currently fading out, just make it fade back in where it is\r\n if (this.hoverPaneState === 'fading-out') {\r\n this.hoverPaneState = 'shown';\r\n this.hoverPane?.classList.add('fade-in');\r\n }\r\n\r\n // Restart the timer to show the hover pane anytime the mouse moves within the tile\r\n if (this.hoverPaneState === 'hidden') {\r\n this.restartShowHoverPaneTimer();\r\n this.lastPointerClientPos = { x: e.clientX, y: e.clientY };\r\n }\r\n };\r\n\r\n /**\r\n * Handler for the mouseleave event on the host element.\r\n * Hides the hover pane if present, and aborts the timer for showing it.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleMouseLeave = (): void => {\r\n // Abort any timer to show the hover pane, as the mouse has left the tile\r\n clearTimeout(this.showTimer);\r\n\r\n // Hide the hover pane if it's already been shown\r\n clearTimeout(this.hideTimer);\r\n if (this.hoverPaneState !== 'hidden') {\r\n this.hideTimer = window.setTimeout(() => {\r\n this.fadeOutHoverPane();\r\n }, this.hideDelay);\r\n }\r\n };\r\n\r\n /**\r\n * Handler for the touchstart event on the host element.\r\n * Begins the timer for recognizing a long press event.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleTouchStart = (e: TouchEvent): void => {\r\n clearTimeout(this.longPressTimer);\r\n\r\n if (e.touches.length === 1) {\r\n this.longPressTimer = window.setTimeout(() => {\r\n if (this.hoverPaneState === 'hidden') {\r\n this.showHoverPane();\r\n }\r\n }, this.longPressDelay);\r\n\r\n this.lastPointerClientPos = {\r\n x: e.touches[0].clientX,\r\n y: e.touches[0].clientY,\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Handler for events that should cancel a pending long press event\r\n * (touchmove, touchend, touchcancel). Aborts the timer for recognizing\r\n * a long press.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleLongPressCancel = (): void => {\r\n clearTimeout(this.longPressTimer);\r\n };\r\n\r\n /**\r\n * Handler for the contextmenu event, which should be suppressed during\r\n * mobile long-press events on the host element.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleContextMenu = (e: Event): void => {\r\n e.preventDefault();\r\n };\r\n\r\n /**\r\n * Immediately causes the hover pane to begin fading out, if it is present.\r\n */\r\n // NB: Arrow function so 'this' remains bound to the controller\r\n private handleBackdropInteraction = (e: Event): void => {\r\n if (this.hoverPaneState !== 'hidden') {\r\n this.fadeOutHoverPane();\r\n }\r\n e.stopPropagation();\r\n };\r\n\r\n /**\r\n * Aborts and restarts the timer for showing the hover pane.\r\n */\r\n private restartShowHoverPaneTimer(): void {\r\n clearTimeout(this.showTimer);\r\n this.showTimer = window.setTimeout(() => {\r\n this.showHoverPane();\r\n }, this.showDelay);\r\n }\r\n\r\n /**\r\n * Causes this tile's hover pane to be rendered, positioned, and made visible.\r\n */\r\n private async showHoverPane(): Promise<void> {\r\n this.hoverPaneState = 'shown';\r\n this.host.requestUpdate();\r\n\r\n // Wait for the state update to render the hover pane\r\n await this.host.updateComplete;\r\n\r\n // Ensure the hover pane element is still in the document before showing,\r\n // as it might have been removed by the previous update.\r\n if (!this.hoverPane?.isConnected) return;\r\n\r\n this.hoverPane?.showPopover?.();\r\n await new Promise(resolve => {\r\n // Pane sizes aren't accurate until next frame\r\n requestAnimationFrame(resolve);\r\n });\r\n\r\n // Apply the correct positioning to the hover pane\r\n this.repositionHoverPane();\r\n\r\n // The hover pane is initially not visible (to avoid it shifting around\r\n // while being positioned). Since it now has the correct positioning, we\r\n // can make it visible and begin its fade-in animation.\r\n this.hoverPane?.classList.add('visible', 'fade-in');\r\n }\r\n\r\n /**\r\n * Causes this tile's hover pane to begin fading out and starts\r\n * the timer for it to be removed.\r\n */\r\n private fadeOutHoverPane(): void {\r\n this.hoverPaneState = 'fading-out';\r\n this.hoverPane?.classList.remove('fade-in');\r\n\r\n clearTimeout(this.hideTimer);\r\n this.hideTimer = window.setTimeout(() => {\r\n this.hoverPaneState = 'hidden';\r\n this.host.requestUpdate();\r\n }, 100);\r\n }\r\n\r\n /**\r\n * Positions the hover pane with the correct offsets.\r\n */\r\n private repositionHoverPane(): void {\r\n if (!this.hoverPane) return;\r\n\r\n const { top, left } = this.hoverPaneDesiredOffsets;\r\n this.hoverPane.style.top = `${top}px`;\r\n this.hoverPane.style.left = `${left}px`;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"hover-pane-controller.js","sourceRoot":"","sources":["../../../../src/tiles/hover/hover-pane-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SortParam } from '@internetarchive/search-service';\nimport {\n html,\n HTMLTemplateResult,\n nothing,\n ReactiveController,\n ReactiveControllerHost,\n} from 'lit';\nimport type { TileModel } from '../../models';\nimport type { CollectionTitles } from '../../data-source/models';\n\ntype HoverPaneState = 'hidden' | 'shown' | 'fading-out';\n\nexport interface HoverPaneProperties {\n model?: TileModel;\n baseNavigationUrl?: string;\n baseImageUrl?: string;\n loggedIn: boolean;\n suppressBlurring: boolean;\n sortParam: SortParam | null;\n collectionTitles?: CollectionTitles;\n}\n\nexport interface HoverPaneControllerOptions {\n offsetX?: number;\n offsetY?: number;\n enableLongPress?: boolean;\n showDelay?: number;\n hideDelay?: number;\n longPressDelay?: number;\n mobileBreakpoint?: number;\n}\n\n/** A common interface for providing a hover pane element. */\nexport interface HoverPaneProviderInterface {\n /** Returns the provider's currently rendered hover pane element. */\n getHoverPane(): HTMLElement | undefined;\n /** Returns properties that should be passed to the hover pane. */\n getHoverPaneProps(): HoverPaneProperties;\n}\n\nexport interface ToggleHoverPaneOptions {\n coords: { x: number; y: number };\n enableTouchBackdrop?: boolean;\n}\n\n/**\n * An interface for interacting with hover pane controllers (e.g.,\n * to retrieve their current hover pane template).\n */\nexport interface HoverPaneControllerInterface extends ReactiveController {\n /**\n * Returns the hover pane template to render based on this controller's\n * current state. The returned template may be `nothing` if the hover\n * pane should not currently be rendered.\n */\n getTemplate(): HTMLTemplateResult | typeof nothing;\n\n /**\n * Requests to manually toggle the state of the hover pane.\n * If the hover pane is already shown, it will begin fading out and then\n * subsequently be hidden and removed. If the hover pane is already fading\n * out or hidden, it will fade back in and be shown.\n */\n toggleHoverPane(options: ToggleHoverPaneOptions): void;\n}\n\nconst clamp = (val: number, min = -Infinity, max = Infinity) =>\n Math.max(min, Math.min(val, max));\n\nexport class HoverPaneController implements HoverPaneControllerInterface {\n /**\n * The hover pane element attached to this controller's host.\n */\n private hoverPane?: HTMLElement;\n\n /**\n * The properties to be passed to the hover pane element\n */\n private hoverPaneProps?: HoverPaneProperties;\n\n /**\n * The breakpoint (in pixels) below which the mobile interface should be used.\n */\n private mobileBreakpoint?: number = 600;\n\n /**\n * The number of horizontal pixels the hover pane should be offset from the\n * pointer position.\n */\n private offsetX: number = -10;\n\n /**\n * The number of vertical pixels the hover pane should be offset from the\n * pointer position.\n */\n private offsetY: number = 15;\n\n /**\n * The delay between the mouse idling within the host element and when the hover\n * pane should begin fading in (in milliseconds).\n */\n private showDelay: number = 300;\n\n /**\n * The delay between when the mouse leaves the host element and when the hover\n * pane should begin fading out (in milliseconds).\n */\n private hideDelay: number = 100;\n\n /**\n * The delay between when a touch event begins on the host element and when the\n * hover pane should begin fading in (in milliseconds).\n */\n private longPressDelay: number = 600;\n\n /**\n * Whether long press interactions should cause the hover pane to appear (when\n * below the mobile breakpoint).\n */\n private enableLongPress: boolean = false;\n\n /**\n * Used to control the current state of this provider's hover pane.\n * - `'hidden'` => The hover pane is not present at all.\n * - `'shown'` => The hover pane is either fading in or fully visible.\n * - `'fading-out'` => The hover pane is fading out and about to be removed.\n */\n private hoverPaneState: HoverPaneState = 'hidden';\n\n /** The timer ID for showing the hover pane */\n private showTimer?: number;\n\n /** The timer ID for hiding the hover pane */\n private hideTimer?: number;\n\n /** The timer ID for recognizing a long press event */\n private longPressTimer?: number;\n\n /**\n * Whether the touch backdrop should currently be rendered irrespective of other touch\n * interactions being enabled.\n */\n private forceTouchBackdrop: boolean = false;\n\n /** A record of the last mouse position on the host element, for positioning the hover pane */\n private lastPointerClientPos = { x: 0, y: 0 };\n\n constructor(\n /** The host element to which this controller should attach listeners */\n private readonly host: ReactiveControllerHost &\n HoverPaneProviderInterface &\n HTMLElement,\n /** Options for adjusting the hover pane behavior (offsets, delays, etc.) */\n options: HoverPaneControllerOptions = {},\n ) {\n this.mobileBreakpoint = options.mobileBreakpoint ?? this.mobileBreakpoint;\n this.offsetX = options.offsetX ?? this.offsetX;\n this.offsetY = options.offsetY ?? this.offsetY;\n this.showDelay = options.showDelay ?? this.showDelay;\n this.hideDelay = options.hideDelay ?? this.hideDelay;\n this.longPressDelay = options.longPressDelay ?? this.longPressDelay;\n this.enableLongPress = options.enableLongPress ?? this.enableLongPress;\n\n this.host.addController(this);\n }\n\n hostConnected(): void {\n this.attachListeners();\n }\n\n hostDisconnected(): void {\n this.detachListeners();\n }\n\n hostUpdated(): void {\n this.hoverPane = this.host.getHoverPane();\n this.hoverPaneProps = this.host.getHoverPaneProps();\n }\n\n /** @inheritdoc */\n getTemplate(): HTMLTemplateResult | typeof nothing {\n this.hoverPaneProps = this.host.getHoverPaneProps();\n\n return this.shouldRenderHoverPane\n ? html` ${this.touchBackdropTemplate}\n <tile-hover-pane\n popover\n .model=${this.hoverPaneProps?.model}\n .baseNavigationUrl=${this.hoverPaneProps?.baseNavigationUrl}\n .baseImageUrl=${this.hoverPaneProps?.baseImageUrl}\n .loggedIn=${this.hoverPaneProps?.loggedIn}\n .suppressBlurring=${this.hoverPaneProps?.suppressBlurring}\n .sortParam=${this.hoverPaneProps?.sortParam}\n .collectionTitles=${this.hoverPaneProps?.collectionTitles}\n .mobileBreakpoint=${this.mobileBreakpoint}\n .currentWidth=${window.innerWidth}\n ></tile-hover-pane>`\n : nothing;\n }\n\n /** @inheritdoc */\n toggleHoverPane(options: ToggleHoverPaneOptions): void {\n if (this.hoverPaneState === 'shown') {\n this.fadeOutHoverPane();\n this.forceTouchBackdrop = false;\n } else {\n this.lastPointerClientPos = options.coords;\n this.forceTouchBackdrop = options.enableTouchBackdrop ?? false;\n this.showHoverPane();\n }\n }\n\n /**\n * Produces a template for the invisible touch capture backdrop that\n * is used to cancel the hover pane on touch devices. We want any\n * touch interaction on the backdrop to remove the hover pane, and\n * we don't want to bubble up mouse events that would otherwise\n * affect the state of the hover pane (e.g., fading it back in).\n */\n private get touchBackdropTemplate(): HTMLTemplateResult | typeof nothing {\n return this.showTouchBackdrop\n ? html`<div\n id=\"touch-backdrop\"\n @touchstart=${this.handleBackdropInteraction}\n @touchmove=${this.handleBackdropInteraction}\n @touchend=${this.handleBackdropInteraction}\n @touchcancel=${this.handleBackdropInteraction}\n @mouseenter=${(e: MouseEvent) => e.stopPropagation()}\n @mousemove=${(e: MouseEvent) => e.stopPropagation()}\n @mouseleave=${(e: MouseEvent) => e.stopPropagation()}\n ></div>`\n : nothing;\n }\n\n private get showTouchBackdrop(): boolean {\n return (\n (this.isTouchEnabled && this.enableLongPress) || this.forceTouchBackdrop\n );\n }\n\n /** Whether to use the mobile layout */\n private get isMobileView(): boolean {\n return !!this.mobileBreakpoint && window.innerWidth < this.mobileBreakpoint;\n }\n\n private get isHoverEnabled(): boolean {\n return window.matchMedia('(hover: hover)').matches;\n }\n\n private get isTouchEnabled(): boolean {\n return (\n 'ontouchstart' in window &&\n window.matchMedia('(any-pointer: coarse)').matches\n );\n }\n\n /** Whether this controller should currently render its hover pane. */\n private get shouldRenderHoverPane(): boolean {\n return this.hoverPaneState !== 'hidden';\n }\n\n /**\n * Returns the desired top/left offsets (in pixels) for this tile's hover pane.\n * The desired offsets balance positioning the hover pane under the primary pointer\n * while preventing it from flowing outside the viewport. The returned offsets are\n * relative to the viewport, intended to position the pane as a popover element.\n *\n * These offsets are only valid if the hover pane is already rendered with its\n * correct width and height. If the hover pane is not present, the returned offsets\n * will simply represent the current pointer position.\n */\n private get hoverPaneDesiredOffsets(): { top: number; left: number } {\n // Try to find offsets for the hover pane that:\n // (a) cause it to lie entirely within the viewport, and\n // (b) to the extent possible, minimize the distance between the\n // nearest corner of the hover pane and the mouse position\n // (with some additional offsets applied after the fact).\n\n let [left, top] = [\n this.lastPointerClientPos.x,\n this.lastPointerClientPos.y,\n ];\n\n // Flip the hover pane according to which quadrant of the viewport the mouse is in.\n // (Similar to how Wikipedia's link hover panes work)\n const flipHorizontal = this.lastPointerClientPos.x > window.innerWidth / 2;\n const flipVertical = this.lastPointerClientPos.y > window.innerHeight / 2;\n\n const hoverPaneRect = this.hoverPane?.getBoundingClientRect();\n if (hoverPaneRect) {\n // If we need to flip the hover pane, do so by subtracting its width/height from left/top\n if (flipHorizontal) {\n left -= hoverPaneRect.width;\n }\n if (flipVertical) {\n top -= hoverPaneRect.height;\n }\n\n // Apply desired offsets from the mouse position\n left += (flipHorizontal ? -1 : 1) * this.offsetX;\n top += (flipVertical ? -1 : 1) * this.offsetY;\n\n // On mobile view, shunt the hover pane to avoid overflowing the viewport\n if (this.isMobileView) {\n left = clamp(left, 20, window.innerWidth - hoverPaneRect.width - 20);\n top = clamp(top, 20, window.innerHeight - hoverPaneRect.height - 20);\n }\n }\n\n left += window.scrollX;\n top += window.scrollY;\n\n return { left, top };\n }\n\n /**\n * Adds to the host element all the listeners necessary to make the\n * hover pane functional.\n */\n private attachListeners(): void {\n if (this.isHoverEnabled) {\n this.host.addEventListener('mouseenter', this.handleMouseEnter);\n this.host.addEventListener('mousemove', this.handleMouseMove);\n this.host.addEventListener('mouseleave', this.handleMouseLeave);\n }\n\n if (this.isTouchEnabled && this.enableLongPress) {\n this.host.addEventListener('touchstart', this.handleTouchStart);\n this.host.addEventListener('touchmove', this.handleLongPressCancel);\n this.host.addEventListener('touchend', this.handleLongPressCancel);\n this.host.addEventListener('touchcancel', this.handleLongPressCancel);\n this.host.addEventListener('contextmenu', this.handleContextMenu);\n }\n }\n\n /**\n * Removes all the hover pane listeners from the host element.\n */\n private detachListeners(): void {\n this.host.removeEventListener('mouseenter', this.handleMouseEnter);\n this.host.removeEventListener('mousemove', this.handleMouseMove);\n this.host.removeEventListener('mouseleave', this.handleMouseLeave);\n this.host.removeEventListener('touchstart', this.handleTouchStart);\n this.host.removeEventListener('touchmove', this.handleLongPressCancel);\n this.host.removeEventListener('touchend', this.handleLongPressCancel);\n this.host.removeEventListener('touchcancel', this.handleLongPressCancel);\n this.host.removeEventListener('contextmenu', this.handleContextMenu);\n }\n\n /**\n * Handler for the mouseenter event on the host element.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseEnter = (e: MouseEvent): void => {\n // Delegate to the mousemove handler, as they are currently processed identically\n this.handleMouseMove(e);\n };\n\n /**\n * Handler for the mousemove event on the host element.\n * Aborts any pending hide/fade-out for the hover pane, and restarts the\n * timer to show it.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseMove = (e: MouseEvent): void => {\n // The mouse is within the tile, so abort any pending removal of the hover pane\n clearTimeout(this.hideTimer);\n\n // If the hover pane is currently fading out, just make it fade back in where it is\n if (this.hoverPaneState === 'fading-out') {\n this.hoverPaneState = 'shown';\n this.hoverPane?.classList.add('fade-in');\n }\n\n // Restart the timer to show the hover pane anytime the mouse moves within the tile\n if (this.hoverPaneState === 'hidden') {\n this.restartShowHoverPaneTimer();\n this.lastPointerClientPos = { x: e.clientX, y: e.clientY };\n }\n };\n\n /**\n * Handler for the mouseleave event on the host element.\n * Hides the hover pane if present, and aborts the timer for showing it.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseLeave = (): void => {\n // Abort any timer to show the hover pane, as the mouse has left the tile\n clearTimeout(this.showTimer);\n\n // Hide the hover pane if it's already been shown\n clearTimeout(this.hideTimer);\n if (this.hoverPaneState !== 'hidden') {\n this.hideTimer = window.setTimeout(() => {\n this.fadeOutHoverPane();\n }, this.hideDelay);\n }\n };\n\n /**\n * Handler for the touchstart event on the host element.\n * Begins the timer for recognizing a long press event.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleTouchStart = (e: TouchEvent): void => {\n clearTimeout(this.longPressTimer);\n\n if (e.touches.length === 1) {\n this.longPressTimer = window.setTimeout(() => {\n if (this.hoverPaneState === 'hidden') {\n this.showHoverPane();\n }\n }, this.longPressDelay);\n\n this.lastPointerClientPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n }\n };\n\n /**\n * Handler for events that should cancel a pending long press event\n * (touchmove, touchend, touchcancel). Aborts the timer for recognizing\n * a long press.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleLongPressCancel = (): void => {\n clearTimeout(this.longPressTimer);\n };\n\n /**\n * Handler for the contextmenu event, which should be suppressed during\n * mobile long-press events on the host element.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleContextMenu = (e: Event): void => {\n e.preventDefault();\n };\n\n /**\n * Immediately causes the hover pane to begin fading out, if it is present.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleBackdropInteraction = (e: Event): void => {\n if (this.hoverPaneState !== 'hidden') {\n this.fadeOutHoverPane();\n }\n e.stopPropagation();\n };\n\n /**\n * Aborts and restarts the timer for showing the hover pane.\n */\n private restartShowHoverPaneTimer(): void {\n clearTimeout(this.showTimer);\n this.showTimer = window.setTimeout(() => {\n this.showHoverPane();\n }, this.showDelay);\n }\n\n /**\n * Causes this tile's hover pane to be rendered, positioned, and made visible.\n */\n private async showHoverPane(): Promise<void> {\n this.hoverPaneState = 'shown';\n this.host.requestUpdate();\n\n // Wait for the state update to render the hover pane\n await this.host.updateComplete;\n\n // Ensure the hover pane element is still in the document before showing,\n // as it might have been removed by the previous update.\n if (!this.hoverPane?.isConnected) return;\n\n this.hoverPane?.showPopover?.();\n await new Promise(resolve => {\n // Pane sizes aren't accurate until next frame\n requestAnimationFrame(resolve);\n });\n\n // Apply the correct positioning to the hover pane\n this.repositionHoverPane();\n\n // The hover pane is initially not visible (to avoid it shifting around\n // while being positioned). Since it now has the correct positioning, we\n // can make it visible and begin its fade-in animation.\n this.hoverPane?.classList.add('visible', 'fade-in');\n }\n\n /**\n * Causes this tile's hover pane to begin fading out and starts\n * the timer for it to be removed.\n */\n private fadeOutHoverPane(): void {\n this.hoverPaneState = 'fading-out';\n this.hoverPane?.classList.remove('fade-in');\n\n clearTimeout(this.hideTimer);\n this.hideTimer = window.setTimeout(() => {\n this.hoverPaneState = 'hidden';\n this.host.requestUpdate();\n }, 100);\n }\n\n /**\n * Positions the hover pane with the correct offsets.\n */\n private repositionHoverPane(): void {\n if (!this.hoverPane) return;\n\n const { top, left } = this.hoverPaneDesiredOffsets;\n this.hoverPane.style.top = `${top}px`;\n this.hoverPane.style.left = `${left}px`;\n }\n}\n"]}