@internetarchive/collection-browser 3.4.1-alpha-webdev7761.2 → 3.4.1-alpha-webdev7761.4

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 (208) hide show
  1. package/dist/src/app-root.js +19 -28
  2. package/dist/src/app-root.js.map +1 -1
  3. package/dist/src/collection-browser.d.ts +14 -10
  4. package/dist/src/collection-browser.js +870 -886
  5. package/dist/src/collection-browser.js.map +1 -1
  6. package/dist/src/collection-facets/facet-row.js +3 -4
  7. package/dist/src/collection-facets/facet-row.js.map +1 -1
  8. package/dist/src/collection-facets/models.js.map +1 -1
  9. package/dist/src/collection-facets/more-facets-content.js +145 -156
  10. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  11. package/dist/src/collection-facets/more-facets-pagination.js +6 -10
  12. package/dist/src/collection-facets/more-facets-pagination.js.map +1 -1
  13. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.js +16 -21
  14. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.js.map +1 -1
  15. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +7 -10
  16. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  17. package/dist/src/collection-facets/smart-facets/smart-facet-button.js +3 -2
  18. package/dist/src/collection-facets/smart-facets/smart-facet-button.js.map +1 -1
  19. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js +9 -11
  20. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.js.map +1 -1
  21. package/dist/src/collection-facets/smart-facets/smart-facet-heuristics.js +7 -7
  22. package/dist/src/collection-facets/smart-facets/smart-facet-heuristics.js.map +1 -1
  23. package/dist/src/collection-facets/toggle-switch.js +4 -6
  24. package/dist/src/collection-facets/toggle-switch.js.map +1 -1
  25. package/dist/src/collection-facets.js +34 -50
  26. package/dist/src/collection-facets.js.map +1 -1
  27. package/dist/src/combo-box/caret-closed.js +5 -11
  28. package/dist/src/combo-box/caret-closed.js.map +1 -1
  29. package/dist/src/combo-box/caret-open.js +5 -11
  30. package/dist/src/combo-box/caret-open.js.map +1 -1
  31. package/dist/src/combo-box/clear.d.ts +2 -0
  32. package/dist/src/combo-box/clear.js +11 -0
  33. package/dist/src/combo-box/clear.js.map +1 -0
  34. package/dist/src/combo-box/ia-combo-box.d.ts +40 -9
  35. package/dist/src/combo-box/ia-combo-box.js +363 -272
  36. package/dist/src/combo-box/ia-combo-box.js.map +1 -1
  37. package/dist/src/combo-box/models.d.ts +14 -0
  38. package/dist/src/combo-box/models.js +32 -1
  39. package/dist/src/combo-box/models.js.map +1 -1
  40. package/dist/src/data-source/collection-browser-data-source.js +35 -47
  41. package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
  42. package/dist/src/empty-placeholder.js +19 -18
  43. package/dist/src/empty-placeholder.js.map +1 -1
  44. package/dist/src/expanded-date-picker.js +6 -10
  45. package/dist/src/expanded-date-picker.js.map +1 -1
  46. package/dist/src/language-code-handler/language-code-handler.js +2 -2
  47. package/dist/src/language-code-handler/language-code-handler.js.map +1 -1
  48. package/dist/src/manage/manage-bar.js +86 -92
  49. package/dist/src/manage/manage-bar.js.map +1 -1
  50. package/dist/src/manage/remove-items-modal-content.js +2 -2
  51. package/dist/src/manage/remove-items-modal-content.js.map +1 -1
  52. package/dist/src/models.js +36 -40
  53. package/dist/src/models.js.map +1 -1
  54. package/dist/src/restoration-state-handler.js +9 -10
  55. package/dist/src/restoration-state-handler.js.map +1 -1
  56. package/dist/src/sort-filter-bar/alpha-bar.js +9 -14
  57. package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
  58. package/dist/src/sort-filter-bar/sort-filter-bar.js +14 -24
  59. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  60. package/dist/src/tiles/base-tile-component.js +1 -2
  61. package/dist/src/tiles/base-tile-component.js.map +1 -1
  62. package/dist/src/tiles/grid/account-tile.js +36 -38
  63. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  64. package/dist/src/tiles/grid/collection-tile.js +79 -82
  65. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  66. package/dist/src/tiles/grid/item-tile.js +154 -164
  67. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  68. package/dist/src/tiles/grid/search-tile.js +42 -43
  69. package/dist/src/tiles/grid/search-tile.js.map +1 -1
  70. package/dist/src/tiles/grid/styles/tile-grid-shared-styles.js +119 -119
  71. package/dist/src/tiles/grid/styles/tile-grid-shared-styles.js.map +1 -1
  72. package/dist/src/tiles/grid/tile-stats.js +2 -3
  73. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  74. package/dist/src/tiles/hover/hover-pane-controller.js +42 -49
  75. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  76. package/dist/src/tiles/hover/tile-hover-pane.js +113 -114
  77. package/dist/src/tiles/hover/tile-hover-pane.js.map +1 -1
  78. package/dist/src/tiles/image-block.js +5 -8
  79. package/dist/src/tiles/image-block.js.map +1 -1
  80. package/dist/src/tiles/item-image.js +12 -19
  81. package/dist/src/tiles/item-image.js.map +1 -1
  82. package/dist/src/tiles/list/tile-list-compact.js +114 -122
  83. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  84. package/dist/src/tiles/list/tile-list.js +326 -347
  85. package/dist/src/tiles/list/tile-list.js.map +1 -1
  86. package/dist/src/tiles/overlay/icon-overlay.js +1 -2
  87. package/dist/src/tiles/overlay/icon-overlay.js.map +1 -1
  88. package/dist/src/tiles/overlay/text-overlay.js +2 -4
  89. package/dist/src/tiles/overlay/text-overlay.js.map +1 -1
  90. package/dist/src/tiles/text-snippet-block.js +2 -4
  91. package/dist/src/tiles/text-snippet-block.js.map +1 -1
  92. package/dist/src/tiles/tile-dispatcher.js +233 -241
  93. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  94. package/dist/src/tiles/tile-display-value-provider.js +5 -9
  95. package/dist/src/tiles/tile-display-value-provider.js.map +1 -1
  96. package/dist/src/tiles/tile-mediatype-icon.js +12 -19
  97. package/dist/src/tiles/tile-mediatype-icon.js.map +1 -1
  98. package/dist/src/utils/collapse-repeated-quotes.js +1 -1
  99. package/dist/src/utils/collapse-repeated-quotes.js.map +1 -1
  100. package/dist/src/utils/facet-utils.js +3 -5
  101. package/dist/src/utils/facet-utils.js.map +1 -1
  102. package/dist/src/utils/format-count.js +10 -10
  103. package/dist/src/utils/format-count.js.map +1 -1
  104. package/dist/src/utils/format-date.js.map +1 -1
  105. package/dist/src/utils/resolve-mediatype.js +2 -3
  106. package/dist/src/utils/resolve-mediatype.js.map +1 -1
  107. package/dist/test/collection-browser.test.js +131 -185
  108. package/dist/test/collection-browser.test.js.map +1 -1
  109. package/dist/test/collection-facets/facet-row.test.js +60 -75
  110. package/dist/test/collection-facets/facet-row.test.js.map +1 -1
  111. package/dist/test/collection-facets/facets-template.test.js +17 -23
  112. package/dist/test/collection-facets/facets-template.test.js.map +1 -1
  113. package/dist/test/collection-facets/more-facets-content.test.js +22 -32
  114. package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
  115. package/dist/test/collection-facets/more-facets-pagination.test.js +16 -22
  116. package/dist/test/collection-facets/more-facets-pagination.test.js.map +1 -1
  117. package/dist/test/collection-facets/toggle-switch.test.js +22 -19
  118. package/dist/test/collection-facets/toggle-switch.test.js.map +1 -1
  119. package/dist/test/collection-facets.test.js +80 -97
  120. package/dist/test/collection-facets.test.js.map +1 -1
  121. package/dist/test/empty-placeholder.test.js +11 -17
  122. package/dist/test/empty-placeholder.test.js.map +1 -1
  123. package/dist/test/expanded-date-picker.test.js +8 -14
  124. package/dist/test/expanded-date-picker.test.js.map +1 -1
  125. package/dist/test/icon-overlay.test.js +7 -6
  126. package/dist/test/icon-overlay.test.js.map +1 -1
  127. package/dist/test/image-block.test.js +16 -26
  128. package/dist/test/image-block.test.js.map +1 -1
  129. package/dist/test/item-image.test.js +23 -32
  130. package/dist/test/item-image.test.js.map +1 -1
  131. package/dist/test/manage/manage-bar.test.js +21 -33
  132. package/dist/test/manage/manage-bar.test.js.map +1 -1
  133. package/dist/test/manage/remove-items-modal-content.test.js +10 -15
  134. package/dist/test/manage/remove-items-modal-content.test.js.map +1 -1
  135. package/dist/test/mocks/mock-search-service.js +2 -3
  136. package/dist/test/mocks/mock-search-service.js.map +1 -1
  137. package/dist/test/restoration-state-handler.test.js +13 -21
  138. package/dist/test/restoration-state-handler.test.js.map +1 -1
  139. package/dist/test/review-block.test.js +16 -18
  140. package/dist/test/review-block.test.js.map +1 -1
  141. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js +2 -3
  142. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js.map +1 -1
  143. package/dist/test/sort-filter-bar/alpha-bar.test.js +18 -24
  144. package/dist/test/sort-filter-bar/alpha-bar.test.js.map +1 -1
  145. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +178 -180
  146. package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +1 -1
  147. package/dist/test/text-overlay.test.js +16 -15
  148. package/dist/test/text-overlay.test.js.map +1 -1
  149. package/dist/test/text-snippet-block.test.js +14 -19
  150. package/dist/test/text-snippet-block.test.js.map +1 -1
  151. package/dist/test/tile-stats.test.js +73 -34
  152. package/dist/test/tile-stats.test.js.map +1 -1
  153. package/dist/test/tiles/grid/account-tile.test.js +25 -25
  154. package/dist/test/tiles/grid/account-tile.test.js.map +1 -1
  155. package/dist/test/tiles/grid/collection-tile.test.js +13 -19
  156. package/dist/test/tiles/grid/collection-tile.test.js.map +1 -1
  157. package/dist/test/tiles/grid/item-tile.test.js +141 -168
  158. package/dist/test/tiles/grid/item-tile.test.js.map +1 -1
  159. package/dist/test/tiles/grid/search-tile.test.js +9 -13
  160. package/dist/test/tiles/grid/search-tile.test.js.map +1 -1
  161. package/dist/test/tiles/hover/hover-pane-controller.test.js +50 -62
  162. package/dist/test/tiles/hover/hover-pane-controller.test.js.map +1 -1
  163. package/dist/test/tiles/hover/tile-hover-pane.test.js +12 -16
  164. package/dist/test/tiles/hover/tile-hover-pane.test.js.map +1 -1
  165. package/dist/test/tiles/list/tile-list-compact.test.js +104 -118
  166. package/dist/test/tiles/list/tile-list-compact.test.js.map +1 -1
  167. package/dist/test/tiles/list/tile-list.test.js +202 -231
  168. package/dist/test/tiles/list/tile-list.test.js.map +1 -1
  169. package/dist/test/tiles/tile-dispatcher.test.js +97 -110
  170. package/dist/test/tiles/tile-dispatcher.test.js.map +1 -1
  171. package/dist/test/tiles/tile-mediatype-icon.test.js +12 -24
  172. package/dist/test/tiles/tile-mediatype-icon.test.js.map +1 -1
  173. package/dist/test/utils/format-date.test.js.map +1 -1
  174. package/index.html +1 -1
  175. package/package.json +5 -3
  176. package/src/collection-browser.ts +3060 -3030
  177. package/src/collection-facets/models.ts +10 -10
  178. package/src/collection-facets/more-facets-content.ts +639 -639
  179. package/src/collection-facets.ts +1 -1
  180. package/src/combo-box/caret-closed.ts +5 -11
  181. package/src/combo-box/caret-open.ts +5 -11
  182. package/src/combo-box/clear.ts +11 -0
  183. package/src/combo-box/ia-combo-box.ts +1288 -1180
  184. package/src/combo-box/models.ts +31 -1
  185. package/src/manage/manage-bar.ts +247 -247
  186. package/src/restoration-state-handler.ts +5 -1
  187. package/src/tiles/base-tile-component.ts +65 -65
  188. package/src/tiles/grid/account-tile.ts +113 -113
  189. package/src/tiles/grid/collection-tile.ts +163 -163
  190. package/src/tiles/grid/item-tile.ts +340 -340
  191. package/src/tiles/grid/search-tile.ts +90 -90
  192. package/src/tiles/grid/styles/tile-grid-shared-styles.ts +130 -130
  193. package/src/tiles/hover/hover-pane-controller.ts +613 -613
  194. package/src/tiles/hover/tile-hover-pane.ts +184 -184
  195. package/src/tiles/list/tile-list-compact.ts +239 -239
  196. package/src/tiles/list/tile-list.ts +700 -700
  197. package/src/tiles/tile-dispatcher.ts +517 -517
  198. package/src/utils/format-date.ts +62 -62
  199. package/test/collection-facets/facet-row.test.ts +375 -375
  200. package/test/collection-facets.test.ts +928 -928
  201. package/test/tiles/grid/item-tile.test.ts +520 -520
  202. package/test/tiles/hover/hover-pane-controller.test.ts +418 -418
  203. package/test/tiles/list/tile-list-compact.test.ts +282 -282
  204. package/test/tiles/list/tile-list.test.ts +552 -552
  205. package/test/tiles/tile-dispatcher.test.ts +283 -283
  206. package/test/utils/format-date.test.ts +89 -89
  207. package/tsconfig.json +8 -3
  208. package/vite.config.ts +29 -22
