@internetarchive/collection-browser 4.4.1 → 4.5.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 (79) hide show
  1. package/.editorconfig +29 -29
  2. package/.github/workflows/ci.yml +27 -27
  3. package/.github/workflows/gh-pages-main.yml +39 -39
  4. package/.github/workflows/npm-publish.yml +39 -39
  5. package/.github/workflows/pr-preview.yml +38 -38
  6. package/.husky/pre-commit +1 -1
  7. package/.prettierignore +1 -1
  8. package/LICENSE +661 -661
  9. package/README.md +83 -83
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/src/app-root.d.ts +8 -0
  13. package/dist/src/app-root.js +698 -672
  14. package/dist/src/app-root.js.map +1 -1
  15. package/dist/src/collection-browser.d.ts +8 -0
  16. package/dist/src/collection-browser.js +782 -764
  17. package/dist/src/collection-browser.js.map +1 -1
  18. package/dist/src/collection-facets/facet-row.d.ts +6 -0
  19. package/dist/src/collection-facets/facet-row.js +158 -140
  20. package/dist/src/collection-facets/facet-row.js.map +1 -1
  21. package/dist/src/collection-facets/facets-template.js +25 -23
  22. package/dist/src/collection-facets/facets-template.js.map +1 -1
  23. package/dist/src/styles/tile-action-styles.d.ts +14 -0
  24. package/dist/src/styles/tile-action-styles.js +59 -0
  25. package/dist/src/styles/tile-action-styles.js.map +1 -0
  26. package/dist/src/tiles/base-tile-component.d.ts +17 -1
  27. package/dist/src/tiles/base-tile-component.js +50 -1
  28. package/dist/src/tiles/base-tile-component.js.map +1 -1
  29. package/dist/src/tiles/grid/item-tile.js +139 -138
  30. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  31. package/dist/src/tiles/list/tile-list-compact-header.js +71 -46
  32. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  33. package/dist/src/tiles/list/tile-list-compact.d.ts +1 -1
  34. package/dist/src/tiles/list/tile-list-compact.js +138 -100
  35. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  36. package/dist/src/tiles/list/tile-list.d.ts +1 -1
  37. package/dist/src/tiles/list/tile-list.js +316 -298
  38. package/dist/src/tiles/list/tile-list.js.map +1 -1
  39. package/dist/src/tiles/models.d.ts +11 -0
  40. package/dist/src/tiles/models.js.map +1 -1
  41. package/dist/src/tiles/tile-dispatcher.d.ts +14 -0
  42. package/dist/src/tiles/tile-dispatcher.js +319 -216
  43. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  44. package/dist/src/tiles/tile-display-value-provider.js.map +1 -1
  45. package/dist/test/collection-facets/facet-row.test.js +55 -23
  46. package/dist/test/collection-facets/facet-row.test.js.map +1 -1
  47. package/dist/test/tiles/grid/item-tile.test.js +77 -77
  48. package/dist/test/tiles/grid/item-tile.test.js.map +1 -1
  49. package/dist/test/tiles/list/tile-list.test.js +134 -134
  50. package/dist/test/tiles/list/tile-list.test.js.map +1 -1
  51. package/dist/test/tiles/tile-dispatcher.test.js +92 -92
  52. package/dist/test/tiles/tile-dispatcher.test.js.map +1 -1
  53. package/eslint.config.mjs +53 -53
  54. package/index.html +24 -24
  55. package/index.ts +29 -28
  56. package/local.archive.org.cert +86 -86
  57. package/local.archive.org.key +27 -27
  58. package/package.json +120 -120
  59. package/renovate.json +6 -6
  60. package/src/app-root.ts +1284 -1254
  61. package/src/collection-browser.ts +3176 -3161
  62. package/src/collection-facets/facet-row.ts +309 -299
  63. package/src/collection-facets/facets-template.ts +85 -83
  64. package/src/styles/tile-action-styles.ts +59 -0
  65. package/src/tiles/base-tile-component.ts +124 -65
  66. package/src/tiles/grid/item-tile.ts +347 -346
  67. package/src/tiles/list/tile-list-compact-header.ts +112 -86
  68. package/src/tiles/list/tile-list-compact.ts +278 -239
  69. package/src/tiles/list/tile-list.ts +718 -700
  70. package/src/tiles/models.ts +21 -8
  71. package/src/tiles/tile-dispatcher.ts +637 -527
  72. package/src/tiles/tile-display-value-provider.ts +133 -133
  73. package/test/collection-facets/facet-row.test.ts +421 -375
  74. package/test/tiles/grid/item-tile.test.ts +520 -520
  75. package/test/tiles/list/tile-list.test.ts +576 -576
  76. package/test/tiles/tile-dispatcher.test.ts +320 -320
  77. package/tsconfig.json +25 -25
  78. package/web-dev-server.config.mjs +30 -30
  79. package/web-test-runner.config.mjs +52 -52
