@internetarchive/collection-browser 4.7.1-alpha-webdev9189.0 → 4.8.1-webdev-9227.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 (396) hide show
  1. package/README.md +33 -0
  2. package/dist/src/app-root.js +0 -2
  3. package/dist/src/app-root.js.map +1 -1
  4. package/dist/src/assets/img/icons/check.d.ts +2 -0
  5. package/dist/src/assets/img/icons/check.js +5 -0
  6. package/dist/src/assets/img/icons/check.js.map +1 -0
  7. package/dist/src/collection-browser.d.ts +2 -1
  8. package/dist/src/collection-browser.js +5 -27
  9. package/dist/src/collection-browser.js.map +1 -1
  10. package/dist/src/collection-facets/facet-row-template.d.ts +38 -0
  11. package/dist/src/collection-facets/facet-row-template.js +200 -0
  12. package/dist/src/collection-facets/facet-row-template.js.map +1 -0
  13. package/dist/src/collection-facets/facet-row.js +11 -186
  14. package/dist/src/collection-facets/facet-row.js.map +1 -1
  15. package/dist/src/collection-facets/models.d.ts +7 -2
  16. package/dist/src/collection-facets/models.js +7 -2
  17. package/dist/src/collection-facets/models.js.map +1 -1
  18. package/dist/src/collection-facets/more-facets-content.d.ts +87 -21
  19. package/dist/src/collection-facets/more-facets-content.js +479 -201
  20. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  21. package/dist/src/collection-facets/more-facets-scroller.d.ts +85 -0
  22. package/dist/src/collection-facets/more-facets-scroller.js +429 -0
  23. package/dist/src/collection-facets/more-facets-scroller.js.map +1 -0
  24. package/dist/src/collection-facets/page-window.d.ts +73 -0
  25. package/dist/src/collection-facets/page-window.js +202 -0
  26. package/dist/src/collection-facets/page-window.js.map +1 -0
  27. package/dist/src/collection-facets/toggle-switch.js +1 -0
  28. package/dist/src/collection-facets/toggle-switch.js.map +1 -1
  29. package/dist/src/collection-facets.js +3 -2
  30. package/dist/src/collection-facets.js.map +1 -1
  31. package/dist/src/empty-placeholder.d.ts +7 -7
  32. package/dist/src/empty-placeholder.js +29 -15
  33. package/dist/src/empty-placeholder.js.map +1 -1
  34. package/dist/src/expanded-date-picker.js +3 -2
  35. package/dist/src/expanded-date-picker.js.map +1 -1
  36. package/dist/src/locales/es.d.ts +94 -0
  37. package/dist/src/locales/es.js +109 -0
  38. package/dist/src/locales/es.js.map +1 -0
  39. package/dist/src/manage/manage-bar.d.ts +3 -2
  40. package/dist/src/manage/manage-bar.js +6 -7
  41. package/dist/src/manage/manage-bar.js.map +1 -1
  42. package/dist/src/manage/remove-items-modal-content.js +3 -2
  43. package/dist/src/manage/remove-items-modal-content.js.map +1 -1
  44. package/dist/src/models.d.ts +4 -0
  45. package/dist/src/models.js +22 -2
  46. package/dist/src/models.js.map +1 -1
  47. package/dist/src/sort-filter-bar/sort-filter-bar.js +3 -3
  48. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  49. package/dist/src/tiles/grid/account-tile.js +3 -2
  50. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  51. package/dist/src/tiles/grid/collection-tile.js +3 -2
  52. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  53. package/dist/src/tiles/grid/item-tile.js +3 -2
  54. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  55. package/dist/src/tiles/grid/tile-stats.js +3 -2
  56. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  57. package/dist/src/tiles/list/tile-list-compact-header.js +3 -2
  58. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  59. package/dist/src/tiles/list/tile-list-compact.js +3 -1
  60. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  61. package/dist/src/tiles/list/tile-list.js +3 -2
  62. package/dist/src/tiles/list/tile-list.js.map +1 -1
  63. package/dist/src/tiles/overlay/text-overlay.js +3 -1
  64. package/dist/src/tiles/overlay/text-overlay.js.map +1 -1
  65. package/dist/src/tiles/review-block.js +3 -2
  66. package/dist/src/tiles/review-block.js.map +1 -1
  67. package/dist/src/tiles/tile-dispatcher.d.ts +2 -1
  68. package/dist/src/tiles/tile-dispatcher.js +5 -4
  69. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  70. package/dist/src/utils/log.d.ts +1 -4
  71. package/dist/src/utils/normalize-filter-text.d.ts +28 -0
  72. package/dist/src/utils/normalize-filter-text.js +35 -0
  73. package/dist/src/utils/normalize-filter-text.js.map +1 -0
  74. package/locales/es.d.ts +1 -0
  75. package/locales/es.js +1 -0
  76. package/package.json +15 -1
  77. package/.editorconfig +0 -29
  78. package/.github/workflows/ci.yml +0 -29
  79. package/.github/workflows/gh-pages-main.yml +0 -41
  80. package/.github/workflows/npm-publish.yml +0 -42
  81. package/.github/workflows/pr-preview.yml +0 -40
  82. package/.husky/pre-commit +0 -1
  83. package/.prettierignore +0 -1
  84. package/dist/src/collection-facets/more-facets-pagination.d.ts +0 -36
  85. package/dist/src/collection-facets/more-facets-pagination.js +0 -260
  86. package/dist/src/collection-facets/more-facets-pagination.js.map +0 -1
  87. package/dist/test/collection-browser.test.d.ts +0 -1
  88. package/dist/test/collection-browser.test.js +0 -1849
  89. package/dist/test/collection-browser.test.js.map +0 -1
  90. package/dist/test/collection-facets/facet-row.test.d.ts +0 -1
  91. package/dist/test/collection-facets/facet-row.test.js +0 -291
  92. package/dist/test/collection-facets/facet-row.test.js.map +0 -1
  93. package/dist/test/collection-facets/facets-template.test.d.ts +0 -1
  94. package/dist/test/collection-facets/facets-template.test.js +0 -95
  95. package/dist/test/collection-facets/facets-template.test.js.map +0 -1
  96. package/dist/test/collection-facets/more-facets-content.test.d.ts +0 -1
  97. package/dist/test/collection-facets/more-facets-content.test.js +0 -159
  98. package/dist/test/collection-facets/more-facets-content.test.js.map +0 -1
  99. package/dist/test/collection-facets/more-facets-pagination.test.d.ts +0 -1
  100. package/dist/test/collection-facets/more-facets-pagination.test.js +0 -126
  101. package/dist/test/collection-facets/more-facets-pagination.test.js.map +0 -1
  102. package/dist/test/collection-facets/toggle-switch.test.d.ts +0 -1
  103. package/dist/test/collection-facets/toggle-switch.test.js +0 -99
  104. package/dist/test/collection-facets/toggle-switch.test.js.map +0 -1
  105. package/dist/test/collection-facets.test.d.ts +0 -2
  106. package/dist/test/collection-facets.test.js +0 -728
  107. package/dist/test/collection-facets.test.js.map +0 -1
  108. package/dist/test/data-source/collection-browser-data-source.test.d.ts +0 -1
  109. package/dist/test/data-source/collection-browser-data-source.test.js +0 -154
  110. package/dist/test/data-source/collection-browser-data-source.test.js.map +0 -1
  111. package/dist/test/empty-placeholder.test.d.ts +0 -1
  112. package/dist/test/empty-placeholder.test.js +0 -57
  113. package/dist/test/empty-placeholder.test.js.map +0 -1
  114. package/dist/test/expanded-date-picker.test.d.ts +0 -1
  115. package/dist/test/expanded-date-picker.test.js +0 -124
  116. package/dist/test/expanded-date-picker.test.js.map +0 -1
  117. package/dist/test/icon-overlay.test.d.ts +0 -1
  118. package/dist/test/icon-overlay.test.js +0 -31
  119. package/dist/test/icon-overlay.test.js.map +0 -1
  120. package/dist/test/image-block.test.d.ts +0 -1
  121. package/dist/test/image-block.test.js +0 -208
  122. package/dist/test/image-block.test.js.map +0 -1
  123. package/dist/test/item-image.test.d.ts +0 -1
  124. package/dist/test/item-image.test.js +0 -187
  125. package/dist/test/item-image.test.js.map +0 -1
  126. package/dist/test/manage/manage-bar.test.d.ts +0 -3
  127. package/dist/test/manage/manage-bar.test.js +0 -216
  128. package/dist/test/manage/manage-bar.test.js.map +0 -1
  129. package/dist/test/manage/remove-items-modal-content.test.d.ts +0 -1
  130. package/dist/test/manage/remove-items-modal-content.test.js +0 -60
  131. package/dist/test/manage/remove-items-modal-content.test.js.map +0 -1
  132. package/dist/test/mediatype-config.test.d.ts +0 -1
  133. package/dist/test/mediatype-config.test.js +0 -11
  134. package/dist/test/mediatype-config.test.js.map +0 -1
  135. package/dist/test/mocks/mock-analytics-handler.d.ts +0 -10
  136. package/dist/test/mocks/mock-analytics-handler.js +0 -16
  137. package/dist/test/mocks/mock-analytics-handler.js.map +0 -1
  138. package/dist/test/mocks/mock-search-responses.d.ts +0 -31
  139. package/dist/test/mocks/mock-search-responses.js +0 -1241
  140. package/dist/test/mocks/mock-search-responses.js.map +0 -1
  141. package/dist/test/mocks/mock-search-service.d.ts +0 -16
  142. package/dist/test/mocks/mock-search-service.js +0 -64
  143. package/dist/test/mocks/mock-search-service.js.map +0 -1
  144. package/dist/test/restoration-state-handler.test.d.ts +0 -1
  145. package/dist/test/restoration-state-handler.test.js +0 -335
  146. package/dist/test/restoration-state-handler.test.js.map +0 -1
  147. package/dist/test/review-block.test.d.ts +0 -1
  148. package/dist/test/review-block.test.js +0 -46
  149. package/dist/test/review-block.test.js.map +0 -1
  150. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.d.ts +0 -1
  151. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js +0 -12
  152. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js.map +0 -1
  153. package/dist/test/sort-filter-bar/alpha-bar.test.d.ts +0 -1
  154. package/dist/test/sort-filter-bar/alpha-bar.test.js +0 -68
  155. package/dist/test/sort-filter-bar/alpha-bar.test.js.map +0 -1
  156. package/dist/test/sort-filter-bar/sort-filter-bar.test.d.ts +0 -1
  157. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +0 -326
  158. package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +0 -1
  159. package/dist/test/text-overlay.test.d.ts +0 -1
  160. package/dist/test/text-overlay.test.js +0 -43
  161. package/dist/test/text-overlay.test.js.map +0 -1
  162. package/dist/test/text-snippet-block.test.d.ts +0 -1
  163. package/dist/test/text-snippet-block.test.js +0 -58
  164. package/dist/test/text-snippet-block.test.js.map +0 -1
  165. package/dist/test/tile-stats.test.d.ts +0 -1
  166. package/dist/test/tile-stats.test.js +0 -167
  167. package/dist/test/tile-stats.test.js.map +0 -1
  168. package/dist/test/tiles/grid/account-tile.test.d.ts +0 -1
  169. package/dist/test/tiles/grid/account-tile.test.js +0 -96
  170. package/dist/test/tiles/grid/account-tile.test.js.map +0 -1
  171. package/dist/test/tiles/grid/collection-tile.test.d.ts +0 -1
  172. package/dist/test/tiles/grid/collection-tile.test.js +0 -90
  173. package/dist/test/tiles/grid/collection-tile.test.js.map +0 -1
  174. package/dist/test/tiles/grid/item-tile.test.d.ts +0 -1
  175. package/dist/test/tiles/grid/item-tile.test.js +0 -400
  176. package/dist/test/tiles/grid/item-tile.test.js.map +0 -1
  177. package/dist/test/tiles/grid/search-tile.test.d.ts +0 -1
  178. package/dist/test/tiles/grid/search-tile.test.js +0 -62
  179. package/dist/test/tiles/grid/search-tile.test.js.map +0 -1
  180. package/dist/test/tiles/hover/hover-pane-controller.test.d.ts +0 -1
  181. package/dist/test/tiles/hover/hover-pane-controller.test.js +0 -351
  182. package/dist/test/tiles/hover/hover-pane-controller.test.js.map +0 -1
  183. package/dist/test/tiles/hover/tile-hover-pane.test.d.ts +0 -1
  184. package/dist/test/tiles/hover/tile-hover-pane.test.js +0 -53
  185. package/dist/test/tiles/hover/tile-hover-pane.test.js.map +0 -1
  186. package/dist/test/tiles/list/tile-list-compact-header.test.d.ts +0 -1
  187. package/dist/test/tiles/list/tile-list-compact-header.test.js +0 -36
  188. package/dist/test/tiles/list/tile-list-compact-header.test.js.map +0 -1
  189. package/dist/test/tiles/list/tile-list-compact.test.d.ts +0 -1
  190. package/dist/test/tiles/list/tile-list-compact.test.js +0 -237
  191. package/dist/test/tiles/list/tile-list-compact.test.js.map +0 -1
  192. package/dist/test/tiles/list/tile-list.test.d.ts +0 -1
  193. package/dist/test/tiles/list/tile-list.test.js +0 -460
  194. package/dist/test/tiles/list/tile-list.test.js.map +0 -1
  195. package/dist/test/tiles/tile-dispatcher.test.d.ts +0 -1
  196. package/dist/test/tiles/tile-dispatcher.test.js +0 -246
  197. package/dist/test/tiles/tile-dispatcher.test.js.map +0 -1
  198. package/dist/test/tiles/tile-display-value-provider.test.d.ts +0 -1
  199. package/dist/test/tiles/tile-display-value-provider.test.js +0 -142
  200. package/dist/test/tiles/tile-display-value-provider.test.js.map +0 -1
  201. package/dist/test/tiles/tile-mediatype-icon.test.d.ts +0 -1
  202. package/dist/test/tiles/tile-mediatype-icon.test.js +0 -133
  203. package/dist/test/tiles/tile-mediatype-icon.test.js.map +0 -1
  204. package/dist/test/utils/array-equals.test.d.ts +0 -1
  205. package/dist/test/utils/array-equals.test.js +0 -27
  206. package/dist/test/utils/array-equals.test.js.map +0 -1
  207. package/dist/test/utils/format-count.test.d.ts +0 -1
  208. package/dist/test/utils/format-count.test.js +0 -24
  209. package/dist/test/utils/format-count.test.js.map +0 -1
  210. package/dist/test/utils/format-date.test.d.ts +0 -1
  211. package/dist/test/utils/format-date.test.js +0 -61
  212. package/dist/test/utils/format-date.test.js.map +0 -1
  213. package/dist/test/utils/format-unit-size.test.d.ts +0 -1
  214. package/dist/test/utils/format-unit-size.test.js +0 -18
  215. package/dist/test/utils/format-unit-size.test.js.map +0 -1
  216. package/dist/test/utils/local-date-from-utc.test.d.ts +0 -1
  217. package/dist/test/utils/local-date-from-utc.test.js +0 -27
  218. package/dist/test/utils/local-date-from-utc.test.js.map +0 -1
  219. package/eslint.config.mjs +0 -53
  220. package/index.html +0 -24
  221. package/index.ts +0 -29
  222. package/local.archive.org.cert +0 -86
  223. package/local.archive.org.key +0 -27
  224. package/pnpm-workspace.yaml +0 -30
  225. package/renovate.json +0 -6
  226. package/src/app-root.ts +0 -1284
  227. package/src/assets/img/icons/arrow-left.ts +0 -10
  228. package/src/assets/img/icons/arrow-right.ts +0 -10
  229. package/src/assets/img/icons/chevron.ts +0 -4
  230. package/src/assets/img/icons/close-circle-dark.ts +0 -5
  231. package/src/assets/img/icons/contract.ts +0 -9
  232. package/src/assets/img/icons/empty-query.ts +0 -5
  233. package/src/assets/img/icons/expand.ts +0 -9
  234. package/src/assets/img/icons/eye-closed.ts +0 -5
  235. package/src/assets/img/icons/eye.ts +0 -5
  236. package/src/assets/img/icons/favorite-filled.ts +0 -10
  237. package/src/assets/img/icons/favorite-unfilled.ts +0 -9
  238. package/src/assets/img/icons/filter.ts +0 -10
  239. package/src/assets/img/icons/login-required.ts +0 -18
  240. package/src/assets/img/icons/mediatype/account.ts +0 -14
  241. package/src/assets/img/icons/mediatype/audio.ts +0 -14
  242. package/src/assets/img/icons/mediatype/collection.ts +0 -12
  243. package/src/assets/img/icons/mediatype/data.ts +0 -15
  244. package/src/assets/img/icons/mediatype/etree.ts +0 -14
  245. package/src/assets/img/icons/mediatype/film.ts +0 -14
  246. package/src/assets/img/icons/mediatype/images.ts +0 -13
  247. package/src/assets/img/icons/mediatype/radio.ts +0 -15
  248. package/src/assets/img/icons/mediatype/search.ts +0 -14
  249. package/src/assets/img/icons/mediatype/software.ts +0 -13
  250. package/src/assets/img/icons/mediatype/texts.ts +0 -13
  251. package/src/assets/img/icons/mediatype/tv-commercial.ts +0 -12
  252. package/src/assets/img/icons/mediatype/tv-fact-check.ts +0 -12
  253. package/src/assets/img/icons/mediatype/tv-quote.ts +0 -12
  254. package/src/assets/img/icons/mediatype/tv.ts +0 -14
  255. package/src/assets/img/icons/mediatype/video.ts +0 -14
  256. package/src/assets/img/icons/mediatype/web.ts +0 -13
  257. package/src/assets/img/icons/null-result.ts +0 -5
  258. package/src/assets/img/icons/quote.ts +0 -7
  259. package/src/assets/img/icons/restricted.ts +0 -13
  260. package/src/assets/img/icons/reviews.ts +0 -11
  261. package/src/assets/img/icons/upload.ts +0 -12
  262. package/src/assets/img/icons/views.ts +0 -11
  263. package/src/circular-activity-indicator.ts +0 -64
  264. package/src/collection-browser.ts +0 -3187
  265. package/src/collection-facets/facet-row.ts +0 -309
  266. package/src/collection-facets/facet-tombstone-row.ts +0 -40
  267. package/src/collection-facets/facets-template.ts +0 -85
  268. package/src/collection-facets/models.ts +0 -10
  269. package/src/collection-facets/more-facets-content.ts +0 -644
  270. package/src/collection-facets/more-facets-pagination.ts +0 -294
  271. package/src/collection-facets/smart-facets/dedupe.ts +0 -44
  272. package/src/collection-facets/smart-facets/heuristics/browser-language/browser-language-heuristic.ts +0 -27
  273. package/src/collection-facets/smart-facets/heuristics/index.ts +0 -3
  274. package/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-heuristic.ts +0 -17
  275. package/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-map.ts +0 -70
  276. package/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.ts +0 -79
  277. package/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +0 -93
  278. package/src/collection-facets/smart-facets/models.ts +0 -36
  279. package/src/collection-facets/smart-facets/smart-facet-bar.ts +0 -437
  280. package/src/collection-facets/smart-facets/smart-facet-button.ts +0 -145
  281. package/src/collection-facets/smart-facets/smart-facet-dropdown.ts +0 -185
  282. package/src/collection-facets/smart-facets/smart-facet-equals.ts +0 -16
  283. package/src/collection-facets/smart-facets/smart-facet-heuristics.ts +0 -26
  284. package/src/collection-facets/toggle-switch.ts +0 -174
  285. package/src/collection-facets.ts +0 -1013
  286. package/src/data-source/collection-browser-data-source-interface.ts +0 -351
  287. package/src/data-source/collection-browser-data-source.ts +0 -1474
  288. package/src/data-source/collection-browser-query-state.ts +0 -60
  289. package/src/data-source/models.ts +0 -56
  290. package/src/empty-placeholder.ts +0 -192
  291. package/src/expanded-date-picker.ts +0 -191
  292. package/src/language-code-handler/language-code-handler.ts +0 -64
  293. package/src/language-code-handler/language-code-mapping.ts +0 -564
  294. package/src/manage/manage-bar.ts +0 -276
  295. package/src/manage/remove-items-modal-content.ts +0 -102
  296. package/src/mediatype/mediatype-config.ts +0 -146
  297. package/src/models.ts +0 -895
  298. package/src/restoration-state-handler.ts +0 -550
  299. package/src/sort-filter-bar/alpha-bar-tooltip.ts +0 -53
  300. package/src/sort-filter-bar/alpha-bar.ts +0 -252
  301. package/src/sort-filter-bar/img/compact.ts +0 -5
  302. package/src/sort-filter-bar/img/list.ts +0 -5
  303. package/src/sort-filter-bar/img/sort-toggle-disabled.ts +0 -15
  304. package/src/sort-filter-bar/img/sort-toggle-down.ts +0 -17
  305. package/src/sort-filter-bar/img/sort-toggle-up.ts +0 -17
  306. package/src/sort-filter-bar/img/sort-triangle.ts +0 -5
  307. package/src/sort-filter-bar/img/tile.ts +0 -5
  308. package/src/sort-filter-bar/sort-filter-bar.ts +0 -734
  309. package/src/styles/ia-button.ts +0 -139
  310. package/src/styles/item-image-styles.ts +0 -124
  311. package/src/styles/sr-only.ts +0 -18
  312. package/src/styles/tile-action-styles.ts +0 -59
  313. package/src/tiles/base-tile-component.ts +0 -124
  314. package/src/tiles/collection-browser-loading-tile.ts +0 -26
  315. package/src/tiles/grid/account-tile.ts +0 -113
  316. package/src/tiles/grid/collection-tile.ts +0 -184
  317. package/src/tiles/grid/item-tile.ts +0 -347
  318. package/src/tiles/grid/search-tile.ts +0 -90
  319. package/src/tiles/grid/styles/tile-grid-shared-styles.ts +0 -130
  320. package/src/tiles/grid/tile-stats.ts +0 -211
  321. package/src/tiles/hover/hover-pane-controller.ts +0 -638
  322. package/src/tiles/hover/tile-hover-pane.ts +0 -184
  323. package/src/tiles/image-block.ts +0 -162
  324. package/src/tiles/item-image.ts +0 -214
  325. package/src/tiles/list/tile-list-compact-header.ts +0 -112
  326. package/src/tiles/list/tile-list-compact.ts +0 -278
  327. package/src/tiles/list/tile-list.ts +0 -718
  328. package/src/tiles/models.ts +0 -21
  329. package/src/tiles/overlay/icon-overlay.ts +0 -57
  330. package/src/tiles/overlay/text-overlay.ts +0 -79
  331. package/src/tiles/review-block.ts +0 -130
  332. package/src/tiles/text-snippet-block.ts +0 -132
  333. package/src/tiles/tile-dispatcher.ts +0 -637
  334. package/src/tiles/tile-display-value-provider.ts +0 -133
  335. package/src/tiles/tile-mediatype-icon.ts +0 -133
  336. package/src/utils/analytics-events.ts +0 -29
  337. package/src/utils/array-equals.ts +0 -8
  338. package/src/utils/collapse-repeated-quotes.ts +0 -13
  339. package/src/utils/date-filter-field.ts +0 -11
  340. package/src/utils/facet-utils.ts +0 -183
  341. package/src/utils/format-count.ts +0 -95
  342. package/src/utils/format-date.ts +0 -62
  343. package/src/utils/format-unit-size.ts +0 -43
  344. package/src/utils/local-date-from-utc.ts +0 -15
  345. package/src/utils/log.ts +0 -14
  346. package/src/utils/resolve-mediatype.ts +0 -26
  347. package/src/utils/sha1.ts +0 -9
  348. package/test/collection-browser.test.ts +0 -2694
  349. package/test/collection-facets/facet-row.test.ts +0 -421
  350. package/test/collection-facets/facets-template.test.ts +0 -139
  351. package/test/collection-facets/more-facets-content.test.ts +0 -231
  352. package/test/collection-facets/more-facets-pagination.test.ts +0 -201
  353. package/test/collection-facets/toggle-switch.test.ts +0 -164
  354. package/test/collection-facets.test.ts +0 -928
  355. package/test/data-source/collection-browser-data-source.test.ts +0 -193
  356. package/test/empty-placeholder.test.ts +0 -88
  357. package/test/expanded-date-picker.test.ts +0 -201
  358. package/test/icon-overlay.test.ts +0 -38
  359. package/test/image-block.test.ts +0 -247
  360. package/test/item-image.test.ts +0 -220
  361. package/test/manage/manage-bar.test.ts +0 -347
  362. package/test/manage/remove-items-modal-content.test.ts +0 -81
  363. package/test/mediatype-config.test.ts +0 -11
  364. package/test/mocks/mock-analytics-handler.ts +0 -30
  365. package/test/mocks/mock-search-responses.ts +0 -1364
  366. package/test/mocks/mock-search-service.ts +0 -134
  367. package/test/restoration-state-handler.test.ts +0 -480
  368. package/test/review-block.test.ts +0 -62
  369. package/test/sort-filter-bar/alpha-bar-tooltip.test.ts +0 -17
  370. package/test/sort-filter-bar/alpha-bar.test.ts +0 -101
  371. package/test/sort-filter-bar/sort-filter-bar.test.ts +0 -472
  372. package/test/text-overlay.test.ts +0 -55
  373. package/test/text-snippet-block.test.ts +0 -85
  374. package/test/tile-stats.test.ts +0 -191
  375. package/test/tiles/grid/account-tile.test.ts +0 -121
  376. package/test/tiles/grid/collection-tile.test.ts +0 -114
  377. package/test/tiles/grid/item-tile.test.ts +0 -520
  378. package/test/tiles/grid/search-tile.test.ts +0 -75
  379. package/test/tiles/hover/hover-pane-controller.test.ts +0 -482
  380. package/test/tiles/hover/tile-hover-pane.test.ts +0 -80
  381. package/test/tiles/list/tile-list-compact-header.test.ts +0 -43
  382. package/test/tiles/list/tile-list-compact.test.ts +0 -282
  383. package/test/tiles/list/tile-list.test.ts +0 -576
  384. package/test/tiles/tile-dispatcher.test.ts +0 -320
  385. package/test/tiles/tile-display-value-provider.test.ts +0 -172
  386. package/test/tiles/tile-mediatype-icon.test.ts +0 -160
  387. package/test/utils/array-equals.test.ts +0 -31
  388. package/test/utils/format-count.test.ts +0 -32
  389. package/test/utils/format-date.test.ts +0 -89
  390. package/test/utils/format-unit-size.test.ts +0 -21
  391. package/test/utils/local-date-from-utc.test.ts +0 -37
  392. package/tsconfig.json +0 -25
  393. package/types/dompurify.d.ts +0 -1
  394. package/vite.config.ts +0 -29
  395. package/web-dev-server.config.mjs +0 -30
  396. package/web-test-runner.config.mjs +0 -52