@@ -1,418 +1,418 @@
1
- import { expect, fixture } from '@open-wc/testing';
2
- import { html, LitElement, nothing, TemplateResult } from 'lit';
3
- import { customElement, property, query } from 'lit/decorators.js';
4
- import {
5
- HoverPaneController,
6
- HoverPaneControllerInterface,
7
- HoverPaneControllerOptions,
8
- HoverPaneProperties,
9
- HoverPaneProviderInterface,
10
- } from '../../../src/tiles/hover/hover-pane-controller';
11
- import type { TileHoverPane } from '../../../src/tiles/hover/tile-hover-pane';
12
- import { TileModel } from '../../../src/models';
13
- import sinon from 'sinon';
14
-
15
- @customElement('host-element')
16
- class HostElement extends LitElement implements HoverPaneProviderInterface {
17
- @property({ type: Object }) controllerOptions?: HoverPaneControllerOptions;
18
-
19
- @property({ type: Boolean }) suppressHoverPane: boolean = false;
20
-
21
- @query('tile-hover-pane') hoverPane?: TileHoverPane;
22
-
23
- controller?: HoverPaneControllerInterface;
24
-
25
- render(): TemplateResult {
26
- return html` ${this.controller?.getTemplate()} `;
27
- }
28
-
29
- protected firstUpdated(): void {
30
- this.controller = new HoverPaneController(this, this.controllerOptions);
31
- }
32
-
33
- acquireFocus(): void {}
34
-
35
- releaseFocus(): void {}
36
-
37
- getHoverPane(): HTMLElement | undefined {
38
- return this.suppressHoverPane ? undefined : this.hoverPane;
39
- }
40
-
41
- getHoverPaneProps(): HoverPaneProperties {
42
- const tileModel = new TileModel({});
43
- tileModel.checked = false;
44
- tileModel.collectionFilesCount = 1;
45
- tileModel.collections = ['foo', 'bar'];
46
- tileModel.collectionSize = 1;
47
- tileModel.commentCount = 1;
48
- tileModel.contentWarning = false;
49
- tileModel.creators = ['foo', 'bar'];
50
- tileModel.favCount = 1;
51
- tileModel.identifier = 'foo';
52
- tileModel.itemCount = 1;
53
- tileModel.loginRequired = false;
54
- tileModel.mediatype = 'data';
55
- tileModel.subjects = ['foo', 'bar'];
56
- tileModel.title = 'foo';
57
- tileModel.viewCount = 1;
58
-
59
- return {
60
- model: tileModel,
61
- loggedIn: false,
62
- suppressBlurring: false,
63
- sortParam: null,
64
- };
65
- }
66
- }
67
-
68
- describe('Hover Pane Controller', () => {
69
- let oldMatchMedia: typeof window.matchMedia;
70
- let oldOnTouchStart: typeof window.ontouchstart;
71
-
72
- before(() => {
73
- oldMatchMedia = window.matchMedia;
74
- oldOnTouchStart = window.ontouchstart;
75
- window.matchMedia = () => ({ matches: true }) as MediaQueryList;
76
- window.ontouchstart = () => {};
77
- });
78
-
79
- after(() => {
80
- window.matchMedia = oldMatchMedia;
81
- window.ontouchstart = oldOnTouchStart;
82
- });
83
-
84
- it('should initially provide empty template', async () => {
85
- const host = await fixture<HostElement>(
86
- html`<host-element></host-element>`,
87
- );
88
- expect(host.controller?.getTemplate()).to.equal(nothing);
89
- });
90
-
91
- it('should produce a hover pane template after mousemove, and hide it after mouseleave', async () => {
92
- const host = await fixture<HostElement>(
93
- html`<host-element
94
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
95
- ></host-element>`,
96
- );
97
-
98
- host.dispatchEvent(new MouseEvent('mousemove'));
99
- // Need to wait a tick for the event handlers to run
100
- await new Promise(resolve => {
101
- setTimeout(resolve, 0);
102
- });
103
-
104
- expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
105
-
106
- host.dispatchEvent(new MouseEvent('mouseleave'));
107
- // Need to wait for the fade out transition
108
- await new Promise(resolve => {
109
- setTimeout(resolve, 150);
110
- });
111
-
112
- expect(host.controller?.getTemplate()).to.equal(nothing);
113
- });
114
-
115
- it('should produce a hover pane template after mouseenter, even without mousemove', async () => {
116
- const host = await fixture<HostElement>(
117
- html`<host-element
118
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
119
- ></host-element>`,
120
- );
121
-
122
- host.dispatchEvent(new MouseEvent('mouseenter'));
123
- // Need to wait a tick for the event handlers to run
124
- await new Promise(resolve => {
125
- setTimeout(resolve, 0);
126
- });
127
-
128
- expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
129
- });
130
-
131
- it('should immediately fade back in if mouse enters while fading out', async () => {
132
- const host = await fixture<HostElement>(
133
- html`<host-element
134
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
135
- ></host-element>`,
136
- );
137
-
138
- // Enter the host element and wait for the show handlers to run
139
- host.dispatchEvent(new MouseEvent('mousemove'));
140
- await new Promise(resolve => {
141
- setTimeout(resolve, 0);
142
- });
143
-
144
- // Leave the host element so it begins fading out, but not all the way
145
- host.dispatchEvent(new MouseEvent('mouseleave'));
146
- await new Promise(resolve => {
147
- setTimeout(resolve, 20);
148
- });
149
-
150
- // Re-enter the host element and wait long enough that it would disappear
151
- // if the hide were not cancelled
152
- host.dispatchEvent(new MouseEvent('mousemove'));
153
- await new Promise(resolve => {
154
- setTimeout(resolve, 150);
155
- });
156
-
157
- expect(host.controller?.getTemplate()).not.to.equal(nothing);
158
- });
159
-
160
- it('should flip hover pane if it would overflow the viewport', async () => {
161
- const host = await fixture<HostElement>(
162
- html`<host-element
163
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
164
- ></host-element>`,
165
- );
166
-
167
- host.dispatchEvent(
168
- new MouseEvent('mousemove', { clientX: 800, clientY: 600 }),
169
- );
170
- // Need to wait a tick for the event handlers to run
171
- await new Promise(resolve => {
172
- setTimeout(resolve, 0);
173
- });
174
- await host.updateComplete;
175
-
176
- expect(host.controller?.getTemplate()).not.to.equal(nothing);
177
- expect(host.getHoverPane()?.getBoundingClientRect()?.right).to.be.lessThan(
178
- window.innerWidth,
179
- );
180
- expect(host.getHoverPane()?.getBoundingClientRect()?.bottom).to.be.lessThan(
181
- window.innerHeight,
182
- );
183
- });
184
-
185
- it('should gracefully handle undefined hover pane from host element', async () => {
186
- const host = await fixture<HostElement>(
187
- html`<host-element
188
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
189
- ?suppressHoverPane=${true}
190
- ></host-element>`,
191
- );
192
-
193
- host.dispatchEvent(new MouseEvent('mousemove'));
194
- // Need to wait a tick for the event handlers to run
195
- await new Promise(resolve => {
196
- setTimeout(resolve, 0);
197
- });
198
-
199
- expect(host.controller?.getTemplate()).not.to.equal(nothing);
200
-
201
- host.dispatchEvent(new MouseEvent('mouseleave'));
202
- await new Promise(resolve => {
203
- setTimeout(resolve, 20);
204
- });
205
-
206
- host.dispatchEvent(new MouseEvent('mousemove'));
207
- await new Promise(resolve => {
208
- setTimeout(resolve, 0);
209
- });
210
-
211
- host.dispatchEvent(new MouseEvent('mouseleave'));
212
- // Need to wait for the fade out transition
213
- await new Promise(resolve => {
214
- setTimeout(resolve, 150);
215
- });
216
-
217
- expect(host.controller?.getTemplate()).to.equal(nothing);
218
- });
219
-
220
- describe('Touch & long-press', () => {
221
- const getTouchStartEvent = (host: EventTarget) =>
222
- new TouchEvent('touchstart', {
223
- touches: [new Touch({ identifier: 0, target: host })],
224
- });
225
-
226
- it('should produce a hover pane after long press', async () => {
227
- const host = await fixture<HostElement>(
228
- html`<host-element
229
- .controllerOptions=${{
230
- showDelay: 0,
231
- longPressDelay: 0,
232
- enableLongPress: true,
233
- }}
234
- ></host-element>`,
235
- );
236
-
237
- // Touch the host element and wait for the long press handlers to run
238
- host.dispatchEvent(getTouchStartEvent(host));
239
- await new Promise(resolve => {
240
- setTimeout(resolve, 0);
241
- });
242
-
243
- expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
244
- });
245
-
246
- it('should cancel a long press by moving', async () => {
247
- const host = await fixture<HostElement>(
248
- html`<host-element
249
- .controllerOptions=${{
250
- showDelay: 0,
251
- longPressDelay: 100,
252
- enableLongPress: true,
253
- }}
254
- ></host-element>`,
255
- );
256
-
257
- // Touch the host element
258
- host.dispatchEvent(getTouchStartEvent(host));
259
- await new Promise(resolve => {
260
- setTimeout(resolve, 0);
261
- });
262
-
263
- // Move the touch point, cancelling the long press
264
- host.dispatchEvent(new TouchEvent('touchmove'));
265
- await new Promise(resolve => {
266
- setTimeout(resolve, 150);
267
- });
268
-
269
- expect(host.controller?.getTemplate()).to.equal(nothing);
270
- });
271
-
272
- it('should cancel a long press by ending touch', async () => {
273
- const host = await fixture<HostElement>(
274
- html`<host-element
275
- .controllerOptions=${{
276
- showDelay: 0,
277
- longPressDelay: 100,
278
- enableLongPress: true,
279
- }}
280
- ></host-element>`,
281
- );
282
-
283
- // Touch the host element
284
- host.dispatchEvent(getTouchStartEvent(host));
285
- await new Promise(resolve => {
286
- setTimeout(resolve, 0);
287
- });
288
-
289
- // Lift the touch point, cancelling the long press
290
- host.dispatchEvent(new TouchEvent('touchend'));
291
- await new Promise(resolve => {
292
- setTimeout(resolve, 150);
293
- });
294
-
295
- expect(host.controller?.getTemplate()).to.equal(nothing);
296
- });
297
-
298
- it('should cancel a long press by cancelling touch (e.g., too many touch points)', async () => {
299
- const host = await fixture<HostElement>(
300
- html`<host-element
301
- .controllerOptions=${{
302
- showDelay: 0,
303
- longPressDelay: 100,
304
- enableLongPress: true,
305
- }}
306
- ></host-element>`,
307
- );
308
-
309
- // Touch the host element
310
- host.dispatchEvent(getTouchStartEvent(host));
311
- await new Promise(resolve => {
312
- setTimeout(resolve, 0);
313
- });
314
-
315
- // Cancel the touch point, also cancelling the long press
316
- host.dispatchEvent(new TouchEvent('touchcancel'));
317
- await new Promise(resolve => {
318
- setTimeout(resolve, 150);
319
- });
320
-
321
- expect(host.controller?.getTemplate()).to.equal(nothing);
322
- });
323
-
324
- it('should close the hover pane on mobile when touching the backdrop', async () => {
325
- const host = await fixture<HostElement>(
326
- html`<host-element
327
- .controllerOptions=${{
328
- showDelay: 0,
329
- hideDelay: 0,
330
- longPressDelay: 0,
331
- enableLongPress: true,
332
- mobileBreakpoint: 9999, // Ensure we get the mobile view
333
- }}
334
- ></host-element>`,
335
- );
336
-
337
- // Touch the host element
338
- host.dispatchEvent(getTouchStartEvent(host));
339
- await new Promise(resolve => {
340
- setTimeout(resolve, 0);
341
- });
342
-
343
- expect(host.controller?.getTemplate()).not.to.equal(nothing);
344
-
345
- await host.updateComplete;
346
-
347
- // Touch the backdrop
348
- host.shadowRoot
349
- ?.querySelector('#touch-backdrop')
350
- ?.dispatchEvent(new TouchEvent('touchstart'));
351
- await new Promise(resolve => {
352
- setTimeout(resolve, 150);
353
- });
354
-
355
- expect(host.controller?.getTemplate()).to.equal(nothing);
356
- });
357
- });
358
-
359
- describe('keyboard accessibility', () => {
360
- it('should call host getBoundingClientRect if anchor is host', async () => {
361
- const host = await fixture<HostElement>(
362
- html`<host-element
363
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
364
- ></host-element>`,
365
- );
366
-
367
- const getBoundingClientRectSpy = sinon.spy(host, 'getBoundingClientRect');
368
-
369
- host.dispatchEvent(new FocusEvent('focus'));
370
- // Need to wait a tick for the event handlers to run
371
- await new Promise(resolve => {
372
- setTimeout(resolve, 0);
373
- });
374
-
375
- expect(getBoundingClientRectSpy.called).to.be.true;
376
- });
377
-
378
- it('should show hover pane on focus', async () => {
379
- const host = await fixture<HostElement>(
380
- html`<host-element
381
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
382
- ></host-element>`,
383
- );
384
-
385
- host.dispatchEvent(new FocusEvent('focus'));
386
- // Need to wait a tick for the event handlers to run
387
- await new Promise(resolve => {
388
- setTimeout(resolve, 0);
389
- });
390
-
391
- expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
392
- });
393
-
394
- it('should hide hover pane on blur', async () => {
395
- const host = await fixture<HostElement>(
396
- html`<host-element
397
- .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
398
- ></host-element>`,
399
- );
400
-
401
- host.dispatchEvent(new FocusEvent('focus'));
402
- // Need to wait a tick for the event handlers to run
403
- await new Promise(resolve => {
404
- setTimeout(resolve, 0);
405
- });
406
-
407
- expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
408
-
409
- host.dispatchEvent(new FocusEvent('blur'));
410
- // Need to wait for the fade out transition
411
- await new Promise(resolve => {
412
- setTimeout(resolve, 150);
413
- });
414
-
415
- expect(host.controller?.getTemplate()).to.equal(nothing);
416
- });
417
- });
418
- });
1
+ import { expect, fixture } from '@open-wc/testing';
2
+ import { html, LitElement, nothing, TemplateResult } from 'lit';
3
+ import { customElement, property, query } from 'lit/decorators.js';
4
+ import {
5
+ HoverPaneController,
6
+ HoverPaneControllerInterface,
7
+ HoverPaneControllerOptions,
8
+ HoverPaneProperties,
9
+ HoverPaneProviderInterface,
10
+ } from '../../../src/tiles/hover/hover-pane-controller';
11
+ import type { TileHoverPane } from '../../../src/tiles/hover/tile-hover-pane';
12
+ import { TileModel } from '../../../src/models';
13
+ import sinon from 'sinon';
14
+
15
+ @customElement('host-element')
16
+ class HostElement extends LitElement implements HoverPaneProviderInterface {
17
+ @property({ type: Object }) controllerOptions?: HoverPaneControllerOptions;
18
+
19
+ @property({ type: Boolean }) suppressHoverPane: boolean = false;
20
+
21
+ @query('tile-hover-pane') hoverPane?: TileHoverPane;
22
+
23
+ controller?: HoverPaneControllerInterface;
24
+
25
+ render(): TemplateResult {
26
+ return html` ${this.controller?.getTemplate()} `;
27
+ }
28
+
29
+ protected firstUpdated(): void {
30
+ this.controller = new HoverPaneController(this, this.controllerOptions);
31
+ }
32
+
33
+ acquireFocus(): void {}
34
+
35
+ releaseFocus(): void {}
36
+
37
+ getHoverPane(): HTMLElement | undefined {
38
+ return this.suppressHoverPane ? undefined : this.hoverPane;
39
+ }
40
+
41
+ getHoverPaneProps(): HoverPaneProperties {
42
+ const tileModel = new TileModel({});
43
+ tileModel.checked = false;
44
+ tileModel.collectionFilesCount = 1;
45
+ tileModel.collections = ['foo', 'bar'];
46
+ tileModel.collectionSize = 1;
47
+ tileModel.commentCount = 1;
48
+ tileModel.contentWarning = false;
49
+ tileModel.creators = ['foo', 'bar'];
50
+ tileModel.favCount = 1;
51
+ tileModel.identifier = 'foo';
52
+ tileModel.itemCount = 1;
53
+ tileModel.loginRequired = false;
54
+ tileModel.mediatype = 'data';
55
+ tileModel.subjects = ['foo', 'bar'];
56
+ tileModel.title = 'foo';
57
+ tileModel.viewCount = 1;
58
+
59
+ return {
60
+ model: tileModel,
61
+ loggedIn: false,
62
+ suppressBlurring: false,
63
+ sortParam: null,
64
+ };
65
+ }
66
+ }
67
+
68
+ describe('Hover Pane Controller', () => {
69
+ let oldMatchMedia: typeof window.matchMedia;
70
+ let oldOnTouchStart: typeof window.ontouchstart;
71
+
72
+ before(() => {
73
+ oldMatchMedia = window.matchMedia;
74
+ oldOnTouchStart = window.ontouchstart;
75
+ window.matchMedia = () => ({ matches: true }) as MediaQueryList;
76
+ window.ontouchstart = () => {};
77
+ });
78
+
79
+ after(() => {
80
+ window.matchMedia = oldMatchMedia;
81
+ window.ontouchstart = oldOnTouchStart;
82
+ });
83
+
84
+ it('should initially provide empty template', async () => {
85
+ const host = await fixture<HostElement>(
86
+ html`<host-element></host-element>`,
87
+ );
88
+ expect(host.controller?.getTemplate()).to.equal(nothing);
89
+ });
90
+
91
+ it('should produce a hover pane template after mousemove, and hide it after mouseleave', async () => {
92
+ const host = await fixture<HostElement>(
93
+ html`<host-element
94
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
95
+ ></host-element>`,
96
+ );
97
+
98
+ host.dispatchEvent(new MouseEvent('mousemove'));
99
+ // Need to wait a tick for the event handlers to run
100
+ await new Promise(resolve => {
101
+ setTimeout(resolve, 0);
102
+ });
103
+
104
+ expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
105
+
106
+ host.dispatchEvent(new MouseEvent('mouseleave'));
107
+ // Need to wait for the fade out transition
108
+ await new Promise(resolve => {
109
+ setTimeout(resolve, 150);
110
+ });
111
+
112
+ expect(host.controller?.getTemplate()).to.equal(nothing);
113
+ });
114
+
115
+ it('should produce a hover pane template after mouseenter, even without mousemove', async () => {
116
+ const host = await fixture<HostElement>(
117
+ html`<host-element
118
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
119
+ ></host-element>`,
120
+ );
121
+
122
+ host.dispatchEvent(new MouseEvent('mouseenter'));
123
+ // Need to wait a tick for the event handlers to run
124
+ await new Promise(resolve => {
125
+ setTimeout(resolve, 0);
126
+ });
127
+
128
+ expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
129
+ });
130
+
131
+ it('should immediately fade back in if mouse enters while fading out', async () => {
132
+ const host = await fixture<HostElement>(
133
+ html`<host-element
134
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
135
+ ></host-element>`,
136
+ );
137
+
138
+ // Enter the host element and wait for the show handlers to run
139
+ host.dispatchEvent(new MouseEvent('mousemove'));
140
+ await new Promise(resolve => {
141
+ setTimeout(resolve, 0);
142
+ });
143
+
144
+ // Leave the host element so it begins fading out, but not all the way
145
+ host.dispatchEvent(new MouseEvent('mouseleave'));
146
+ await new Promise(resolve => {
147
+ setTimeout(resolve, 20);
148
+ });
149
+
150
+ // Re-enter the host element and wait long enough that it would disappear
151
+ // if the hide were not cancelled
152
+ host.dispatchEvent(new MouseEvent('mousemove'));
153
+ await new Promise(resolve => {
154
+ setTimeout(resolve, 150);
155
+ });
156
+
157
+ expect(host.controller?.getTemplate()).not.to.equal(nothing);
158
+ });
159
+
160
+ it('should flip hover pane if it would overflow the viewport', async () => {
161
+ const host = await fixture<HostElement>(
162
+ html`<host-element
163
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
164
+ ></host-element>`,
165
+ );
166
+
167
+ host.dispatchEvent(
168
+ new MouseEvent('mousemove', { clientX: 800, clientY: 600 }),
169
+ );
170
+ // Need to wait a tick for the event handlers to run
171
+ await new Promise(resolve => {
172
+ setTimeout(resolve, 0);
173
+ });
174
+ await host.updateComplete;
175
+
176
+ expect(host.controller?.getTemplate()).not.to.equal(nothing);
177
+ expect(host.getHoverPane()?.getBoundingClientRect()?.right).to.be.lessThan(
178
+ window.innerWidth,
179
+ );
180
+ expect(host.getHoverPane()?.getBoundingClientRect()?.bottom).to.be.lessThan(
181
+ window.innerHeight,
182
+ );
183
+ });
184
+
185
+ it('should gracefully handle undefined hover pane from host element', async () => {
186
+ const host = await fixture<HostElement>(
187
+ html`<host-element
188
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
189
+ ?suppressHoverPane=${true}
190
+ ></host-element>`,
191
+ );
192
+
193
+ host.dispatchEvent(new MouseEvent('mousemove'));
194
+ // Need to wait a tick for the event handlers to run
195
+ await new Promise(resolve => {
196
+ setTimeout(resolve, 0);
197
+ });
198
+
199
+ expect(host.controller?.getTemplate()).not.to.equal(nothing);
200
+
201
+ host.dispatchEvent(new MouseEvent('mouseleave'));
202
+ await new Promise(resolve => {
203
+ setTimeout(resolve, 20);
204
+ });
205
+
206
+ host.dispatchEvent(new MouseEvent('mousemove'));
207
+ await new Promise(resolve => {
208
+ setTimeout(resolve, 0);
209
+ });
210
+
211
+ host.dispatchEvent(new MouseEvent('mouseleave'));
212
+ // Need to wait for the fade out transition
213
+ await new Promise(resolve => {
214
+ setTimeout(resolve, 150);
215
+ });
216
+
217
+ expect(host.controller?.getTemplate()).to.equal(nothing);
218
+ });
219
+
220
+ describe('Touch & long-press', () => {
221
+ const getTouchStartEvent = (host: EventTarget) =>
222
+ new TouchEvent('touchstart', {
223
+ touches: [new Touch({ identifier: 0, target: host })],
224
+ });
225
+
226
+ it('should produce a hover pane after long press', async () => {
227
+ const host = await fixture<HostElement>(
228
+ html`<host-element
229
+ .controllerOptions=${{
230
+ showDelay: 0,
231
+ longPressDelay: 0,
232
+ enableLongPress: true,
233
+ }}
234
+ ></host-element>`,
235
+ );
236
+
237
+ // Touch the host element and wait for the long press handlers to run
238
+ host.dispatchEvent(getTouchStartEvent(host));
239
+ await new Promise(resolve => {
240
+ setTimeout(resolve, 0);
241
+ });
242
+
243
+ expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
244
+ });
245
+
246
+ it('should cancel a long press by moving', async () => {
247
+ const host = await fixture<HostElement>(
248
+ html`<host-element
249
+ .controllerOptions=${{
250
+ showDelay: 0,
251
+ longPressDelay: 100,
252
+ enableLongPress: true,
253
+ }}
254
+ ></host-element>`,
255
+ );
256
+
257
+ // Touch the host element
258
+ host.dispatchEvent(getTouchStartEvent(host));
259
+ await new Promise(resolve => {
260
+ setTimeout(resolve, 0);
261
+ });
262
+
263
+ // Move the touch point, cancelling the long press
264
+ host.dispatchEvent(new TouchEvent('touchmove'));
265
+ await new Promise(resolve => {
266
+ setTimeout(resolve, 150);
267
+ });
268
+
269
+ expect(host.controller?.getTemplate()).to.equal(nothing);
270
+ });
271
+
272
+ it('should cancel a long press by ending touch', async () => {
273
+ const host = await fixture<HostElement>(
274
+ html`<host-element
275
+ .controllerOptions=${{
276
+ showDelay: 0,
277
+ longPressDelay: 100,
278
+ enableLongPress: true,
279
+ }}
280
+ ></host-element>`,
281
+ );
282
+
283
+ // Touch the host element
284
+ host.dispatchEvent(getTouchStartEvent(host));
285
+ await new Promise(resolve => {
286
+ setTimeout(resolve, 0);
287
+ });
288
+
289
+ // Lift the touch point, cancelling the long press
290
+ host.dispatchEvent(new TouchEvent('touchend'));
291
+ await new Promise(resolve => {
292
+ setTimeout(resolve, 150);
293
+ });
294
+
295
+ expect(host.controller?.getTemplate()).to.equal(nothing);
296
+ });
297
+
298
+ it('should cancel a long press by cancelling touch (e.g., too many touch points)', async () => {
299
+ const host = await fixture<HostElement>(
300
+ html`<host-element
301
+ .controllerOptions=${{
302
+ showDelay: 0,
303
+ longPressDelay: 100,
304
+ enableLongPress: true,
305
+ }}
306
+ ></host-element>`,
307
+ );
308
+
309
+ // Touch the host element
310
+ host.dispatchEvent(getTouchStartEvent(host));
311
+ await new Promise(resolve => {
312
+ setTimeout(resolve, 0);
313
+ });
314
+
315
+ // Cancel the touch point, also cancelling the long press
316
+ host.dispatchEvent(new TouchEvent('touchcancel'));
317
+ await new Promise(resolve => {
318
+ setTimeout(resolve, 150);
319
+ });
320
+
321
+ expect(host.controller?.getTemplate()).to.equal(nothing);
322
+ });
323
+
324
+ it('should close the hover pane on mobile when touching the backdrop', async () => {
325
+ const host = await fixture<HostElement>(
326
+ html`<host-element
327
+ .controllerOptions=${{
328
+ showDelay: 0,
329
+ hideDelay: 0,
330
+ longPressDelay: 0,
331
+ enableLongPress: true,
332
+ mobileBreakpoint: 9999, // Ensure we get the mobile view
333
+ }}
334
+ ></host-element>`,
335
+ );
336
+
337
+ // Touch the host element
338
+ host.dispatchEvent(getTouchStartEvent(host));
339
+ await new Promise(resolve => {
340
+ setTimeout(resolve, 0);
341
+ });
342
+
343
+ expect(host.controller?.getTemplate()).not.to.equal(nothing);
344
+
345
+ await host.updateComplete;
346
+
347
+ // Touch the backdrop
348
+ host.shadowRoot
349
+ ?.querySelector('#touch-backdrop')
350
+ ?.dispatchEvent(new TouchEvent('touchstart'));
351
+ await new Promise(resolve => {
352
+ setTimeout(resolve, 150);
353
+ });
354
+
355
+ expect(host.controller?.getTemplate()).to.equal(nothing);
356
+ });
357
+ });
358
+
359
+ describe('keyboard accessibility', () => {
360
+ it('should call host getBoundingClientRect if anchor is host', async () => {
361
+ const host = await fixture<HostElement>(
362
+ html`<host-element
363
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
364
+ ></host-element>`,
365
+ );
366
+
367
+ const getBoundingClientRectSpy = sinon.spy(host, 'getBoundingClientRect');
368
+
369
+ host.dispatchEvent(new FocusEvent('focus'));
370
+ // Need to wait a tick for the event handlers to run
371
+ await new Promise(resolve => {
372
+ setTimeout(resolve, 0);
373
+ });
374
+
375
+ expect(getBoundingClientRectSpy.called).to.be.true;
376
+ });
377
+
378
+ it('should show hover pane on focus', async () => {
379
+ const host = await fixture<HostElement>(
380
+ html`<host-element
381
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
382
+ ></host-element>`,
383
+ );
384
+
385
+ host.dispatchEvent(new FocusEvent('focus'));
386
+ // Need to wait a tick for the event handlers to run
387
+ await new Promise(resolve => {
388
+ setTimeout(resolve, 0);
389
+ });
390
+
391
+ expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
392
+ });
393
+
394
+ it('should hide hover pane on blur', async () => {
395
+ const host = await fixture<HostElement>(
396
+ html`<host-element
397
+ .controllerOptions=${{ showDelay: 0, hideDelay: 0 }}
398
+ ></host-element>`,
399
+ );
400
+
401
+ host.dispatchEvent(new FocusEvent('focus'));
402
+ // Need to wait a tick for the event handlers to run
403
+ await new Promise(resolve => {
404
+ setTimeout(resolve, 0);
405
+ });
406
+
407
+ expect(host.controller?.getTemplate()).not.to.equal(nothing); // Is a TemplateResult
408
+
409
+ host.dispatchEvent(new FocusEvent('blur'));
410
+ // Need to wait for the fade out transition
411
+ await new Promise(resolve => {
412
+ setTimeout(resolve, 150);
413
+ });
414
+
415
+ expect(host.controller?.getTemplate()).to.equal(nothing);
416
+ });
417
+ });
418
+ });