@internetarchive/collection-browser 4.7.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. package/.husky/pre-commit +0 -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-facets/facet-row-template.d.ts +38 -0
  8. package/dist/src/collection-facets/facet-row-template.js +200 -0
  9. package/dist/src/collection-facets/facet-row-template.js.map +1 -0
  10. package/dist/src/collection-facets/facet-row.js +11 -186
  11. package/dist/src/collection-facets/facet-row.js.map +1 -1
  12. package/dist/src/collection-facets/models.d.ts +7 -2
  13. package/dist/src/collection-facets/models.js +7 -2
  14. package/dist/src/collection-facets/models.js.map +1 -1
  15. package/dist/src/collection-facets/more-facets-content.d.ts +87 -21
  16. package/dist/src/collection-facets/more-facets-content.js +477 -200
  17. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  18. package/dist/src/collection-facets/more-facets-scroller.d.ts +85 -0
  19. package/dist/src/collection-facets/more-facets-scroller.js +428 -0
  20. package/dist/src/collection-facets/more-facets-scroller.js.map +1 -0
  21. package/dist/src/collection-facets/page-window.d.ts +73 -0
  22. package/dist/src/collection-facets/page-window.js +202 -0
  23. package/dist/src/collection-facets/page-window.js.map +1 -0
  24. package/dist/src/collection-facets/toggle-switch.js +1 -0
  25. package/dist/src/collection-facets/toggle-switch.js.map +1 -1
  26. package/dist/src/models.d.ts +4 -0
  27. package/dist/src/models.js +16 -0
  28. package/dist/src/models.js.map +1 -1
  29. package/dist/src/utils/log.d.ts +1 -4
  30. package/dist/src/utils/normalize-filter-text.d.ts +28 -0
  31. package/dist/src/utils/normalize-filter-text.js +35 -0
  32. package/dist/src/utils/normalize-filter-text.js.map +1 -0
  33. package/dist/test/collection-facets/more-facets-content.test.js +367 -17
  34. package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
  35. package/dist/test/collection-facets/more-facets-scroller.test.d.ts +1 -0
  36. package/dist/test/collection-facets/more-facets-scroller.test.js +288 -0
  37. package/dist/test/collection-facets/more-facets-scroller.test.js.map +1 -0
  38. package/dist/test/collection-facets/page-window.test.d.ts +1 -0
  39. package/dist/test/collection-facets/page-window.test.js +175 -0
  40. package/dist/test/collection-facets/page-window.test.js.map +1 -0
  41. package/dist/test/mocks/mock-search-responses.d.ts +6 -0
  42. package/dist/test/mocks/mock-search-responses.js +52 -0
  43. package/dist/test/mocks/mock-search-responses.js.map +1 -1
  44. package/dist/test/mocks/mock-search-service.js +2 -1
  45. package/dist/test/mocks/mock-search-service.js.map +1 -1
  46. package/dist/test/utils/normalize-filter-text.test.d.ts +1 -0
  47. package/dist/test/utils/normalize-filter-text.test.js +69 -0
  48. package/dist/test/utils/normalize-filter-text.test.js.map +1 -0
  49. package/docs/design/column-virtualization.md +214 -0
  50. package/package.json +20 -16
  51. package/src/app-root.ts +0 -2
  52. package/src/assets/img/icons/check.ts +5 -0
  53. package/src/collection-facets/facet-row-template.ts +242 -0
  54. package/src/collection-facets/facet-row.ts +15 -202
  55. package/src/collection-facets/models.ts +8 -2
  56. package/src/collection-facets/more-facets-content.ts +528 -221
  57. package/src/collection-facets/more-facets-scroller.ts +485 -0
  58. package/src/collection-facets/page-window.ts +247 -0
  59. package/src/collection-facets/toggle-switch.ts +1 -0
  60. package/src/models.ts +17 -0
  61. package/src/utils/normalize-filter-text.ts +54 -0
  62. package/test/collection-facets/more-facets-content.test.ts +509 -24
  63. package/test/collection-facets/more-facets-scroller.test.ts +401 -0
  64. package/test/collection-facets/page-window.test.ts +208 -0
  65. package/test/mocks/mock-search-responses.ts +56 -0
  66. package/test/mocks/mock-search-service.ts +2 -0
  67. package/test/utils/normalize-filter-text.test.ts +87 -0
  68. package/web-test-runner.config.mjs +7 -2
  69. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.editorconfig +0 -29
  70. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/ci.yml +0 -27
  71. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/gh-pages-main.yml +0 -39
  72. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/npm-publish.yml +0 -39
  73. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/pr-preview.yml +0 -38
  74. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.husky/pre-commit +0 -1
  75. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.prettierignore +0 -1
  76. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/LICENSE +0 -661
  77. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/README.md +0 -84
  78. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/eslint.config.mjs +0 -53
  79. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/index.html +0 -24
  80. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/index.ts +0 -29
  81. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/local.archive.org.cert +0 -86
  82. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/local.archive.org.key +0 -27
  83. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/package.json +0 -120
  84. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/renovate.json +0 -6
  85. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/app-root.ts +0 -1284
  86. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/arrow-left.ts +0 -10
  87. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/arrow-right.ts +0 -10
  88. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/chevron.ts +0 -4
  89. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/close-circle-dark.ts +0 -5
  90. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/contract.ts +0 -9
  91. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/empty-query.ts +0 -5
  92. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/expand.ts +0 -9
  93. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/eye-closed.ts +0 -5
  94. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/eye.ts +0 -5
  95. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/favorite-filled.ts +0 -10
  96. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/favorite-unfilled.ts +0 -9
  97. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/filter.ts +0 -10
  98. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/login-required.ts +0 -18
  99. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/account.ts +0 -14
  100. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/audio.ts +0 -14
  101. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/collection.ts +0 -12
  102. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/data.ts +0 -15
  103. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/etree.ts +0 -14
  104. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/film.ts +0 -14
  105. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/images.ts +0 -13
  106. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/radio.ts +0 -15
  107. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/search.ts +0 -14
  108. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/software.ts +0 -13
  109. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/texts.ts +0 -13
  110. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv-commercial.ts +0 -12
  111. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv-fact-check.ts +0 -12
  112. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv-quote.ts +0 -12
  113. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv.ts +0 -14
  114. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/video.ts +0 -14
  115. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/web.ts +0 -13
  116. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/null-result.ts +0 -5
  117. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/quote.ts +0 -7
  118. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/restricted.ts +0 -13
  119. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/reviews.ts +0 -11
  120. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/upload.ts +0 -12
  121. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/views.ts +0 -11
  122. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/circular-activity-indicator.ts +0 -64
  123. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-browser.ts +0 -3165
  124. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/facet-row.ts +0 -309
  125. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/facet-tombstone-row.ts +0 -40
  126. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/facets-template.ts +0 -85
  127. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/models.ts +0 -10
  128. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/more-facets-content.ts +0 -644
  129. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/more-facets-pagination.ts +0 -294
  130. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/dedupe.ts +0 -44
  131. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/browser-language/browser-language-heuristic.ts +0 -27
  132. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/index.ts +0 -3
  133. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-heuristic.ts +0 -17
  134. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-map.ts +0 -70
  135. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.ts +0 -79
  136. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +0 -93
  137. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/models.ts +0 -36
  138. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-bar.ts +0 -437
  139. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-button.ts +0 -145
  140. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-dropdown.ts +0 -185
  141. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-equals.ts +0 -16
  142. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-heuristics.ts +0 -26
  143. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/toggle-switch.ts +0 -174
  144. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets.ts +0 -1013
  145. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/collection-browser-data-source-interface.ts +0 -351
  146. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/collection-browser-data-source.ts +0 -1474
  147. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/collection-browser-query-state.ts +0 -60
  148. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/models.ts +0 -56
  149. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/empty-placeholder.ts +0 -192
  150. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/expanded-date-picker.ts +0 -191
  151. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/language-code-handler/language-code-handler.ts +0 -64
  152. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/language-code-handler/language-code-mapping.ts +0 -564
  153. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/manage/manage-bar.ts +0 -276
  154. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/manage/remove-items-modal-content.ts +0 -102
  155. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/mediatype/mediatype-config.ts +0 -146
  156. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/models.ts +0 -895
  157. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/restoration-state-handler.ts +0 -550
  158. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/alpha-bar-tooltip.ts +0 -53
  159. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/alpha-bar.ts +0 -252
  160. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/compact.ts +0 -5
  161. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/list.ts +0 -5
  162. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-toggle-disabled.ts +0 -15
  163. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-toggle-down.ts +0 -17
  164. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-toggle-up.ts +0 -17
  165. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-triangle.ts +0 -5
  166. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/tile.ts +0 -5
  167. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/sort-filter-bar.ts +0 -733
  168. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/ia-button.ts +0 -139
  169. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/item-image-styles.ts +0 -124
  170. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/sr-only.ts +0 -18
  171. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/tile-action-styles.ts +0 -59
  172. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/base-tile-component.ts +0 -124
  173. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/collection-browser-loading-tile.ts +0 -26
  174. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/account-tile.ts +0 -113
  175. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/collection-tile.ts +0 -184
  176. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/item-tile.ts +0 -347
  177. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/search-tile.ts +0 -90
  178. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/styles/tile-grid-shared-styles.ts +0 -130
  179. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/tile-stats.ts +0 -211
  180. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/hover/hover-pane-controller.ts +0 -638
  181. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/hover/tile-hover-pane.ts +0 -184
  182. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/image-block.ts +0 -162
  183. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/item-image.ts +0 -214
  184. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/list/tile-list-compact-header.ts +0 -112
  185. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/list/tile-list-compact.ts +0 -278
  186. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/list/tile-list.ts +0 -718
  187. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/models.ts +0 -21
  188. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/overlay/icon-overlay.ts +0 -57
  189. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/overlay/text-overlay.ts +0 -79
  190. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/review-block.ts +0 -130
  191. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/text-snippet-block.ts +0 -132
  192. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/tile-dispatcher.ts +0 -637
  193. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/tile-display-value-provider.ts +0 -133
  194. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/tile-mediatype-icon.ts +0 -133
  195. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/analytics-events.ts +0 -29
  196. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/array-equals.ts +0 -8
  197. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/collapse-repeated-quotes.ts +0 -13
  198. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/date-filter-field.ts +0 -11
  199. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/facet-utils.ts +0 -183
  200. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/format-count.ts +0 -95
  201. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/format-date.ts +0 -62
  202. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/format-unit-size.ts +0 -43
  203. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/local-date-from-utc.ts +0 -15
  204. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/log.ts +0 -14
  205. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/resolve-mediatype.ts +0 -26
  206. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/sha1.ts +0 -9
  207. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-browser.test.ts +0 -2639
  208. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/facet-row.test.ts +0 -421
  209. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/facets-template.test.ts +0 -139
  210. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/more-facets-content.test.ts +0 -231
  211. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/more-facets-pagination.test.ts +0 -201
  212. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/toggle-switch.test.ts +0 -164
  213. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets.test.ts +0 -928
  214. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/data-source/collection-browser-data-source.test.ts +0 -193
  215. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/empty-placeholder.test.ts +0 -88
  216. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/expanded-date-picker.test.ts +0 -201
  217. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/icon-overlay.test.ts +0 -38
  218. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/image-block.test.ts +0 -247
  219. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/item-image.test.ts +0 -220
  220. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/manage/manage-bar.test.ts +0 -347
  221. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/manage/remove-items-modal-content.test.ts +0 -81
  222. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mediatype-config.test.ts +0 -11
  223. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mocks/mock-analytics-handler.ts +0 -30
  224. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mocks/mock-search-responses.ts +0 -1364
  225. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mocks/mock-search-service.ts +0 -134
  226. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/restoration-state-handler.test.ts +0 -480
  227. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/review-block.test.ts +0 -62
  228. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/sort-filter-bar/alpha-bar-tooltip.test.ts +0 -17
  229. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/sort-filter-bar/alpha-bar.test.ts +0 -101
  230. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/sort-filter-bar/sort-filter-bar.test.ts +0 -443
  231. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/text-overlay.test.ts +0 -55
  232. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/text-snippet-block.test.ts +0 -85
  233. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tile-stats.test.ts +0 -191
  234. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/account-tile.test.ts +0 -121
  235. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/collection-tile.test.ts +0 -114
  236. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/item-tile.test.ts +0 -520
  237. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/search-tile.test.ts +0 -75
  238. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/hover/hover-pane-controller.test.ts +0 -482
  239. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/hover/tile-hover-pane.test.ts +0 -80
  240. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/list/tile-list-compact-header.test.ts +0 -43
  241. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/list/tile-list-compact.test.ts +0 -282
  242. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/list/tile-list.test.ts +0 -576
  243. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/tile-dispatcher.test.ts +0 -320
  244. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/tile-display-value-provider.test.ts +0 -172
  245. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/tile-mediatype-icon.test.ts +0 -160
  246. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/array-equals.test.ts +0 -31
  247. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/format-count.test.ts +0 -32
  248. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/format-date.test.ts +0 -89
  249. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/format-unit-size.test.ts +0 -21
  250. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/local-date-from-utc.test.ts +0 -37
  251. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/tsconfig.json +0 -25
  252. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/types/dompurify.d.ts +0 -1
  253. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/vite.config.ts +0 -29
  254. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/web-dev-server.config.mjs +0 -30
  255. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/web-test-runner.config.mjs +0 -52
  256. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/yarn.lock +0 -5965
  257. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.editorconfig +0 -29
  258. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.github/workflows/ci.yml +0 -29
  259. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.github/workflows/gh-pages-main.yml +0 -41
  260. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.github/workflows/npm-publish.yml +0 -49
  261. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.github/workflows/pr-preview.yml +0 -40
  262. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.husky/pre-commit +0 -1
  263. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/.prettierignore +0 -1
  264. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/LICENSE +0 -661
  265. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/README.md +0 -68
  266. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/eslint.config.mjs +0 -53
  267. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/index.html +0 -24
  268. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/index.ts +0 -29
  269. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/local.archive.org.cert +0 -86
  270. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/local.archive.org.key +0 -27
  271. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/package.json +0 -129
  272. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/pnpm-lock.yaml +0 -7366
  273. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/pnpm-workspace.yaml +0 -46
  274. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/renovate.json +0 -6
  275. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/app-root.ts +0 -1284
  276. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/arrow-left.ts +0 -10
  277. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/arrow-right.ts +0 -10
  278. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/chevron.ts +0 -4
  279. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/close-circle-dark.ts +0 -5
  280. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/contract.ts +0 -9
  281. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/empty-query.ts +0 -5
  282. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/expand.ts +0 -9
  283. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/eye-closed.ts +0 -5
  284. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/eye.ts +0 -5
  285. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/favorite-filled.ts +0 -10
  286. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/favorite-unfilled.ts +0 -9
  287. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/filter.ts +0 -10
  288. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/login-required.ts +0 -18
  289. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/account.ts +0 -14
  290. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/audio.ts +0 -14
  291. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/collection.ts +0 -12
  292. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/data.ts +0 -15
  293. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/etree.ts +0 -14
  294. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/film.ts +0 -14
  295. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/images.ts +0 -13
  296. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/radio.ts +0 -15
  297. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/search.ts +0 -14
  298. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/software.ts +0 -13
  299. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/texts.ts +0 -13
  300. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/tv-commercial.ts +0 -12
  301. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/tv-fact-check.ts +0 -12
  302. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/tv-quote.ts +0 -12
  303. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/tv.ts +0 -14
  304. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/video.ts +0 -14
  305. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/mediatype/web.ts +0 -13
  306. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/null-result.ts +0 -5
  307. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/quote.ts +0 -7
  308. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/restricted.ts +0 -13
  309. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/reviews.ts +0 -11
  310. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/upload.ts +0 -12
  311. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/assets/img/icons/views.ts +0 -11
  312. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/circular-activity-indicator.ts +0 -64
  313. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-browser.ts +0 -3165
  314. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/facet-row.ts +0 -309
  315. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/facet-tombstone-row.ts +0 -40
  316. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/facets-template.ts +0 -85
  317. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/models.ts +0 -10
  318. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/more-facets-content.ts +0 -644
  319. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/more-facets-pagination.ts +0 -294
  320. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/dedupe.ts +0 -44
  321. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/heuristics/browser-language/browser-language-heuristic.ts +0 -27
  322. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/heuristics/index.ts +0 -3
  323. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-heuristic.ts +0 -17
  324. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-map.ts +0 -70
  325. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.ts +0 -79
  326. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +0 -93
  327. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/models.ts +0 -36
  328. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/smart-facet-bar.ts +0 -437
  329. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/smart-facet-button.ts +0 -145
  330. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/smart-facet-dropdown.ts +0 -185
  331. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/smart-facet-equals.ts +0 -16
  332. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/smart-facets/smart-facet-heuristics.ts +0 -26
  333. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets/toggle-switch.ts +0 -174
  334. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/collection-facets.ts +0 -1013
  335. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/data-source/collection-browser-data-source-interface.ts +0 -351
  336. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/data-source/collection-browser-data-source.ts +0 -1474
  337. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/data-source/collection-browser-query-state.ts +0 -60
  338. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/data-source/models.ts +0 -56
  339. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/empty-placeholder.ts +0 -192
  340. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/expanded-date-picker.ts +0 -191
  341. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/language-code-handler/language-code-handler.ts +0 -64
  342. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/language-code-handler/language-code-mapping.ts +0 -564
  343. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/manage/manage-bar.ts +0 -276
  344. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/manage/remove-items-modal-content.ts +0 -102
  345. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/mediatype/mediatype-config.ts +0 -146
  346. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/models.ts +0 -895
  347. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/restoration-state-handler.ts +0 -550
  348. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/alpha-bar-tooltip.ts +0 -53
  349. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/alpha-bar.ts +0 -252
  350. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/compact.ts +0 -5
  351. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/list.ts +0 -5
  352. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/sort-toggle-disabled.ts +0 -15
  353. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/sort-toggle-down.ts +0 -17
  354. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/sort-toggle-up.ts +0 -17
  355. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/sort-triangle.ts +0 -5
  356. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/img/tile.ts +0 -5
  357. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/sort-filter-bar/sort-filter-bar.ts +0 -733
  358. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/styles/ia-button.ts +0 -139
  359. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/styles/item-image-styles.ts +0 -124
  360. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/styles/sr-only.ts +0 -18
  361. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/styles/tile-action-styles.ts +0 -59
  362. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/base-tile-component.ts +0 -124
  363. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/collection-browser-loading-tile.ts +0 -26
  364. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/grid/account-tile.ts +0 -113
  365. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/grid/collection-tile.ts +0 -184
  366. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/grid/item-tile.ts +0 -347
  367. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/grid/search-tile.ts +0 -90
  368. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/grid/styles/tile-grid-shared-styles.ts +0 -130
  369. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/grid/tile-stats.ts +0 -211
  370. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/hover/hover-pane-controller.ts +0 -638
  371. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/hover/tile-hover-pane.ts +0 -184
  372. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/image-block.ts +0 -162
  373. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/item-image.ts +0 -214
  374. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/list/tile-list-compact-header.ts +0 -112
  375. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/list/tile-list-compact.ts +0 -278
  376. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/list/tile-list.ts +0 -718
  377. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/models.ts +0 -21
  378. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/overlay/icon-overlay.ts +0 -57
  379. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/overlay/text-overlay.ts +0 -79
  380. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/review-block.ts +0 -130
  381. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/text-snippet-block.ts +0 -132
  382. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/tile-dispatcher.ts +0 -637
  383. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/tile-display-value-provider.ts +0 -133
  384. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/tiles/tile-mediatype-icon.ts +0 -133
  385. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/analytics-events.ts +0 -29
  386. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/array-equals.ts +0 -8
  387. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/collapse-repeated-quotes.ts +0 -13
  388. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/date-filter-field.ts +0 -11
  389. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/facet-utils.ts +0 -183
  390. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/format-count.ts +0 -95
  391. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/format-date.ts +0 -62
  392. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/format-unit-size.ts +0 -43
  393. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/local-date-from-utc.ts +0 -15
  394. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/log.ts +0 -14
  395. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/resolve-mediatype.ts +0 -26
  396. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/src/utils/sha1.ts +0 -9
  397. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-browser.test.ts +0 -2639
  398. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-facets/facet-row.test.ts +0 -421
  399. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-facets/facets-template.test.ts +0 -139
  400. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-facets/more-facets-content.test.ts +0 -231
  401. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-facets/more-facets-pagination.test.ts +0 -201
  402. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-facets/toggle-switch.test.ts +0 -164
  403. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/collection-facets.test.ts +0 -928
  404. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/data-source/collection-browser-data-source.test.ts +0 -193
  405. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/empty-placeholder.test.ts +0 -88
  406. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/expanded-date-picker.test.ts +0 -201
  407. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/icon-overlay.test.ts +0 -38
  408. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/image-block.test.ts +0 -247
  409. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/item-image.test.ts +0 -220
  410. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/manage/manage-bar.test.ts +0 -347
  411. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/manage/remove-items-modal-content.test.ts +0 -81
  412. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/mediatype-config.test.ts +0 -11
  413. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/mocks/mock-analytics-handler.ts +0 -30
  414. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/mocks/mock-search-responses.ts +0 -1364
  415. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/mocks/mock-search-service.ts +0 -134
  416. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/restoration-state-handler.test.ts +0 -480
  417. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/review-block.test.ts +0 -62
  418. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/sort-filter-bar/alpha-bar-tooltip.test.ts +0 -17
  419. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/sort-filter-bar/alpha-bar.test.ts +0 -101
  420. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/sort-filter-bar/sort-filter-bar.test.ts +0 -443
  421. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/text-overlay.test.ts +0 -55
  422. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/text-snippet-block.test.ts +0 -85
  423. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tile-stats.test.ts +0 -191
  424. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/grid/account-tile.test.ts +0 -121
  425. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/grid/collection-tile.test.ts +0 -114
  426. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/grid/item-tile.test.ts +0 -520
  427. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/grid/search-tile.test.ts +0 -75
  428. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/hover/hover-pane-controller.test.ts +0 -482
  429. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/hover/tile-hover-pane.test.ts +0 -80
  430. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/list/tile-list-compact-header.test.ts +0 -43
  431. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/list/tile-list-compact.test.ts +0 -282
  432. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/list/tile-list.test.ts +0 -576
  433. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/tile-dispatcher.test.ts +0 -320
  434. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/tile-display-value-provider.test.ts +0 -172
  435. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/tiles/tile-mediatype-icon.test.ts +0 -160
  436. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/utils/array-equals.test.ts +0 -31
  437. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/utils/format-count.test.ts +0 -32
  438. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/utils/format-date.test.ts +0 -89
  439. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/utils/format-unit-size.test.ts +0 -21
  440. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/test/utils/local-date-from-utc.test.ts +0 -37
  441. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/tsconfig.json +0 -25
  442. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/types/dompurify.d.ts +0 -1
  443. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/vite.config.ts +0 -29
  444. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/web-dev-server.config.mjs +0 -30
  445. package/.claude/worktrees/WEBDEV-9127-fix-publish-dist-tag/web-test-runner.config.mjs +0 -52
  446. package/dist/src/collection-facets/more-facets-pagination.d.ts +0 -36
  447. package/dist/src/collection-facets/more-facets-pagination.js +0 -260
  448. package/dist/src/collection-facets/more-facets-pagination.js.map +0 -1
  449. package/dist/test/collection-facets/more-facets-pagination.test.d.ts +0 -1
  450. package/dist/test/collection-facets/more-facets-pagination.test.js +0 -126
  451. package/dist/test/collection-facets/more-facets-pagination.test.js.map +0 -1
  452. package/src/collection-facets/more-facets-pagination.ts +0 -294
  453. package/test/collection-facets/more-facets-pagination.test.ts +0 -201
@@ -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 { 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,7 +800,16 @@ __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
814
  customElement('more-facets-content')
538
815
  ], MoreFacetsContent);