@@ -1,24 +1,28 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, nothing, } from 'lit';
3
- import { customElement, property, state } from 'lit/decorators.js';
3
+ import { customElement, property, query, state } from 'lit/decorators.js';
4
+ import { ifDefined } from 'lit/directives/if-defined.js';
5
+ import { repeat } from 'lit/directives/repeat.js';
6
+ import { when } from 'lit/directives/when.js';
4
7
  import { SearchType, AggregationSortType, } from '@internetarchive/search-service';
5
- import { msg } from '@lit/localize';
6
- import { facetTitles, suppressedCollections, valueFacetSort, defaultFacetSort, getDefaultSelectedFacets, tvMoreFacetSort, } from '../models';
8
+ import { localized, msg, str } from '@lit/localize';
9
+ import { facetTitles, facetPluralTitles, suppressedCollections, valueFacetSort, defaultFacetSort, getDefaultSelectedFacets, tvMoreFacetSort, } from '../models';
7
10
  import '@internetarchive/elements/ia-status-indicator/ia-status-indicator';
8
- import './more-facets-pagination';
9
- import './facets-template';
11
+ import '@internetarchive/ia-clearable-text-input';
12
+ import './more-facets-scroller';
10
13
  import { analyticsActions, analyticsCategories, } from '../utils/analytics-events';