@@ -6,6 +6,12 @@ export declare class FacetRow extends LitElement {
6
6
  facetType?: FacetOption;
7
7
  /** The facet bucket containing details about the state, count, and key for this row */
8
8
  bucket?: FacetBucket;
9
+ /**
10
+ * Whether to omit the negative/hide button from this facet row if possible.
11
+ * Has no effect if the facet bucket is itself hidden, in which case the hide
12
+ * button *must* be shown to represent the state accurately.
13
+ */
14
+ omitHideButton: boolean;
9
15
  /** The collection name cache for converting collection identifiers to titles */
10
16
  collectionTitles?: CollectionTitles;
11
17
  render(): TemplateResult<1>;
@@ -6,6 +6,18 @@ import eyeIcon from '../assets/img/icons/eye';
6
6
  import eyeClosedIcon from '../assets/img/icons/eye-closed';
7
7
  import { srOnlyStyle } from '../styles/sr-only';
8
8
  let FacetRow = FacetRow_1 = class FacetRow extends LitElement {
9
+ constructor() {
10
+ //
11
+ // UI STATE
12
+ //
13
+ super(...arguments);
14
+ /**
15
+ * Whether to omit the negative/hide button from this facet row if possible.
16
+ * Has no effect if the facet bucket is itself hidden, in which case the hide
17
+ * button *must* be shown to represent the state accurately.
18
+ */
19
+ this.omitHideButton = false;
20
+ }
9
21
  //
10
22
  // COMPONENT LIFECYCLE METHODS
11
23
  //
@@ -32,8 +44,8 @@ let FacetRow = FacetRow_1 = class FacetRow extends LitElement {
32
44
  // For other facet types, we just have a static value to use.
33
45
  const bucketTextDisplay = facetType !== 'collection'
34
46
  ? html `${bucket.displayText ?? bucket.key} ${extraNoteSpan}`
35
- : html `<a href="/details/${bucket.key}">
36
- ${this.collectionTitles?.get(bucket.key) ?? bucket.key}
47
+ : html `<a href="/details/${bucket.key}">
48
+ ${this.collectionTitles?.get(bucket.key) ?? bucket.key}
37
49
  </a> `;
38
50
  const bucketCountText = bucket.count > 0 ? bucket.count.toLocaleString() : '';
39
51
  const facetHidden = bucket.state === 'hidden';
@@ -47,56 +59,59 @@ let FacetRow = FacetRow_1 = class FacetRow extends LitElement {
47
59
  const showHideText = facetHidden ? unhideText : hideText;
48
60
  const ariaLabel = `${titleText}, ${bucket.count} results`;
49
61
  // Added data-testid for Playwright testing
50
- return html `
51
- <div class="facet-row-container">
52
- <div class="facet-checkboxes">
53
- <input
54
- type="checkbox"
55
- .name=${facetType}
56
- .value=${bucket.key}
62
+ return html `
63
+ <div class="facet-row-container">
64
+ <div class="facet-checkboxes">
65
+ <input
66
+ type="checkbox"
67
+ .name=${facetType}
68
+ .value=${bucket.key}
57
69
  @click=${(e) => {
58
70
  this.facetClicked(e, false);
59
- }}
60
- .checked=${facetSelected}
61
- class="select-facet-checkbox"
62
- title=${onlyShowText}
63
- id=${showOnlyCheckboxId}
64
- data-testid=${showOnlyCheckboxId}
65
- />
66
- <div class="hide-facet-container">
67
- <input
68
- type="checkbox"
69
- id=${negativeCheckboxId}
70
- .name=${facetType}
71
- .value=${bucket.key}
71
+ }}
72
+ .checked=${facetSelected}
73
+ class="select-facet-checkbox"
74
+ title=${onlyShowText}
75
+ id=${showOnlyCheckboxId}
76
+ data-testid=${showOnlyCheckboxId}
77
+ />
78
+ <div
79
+ class="hide-facet-container"
80
+ ?hidden=${this.omitHideButton && !facetHidden}
81
+ >
82
+ <input
83
+ type="checkbox"
84
+ id=${negativeCheckboxId}
85
+ .name=${facetType}
86
+ .value=${bucket.key}
72
87
  @click=${(e) => {
73
88
  this.facetClicked(e, true);
74
- }}
75
- .checked=${facetHidden}
76
- class="hide-facet-checkbox"
77
- />
78
- <label
79
- for=${negativeCheckboxId}
80
- class="hide-facet-icon${facetHidden ? ' active' : ''}"
81
- title=${showHideText}
82
- data-testid=${negativeCheckboxId}
83
- >
84
- <span class="sr-only">${showHideText}</span>
85
- <span class="eye eye-open">${eyeIcon}</span>
86
- <span class="eye eye-closed">${eyeClosedIcon}</span>
87
- </label>
88
- </div>
89
- </div>
90
- <label
91
- for=${showOnlyCheckboxId}
92
- class="facet-info-display"
93
- title=${onlyShowText}
94
- aria-label=${ariaLabel}
95
- >
96
- <div class="facet-title">${bucketTextDisplay}</div>
97
- <div class="facet-count">${bucketCountText}</div>
98
- </label>
99
- </div>
89
+ }}
90
+ .checked=${facetHidden}
91
+ class="hide-facet-checkbox"
92
+ />
93
+ <label
94
+ for=${negativeCheckboxId}
95
+ class="hide-facet-icon${facetHidden ? ' active' : ''}"
96
+ title=${showHideText}
97
+ data-testid=${negativeCheckboxId}
98
+ >
99
+ <span class="sr-only">${showHideText}</span>
100
+ <span class="eye eye-open">${eyeIcon}</span>
101
+ <span class="eye eye-closed">${eyeClosedIcon}</span>
102
+ </label>
103
+ </div>
104
+ </div>
105
+ <label
106
+ for=${showOnlyCheckboxId}
107
+ class="facet-info-display"
108
+ title=${onlyShowText}
109
+ aria-label=${ariaLabel}
110
+ >
111
+ <div class="facet-title">${bucketTextDisplay}</div>
112
+ <div class="facet-count">${bucketCountText}</div>
113
+ </label>
114
+ </div>
100
115
  `;
101
116
  }
102
117
  //
@@ -153,98 +168,98 @@ let FacetRow = FacetRow_1 = class FacetRow extends LitElement {
153
168
  const facetRowBorderTop = css `var(--facet-row-border-top, 1px solid transparent)`;
154
169
  const facetRowBorderBottom = css `var(--facet-row-border-bottom, 1px solid transparent)`;
155
170
  const checkboxHeight = css `15px`;
156
- const ownCss = css `
157
- .facet-checkboxes {
158
- margin: 0 5px 0 0;
159
- display: flex;
160
- height: ${checkboxHeight};
161
- }
162
- .facet-checkboxes input:first-child {
163
- margin-right: 5px;
164
- }
165
- .facet-checkboxes input {
166
- height: ${checkboxHeight};
167
- width: ${checkboxHeight};
168
- margin: 0;
169
- }
170
- .facet-row-container {
171
- display: flex;
172
- font-weight: 500;
173
- font-size: 1.2rem;
174
- margin: 0 auto;
175
- padding: 0.25rem 0;
176
- height: auto;
177
- border-top: ${facetRowBorderTop};
178
- border-bottom: ${facetRowBorderBottom};
179
- }
180
- .facet-info-display {
181
- display: flex;
182
- flex: 1 1 0%;
183
- cursor: pointer;
184
- flex-wrap: wrap;
185
- }
186
- .facet-title {
187
- word-break: break-word;
188
- display: inline-block;
189
- flex: 1 1 0%;
190
- }
191
- .facet-note {
192
- color: #bbb;
193
- }
194
- .facet-count {
195
- text-align: right;
196
- }
197
- .select-facet-checkbox {
198
- cursor: pointer;
199
- display: inline-block;
200
- }
201
- .hide-facet-checkbox {
202
- position: absolute;
203
- clip: rect(0, 0, 0, 0);
204
- pointer-events: none;
205
- }
206
- .hide-facet-checkbox:focus-visible + .hide-facet-icon {
207
- outline-style: auto;
208
- outline-offset: 2px;
209
- }
210
- .hide-facet-icon {
211
- width: ${checkboxHeight};
212
- height: ${checkboxHeight};
213
- cursor: pointer;
214
- display: flex;
215
- }
216
- .eye {
217
- width: ${checkboxHeight};
218
- height: ${checkboxHeight};
219
- opacity: 0.3;
220
- }
221
- .hide-facet-icon:hover .eye,
222
- .active .eye {
223
- opacity: 1;
224
- }
225
- .hide-facet-icon:hover .eye-open,
226
- .hide-facet-icon .eye-closed {
227
- display: none;
228
- }
229
- .hide-facet-icon:hover .eye-closed,
230
- .hide-facet-icon.active .eye-closed {
231
- display: inline;
232
- }
233
- .hide-facet-icon.active .eye-open {
234
- display: none;
235
- }
236
- .sorting-icon {
237
- cursor: pointer;
238
- }
239
-
240
- a:link,
241
- a:visited {
242
- text-decoration: none;
243
- color: var(--ia-theme-link-color, #4b64ff);
244
- }
245
- a:hover {
246
- text-decoration: underline;
247
- }
171
+ const ownCss = css `
172
+ .facet-checkboxes {
173
+ margin: 0 5px 0 0;
174
+ display: flex;
175
+ height: ${checkboxHeight};
176
+ }
177
+ .facet-checkboxes input:first-child {
178
+ margin-right: 5px;
179
+ }
180
+ .facet-checkboxes input {
181
+ height: ${checkboxHeight};
182
+ width: ${checkboxHeight};
183
+ margin: 0;
184
+ }
185
+ .facet-row-container {
186
+ display: flex;
187
+ font-weight: 500;
188
+ font-size: 1.2rem;
189
+ margin: 0 auto;
190
+ padding: 0.25rem 0;
191
+ height: auto;
192
+ border-top: ${facetRowBorderTop};
193
+ border-bottom: ${facetRowBorderBottom};
194
+ }
195
+ .facet-info-display {
196
+ display: flex;
197
+ flex: 1 1 0%;
198
+ cursor: pointer;
199
+ flex-wrap: wrap;
200
+ }
201
+ .facet-title {
202
+ word-break: break-word;
203
+ display: inline-block;
204
+ flex: 1 1 0%;
205
+ }
206
+ .facet-note {
207
+ color: #bbb;
208
+ }
209
+ .facet-count {
210
+ text-align: right;
211
+ }
212
+ .select-facet-checkbox {
213
+ cursor: pointer;
214
+ display: inline-block;
215
+ }
216
+ .hide-facet-checkbox {
217
+ position: absolute;
218
+ clip: rect(0, 0, 0, 0);
219
+ pointer-events: none;
220
+ }
221
+ .hide-facet-checkbox:focus-visible + .hide-facet-icon {
222
+ outline-style: auto;
223
+ outline-offset: 2px;
224
+ }
225
+ .hide-facet-icon {
226
+ width: ${checkboxHeight};
227
+ height: ${checkboxHeight};
228
+ cursor: pointer;
229
+ display: flex;
230
+ }
231
+ .eye {
232
+ width: ${checkboxHeight};
233
+ height: ${checkboxHeight};
234
+ opacity: 0.3;
235
+ }
236
+ .hide-facet-icon:hover .eye,
237
+ .active .eye {
238
+ opacity: 1;
239
+ }
240
+ .hide-facet-icon:hover .eye-open,
241
+ .hide-facet-icon .eye-closed {
242
+ display: none;
243
+ }
244
+ .hide-facet-icon:hover .eye-closed,
245
+ .hide-facet-icon.active .eye-closed {
246
+ display: inline;
247
+ }
248
+ .hide-facet-icon.active .eye-open {
249
+ display: none;
250
+ }
251
+ .sorting-icon {
252
+ cursor: pointer;
253
+ }
254
+
255
+ a:link,
256
+ a:visited {
257
+ text-decoration: none;
258
+ color: var(--ia-theme-link-color, #4b64ff);
259
+ }
260
+ a:hover {
261
+ text-decoration: underline;
262
+ }
248
263
  `;
249
264
  return [srOnlyStyle, ownCss];
250
265
  }
@@ -255,6 +270,9 @@ __decorate([
255
270
  __decorate([
256
271
  property({ type: Object })
257
272
  ], FacetRow.prototype, "bucket", void 0);
273
+ __decorate([
274
+ property({ type: Boolean, reflect: true })
275
+ ], FacetRow.prototype, "omitHideButton", void 0);
258
276
  __decorate([
259
277
  property({ type: Object })
260
278
  ], FacetRow.prototype, "collectionTitles", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"facet-row.js","sourceRoot":"","sources":["../../../src/collection-facets/facet-row.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n nothing,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport eyeIcon from '../assets/img/icons/eye';\nimport eyeClosedIcon from '../assets/img/icons/eye-closed';\nimport type {\n FacetOption,\n FacetBucket,\n FacetEventDetails,\n FacetState,\n} from '../models';\nimport type { CollectionTitles } from '../data-source/models';\nimport { srOnlyStyle } from '../styles/sr-only';\n\n@customElement('facet-row')\nexport class FacetRow extends LitElement {\n //\n // UI STATE\n //\n\n /** The name of the facet group to which this facet belongs (e.g., \"mediatype\") */\n @property({ type: String }) facetType?: FacetOption;\n\n /** The facet bucket containing details about the state, count, and key for this row */\n @property({ type: Object }) bucket?: FacetBucket;\n\n /** The collection name cache for converting collection identifiers to titles */\n @property({ type: Object })\n collectionTitles?: CollectionTitles;\n\n //\n // COMPONENT LIFECYCLE METHODS\n //\n\n render() {\n return html`${this.facetRowTemplate}`;\n }\n\n //\n // TEMPLATE GETTERS\n //\n\n /**\n * Template for the full facet row, including the positive/negative checks,\n * the display name, and the count.\n */\n private get facetRowTemplate(): TemplateResult | typeof nothing {\n const { bucket, facetType } = this;\n if (!bucket || !facetType) return nothing;\n\n const showOnlyCheckboxId = `${facetType}:${bucket.key}-show-only`;\n const negativeCheckboxId = `${facetType}:${bucket.key}-negative`;\n\n const extraNoteSpan = bucket.extraNote\n ? html`<span class=\"facet-note\">${bucket.extraNote}</span>`\n : nothing;\n\n // For collections, we render the collection title as a link.\n // For other facet types, we just have a static value to use.\n const bucketTextDisplay =\n facetType !== 'collection'\n ? html`${bucket.displayText ?? bucket.key} ${extraNoteSpan}`\n : html`<a href=\"/details/${bucket.key}\">\n ${this.collectionTitles?.get(bucket.key) ?? bucket.key}\n </a> `;\n\n const bucketCountText =\n bucket.count > 0 ? bucket.count.toLocaleString() : '';\n\n const facetHidden = bucket.state === 'hidden';\n const facetSelected = bucket.state === 'selected';\n\n const titleText = `${facetType}: ${bucket.displayText ?? bucket.key}`;\n const onlyShowText = facetSelected\n ? `Show all ${facetType}s`\n : `Only show ${titleText}`;\n const hideText = `Hide ${titleText}`;\n const unhideText = `Unhide ${titleText}`;\n const showHideText = facetHidden ? unhideText : hideText;\n const ariaLabel = `${titleText}, ${bucket.count} results`;\n\n // Added data-testid for Playwright testing\n return html`\n <div class=\"facet-row-container\">\n <div class=\"facet-checkboxes\">\n <input\n type=\"checkbox\"\n .name=${facetType}\n .value=${bucket.key}\n @click=${(e: Event) => {\n this.facetClicked(e, false);\n }}\n .checked=${facetSelected}\n class=\"select-facet-checkbox\"\n title=${onlyShowText}\n id=${showOnlyCheckboxId}\n data-testid=${showOnlyCheckboxId}\n />\n <div class=\"hide-facet-container\">\n <input\n type=\"checkbox\"\n id=${negativeCheckboxId}\n .name=${facetType}\n .value=${bucket.key}\n @click=${(e: Event) => {\n this.facetClicked(e, true);\n }}\n .checked=${facetHidden}\n class=\"hide-facet-checkbox\"\n />\n <label\n for=${negativeCheckboxId}\n class=\"hide-facet-icon${facetHidden ? ' active' : ''}\"\n title=${showHideText}\n data-testid=${negativeCheckboxId}\n >\n <span class=\"sr-only\">${showHideText}</span>\n <span class=\"eye eye-open\">${eyeIcon}</span>\n <span class=\"eye eye-closed\">${eyeClosedIcon}</span>\n </label>\n </div>\n </div>\n <label\n for=${showOnlyCheckboxId}\n class=\"facet-info-display\"\n title=${onlyShowText}\n aria-label=${ariaLabel}\n >\n <div class=\"facet-title\">${bucketTextDisplay}</div>\n <div class=\"facet-count\">${bucketCountText}</div>\n </label>\n </div>\n `;\n }\n\n //\n // EVENT HANDLERS & DISPATCHERS\n //\n\n /**\n * Handler for whenever this facet is clicked & its state changes\n */\n private facetClicked(e: Event, negative: boolean) {\n const { bucket, facetType } = this;\n if (!bucket || !facetType) return;\n\n const target = e.target as HTMLInputElement;\n const { checked } = target;\n this.bucket = {\n ...bucket,\n state: FacetRow.getFacetState(checked, negative),\n };\n\n this.dispatchFacetClickEvent({\n facetType,\n bucket: this.bucket,\n negative,\n });\n }\n\n /**\n * Emits a `facetClick` event with details about this facet & its current state\n */\n private dispatchFacetClickEvent(detail: FacetEventDetails) {\n const event = new CustomEvent<FacetEventDetails>('facetClick', {\n detail,\n });\n this.dispatchEvent(event);\n }\n\n //\n // OTHER METHODS\n //\n\n /**\n * Returns the composed facet state corresponding to a positive or negative facet's checked state\n */\n static getFacetState(checked: boolean, negative: boolean): FacetState {\n let state: FacetState;\n if (checked) {\n state = negative ? 'hidden' : 'selected';\n } else {\n state = 'none';\n }\n return state;\n }\n\n //\n // STYLES\n //\n\n static get styles(): CSSResultGroup {\n const facetRowBorderTop = css`var(--facet-row-border-top, 1px solid transparent)`;\n const facetRowBorderBottom = css`var(--facet-row-border-bottom, 1px solid transparent)`;\n const checkboxHeight = css`15px`;\n\n const ownCss = css`\n .facet-checkboxes {\n margin: 0 5px 0 0;\n display: flex;\n height: ${checkboxHeight};\n }\n .facet-checkboxes input:first-child {\n margin-right: 5px;\n }\n .facet-checkboxes input {\n height: ${checkboxHeight};\n width: ${checkboxHeight};\n margin: 0;\n }\n .facet-row-container {\n display: flex;\n font-weight: 500;\n font-size: 1.2rem;\n margin: 0 auto;\n padding: 0.25rem 0;\n height: auto;\n border-top: ${facetRowBorderTop};\n border-bottom: ${facetRowBorderBottom};\n }\n .facet-info-display {\n display: flex;\n flex: 1 1 0%;\n cursor: pointer;\n flex-wrap: wrap;\n }\n .facet-title {\n word-break: break-word;\n display: inline-block;\n flex: 1 1 0%;\n }\n .facet-note {\n color: #bbb;\n }\n .facet-count {\n text-align: right;\n }\n .select-facet-checkbox {\n cursor: pointer;\n display: inline-block;\n }\n .hide-facet-checkbox {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n }\n .hide-facet-checkbox:focus-visible + .hide-facet-icon {\n outline-style: auto;\n outline-offset: 2px;\n }\n .hide-facet-icon {\n width: ${checkboxHeight};\n height: ${checkboxHeight};\n cursor: pointer;\n display: flex;\n }\n .eye {\n width: ${checkboxHeight};\n height: ${checkboxHeight};\n opacity: 0.3;\n }\n .hide-facet-icon:hover .eye,\n .active .eye {\n opacity: 1;\n }\n .hide-facet-icon:hover .eye-open,\n .hide-facet-icon .eye-closed {\n display: none;\n }\n .hide-facet-icon:hover .eye-closed,\n .hide-facet-icon.active .eye-closed {\n display: inline;\n }\n .hide-facet-icon.active .eye-open {\n display: none;\n }\n .sorting-icon {\n cursor: pointer;\n }\n\n a:link,\n a:visited {\n text-decoration: none;\n color: var(--ia-theme-link-color, #4b64ff);\n }\n a:hover {\n text-decoration: underline;\n }\n `;\n\n return [srOnlyStyle, ownCss];\n }\n}\n"]}
1
+ {"version":3,"file":"facet-row.js","sourceRoot":"","sources":["../../../src/collection-facets/facet-row.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n css,\r\n html,\r\n LitElement,\r\n TemplateResult,\r\n CSSResultGroup,\r\n nothing,\r\n} from 'lit';\r\nimport { customElement, property } from 'lit/decorators.js';\r\nimport eyeIcon from '../assets/img/icons/eye';\r\nimport eyeClosedIcon from '../assets/img/icons/eye-closed';\r\nimport type {\r\n FacetOption,\r\n FacetBucket,\r\n FacetEventDetails,\r\n FacetState,\r\n} from '../models';\r\nimport type { CollectionTitles } from '../data-source/models';\r\nimport { srOnlyStyle } from '../styles/sr-only';\r\n\r\n@customElement('facet-row')\r\nexport class FacetRow extends LitElement {\r\n //\r\n // UI STATE\r\n //\r\n\r\n /** The name of the facet group to which this facet belongs (e.g., \"mediatype\") */\r\n @property({ type: String }) facetType?: FacetOption;\r\n\r\n /** The facet bucket containing details about the state, count, and key for this row */\r\n @property({ type: Object }) bucket?: FacetBucket;\r\n\r\n /**\r\n * Whether to omit the negative/hide button from this facet row if possible.\r\n * Has no effect if the facet bucket is itself hidden, in which case the hide\r\n * button *must* be shown to represent the state accurately.\r\n */\r\n @property({ type: Boolean, reflect: true }) omitHideButton = false;\r\n\r\n /** The collection name cache for converting collection identifiers to titles */\r\n @property({ type: Object })\r\n collectionTitles?: CollectionTitles;\r\n\r\n //\r\n // COMPONENT LIFECYCLE METHODS\r\n //\r\n\r\n render() {\r\n return html`${this.facetRowTemplate}`;\r\n }\r\n\r\n //\r\n // TEMPLATE GETTERS\r\n //\r\n\r\n /**\r\n * Template for the full facet row, including the positive/negative checks,\r\n * the display name, and the count.\r\n */\r\n private get facetRowTemplate(): TemplateResult | typeof nothing {\r\n const { bucket, facetType } = this;\r\n if (!bucket || !facetType) return nothing;\r\n\r\n const showOnlyCheckboxId = `${facetType}:${bucket.key}-show-only`;\r\n const negativeCheckboxId = `${facetType}:${bucket.key}-negative`;\r\n\r\n const extraNoteSpan = bucket.extraNote\r\n ? html`<span class=\"facet-note\">${bucket.extraNote}</span>`\r\n : nothing;\r\n\r\n // For collections, we render the collection title as a link.\r\n // For other facet types, we just have a static value to use.\r\n const bucketTextDisplay =\r\n facetType !== 'collection'\r\n ? html`${bucket.displayText ?? bucket.key} ${extraNoteSpan}`\r\n : html`<a href=\"/details/${bucket.key}\">\r\n ${this.collectionTitles?.get(bucket.key) ?? bucket.key}\r\n </a> `;\r\n\r\n const bucketCountText =\r\n bucket.count > 0 ? bucket.count.toLocaleString() : '';\r\n\r\n const facetHidden = bucket.state === 'hidden';\r\n const facetSelected = bucket.state === 'selected';\r\n\r\n const titleText = `${facetType}: ${bucket.displayText ?? bucket.key}`;\r\n const onlyShowText = facetSelected\r\n ? `Show all ${facetType}s`\r\n : `Only show ${titleText}`;\r\n const hideText = `Hide ${titleText}`;\r\n const unhideText = `Unhide ${titleText}`;\r\n const showHideText = facetHidden ? unhideText : hideText;\r\n const ariaLabel = `${titleText}, ${bucket.count} results`;\r\n\r\n // Added data-testid for Playwright testing\r\n return html`\r\n <div class=\"facet-row-container\">\r\n <div class=\"facet-checkboxes\">\r\n <input\r\n type=\"checkbox\"\r\n .name=${facetType}\r\n .value=${bucket.key}\r\n @click=${(e: Event) => {\r\n this.facetClicked(e, false);\r\n }}\r\n .checked=${facetSelected}\r\n class=\"select-facet-checkbox\"\r\n title=${onlyShowText}\r\n id=${showOnlyCheckboxId}\r\n data-testid=${showOnlyCheckboxId}\r\n />\r\n <div\r\n class=\"hide-facet-container\"\r\n ?hidden=${this.omitHideButton && !facetHidden}\r\n >\r\n <input\r\n type=\"checkbox\"\r\n id=${negativeCheckboxId}\r\n .name=${facetType}\r\n .value=${bucket.key}\r\n @click=${(e: Event) => {\r\n this.facetClicked(e, true);\r\n }}\r\n .checked=${facetHidden}\r\n class=\"hide-facet-checkbox\"\r\n />\r\n <label\r\n for=${negativeCheckboxId}\r\n class=\"hide-facet-icon${facetHidden ? ' active' : ''}\"\r\n title=${showHideText}\r\n data-testid=${negativeCheckboxId}\r\n >\r\n <span class=\"sr-only\">${showHideText}</span>\r\n <span class=\"eye eye-open\">${eyeIcon}</span>\r\n <span class=\"eye eye-closed\">${eyeClosedIcon}</span>\r\n </label>\r\n </div>\r\n </div>\r\n <label\r\n for=${showOnlyCheckboxId}\r\n class=\"facet-info-display\"\r\n title=${onlyShowText}\r\n aria-label=${ariaLabel}\r\n >\r\n <div class=\"facet-title\">${bucketTextDisplay}</div>\r\n <div class=\"facet-count\">${bucketCountText}</div>\r\n </label>\r\n </div>\r\n `;\r\n }\r\n\r\n //\r\n // EVENT HANDLERS & DISPATCHERS\r\n //\r\n\r\n /**\r\n * Handler for whenever this facet is clicked & its state changes\r\n */\r\n private facetClicked(e: Event, negative: boolean) {\r\n const { bucket, facetType } = this;\r\n if (!bucket || !facetType) return;\r\n\r\n const target = e.target as HTMLInputElement;\r\n const { checked } = target;\r\n this.bucket = {\r\n ...bucket,\r\n state: FacetRow.getFacetState(checked, negative),\r\n };\r\n\r\n this.dispatchFacetClickEvent({\r\n facetType,\r\n bucket: this.bucket,\r\n negative,\r\n });\r\n }\r\n\r\n /**\r\n * Emits a `facetClick` event with details about this facet & its current state\r\n */\r\n private dispatchFacetClickEvent(detail: FacetEventDetails) {\r\n const event = new CustomEvent<FacetEventDetails>('facetClick', {\r\n detail,\r\n });\r\n this.dispatchEvent(event);\r\n }\r\n\r\n //\r\n // OTHER METHODS\r\n //\r\n\r\n /**\r\n * Returns the composed facet state corresponding to a positive or negative facet's checked state\r\n */\r\n static getFacetState(checked: boolean, negative: boolean): FacetState {\r\n let state: FacetState;\r\n if (checked) {\r\n state = negative ? 'hidden' : 'selected';\r\n } else {\r\n state = 'none';\r\n }\r\n return state;\r\n }\r\n\r\n //\r\n // STYLES\r\n //\r\n\r\n static get styles(): CSSResultGroup {\r\n const facetRowBorderTop = css`var(--facet-row-border-top, 1px solid transparent)`;\r\n const facetRowBorderBottom = css`var(--facet-row-border-bottom, 1px solid transparent)`;\r\n const checkboxHeight = css`15px`;\r\n\r\n const ownCss = css`\r\n .facet-checkboxes {\r\n margin: 0 5px 0 0;\r\n display: flex;\r\n height: ${checkboxHeight};\r\n }\r\n .facet-checkboxes input:first-child {\r\n margin-right: 5px;\r\n }\r\n .facet-checkboxes input {\r\n height: ${checkboxHeight};\r\n width: ${checkboxHeight};\r\n margin: 0;\r\n }\r\n .facet-row-container {\r\n display: flex;\r\n font-weight: 500;\r\n font-size: 1.2rem;\r\n margin: 0 auto;\r\n padding: 0.25rem 0;\r\n height: auto;\r\n border-top: ${facetRowBorderTop};\r\n border-bottom: ${facetRowBorderBottom};\r\n }\r\n .facet-info-display {\r\n display: flex;\r\n flex: 1 1 0%;\r\n cursor: pointer;\r\n flex-wrap: wrap;\r\n }\r\n .facet-title {\r\n word-break: break-word;\r\n display: inline-block;\r\n flex: 1 1 0%;\r\n }\r\n .facet-note {\r\n color: #bbb;\r\n }\r\n .facet-count {\r\n text-align: right;\r\n }\r\n .select-facet-checkbox {\r\n cursor: pointer;\r\n display: inline-block;\r\n }\r\n .hide-facet-checkbox {\r\n position: absolute;\r\n clip: rect(0, 0, 0, 0);\r\n pointer-events: none;\r\n }\r\n .hide-facet-checkbox:focus-visible + .hide-facet-icon {\r\n outline-style: auto;\r\n outline-offset: 2px;\r\n }\r\n .hide-facet-icon {\r\n width: ${checkboxHeight};\r\n height: ${checkboxHeight};\r\n cursor: pointer;\r\n display: flex;\r\n }\r\n .eye {\r\n width: ${checkboxHeight};\r\n height: ${checkboxHeight};\r\n opacity: 0.3;\r\n }\r\n .hide-facet-icon:hover .eye,\r\n .active .eye {\r\n opacity: 1;\r\n }\r\n .hide-facet-icon:hover .eye-open,\r\n .hide-facet-icon .eye-closed {\r\n display: none;\r\n }\r\n .hide-facet-icon:hover .eye-closed,\r\n .hide-facet-icon.active .eye-closed {\r\n display: inline;\r\n }\r\n .hide-facet-icon.active .eye-open {\r\n display: none;\r\n }\r\n .sorting-icon {\r\n cursor: pointer;\r\n }\r\n\r\n a:link,\r\n a:visited {\r\n text-decoration: none;\r\n color: var(--ia-theme-link-color, #4b64ff);\r\n }\r\n a:hover {\r\n text-decoration: underline;\r\n }\r\n `;\r\n\r\n return [srOnlyStyle, ownCss];\r\n }\r\n}\r\n"]}
@@ -19,17 +19,19 @@ let FacetsTemplate = class FacetsTemplate extends LitElement {
19
19
  if (!facetGroup)
20
20
  return nothing;
21
21
  const facetBuckets = facetGroup.buckets;
22
+ const isLoneBucket = facetBuckets.length === 1;
22
23
  // Added data-testid for Playwright testing
23
24
  // Using className and aria-labels is not ideal for Playwright locator
24
- return html `
25
- <div class="facet-rows" data-testid="facets-on-${facetGroup.key}">
26
- ${repeat(facetBuckets, bucket => `${facetGroup.key}:${bucket.key}`, bucket => html `<facet-row
27
- .facetType=${facetGroup.key}
28
- .bucket=${bucket}
29
- .collectionTitles=${this.collectionTitles}
30
- @facetClick=${this.facetClicked}
31
- ></facet-row>`)}
32
- </div>
25
+ return html `
26
+ <div class="facet-rows" data-testid="facets-on-${facetGroup.key}">
27
+ ${repeat(facetBuckets, bucket => `${facetGroup.key}:${bucket.key}`, bucket => html `<facet-row
28
+ .facetType=${facetGroup.key}
29
+ .bucket=${bucket}
30
+ .collectionTitles=${this.collectionTitles}
31
+ ?omitHideButton=${isLoneBucket}
32
+ @facetClick=${this.facetClicked}
33
+ ></facet-row>`)}
34
+ </div>
33
35
  `;
34
36
  }
35
37
  render() {
@@ -38,20 +40,20 @@ let FacetsTemplate = class FacetsTemplate extends LitElement {
38
40
  static get styles() {
39
41
  const columnCount = css `var(--facetsColumnCount, 1)`;
40
42
  const columnGap = css `var(--facetsColumnGap, 15px)`;
41
- return css `
42
- .facet-rows {
43
- column-count: ${columnCount};
44
- column-gap: ${columnGap};
45
- }
46
-
47
- a:link,
48
- a:visited {
49
- text-decoration: none;
50
- color: var(--ia-theme-link-color, #4b64ff);
51
- }
52
- a:hover {
53
- text-decoration: underline;
54
- }
43
+ return css `
44
+ .facet-rows {
45
+ column-count: ${columnCount};
46
+ column-gap: ${columnGap};
47
+ }
48
+
49
+ a:link,
50
+ a:visited {
51
+ text-decoration: none;
52
+ color: var(--ia-theme-link-color, #4b64ff);
53
+ }
54
+ a:hover {
55
+ text-decoration: underline;
56
+ }
55
57
  `;
56
58
  }
57
59
  };
@@ -1 +1 @@
1
- {"version":3,"file":"facets-template.js","sourceRoot":"","sources":["../../../src/collection-facets/facets-template.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EACH,IAAI,EACJ,UAAU,EAGV,OAAO,GACR,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAGlD,OAAO,aAAa,CAAC;AAGd,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAMpC,YAAY,CAAC,CAAiC;QACpD,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAEO,uBAAuB,CAAC,MAAyB;QACvD,MAAM,KAAK,GAAG,IAAI,WAAW,CAAoB,YAAY,EAAE;YAC7D,MAAM;YACN,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,IAAY,cAAc;QACxB,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,UAAU;YAAE,OAAO,OAAO,CAAC;QAEhC,MAAM,YAAY,GAAG,UAAU,CAAC,OAAwB,CAAC;QAEzD,2CAA2C;QAC3C,sEAAsE;QACtE,OAAO,IAAI,CAAA;uDACwC,UAAU,CAAC,GAAG;UAC3D,MAAM,CACN,YAAY,EACZ,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,EAAE,EAC3C,MAAM,CAAC,EAAE,CACP,IAAI,CAAA;2BACW,UAAU,CAAC,GAAG;wBACjB,MAAM;kCACI,IAAI,CAAC,gBAAgB;4BAC3B,IAAI,CAAC,YAAY;0BACnB,CACjB;;KAEJ,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACtC,CAAC;IAED,MAAM,KAAK,MAAM;QACf,MAAM,WAAW,GAAG,GAAG,CAAA,6BAA6B,CAAC;QACrD,MAAM,SAAS,GAAG,GAAG,CAAA,8BAA8B,CAAC;QAEpD,OAAO,GAAG,CAAA;;wBAEU,WAAW;sBACb,SAAS;;;;;;;;;;;KAW1B,CAAC;IACJ,CAAC;CACF,CAAA;AAlE6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;kDAAyB;AAGpD;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDACS;AAJzB,cAAc;IAD1B,aAAa,CAAC,iBAAiB,CAAC;GACpB,cAAc,CAmE1B","sourcesContent":["import {\n css,\n html,\n LitElement,\n TemplateResult,\n CSSResultGroup,\n nothing,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport type { FacetGroup, FacetBucket, FacetEventDetails } from '../models';\nimport type { CollectionTitles } from '../data-source/models';\nimport './facet-row';\n\n@customElement('facets-template')\nexport class FacetsTemplate extends LitElement {\n @property({ type: Object }) facetGroup?: FacetGroup;\n\n @property({ type: Object })\n collectionTitles?: CollectionTitles;\n\n private facetClicked(e: CustomEvent<FacetEventDetails>) {\n this.dispatchFacetClickEvent(e.detail);\n }\n\n private dispatchFacetClickEvent(detail: FacetEventDetails) {\n const event = new CustomEvent<FacetEventDetails>('facetClick', {\n detail,\n composed: true,\n });\n this.dispatchEvent(event);\n }\n\n private get facetsTemplate(): TemplateResult | typeof nothing {\n const { facetGroup } = this;\n if (!facetGroup) return nothing;\n\n const facetBuckets = facetGroup.buckets as FacetBucket[];\n\n // Added data-testid for Playwright testing\n // Using className and aria-labels is not ideal for Playwright locator\n return html`\n <div class=\"facet-rows\" data-testid=\"facets-on-${facetGroup.key}\">\n ${repeat(\n facetBuckets,\n bucket => `${facetGroup.key}:${bucket.key}`,\n bucket =>\n html`<facet-row\n .facetType=${facetGroup.key}\n .bucket=${bucket}\n .collectionTitles=${this.collectionTitles}\n @facetClick=${this.facetClicked}\n ></facet-row>`,\n )}\n </div>\n `;\n }\n\n render() {\n return html`${this.facetsTemplate}`;\n }\n\n static get styles(): CSSResultGroup {\n const columnCount = css`var(--facetsColumnCount, 1)`;\n const columnGap = css`var(--facetsColumnGap, 15px)`;\n\n return css`\n .facet-rows {\n column-count: ${columnCount};\n column-gap: ${columnGap};\n }\n\n a:link,\n a:visited {\n text-decoration: none;\n color: var(--ia-theme-link-color, #4b64ff);\n }\n a:hover {\n text-decoration: underline;\n }\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"facets-template.js","sourceRoot":"","sources":["../../../src/collection-facets/facets-template.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EACH,IAAI,EACJ,UAAU,EAGV,OAAO,GACR,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAGlD,OAAO,aAAa,CAAC;AAGd,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAMpC,YAAY,CAAC,CAAiC;QACpD,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAEO,uBAAuB,CAAC,MAAyB;QACvD,MAAM,KAAK,GAAG,IAAI,WAAW,CAAoB,YAAY,EAAE;YAC7D,MAAM;YACN,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,IAAY,cAAc;QACxB,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,UAAU;YAAE,OAAO,OAAO,CAAC;QAEhC,MAAM,YAAY,GAAG,UAAU,CAAC,OAAwB,CAAC;QACzD,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC;QAE/C,2CAA2C;QAC3C,sEAAsE;QACtE,OAAO,IAAI,CAAA;uDACwC,UAAU,CAAC,GAAG;UAC3D,MAAM,CACN,YAAY,EACZ,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,EAAE,EAC3C,MAAM,CAAC,EAAE,CACP,IAAI,CAAA;2BACW,UAAU,CAAC,GAAG;wBACjB,MAAM;kCACI,IAAI,CAAC,gBAAgB;gCACvB,YAAY;4BAChB,IAAI,CAAC,YAAY;0BACnB,CACjB;;KAEJ,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACtC,CAAC;IAED,MAAM,KAAK,MAAM;QACf,MAAM,WAAW,GAAG,GAAG,CAAA,6BAA6B,CAAC;QACrD,MAAM,SAAS,GAAG,GAAG,CAAA,8BAA8B,CAAC;QAEpD,OAAO,GAAG,CAAA;;wBAEU,WAAW;sBACb,SAAS;;;;;;;;;;;KAW1B,CAAC;IACJ,CAAC;CACF,CAAA;AApE6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;kDAAyB;AAGpD;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDACS;AAJzB,cAAc;IAD1B,aAAa,CAAC,iBAAiB,CAAC;GACpB,cAAc,CAqE1B","sourcesContent":["import {\r\n css,\r\n html,\r\n LitElement,\r\n TemplateResult,\r\n CSSResultGroup,\r\n nothing,\r\n} from 'lit';\r\nimport { customElement, property } from 'lit/decorators.js';\r\nimport { repeat } from 'lit/directives/repeat.js';\r\nimport type { FacetGroup, FacetBucket, FacetEventDetails } from '../models';\r\nimport type { CollectionTitles } from '../data-source/models';\r\nimport './facet-row';\r\n\r\n@customElement('facets-template')\r\nexport class FacetsTemplate extends LitElement {\r\n @property({ type: Object }) facetGroup?: FacetGroup;\r\n\r\n @property({ type: Object })\r\n collectionTitles?: CollectionTitles;\r\n\r\n private facetClicked(e: CustomEvent<FacetEventDetails>) {\r\n this.dispatchFacetClickEvent(e.detail);\r\n }\r\n\r\n private dispatchFacetClickEvent(detail: FacetEventDetails) {\r\n const event = new CustomEvent<FacetEventDetails>('facetClick', {\r\n detail,\r\n composed: true,\r\n });\r\n this.dispatchEvent(event);\r\n }\r\n\r\n private get facetsTemplate(): TemplateResult | typeof nothing {\r\n const { facetGroup } = this;\r\n if (!facetGroup) return nothing;\r\n\r\n const facetBuckets = facetGroup.buckets as FacetBucket[];\r\n const isLoneBucket = facetBuckets.length === 1;\r\n\r\n // Added data-testid for Playwright testing\r\n // Using className and aria-labels is not ideal for Playwright locator\r\n return html`\r\n <div class=\"facet-rows\" data-testid=\"facets-on-${facetGroup.key}\">\r\n ${repeat(\r\n facetBuckets,\r\n bucket => `${facetGroup.key}:${bucket.key}`,\r\n bucket =>\r\n html`<facet-row\r\n .facetType=${facetGroup.key}\r\n .bucket=${bucket}\r\n .collectionTitles=${this.collectionTitles}\r\n ?omitHideButton=${isLoneBucket}\r\n @facetClick=${this.facetClicked}\r\n ></facet-row>`,\r\n )}\r\n </div>\r\n `;\r\n }\r\n\r\n render() {\r\n return html`${this.facetsTemplate}`;\r\n }\r\n\r\n static get styles(): CSSResultGroup {\r\n const columnCount = css`var(--facetsColumnCount, 1)`;\r\n const columnGap = css`var(--facetsColumnGap, 15px)`;\r\n\r\n return css`\r\n .facet-rows {\r\n column-count: ${columnCount};\r\n column-gap: ${columnGap};\r\n }\r\n\r\n a:link,\r\n a:visited {\r\n text-decoration: none;\r\n color: var(--ia-theme-link-color, #4b64ff);\r\n }\r\n a:hover {\r\n text-decoration: underline;\r\n }\r\n `;\r\n }\r\n}\r\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Shared styles for tile action buttons rendered in grid, list-detail, and
3
+ * list-compact display modes. Layout positioning is handled by each tile
4
+ * component; these styles cover only the button appearance and the row
5
+ * container's default flex behavior.
6
+ *
7
+ * Customizable via CSS custom properties:
8
+ * - `--tileActionColor` (defaults to --primaryErrorCTAFill, then #d9534f)
9
+ * - `--tileActionBg` (default: #fff)
10
+ * - `--tileActionBorderColor` (defaults to --primaryErrorCTAFill, then #d9534f)
11
+ * - `--tileActionHoverBg` (defaults to --primaryErrorCTAFillRGB at 20% alpha)
12
+ * - `--tileActionHoverColor` (defaults to --tileActionColor)
13
+ */
14
+ export declare const tileActionStyles: import("lit").CSSResult;
@@ -0,0 +1,59 @@
1
+ import { css } from 'lit';
2
+ /**
3
+ * Shared styles for tile action buttons rendered in grid, list-detail, and
4
+ * list-compact display modes. Layout positioning is handled by each tile
5
+ * component; these styles cover only the button appearance and the row
6
+ * container's default flex behavior.
7
+ *
8
+ * Customizable via CSS custom properties:
9
+ * - `--tileActionColor` (defaults to --primaryErrorCTAFill, then #d9534f)
10
+ * - `--tileActionBg` (default: #fff)
11
+ * - `--tileActionBorderColor` (defaults to --primaryErrorCTAFill, then #d9534f)
12
+ * - `--tileActionHoverBg` (defaults to --primaryErrorCTAFillRGB at 20% alpha)
13
+ * - `--tileActionHoverColor` (defaults to --tileActionColor)
14
+ */
15
+ export const tileActionStyles = css `
16
+ .tile-actions {
17
+ flex-shrink: 0;
18
+ display: flex;
19
+ gap: var(--tileActionGap, 0);
20
+ }
21
+
22
+ .tile-action-btn {
23
+ flex: 1;
24
+ padding: 6px 5px;
25
+ border: 2px solid
26
+ var(--tileActionBorderColor, var(--primaryErrorCTAFill, #d9534f));
27
+ border-radius: var(--tileActionBorderRadius, 0);
28
+ /* Inherit from the surrounding tile rather than the UA default for <button> */
29
+ font-family: inherit;
30
+ font-size: 1.2rem;
31
+ font-weight: bold;
32
+ cursor: pointer;
33
+ color: var(--tileActionColor, var(--primaryErrorCTAFill, #d9534f));
34
+ background: var(--tileActionBg, #fff);
35
+ transition:
36
+ background 0.15s,
37
+ color 0.15s;
38
+ }
39
+
40
+ /*
41
+ * When buttons are flush against each other (no gap), overlap their shared
42
+ * edge by 1px so adjacent borders don't double up.
43
+ */
44
+ .tile-action-btn + .tile-action-btn {
45
+ margin-left: -1px;
46
+ }
47
+
48
+ .tile-action-btn:hover {
49
+ background: var(
50
+ --tileActionHoverBg,
51
+ rgba(var(--primaryErrorCTAFillRGB, 229, 28, 38), 0.2)
52
+ );
53
+ color: var(
54
+ --tileActionHoverColor,
55
+ var(--tileActionColor, var(--primaryErrorCTAFill, #d9534f))
56
+ );
57
+ }
58
+ `;
59
+ //# sourceMappingURL=tile-action-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tile-action-styles.js","sourceRoot":"","sources":["../../../src/styles/tile-action-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ClC,CAAC","sourcesContent":["import { css } from 'lit';\r\n\r\n/**\r\n * Shared styles for tile action buttons rendered in grid, list-detail, and\r\n * list-compact display modes. Layout positioning is handled by each tile\r\n * component; these styles cover only the button appearance and the row\r\n * container's default flex behavior.\r\n *\r\n * Customizable via CSS custom properties:\r\n * - `--tileActionColor` (defaults to --primaryErrorCTAFill, then #d9534f)\r\n * - `--tileActionBg` (default: #fff)\r\n * - `--tileActionBorderColor` (defaults to --primaryErrorCTAFill, then #d9534f)\r\n * - `--tileActionHoverBg` (defaults to --primaryErrorCTAFillRGB at 20% alpha)\r\n * - `--tileActionHoverColor` (defaults to --tileActionColor)\r\n */\r\nexport const tileActionStyles = css`\r\n .tile-actions {\r\n flex-shrink: 0;\r\n display: flex;\r\n gap: var(--tileActionGap, 0);\r\n }\r\n\r\n .tile-action-btn {\r\n flex: 1;\r\n padding: 6px 5px;\r\n border: 2px solid\r\n var(--tileActionBorderColor, var(--primaryErrorCTAFill, #d9534f));\r\n border-radius: var(--tileActionBorderRadius, 0);\r\n /* Inherit from the surrounding tile rather than the UA default for <button> */\r\n font-family: inherit;\r\n font-size: 1.2rem;\r\n font-weight: bold;\r\n cursor: pointer;\r\n color: var(--tileActionColor, var(--primaryErrorCTAFill, #d9534f));\r\n background: var(--tileActionBg, #fff);\r\n transition:\r\n background 0.15s,\r\n color 0.15s;\r\n }\r\n\r\n /*\r\n * When buttons are flush against each other (no gap), overlap their shared\r\n * edge by 1px so adjacent borders don't double up.\r\n */\r\n .tile-action-btn + .tile-action-btn {\r\n margin-left: -1px;\r\n }\r\n\r\n .tile-action-btn:hover {\r\n background: var(\r\n --tileActionHoverBg,\r\n rgba(var(--primaryErrorCTAFillRGB, 229, 28, 38), 0.2)\r\n );\r\n color: var(\r\n --tileActionHoverColor,\r\n var(--tileActionColor, var(--primaryErrorCTAFill, #d9534f))\r\n );\r\n }\r\n`;\r\n"]}
@@ -1,10 +1,13 @@
1
- import { LitElement, PropertyValues } from 'lit';
1
+ import { LitElement, nothing, PropertyValues, TemplateResult } from 'lit';
2
2
  import type { SortParam } from '@internetarchive/search-service';
3
3
  import { TileDisplayValueProvider } from './tile-display-value-provider';
4
4
  import type { TileModel } from '../models';
5
5
  import { DateFormat } from '../utils/format-date';
6
+ import type { TileAction } from './models';
6
7
  export declare abstract class BaseTileComponent extends LitElement {
7
8
  model?: TileModel;
9
+ /** Action buttons to display on this tile (rendered by subclasses) */
10
+ tileActions: TileAction[];
8
11
  currentWidth?: number;
9
12
  currentHeight?: number;
10
13
  baseNavigationUrl?: string;
@@ -24,4 +27,17 @@ export declare abstract class BaseTileComponent extends LitElement {
24
27
  * account whether this tile component should be using local time or UTC.
25
28
  */
26
29
  protected getFormattedDate(date?: Date, format?: DateFormat): string;
30
+ /**
31
+ * Renders the action buttons configured for this tile, or `nothing` if
32
+ * there are none. Optional `extraClass` is appended to the container's
33
+ * class list so subclasses can target their own layout tweaks.
34
+ */
35
+ protected renderTileActions(extraClass?: string): TemplateResult | typeof nothing;
36
+ /**
37
+ * Click handler for tile action buttons. Stops propagation so the click
38
+ * doesn't activate a wrapping tile link, and dispatches a
39
+ * `tileActionClicked` event (bubbling + composed) carrying the action ID
40
+ * and the tile model.
41
+ */
42
+ protected handleTileActionClick(e: Event, action: TileAction): void;
27
43
  }