11
14
  import './toggle-switch';
12
15
  import { srOnlyStyle } from '../styles/sr-only';
13
- import { mergeSelectedFacets, sortBucketsBySelectionState, updateSelectedFacetBucket, } from '../utils/facet-utils';
14
- import { MORE_FACETS__DEFAULT_PAGE_SIZE, MORE_FACETS__MAX_AGGREGATIONS, } from './models';
16
+ import checkIcon from '../assets/img/icons/check';
17
+ import eyeClosedIcon from '../assets/img/icons/eye-closed';
18
+ import closeCircleDark from '../assets/img/icons/close-circle-dark';
19
+ import { mergeSelectedFacets, updateSelectedFacetBucket, } from '../utils/facet-utils';
20
+ import { filterTextIncludes, normalizeFilterText, } from '../utils/normalize-filter-text';
21
+ import { log } from '../utils/log';
22
+ import { MORE_FACETS__MAX_AGGREGATIONS } from './models';
15
23
  let MoreFacetsContent = class MoreFacetsContent extends LitElement {
16
24
  constructor() {
17
25
  super(...arguments);
18
- /**
19
- * Maximum number of facets to show per page within the modal.
20
- */
21
- this.facetsPerPage = MORE_FACETS__DEFAULT_PAGE_SIZE;
22
26
  /**
23
27
  * Whether we are waiting for facet data to load.
24
28
  * We begin with this set to true so that we show an initial loading indicator.
@@ -34,19 +38,53 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
34
38
  */
35
39
  this.unappliedFacetChanges = getDefaultSelectedFacets();
36
40
  /**
37
- * Which page of facets we are showing.
41
+ * Text the patron has entered to narrow down the facet values shown.
42
+ */
43
+ this.filterText = '';
44
+ /**
45
+ * Whether the search for this facet's values failed, either with an error
46
+ * result or by throwing.
47
+ */
48
+ this.loadFailed = false;
49
+ /**
50
+ * The buckets from `facetGroup` that match `filterText`, in display order.
51
+ * Derived in `willUpdate`.
52
+ */
53
+ this.filteredBuckets = [];
54
+ /**
55
+ * Each bucket's display text in the normalized form that filtering compares
56
+ * against, keyed by bucket key. Filled lazily so that each value is only
57
+ * normalized once, however many times the filter text changes.
58
+ */
59
+ this.filterKeys = new Map();
60
+ /**
61
+ * The values currently selected or hidden, in the order they were selected.
62
+ * Shown as chiclets above the list. Derived in `willUpdate`.
63
+ */
64
+ this.chosenBuckets = [];
65
+ /**
66
+ * Close more facets modal on Escape click
38
67
  */
39
- this.pageNumber = 1;
68
+ this.escapeHandler = (e) => {
69
+ if (e.key === 'Escape')
70
+ this.modalManager?.closeModal();
71
+ };
40
72
  }
41
73
  willUpdate(changed) {
42
- if (changed.has('aggregations') ||
43
- changed.has('facetsPerPage') ||
74
+ if (changed.has('aggregations')) {
75
+ this.filterKeys.clear();
76
+ }
77
+ const facetGroupChanged = changed.has('aggregations') ||
44
78
  changed.has('sortedBy') ||
45
79
  changed.has('selectedFacets') ||
46
- changed.has('unappliedFacetChanges')) {
47
- // Convert the merged selected facets & aggregations into a facet group, and
48
- // store it for reuse across pages.
80
+ changed.has('unappliedFacetChanges');
81
+ if (facetGroupChanged) {
82
+ // Convert the merged selected facets & aggregations into a facet group
49
83
  this.facetGroup = this.mergedFacets;
84
+ this.chosenBuckets = this.listChosenBuckets();
85
+ }
86
+ if (facetGroupChanged || changed.has('filterText')) {
87
+ this.filteredBuckets = this.filterBuckets();
50
88
  }
51
89
  // If any of the search properties change, it triggers a facet fetch
52
90
  if (changed.has('facetKey') ||
@@ -54,7 +92,7 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
54
92
  changed.has('searchType') ||
55
93
  changed.has('filterMap')) {
56
94
  this.facetsLoading = true;
57
- this.pageNumber = 1;
95
+ this.loadFailed = false;
58
96
  this.sortedBy =
59
97
  this.searchType === SearchType.TV
60
98
  ? tvMoreFacetSort[this.facetKey]
@@ -62,22 +100,31 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
62
100
  this.updateSpecificFacets();
63
101
  }
64
102
  }
103
+ updated(changed) {
104
+ // A new filter or sort order shows different values, so start over from
105
+ // the first page rather than somewhere in the middle of them.
106
+ if (changed.has('filterText') || changed.has('sortedBy')) {
107
+ this.scroller?.scrollToPage(0);
108
+ }
109
+ // A removed chiclet took its focused button with it; move focus to the
110
+ // chiclet that took its place, or back to the filter field if none are left.
111
+ if (this.chicletFocusIndex !== undefined) {
112
+ const buttons = this.shadowRoot?.querySelectorAll('.chiclet-remove') ?? [];
113
+ const index = Math.min(this.chicletFocusIndex, buttons.length - 1);
114
+ this.chicletFocusIndex = undefined;
115
+ (buttons[index] ?? this.filterInput)?.focus();
116
+ }
117
+ }
65
118
  firstUpdated() {
66
119
  this.setupEscapeListeners();
67
120
  }
68
- /**
69
- * Close more facets modal on Escape click
70
- */
121
+ disconnectedCallback() {
122
+ super.disconnectedCallback();
123
+ document.removeEventListener('keydown', this.escapeHandler);
124
+ }
71
125
  setupEscapeListeners() {
72
126
  if (this.modalManager) {
73
- document.addEventListener('keydown', (e) => {
74
- if (e.key === 'Escape') {
75
- this.modalManager?.closeModal();
76
- }
77
- });
78
- }
79
- else {
80
- document.removeEventListener('keydown', () => { });
127
+ document.addEventListener('keydown', this.escapeHandler);
81
128
  }
82
129
  }
83
130
  /**
@@ -112,74 +159,72 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
112
159
  aggregationsSize,
113
160
  rows: 0, // todo - do we want server-side pagination with offset/page/limit flag?
114
161
  };
115
- const results = await this.searchService?.search(params, this.searchType);
116
- this.aggregations = results?.success?.response.aggregations;
117
- this.facetsLoading = false;
118
- const collectionTitles = results?.success?.response?.collectionTitles;
119
- if (collectionTitles) {
120
- for (const [id, title] of Object.entries(collectionTitles)) {
121
- this.collectionTitles?.set(id, title);
162
+ try {
163
+ const results = await this.searchService?.search(params, this.searchType);
164
+ const response = results?.success?.response;
165
+ if (!response) {
166
+ log('More facets search failed', results?.error);
167
+ this.loadFailed = true;
168
+ this.aggregations = undefined;
169
+ return;
170
+ }
171
+ // Record collection titles before the aggregations, so that they're
172
+ // available for sorting & filtering once the facet group is built.
173
+ const { collectionTitles } = response;
174
+ if (collectionTitles) {
175
+ for (const [id, title] of Object.entries(collectionTitles)) {
176
+ this.collectionTitles?.set(id, title);
177
+ }
122
178
  }
179
+ this.aggregations = response.aggregations;
123
180
  }
124
- }
125
- /**
126
- * Handler for page number changes from the pagination widget.
127
- */
128
- pageNumberClicked(e) {
129
- const page = e?.detail?.page;
130
- if (page) {
131
- this.pageNumber = Number(page);
181
+ catch (err) {
182
+ log('More facets search threw', err);
183
+ this.loadFailed = true;
184
+ this.aggregations = undefined;
185
+ }
186
+ finally {
187
+ this.facetsLoading = false;
132
188
  }
133
- this.analyticsHandler?.sendEvent({
134
- category: analyticsCategories.default,
135
- action: analyticsActions.moreFacetsPageChange,
136
- label: `${this.pageNumber}`,
137
- });
138
189
  }
139
190
  /**
140
- * Combines the selected facets with the aggregations to create a single list of facets
191
+ * Combines the selected facets with the aggregations into the single list of
192
+ * values the dialog shows. Selected and hidden values keep their place in the
193
+ * current sort order rather than moving to the front; the chiclets above the
194
+ * list are what call them out.
141
195
  */
142
196
  get mergedFacets() {
143
197
  if (!this.facetKey || !this.selectedFacets)
144
198
  return undefined;
145
- const { selectedFacetGroup, aggregationFacetGroup } = this;
199
+ const { aggregationFacetGroup } = this;
146
200
  // If we don't have any aggregations, then there is nothing to show yet
147
201
  if (!aggregationFacetGroup)
148
202
  return undefined;
149
- // Start with either the selected group if we have one, or the aggregate group otherwise
150
- const facetGroup = { ...(selectedFacetGroup ?? aggregationFacetGroup) };
151
- // Attach the counts to the selected buckets
152
- const bucketsWithCount = selectedFacetGroup?.buckets.map(bucket => {
153
- const selectedBucket = aggregationFacetGroup.buckets.find(b => b.key === bucket.key);
154
- return selectedBucket
155
- ? {
156
- ...bucket,
157
- count: selectedBucket.count,
158
- }
159
- : bucket;
160
- }) ?? [];
161
- // Sort the buckets by selection state
162
- // We do this *prior* to considering unapplied selections, because we want the facets
163
- // to remain in position when they are selected/unselected, rather than re-sort themselves.
164
- sortBucketsBySelectionState(bucketsWithCount, this.sortedBy);
165
- // Append any additional buckets that were not selected
166
- aggregationFacetGroup.buckets.forEach(bucket => {
167
- const existingBucket = selectedFacetGroup?.buckets.find(b => b.key === bucket.key);
168
- if (existingBucket)
169
- return;
170
- bucketsWithCount.push(bucket);
203
+ const selections = this.currentSelections;
204
+ // Mark each aggregated value with its selection state, if it has one
205
+ const buckets = aggregationFacetGroup.buckets.map(bucket => {
206
+ const selection = selections[bucket.key];
207
+ return selection ? { ...bucket, state: selection.state } : bucket;
171
208
  });
172
- // Apply any unapplied selections that appear on this page
173
- const unappliedBuckets = this.unappliedFacetChanges[this.facetKey];
174
- for (const [index, bucket] of bucketsWithCount.entries()) {
175
- const unappliedBucket = unappliedBuckets?.[bucket.key];
176
- if (unappliedBucket) {
177
- bucketsWithCount[index] = { ...unappliedBucket };
178
- }
209
+ // Values selected before the dialog opened can be missing from the
210
+ // aggregations (a hidden value is excluded from the results it would be
211
+ // counted in). Slot them in where the current sort puts them, so they can
212
+ // still be changed from the list.
213
+ const aggregatedKeys = new Set(buckets.map(b => b.key));
214
+ const preexisting = this.selectedFacets[this.facetKey] ?? {};
215
+ for (const [key, data] of Object.entries(preexisting)) {
216
+ if (aggregatedKeys.has(key))
217
+ continue;
218
+ this.insertInSortOrder(buckets, {
219
+ displayText: this.displayTextFor(key),
220
+ key,
221
+ count: data.count,
222
+ state: selections[key]?.state ?? data.state,
223
+ });
179
224
  }
180
225
  // For TV creator facets, uppercase the display text
181
226
  if (this.facetKey === 'creator' && this.isTvSearch) {
182
- bucketsWithCount.forEach(b => {
227
+ buckets.forEach(b => {
183
228
  b.displayText = (b.displayText ?? b.key)?.toLocaleUpperCase();
184
229
  const channelLabel = this.tvChannelAliases?.get(b.displayText);
185
230
  if (channelLabel && channelLabel !== b.displayText) {
@@ -187,35 +232,68 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
187
232
  }
188
233
  });
189
234
  }
190
- facetGroup.buckets = bucketsWithCount;
191
- return facetGroup;
235
+ return { ...aggregationFacetGroup, buckets };
192
236
  }
193
237
  /**
194
- * Converts the selected facets for the current facet key to a `FacetGroup`,
195
- * which is easier to work with.
238
+ * This facet type's selections: the ones made before the dialog opened,
239
+ * overridden by any unapplied changes made in it. Values stay in the order
240
+ * they were first selected, and cleared ones remain with state `'none'`.
196
241
  */
197
- get selectedFacetGroup() {
198
- if (!this.selectedFacets || !this.facetKey)
199
- return undefined;
200
- const selectedFacetsForKey = this.selectedFacets[this.facetKey];
201
- if (!selectedFacetsForKey)
202
- return undefined;
203
- const facetGroupTitle = facetTitles[this.facetKey];
204
- const buckets = Object.entries(selectedFacetsForKey).map(([value, data]) => {
205
- const displayText = value;
206
- return {
207
- displayText,
208
- key: value,
209
- count: data?.count,
210
- state: data?.state,
211
- };
212
- });
242
+ get currentSelections() {
243
+ if (!this.facetKey)
244
+ return {};
213
245
  return {
214
- title: facetGroupTitle,
215
- key: this.facetKey,
216
- buckets,
246
+ ...this.selectedFacets?.[this.facetKey],
247
+ ...this.unappliedFacetChanges[this.facetKey],
217
248
  };
218
249
  }
250
+ /**
251
+ * The values that are currently selected or hidden, in the order they were
252
+ * selected, as they appear in `facetGroup`.
253
+ */
254
+ listChosenBuckets() {
255
+ const byKey = new Map(this.facetGroup?.buckets.map(b => [b.key, b]));
256
+ // Without a list (e.g. the search failed), fall back on the selections
257
+ // themselves, so they can still be seen and cleared.
258
+ return Object.entries(this.currentSelections)
259
+ .map(([key, selection]) => byKey.get(key) ?? {
260
+ ...selection,
261
+ displayText: this.displayTextFor(key),
262
+ })
263
+ .filter(bucket => bucket.state !== 'none');
264
+ }
265
+ /**
266
+ * Inserts `bucket` ahead of the first bucket that the current sort would put
267
+ * after it.
268
+ */
269
+ insertInSortOrder(buckets, bucket) {
270
+ const index = buckets.findIndex(b => this.compareForSort(bucket, b) < 0);
271
+ buckets.splice(index === -1 ? buckets.length : index, 0, bucket);
272
+ }
273
+ /**
274
+ * Orders two buckets the way the aggregations are ordered for the current
275
+ * sort (see `getSortedBuckets` in search-service).
276
+ */
277
+ compareForSort(a, b) {
278
+ switch (this.sortedBy) {
279
+ case AggregationSortType.ALPHABETICAL:
280
+ return (a.displayText ?? a.key).localeCompare(b.displayText ?? b.key);
281
+ case AggregationSortType.NUMERIC:
282
+ return Number(b.key) - Number(a.key);
283
+ default:
284
+ return b.count - a.count;
285
+ }
286
+ }
287
+ /**
288
+ * The text patrons see for a bucket: the collection title for collections,
289
+ * and the bucket key for everything else.
290
+ */
291
+ displayTextFor(key) {
292
+ const collectionTitle = this.facetKey === 'collection'
293
+ ? this.collectionTitles?.get(key)
294
+ : undefined;
295
+ return collectionTitle ?? key;
296
+ }
219
297
  /**
220
298
  * Converts the raw `aggregations` for the current facet key to a `FacetGroup`,
221
299
  * which is easier to work with.
@@ -240,12 +318,18 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
240
318
  const facetBuckets = sortedBuckets.map(bucket => {
241
319
  const bucketKeyStr = `${bucket.key}`;
242
320
  return {
243
- displayText: `${bucketKeyStr}`,
244
- key: `${bucketKeyStr}`,
321
+ displayText: this.displayTextFor(bucketKeyStr),
322
+ key: bucketKeyStr,
245
323
  count: bucket.doc_count,
246
324
  state: 'none',
247
325
  };
248
326
  });
327
+ // Collections sorted alphabetically should be in order of the titles
328
+ // patrons see, not of the identifiers that getSortedBuckets used.
329
+ if (this.facetKey === 'collection' &&
330
+ this.sortedBy === AggregationSortType.ALPHABETICAL) {
331
+ facetBuckets.sort((a, b) => (a.displayText ?? a.key).localeCompare(b.displayText ?? b.key));
332
+ }
249
333
  return {
250
334
  title: facetGroupTitle,
251
335
  key: this.facetKey,
@@ -253,34 +337,100 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
253
337
  };
254
338
  }
255
339
  /**
256
- * Returns a FacetGroup representing only the current page of facet buckets to show.
340
+ * The buckets whose visible text contains the filter text, ignoring case,
341
+ * accents and punctuation.
257
342
  */
258
- get facetGroupForCurrentPage() {
259
- const { facetGroup } = this;
260
- if (!facetGroup)
261
- return undefined;
262
- // Slice out only the current page of facet buckets
263
- const firstBucketIndexOnPage = (this.pageNumber - 1) * this.facetsPerPage;
264
- const truncatedBuckets = facetGroup.buckets.slice(firstBucketIndexOnPage, firstBucketIndexOnPage + this.facetsPerPage);
265
- return {
266
- ...facetGroup,
267
- buckets: truncatedBuckets,
268
- };
343
+ filterBuckets() {
344
+ const buckets = this.facetGroup?.buckets ?? [];
345
+ const needle = normalizeFilterText(this.filterText);
346
+ if (!needle.spaced)
347
+ return buckets;
348
+ return buckets.filter(bucket => filterTextIncludes(this.filterKeyFor(bucket), needle));
349
+ }
350
+ filterKeyFor(bucket) {
351
+ let filterKey = this.filterKeys.get(bucket.key);
352
+ if (filterKey === undefined) {
353
+ const visibleText = [bucket.displayText ?? bucket.key, bucket.extraNote]
354
+ .filter(Boolean)
355
+ .join(' ');
356
+ filterKey = normalizeFilterText(visibleText);
357
+ this.filterKeys.set(bucket.key, filterKey);
358
+ }
359
+ return filterKey;
360
+ }
361
+ /**
362
+ * Whether the patron's filter text has ruled out every value
363
+ */
364
+ get noValuesMatch() {
365
+ const isFiltering = normalizeFilterText(this.filterText).spaced !== '';
366
+ return isFiltering && this.filteredBuckets.length === 0;
269
367
  }
270
368
  get moreFacetsTemplate() {
369
+ const valuesLabel = this.facetKey
370
+ ? msg(str `${facetTitles[this.facetKey]} values`)
371
+ : undefined;
271
372
  return html `
272
- <facets-template
273
- .facetGroup=${this.facetGroupForCurrentPage}
274
- .selectedFacets=${this.selectedFacets}
373
+ <more-facets-scroller
374
+ .facetType=${this.facetKey}
375
+ .buckets=${this.filteredBuckets}
275
376
  .collectionTitles=${this.collectionTitles}
276
- @facetClick=${(e) => {
277
- if (this.facetKey) {
278
- this.unappliedFacetChanges = updateSelectedFacetBucket(this.unappliedFacetChanges, this.facetKey, e.detail.bucket);
279
- }
280
- }}
281
- ></facets-template>
377
+ ?omitHideButtons=${this.facetGroup?.buckets.length === 1}
378
+ label=${ifDefined(valuesLabel)}
379
+ @facetClick=${this.facetClicked}
380
+ @pageChanged=${this.pageChanged}
381
+ ></more-facets-scroller>
382
+ ${when(this.loadFailed, () => this.loadErrorTemplate, () => when(this.noValuesMatch, () => this.noMatchesTemplate))}
383
+ `;
384
+ }
385
+ /**
386
+ * A chiclet for each selected or hidden value, each with a button to clear it
387
+ */
388
+ get chicletsTemplate() {
389
+ const valuesName = this.facetKey ? facetPluralTitles[this.facetKey] : '';
390
+ return html `
391
+ <ul class="chiclets" aria-label=${msg(str `Selected ${valuesName}`)}>
392
+ ${repeat(this.chosenBuckets, bucket => bucket.key, (bucket, index) => this.chicletTemplate(bucket, index))}
393
+ </ul>
394
+ `;
395
+ }
396
+ chicletTemplate(bucket, index) {
397
+ const isHidden = bucket.state === 'hidden';
398
+ const text = [bucket.displayText ?? bucket.key, bucket.extraNote]
399
+ .filter(Boolean)
400
+ .join(' ');
401
+ const removeLabel = isHidden
402
+ ? msg(str `Unhide ${text}`)
403
+ : msg(str `Deselect ${text}`);
404
+ return html `
405
+ <li class="chiclet" title=${text}>
406
+ <span class="chiclet-icon" aria-hidden="true"
407
+ >${isHidden ? eyeClosedIcon : checkIcon}</span
408
+ >
409
+ <span class="sr-only"
410
+ >${isHidden ? msg('Hidden:') : msg('Selected:')}</span
411
+ >
412
+ <span class="chiclet-text">${text}</span>
413
+ <button
414
+ type="button"
415
+ class="chiclet-remove"
416
+ aria-label=${removeLabel}
417
+ @click=${() => this.chicletRemoved(bucket, index)}
418
+ >
419
+ ${closeCircleDark}
420
+ </button>
421
+ </li>
282
422
  `;
283
423
  }
424
+ get noMatchesTemplate() {
425
+ return html `<p class="facets-message no-matches" role="status">
426
+ ${msg('No matching values found.')}
427
+ </p>`;
428
+ }
429
+ get loadErrorTemplate() {
430
+ return html `<p class="facets-message load-error" role="alert">
431
+ ${msg('Sorry, these values couldn’t be loaded. Please try again later.')}
432
+ </p>`;
433
+ }
284
434
  get loaderTemplate() {
285
435
  return html `
286
436
  <ia-status-indicator
@@ -289,47 +439,21 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
289
439
  ></ia-status-indicator>
290
440
  `;
291
441
  }
292
- /**
293
- * How many pages of facets to show in the modal pagination widget
294
- */
295
- get paginationSize() {
296
- if (!this.aggregations || !this.facetKey)
297
- return 0;
298
- // Calculate the appropriate number of pages to show in the modal pagination widget
299
- const length = this.aggregations[this.facetKey]?.buckets.length;
300
- return Math.ceil(length / this.facetsPerPage);
301
- }
302
- // render pagination if more then 1 page
303
- get facetsPaginationTemplate() {
304
- return this.paginationSize > 1
305
- ? html `<more-facets-pagination
306
- .size=${this.paginationSize}
307
- .currentPage=${1}
308
- @pageNumberClicked=${this.pageNumberClicked}
309
- ></more-facets-pagination>`
310
- : nothing;
311
- }
312
442
  get footerTemplate() {
313
- if (this.paginationSize > 0) {
314
- return html `${this.facetsPaginationTemplate}
315
- <div class="footer">
316
- <button
317
- class="btn btn-cancel"
318
- type="button"
319
- @click=${this.cancelClick}
320
- >
321
- Cancel
322
- </button>
323
- <button
324
- class="btn btn-submit"
325
- type="button"
326
- @click=${this.applySearchFacetsClicked}
327
- >
328
- Apply filters
329
- </button>
330
- </div> `;
331
- }
332
- return nothing;
443
+ return html `
444
+ <div class="footer">
445
+ <button class="btn btn-cancel" type="button" @click=${this.cancelClick}>
446
+ Cancel
447
+ </button>
448
+ <button
449
+ class="btn btn-submit"
450
+ type="button"
451
+ @click=${this.applySearchFacetsClicked}
452
+ >
453
+ Apply filters
454
+ </button>
455
+ </div>
456
+ `;
333
457
  }
334
458
  sortFacetAggregation(facetSortType) {
335
459
  this.sortedBy = facetSortType;
@@ -338,24 +462,40 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
338
462
  get modalHeaderTemplate() {
339
463
  const facetSort = this.sortedBy ?? defaultFacetSort[this.facetKey];
340
464
  const defaultSwitchSide = facetSort === AggregationSortType.COUNT ? 'left' : 'right';
465
+ const valuesName = this.facetKey ? facetPluralTitles[this.facetKey] : '';
466
+ // From the facet key rather than the facet group, which is missing
467
+ // until the values load (or if they fail to)
468
+ const title = this.facetKey ? facetTitles[this.facetKey] : '';
341
469
  return html `<span class="sr-only">${msg('More facets for:')}</span>
342
- <span class="title">
343
- ${this.facetGroup?.title}
344
-
345
- <label class="sort-label">${msg('Sort by:')}</label>
346
- ${this.facetKey
470
+ <span class="title">${title}</span>
471
+ <span class="header-controls">
472
+ <span class="sort-controls">
473
+ <label class="sort-label">${msg('Sort by:')}</label>
474
+ ${this.facetKey
347
475
  ? html `<toggle-switch
348
- class="sort-toggle"
349
- leftValue=${AggregationSortType.COUNT}
350
- leftLabel="Count"
351
- rightValue=${valueFacetSort[this.facetKey]}
352
- .rightLabel=${this.facetGroup?.title}
353
- side=${defaultSwitchSide}
354
- @change=${(e) => {
476
+ class="sort-toggle"
477
+ leftValue=${AggregationSortType.COUNT}
478
+ leftLabel="Count"
479
+ rightValue=${valueFacetSort[this.facetKey]}
480
+ .rightLabel=${title}
481
+ side=${defaultSwitchSide}
482
+ @change=${(e) => {
355
483
  this.sortFacetAggregation(Number(e.detail));
356
484
  }}
357
- ></toggle-switch>`
485
+ ></toggle-switch>`
358
486
  : nothing}
487
+ </span>
488
+ <span class="filter-controls">
489
+ <label class="filter-label">${msg('Filter by:')}</label>
490
+ <ia-clearable-text-input
491
+ class="filter-input"
492
+ .value=${this.filterText}
493
+ .placeholder=${msg(str `Search ${valuesName}…`)}
494
+ .screenReaderLabel=${msg(str `Filter ${valuesName}`)}
495
+ .clearButtonScreenReaderLabel=${msg('Clear filter')}
496
+ @input=${this.filterTextChanged}
497
+ ></ia-clearable-text-input>
498
+ </span>
359
499
  </span>`;
360
500
  }
361
501
  render() {
@@ -365,12 +505,42 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
365
505
  : html `
366
506
  <section id="more-facets">
367
507
  <div class="header-content">${this.modalHeaderTemplate}</div>
508
+ ${when(this.chosenBuckets.length, () => this.chicletsTemplate)}
368
509
  <div class="facets-content">${this.moreFacetsTemplate}</div>
369
510
  ${this.footerTemplate}
370
511
  </section>
371
512
  `}
372
513
  `;
373
514
  }
515
+ /**
516
+ * Handler for typing in (or clearing) the filter text field
517
+ */
518
+ filterTextChanged(e) {
519
+ const input = e.target;
520
+ this.filterText = input.value;
521
+ }
522
+ facetClicked(e) {
523
+ if (!this.facetKey)
524
+ return;
525
+ this.unappliedFacetChanges = updateSelectedFacetBucket(this.unappliedFacetChanges, this.facetKey, e.detail.bucket);
526
+ }
527
+ /**
528
+ * Clears the selection a chiclet stands for, which removes the chiclet and
529
+ * unchecks the value in the list.
530
+ */
531
+ chicletRemoved(bucket, index) {
532
+ if (!this.facetKey)
533
+ return;
534
+ this.unappliedFacetChanges = updateSelectedFacetBucket(this.unappliedFacetChanges, this.facetKey, { ...bucket, state: 'none' });
535
+ this.chicletFocusIndex = index;
536
+ }
537
+ pageChanged(e) {
538
+ this.analyticsHandler?.sendEvent({
539
+ category: analyticsCategories.default,
540
+ action: analyticsActions.moreFacetsPageChange,
541
+ label: `${e.detail + 1}`,
542
+ });
543
+ }
374
544
  applySearchFacetsClicked() {
375
545
  const mergedSelections = mergeSelectedFacets(this.selectedFacets, this.unappliedFacetChanges);
376
546
  const event = new CustomEvent('facetsChanged', {
@@ -404,10 +574,9 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
404
574
  srOnlyStyle,
405
575
  css `
406
576
  section#more-facets {
407
- overflow: auto;
408
- padding: 10px; /* leaves room for scroll bar to appear without overlaying on content */
409
- --facetsColumnCount: 3;
577
+ padding: 10px;
410
578
  }
579
+
411
580
  .header-content .title {
412
581
  display: block;
413
582
  text-align: left;
@@ -416,8 +585,25 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
416
585
  font-weight: bold;
417
586
  }
418
587
 
419
- .sort-label {
420
- margin-left: 20px;
588
+ .header-controls {
589
+ display: flex;
590
+ flex-wrap: wrap;
591
+ align-items: center;
592
+ gap: 8px 20px;
593
+ padding: 5px 10px 0;
594
+ }
595
+
596
+ /* Each label stays on the same line as its control when these wrap */
597
+ .sort-controls,
598
+ .filter-controls {
599
+ display: inline-flex;
600
+ align-items: center;
601
+ gap: 5px;
602
+ white-space: nowrap;
603
+ }
604
+
605
+ .sort-label,
606
+ .filter-label {
421
607
  font-size: 1.3rem;
422
608
  }
423
609
 
@@ -425,12 +611,95 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
425
611
  font-weight: normal;
426
612
  }
427
613
 
614
+ .filter-input {
615
+ --input-height: 2.5rem;
616
+ --input-font-size: 1.3rem;
617
+ --input-border-radius: 4px;
618
+ --input-padding: 4px 8px;
619
+ --input-focused-border-color: ${modalSubmitButton};
620
+ width: 16rem;
621
+ }
622
+
623
+ .chiclets {
624
+ display: flex;
625
+ flex-wrap: wrap;
626
+ gap: 6px;
627
+ margin: 0;
628
+ padding: 10px 10px 0;
629
+ list-style: none;
630
+ /* About three rows; any more scroll, so the values stay in view */
631
+ max-height: 7.8rem;
632
+ overflow-y: auto;
633
+ }
634
+
635
+ .chiclet {
636
+ display: inline-flex;
637
+ align-items: center;
638
+ gap: 4px;
639
+ max-width: 24rem;
640
+ padding: 2px 3px 2px 6px;
641
+ border: 1px solid ${modalSubmitButton};
642
+ border-radius: 5px;
643
+ background: #fff;
644
+ color: #2c2c2c;
645
+ font-size: 1.2rem;
646
+ line-height: normal;
647
+ }
648
+
649
+ .chiclet-icon {
650
+ display: flex;
651
+ flex: none;
652
+ }
653
+
654
+ .chiclet-icon svg {
655
+ width: 12px;
656
+ height: 12px;
657
+ }
658
+
659
+ .chiclet-text {
660
+ overflow: hidden;
661
+ white-space: nowrap;
662
+ text-overflow: ellipsis;
663
+ }
664
+
665
+ .chiclet-remove {
666
+ display: flex;
667
+ flex: none;
668
+ padding: 2px;
669
+ border: none;
670
+ border-radius: 50%;
671
+ background: none;
672
+ cursor: pointer;
673
+ }
674
+
675
+ .chiclet-remove svg {
676
+ width: 10px;
677
+ height: 10px;
678
+ opacity: 0.55;
679
+ }
680
+
681
+ .chiclet-remove:hover svg,
682
+ .chiclet-remove:focus-visible svg {
683
+ opacity: 1;
684
+ }
685
+
428
686
  .facets-content {
687
+ position: relative;
429
688
  font-size: 1.2rem;
430
- max-height: 300px;
431
- overflow: auto;
432
- padding: 10px;
689
+ padding: 10px 0;
433
690
  }
691
+
692
+ .facets-message {
693
+ position: absolute;
694
+ inset: 0;
695
+ display: flex;
696
+ align-items: center;
697
+ justify-content: center;
698
+ margin: 0;
699
+ font-size: 1.4rem;
700
+ color: #666;
701
+ }
702
+
434
703
  .facets-loader {
435
704
  --icon-width: 70px;
436
705
  margin-bottom: 20px;
@@ -445,6 +714,7 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
445
714
  width: auto;
446
715
  border-radius: 4px;
447
716
  cursor: pointer;
717
+ font-family: inherit;
448
718
  }
449
719
  .btn-cancel {
450
720
  background-color: #2c2c2c;
@@ -456,17 +726,18 @@ let MoreFacetsContent = class MoreFacetsContent extends LitElement {
456
726
  }
457
727
  .footer {
458
728
  text-align: center;
459
- margin-top: 10px;
460
729
  }
461
730
 
462
731
  @media (max-width: 560px) {
463
- section#more-facets {
464
- max-height: 450px;
465
- --facetsColumnCount: 1;
732
+ /* The filter gets a line of its own here, so let it fill that line */
733
+ .filter-controls {
734
+ flex: 1 1 auto;
466
735
  }
467
- .facets-content {
468
- overflow-y: auto;
469
- height: 300px;
736
+ .filter-input {
737
+ flex: 1 1 auto;
738
+ width: auto;
739
+ min-width: 12rem;
740
+ --input-font-size: 1.2rem;
470
741
  }
471
742
  }
472
743
  `,
@@ -497,9 +768,6 @@ __decorate([
497
768
  __decorate([
498
769
  property({ type: Object })
499
770
  ], MoreFacetsContent.prototype, "tvChannelAliases", void 0);
500
- __decorate([
501
- property({ type: Number })
502
- ], MoreFacetsContent.prototype, "facetsPerPage", void 0);
503
771
  __decorate([
504
772
  property({ type: Boolean })
505
773
  ], MoreFacetsContent.prototype, "facetsLoading", void 0);
@@ -532,9 +800,19 @@ __decorate([
532
800
  ], MoreFacetsContent.prototype, "unappliedFacetChanges", void 0);
533
801
  __decorate([
534
802
  state()
535
- ], MoreFacetsContent.prototype, "pageNumber", void 0);
803
+ ], MoreFacetsContent.prototype, "filterText", void 0);
804
+ __decorate([
805
+ state()
806
+ ], MoreFacetsContent.prototype, "loadFailed", void 0);
807
+ __decorate([
808
+ query('more-facets-scroller')
809
+ ], MoreFacetsContent.prototype, "scroller", void 0);
810
+ __decorate([
811
+ query('ia-clearable-text-input')
812
+ ], MoreFacetsContent.prototype, "filterInput", void 0);
536
813
  MoreFacetsContent = __decorate([
537
- customElement('more-facets-content')
814
+ customElement('more-facets-content'),
815
+ localized()
538
816
  ], MoreFacetsContent);
539
817
  export { MoreFacetsContent };
540
818
  //# sourceMappingURL=more-facets-content.js.map