@internetarchive/elements 0.4.0 → 0.4.2-webdev-9107.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 (134) hide show
  1. package/dist/src/elements/ia-audio-element/ia-audio-element.d.ts.map +1 -1
  2. package/dist/src/elements/ia-audio-element/ia-audio-element.js +2 -1
  3. package/dist/src/elements/ia-audio-element/ia-audio-element.js.map +1 -1
  4. package/dist/src/elements/ia-button/ia-button.d.ts.map +1 -1
  5. package/dist/src/elements/ia-button/ia-button.js +2 -1
  6. package/dist/src/elements/ia-button/ia-button.js.map +1 -1
  7. package/dist/src/elements/ia-combo-box/ia-combo-box.d.ts.map +1 -1
  8. package/dist/src/elements/ia-combo-box/ia-combo-box.js +2 -1
  9. package/dist/src/elements/ia-combo-box/ia-combo-box.js.map +1 -1
  10. package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.d.ts.map +1 -1
  11. package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js +2 -1
  12. package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js.map +1 -1
  13. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.d.ts.map +1 -1
  14. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js +2 -1
  15. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js.map +1 -1
  16. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.d.ts.map +1 -1
  17. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js +2 -1
  18. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js.map +1 -1
  19. package/dist/src/elements/ia-image-viewer/ia-image-viewer.d.ts.map +1 -1
  20. package/dist/src/elements/ia-image-viewer/ia-image-viewer.js +2 -1
  21. package/dist/src/elements/ia-image-viewer/ia-image-viewer.js.map +1 -1
  22. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.d.ts.map +1 -1
  23. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js +2 -1
  24. package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js.map +1 -1
  25. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.d.ts.map +1 -1
  26. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.js +2 -1
  27. package/dist/src/elements/ia-image-viewer/ia-imgview-slide.js.map +1 -1
  28. package/dist/src/elements/ia-item-navigator/ia-item-navigator.d.ts.map +1 -1
  29. package/dist/src/elements/ia-item-navigator/ia-item-navigator.js +2 -1
  30. package/dist/src/elements/ia-item-navigator/ia-item-navigator.js.map +1 -1
  31. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.d.ts.map +1 -1
  32. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.js +2 -1
  33. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.js.map +1 -1
  34. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.d.ts.map +1 -1
  35. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.js +2 -1
  36. package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.js.map +1 -1
  37. package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.d.ts.map +1 -1
  38. package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.js +2 -1
  39. package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.js.map +1 -1
  40. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.d.ts.map +1 -1
  41. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.js +2 -1
  42. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.js.map +1 -1
  43. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.d.ts.map +1 -1
  44. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.js +2 -1
  45. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.js.map +1 -1
  46. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.d.ts.map +1 -1
  47. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js +2 -1
  48. package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js.map +1 -1
  49. package/dist/src/elements/ia-otp-form/ia-otp-form.d.ts.map +1 -1
  50. package/dist/src/elements/ia-otp-form/ia-otp-form.js +2 -1
  51. package/dist/src/elements/ia-otp-form/ia-otp-form.js.map +1 -1
  52. package/dist/src/elements/ia-otp-input/ia-otp-input.d.ts.map +1 -1
  53. package/dist/src/elements/ia-otp-input/ia-otp-input.js +2 -1
  54. package/dist/src/elements/ia-otp-input/ia-otp-input.js.map +1 -1
  55. package/dist/src/elements/ia-playback-controls/ia-playback-controls.d.ts.map +1 -1
  56. package/dist/src/elements/ia-playback-controls/ia-playback-controls.js +2 -1
  57. package/dist/src/elements/ia-playback-controls/ia-playback-controls.js.map +1 -1
  58. package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts.map +1 -1
  59. package/dist/src/elements/ia-radio-player/ia-radio-player.js +2 -1
  60. package/dist/src/elements/ia-radio-player/ia-radio-player.js.map +1 -1
  61. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.d.ts.map +1 -1
  62. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js +2 -1
  63. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js.map +1 -1
  64. package/dist/src/elements/ia-reviews/assets/delete-icon.svg +8 -0
  65. package/dist/src/elements/ia-reviews/assets/star-basic.svg +6 -0
  66. package/dist/src/elements/ia-reviews/assets/star-selected.svg +8 -0
  67. package/dist/src/elements/ia-reviews/assets/star-unselected.svg +8 -0
  68. package/dist/src/elements/ia-reviews/ia-review-form.d.ts +104 -0
  69. package/dist/src/elements/ia-reviews/ia-review-form.d.ts.map +1 -0
  70. package/dist/src/elements/ia-reviews/ia-review-form.js +678 -0
  71. package/dist/src/elements/ia-reviews/ia-review-form.js.map +1 -0
  72. package/dist/src/elements/ia-reviews/ia-review.d.ts +49 -0
  73. package/dist/src/elements/ia-reviews/ia-review.d.ts.map +1 -0
  74. package/dist/src/elements/ia-reviews/ia-review.js +349 -0
  75. package/dist/src/elements/ia-reviews/ia-review.js.map +1 -0
  76. package/dist/src/elements/ia-reviews/ia-reviews.d.ts +63 -0
  77. package/dist/src/elements/ia-reviews/ia-reviews.d.ts.map +1 -0
  78. package/dist/src/elements/ia-reviews/ia-reviews.js +357 -0
  79. package/dist/src/elements/ia-reviews/ia-reviews.js.map +1 -0
  80. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts +8 -0
  81. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts.map +1 -0
  82. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js +15 -0
  83. package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js.map +1 -0
  84. package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts +13 -0
  85. package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts.map +1 -0
  86. package/dist/src/elements/ia-reviews/utils/collapse-space.js +19 -0
  87. package/dist/src/elements/ia-reviews/utils/collapse-space.js.map +1 -0
  88. package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts +14 -0
  89. package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts.map +1 -0
  90. package/dist/src/elements/ia-reviews/utils/friendly-truncate.js +65 -0
  91. package/dist/src/elements/ia-reviews/utils/friendly-truncate.js.map +1 -0
  92. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts +9 -0
  93. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts.map +1 -0
  94. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js +40 -0
  95. package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js.map +1 -0
  96. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts +9 -0
  97. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts.map +1 -0
  98. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js +29 -0
  99. package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js.map +1 -0
  100. package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts +13 -0
  101. package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts.map +1 -0
  102. package/dist/src/elements/ia-reviews/utils/truncate-screenname.js +19 -0
  103. package/dist/src/elements/ia-reviews/utils/truncate-screenname.js.map +1 -0
  104. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.d.ts.map +1 -1
  105. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js +2 -1
  106. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js.map +1 -1
  107. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.d.ts.map +1 -1
  108. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js +2 -1
  109. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js.map +1 -1
  110. package/dist/src/elements/ia-sr-only-text/ia-sr-only-text.js +1 -1
  111. package/dist/src/elements/ia-sr-only-text/ia-sr-only-text.js.map +1 -1
  112. package/dist/src/elements/ia-status-indicator/ia-status-indicator.d.ts.map +1 -1
  113. package/dist/src/elements/ia-status-indicator/ia-status-indicator.js +2 -1
  114. package/dist/src/elements/ia-status-indicator/ia-status-indicator.js.map +1 -1
  115. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.d.ts.map +1 -1
  116. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js +2 -1
  117. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js.map +1 -1
  118. package/dist/src/elements/ia-transcript-view/ia-transcript-view.d.ts.map +1 -1
  119. package/dist/src/elements/ia-transcript-view/ia-transcript-view.js +2 -1
  120. package/dist/src/elements/ia-transcript-view/ia-transcript-view.js.map +1 -1
  121. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.d.ts.map +1 -1
  122. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js +2 -1
  123. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js.map +1 -1
  124. package/dist/src/elements/index.d.ts +3 -0
  125. package/dist/src/elements/index.d.ts.map +1 -1
  126. package/dist/src/elements/index.js +3 -0
  127. package/dist/src/elements/index.js.map +1 -1
  128. package/dist/src/labs/ia-snow/ia-snow.js +1 -1
  129. package/dist/src/labs/ia-snow/ia-snow.js.map +1 -1
  130. package/dist/src/util/custom-element.d.ts +39 -0
  131. package/dist/src/util/custom-element.d.ts.map +1 -0
  132. package/dist/src/util/custom-element.js +50 -0
  133. package/dist/src/util/custom-element.js.map +1 -0
  134. package/package.json +17 -1
@@ -0,0 +1,29 @@
1
+ import DOMPurify from 'dompurify';
2
+ const ALLOWED_TAGS = ['a'];
3
+ /**
4
+ * Uses DOMpurify to sanitize a given review body.
5
+ * Currently only allows a tags.
6
+ *
7
+ * @param {string} reviewBody The review to be sanitized
8
+ * @returns {string} The sanitized review
9
+ */
10
+ export default function sanitizeReviewBody(reviewBody) {
11
+ // DOMPurify is a shared singleton, so the hook is added around this one call
12
+ // and taken off again. Leaving it registered would stack up another copy per
13
+ // review and force these attributes onto every other caller's anchors too.
14
+ DOMPurify.addHook('afterSanitizeAttributes', forceExternalLinkAttributes);
15
+ try {
16
+ return DOMPurify.sanitize(reviewBody, { ALLOWED_TAGS: ALLOWED_TAGS });
17
+ }
18
+ finally {
19
+ DOMPurify.removeHook('afterSanitizeAttributes');
20
+ }
21
+ }
22
+ /** Marks links as untrusted user content and opens them away from the page. */
23
+ function forceExternalLinkAttributes(node) {
24
+ if (node.nodeName.toLowerCase() !== 'a')
25
+ return;
26
+ node.setAttribute('rel', 'ugc nofollow');
27
+ node.setAttribute('target', '_blank');
28
+ }
29
+ //# sourceMappingURL=sanitize-review-body.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-review-body.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/sanitize-review-body.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,UAAkB;IAC3D,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,SAAS,CAAC,OAAO,CAAC,yBAAyB,EAAE,2BAA2B,CAAC,CAAC;IAC1E,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC;IACxE,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,SAAS,2BAA2B,CAAC,IAAU;IAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,GAAG;QAAE,OAAO;IAC/C,IAAgB,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACrD,IAAgB,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import DOMPurify from 'dompurify';\n\nconst ALLOWED_TAGS = ['a'];\n\n/**\n * Uses DOMpurify to sanitize a given review body.\n * Currently only allows a tags.\n *\n * @param {string} reviewBody The review to be sanitized\n * @returns {string} The sanitized review\n */\nexport default function sanitizeReviewBody(reviewBody: string): string {\n // DOMPurify is a shared singleton, so the hook is added around this one call\n // and taken off again. Leaving it registered would stack up another copy per\n // review and force these attributes onto every other caller's anchors too.\n DOMPurify.addHook('afterSanitizeAttributes', forceExternalLinkAttributes);\n try {\n return DOMPurify.sanitize(reviewBody, { ALLOWED_TAGS: ALLOWED_TAGS });\n } finally {\n DOMPurify.removeHook('afterSanitizeAttributes');\n }\n}\n\n/** Marks links as untrusted user content and opens them away from the page. */\nfunction forceExternalLinkAttributes(node: Node): void {\n if (node.nodeName.toLowerCase() !== 'a') return;\n (node as Element).setAttribute('rel', 'ugc nofollow');\n (node as Element).setAttribute('target', '_blank');\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { HTMLTemplateResult } from 'lit';
2
+ /**
3
+ * Truncates screenname as needed to ensure we only display the correct
4
+ * number of chars throughout site. Must be kept in sync with screenname
5
+ * limit in Account.inc.
6
+ *
7
+ * Adds a title tooltip with full screenname if truncated.
8
+ *
9
+ * @param {string} screenname Screenname to be truncated
10
+ * @returns {HTMLTemplateResult} String or HTML to be displayed
11
+ */
12
+ export declare function truncateScreenname(screenname?: string): HTMLTemplateResult | string;
13
+ //# sourceMappingURL=truncate-screenname.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate-screenname.d.ts","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/truncate-screenname.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,kBAAkB,EAAE,MAAM,KAAK,CAAC;AAE/C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,GAAE,MAAW,GACtB,kBAAkB,GAAG,MAAM,CAQ7B"}
@@ -0,0 +1,19 @@
1
+ import { html } from 'lit';
2
+ /**
3
+ * Truncates screenname as needed to ensure we only display the correct
4
+ * number of chars throughout site. Must be kept in sync with screenname
5
+ * limit in Account.inc.
6
+ *
7
+ * Adds a title tooltip with full screenname if truncated.
8
+ *
9
+ * @param {string} screenname Screenname to be truncated
10
+ * @returns {HTMLTemplateResult} String or HTML to be displayed
11
+ */
12
+ export function truncateScreenname(screenname = '') {
13
+ const SCREENNAME_MAX_LENGTH = 40;
14
+ if (screenname.length <= SCREENNAME_MAX_LENGTH)
15
+ return screenname;
16
+ const truncatedScreenname = screenname.substring(0, SCREENNAME_MAX_LENGTH) + '...';
17
+ return html `<span title="${screenname}">${truncatedScreenname}</span>`;
18
+ }
19
+ //# sourceMappingURL=truncate-screenname.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate-screenname.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/truncate-screenname.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAsB,MAAM,KAAK,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAqB,EAAE;IAEvB,MAAM,qBAAqB,GAAG,EAAE,CAAC;IAEjC,IAAI,UAAU,CAAC,MAAM,IAAI,qBAAqB;QAAE,OAAO,UAAU,CAAC;IAElE,MAAM,mBAAmB,GACvB,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,KAAK,CAAC;IACzD,OAAO,IAAI,CAAA,gBAAgB,UAAU,KAAK,mBAAmB,SAAS,CAAC;AACzE,CAAC","sourcesContent":["import { html, HTMLTemplateResult } from 'lit';\n\n/**\n * Truncates screenname as needed to ensure we only display the correct\n * number of chars throughout site. Must be kept in sync with screenname\n * limit in Account.inc.\n *\n * Adds a title tooltip with full screenname if truncated.\n *\n * @param {string} screenname Screenname to be truncated\n * @returns {HTMLTemplateResult} String or HTML to be displayed\n */\nexport function truncateScreenname(\n screenname: string = '',\n): HTMLTemplateResult | string {\n const SCREENNAME_MAX_LENGTH = 40;\n\n if (screenname.length <= SCREENNAME_MAX_LENGTH) return screenname;\n\n const truncatedScreenname =\n screenname.substring(0, SCREENNAME_MAX_LENGTH) + '...';\n return html`<span title=\"${screenname}\">${truncatedScreenname}</span>`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-scrubber-bar.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-scrubber-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAMb,OAAO,qBAAqB,CAAC;AAuC7B;;;GAGG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,2CAA2C;IACf,KAAK,SAAK;IAEtC,iDAAiD;IACrB,GAAG,SAAK;IAEpC,kDAAkD;IACtB,GAAG,SAAO;IAEtC,2CAA2C;IACf,IAAI,SAAO;IAEvC,oEAAoE;IACzC,wBAAwB,EAAE,MAAM,EAAE,CAAM;IAEnE,uEAAuE;IAC1C,oBAAoB,UAAS;IAE1D,yCAAyC;IACb,KAAK,SAA4B;IAE7D;;;;;;OAMG;IACM,OAAO,CAAC,YAAY,CAAK;IAElC,OAAO,CAAC,iBAAiB,CAAS;IAElC,+DAA+D;IAC/D,IAAI,UAAU,IAAI,MAAM,CAKvB;IAED,MAAM,IAAI,cAAc;IA0CxB,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAMhD;;;;;OAKG;IACH,OAAO,KAAK,kBAAkB,GAS7B;IAED;;;;;;OAMG;IACH,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,kBAAkB;IAK1B;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,WAAW;IAMnB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAMlB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAKxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAiKlC;CACF"}
1
+ {"version":3,"file":"ia-scrubber-bar.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-scrubber-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAOb,OAAO,qBAAqB,CAAC;AAuC7B;;;GAGG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,2CAA2C;IACf,KAAK,SAAK;IAEtC,iDAAiD;IACrB,GAAG,SAAK;IAEpC,kDAAkD;IACtB,GAAG,SAAO;IAEtC,2CAA2C;IACf,IAAI,SAAO;IAEvC,oEAAoE;IACzC,wBAAwB,EAAE,MAAM,EAAE,CAAM;IAEnE,uEAAuE;IAC1C,oBAAoB,UAAS;IAE1D,yCAAyC;IACb,KAAK,SAA4B;IAE7D;;;;;;OAMG;IACM,OAAO,CAAC,YAAY,CAAK;IAElC,OAAO,CAAC,iBAAiB,CAAS;IAElC,+DAA+D;IAC/D,IAAI,UAAU,IAAI,MAAM,CAKvB;IAED,MAAM,IAAI,cAAc;IA0CxB,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAMhD;;;;;OAKG;IACH,OAAO,KAAK,kBAAkB,GAS7B;IAED;;;;;;OAMG;IACH,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,kBAAkB;IAK1B;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,WAAW;IAMnB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAMlB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAKxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAiKlC;CACF"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, } from 'lit';
3
- import { customElement, property, state } from 'lit/decorators.js';
3
+ import { property, state } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  import { msg } from '@lit/localize';
5
6
  import { SectionMarkerMode } from './models.js';
6
7
  import './ia-section-marker.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ia-scrubber-bar.js","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-scrubber-bar.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { msg } from '@lit/localize';\n\nimport { SectionMarkerMode } from './models';\n\nimport './ia-section-marker';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n ValueChange: 'valuechange',\n UserInteractionStarted: 'userInteractionStarted',\n UserInteractionEnded: 'userInteractionEnded',\n};\n\n/**\n * The keys that move a range input.\n *\n * Only these count as scrubbing. Tab in particular must not, since it takes\n * focus away and its keyup lands on whatever it moved to, never here.\n */\nconst VALUE_KEYS = new Set([\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'ArrowDown',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n]);\n\n/**\n * The section boundaries either side of the playhead.\n *\n * `undefined` where there is no boundary on that side, which is the case at\n * the very start and the very end of the track.\n */\ninterface SurroundingMarkers {\n lower?: number;\n upper?: number;\n}\n\n/**\n * A range slider styled as a playback scrubber, with optional section markers\n * laid over the track.\n */\n@customElement('ia-scrubber-bar')\nexport class IAScrubberBar extends LitElement {\n /** The current position along the track */\n @property({ type: Number }) value = 0;\n\n /** The lowest position the scrubber can reach */\n @property({ type: Number }) min = 0;\n\n /** The highest position the scrubber can reach */\n @property({ type: Number }) max = 100;\n\n /** How finely the scrubber can be moved */\n @property({ type: Number }) step = 0.1;\n\n /** Where to draw section boundaries, as percentages of the track */\n @property({ type: Array }) sectionMarkerPercentages: number[] = [];\n\n /** Whether the markers either side of the playhead point towards it */\n @property({ type: Boolean }) expandSectionMarkers = false;\n\n /** The accessible name for the slider */\n @property({ type: String }) label = msg('Playback position');\n\n /**\n * The position actually shown.\n *\n * `value` is driven from outside by whatever is playing the audio, but while\n * the listener is scrubbing their position wins. Keeping the two apart is\n * what stops playback updates fighting the drag.\n */\n @state() private currentValue = 0;\n\n private userIsInteracting = false;\n\n /** How far along the track the playhead is, as a percentage */\n get percentage(): number {\n const range = this.max - this.min;\n if (range === 0) return 0;\n\n return ((this.currentValue - this.min) / range) * 100;\n }\n\n render(): TemplateResult {\n const surrounding = this.surroundingMarkers;\n\n return html`\n <div class=\"container\" style=\"--fill-percent--: ${this.percentage}%\">\n <div class=\"color-fill\"></div>\n\n <div class=\"marker-container\">\n ${this.sectionMarkerPercentages.map(\n (markerPercent) => html`\n <ia-section-marker\n data-location=${markerPercent}\n style=\"left: ${markerPercent}%\"\n .markerMode=${this.markerModeFor(markerPercent, surrounding)}\n ></ia-section-marker>\n `,\n )}\n </div>\n\n <input\n id=\"slider\"\n type=\"range\"\n aria-label=${this.label}\n min=${this.min}\n max=${this.max}\n step=${this.step}\n .value=${String(this.currentValue)}\n @mousedown=${this.interactionStarted}\n @mouseup=${this.interactionEnded}\n @touchstart=${this.interactionStarted}\n @touchend=${this.interactionEnded}\n @touchcancel=${this.interactionEnded}\n @keydown=${this.handleKeyDown}\n @keyup=${this.handleKeyUp}\n @blur=${this.handleBlur}\n @input=${this.handleSlide}\n @change=${this.handleSlide}\n />\n </div>\n `;\n }\n\n updated(changedProperties: PropertyValues): void {\n if (this.userIsInteracting || !changedProperties.has('value')) return;\n\n this.currentValue = this.value;\n }\n\n /**\n * The section boundaries immediately below and above the playhead.\n *\n * Returns nothing when the markers aren't meant to react to the playhead, so\n * every marker falls back to its resting state.\n */\n private get surroundingMarkers(): SurroundingMarkers {\n if (!this.expandSectionMarkers) return {};\n\n const sorted = this.sortedMarkers;\n\n return {\n lower: sorted.filter((percent) => percent <= this.currentValue).pop(),\n upper: sorted.find((percent) => percent > this.currentValue),\n };\n }\n\n /**\n * The marker percentages in ascending numeric order.\n *\n * Sorted on a copy with an explicit comparator: the default `sort()` orders\n * lexicographically, which puts 100 before 9, and it sorts in place, which\n * would reorder the caller's own array.\n */\n private get sortedMarkers(): number[] {\n return [...this.sectionMarkerPercentages].sort((a, b) => a - b);\n }\n\n private markerModeFor(\n markerPercent: number,\n surrounding: SurroundingMarkers,\n ): SectionMarkerMode {\n if (markerPercent === surrounding.upper) return SectionMarkerMode.left;\n if (markerPercent === surrounding.lower) return SectionMarkerMode.right;\n\n return SectionMarkerMode.neither;\n }\n\n private handleSlide(e: Event): void {\n this.currentValue = parseFloat((e.target as HTMLInputElement).value);\n\n this.dispatchEvent(\n new CustomEvent<{ value: number }>(Events.ValueChange, {\n detail: { value: this.currentValue },\n }),\n );\n }\n\n private interactionStarted(): void {\n this.userIsInteracting = true;\n this.dispatchEvent(new Event(Events.UserInteractionStarted));\n }\n\n /**\n * Starts an interaction when the slider is scrubbed from the keyboard.\n *\n * Without this, arrowing along the bar sets the value but leaves\n * `userIsInteracting` false, so the next playback tick snaps the thumb back\n * to the playhead mid-scrub.\n *\n * Guarded against the auto-repeat that holding a key produces, which would\n * otherwise emit a fresh `userInteractionStarted` on every repeat.\n */\n private handleKeyDown(e: KeyboardEvent): void {\n if (!VALUE_KEYS.has(e.key) || this.userIsInteracting) return;\n\n this.interactionStarted();\n }\n\n private handleKeyUp(e: KeyboardEvent): void {\n if (!VALUE_KEYS.has(e.key)) return;\n\n this.interactionEnded();\n }\n\n /**\n * Releases an interaction that focus left behind.\n *\n * A keyup can go missing, e.g. focus moves while the key is still down, and\n * an interaction left latched on would ignore playback updates for good.\n */\n private handleBlur(): void {\n if (!this.userIsInteracting) return;\n\n this.interactionEnded();\n }\n\n /**\n * Ends the interaction.\n *\n * Bound to `touchcancel` as well as `touchend`, because a touch the system\n * takes over never delivers `touchend`, and an interaction left latched on\n * would ignore playback updates from then on.\n */\n private interactionEnded(): void {\n this.userIsInteracting = false;\n this.dispatchEvent(new Event(Events.UserInteractionEnded));\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --scrubber-bar-height--: var(--ia-theme-scrubber-bar-height, 20px);\n --scrubber-marker-inset--: var(--ia-theme-scrubber-marker-inset, 10px);\n\n --scrubber-thumb-color--: var(--ia-theme-scrubber-thumb-color, #fff);\n --scrubber-thumb-diameter--: var(\n --ia-theme-scrubber-thumb-diameter,\n 20px\n );\n --scrubber-thumb-border--: var(\n --ia-theme-scrubber-thumb-border,\n 1px solid #000\n );\n --scrubber-thumb-border-radius--: var(\n --ia-theme-scrubber-thumb-border-radius,\n 50%\n );\n /*\n Centres the thumb on the track. The thumb is content-box, so its\n border adds 1px above and below the diameter, hence the extra -1px.\n Comes out at -6px for the default track and thumb sizes.\n */\n --scrubber-thumb-top-margin--: var(\n --ia-theme-scrubber-thumb-top-margin,\n calc(\n (\n var(--scrubber-track-height--) - var(\n --scrubber-thumb-diameter--\n )\n ) /\n 2 - 1px\n )\n );\n\n --scrubber-track-height--: var(--ia-theme-scrubber-track-height, 10px);\n --scrubber-track-border--: var(\n --ia-theme-scrubber-track-border,\n 1px solid #fff\n );\n --scrubber-track-border-radius--: var(\n --ia-theme-scrubber-track-border-radius,\n 5px\n );\n --scrubber-track-color--: var(\n --ia-theme-scrubber-track-color,\n rgba(0, 0, 0, 0.1)\n );\n --scrubber-track-fill-color--: var(\n --ia-theme-scrubber-track-fill-color,\n #3272b6\n );\n\n /*\n How far off the bottom the track sits. The fill and the section\n markers both line up against this, so they follow the track when its\n height is themed. Comes out at 7px for the default sizes.\n */\n --scrubber-track-offset--: calc(\n (var(--scrubber-bar-height--) - var(--scrubber-track-height--)) / 2 +\n 2px\n );\n }\n\n .container {\n position: relative;\n height: var(--scrubber-bar-height--);\n }\n\n /*\n The fill is a plain element rather than a track pseudo-element, so the\n played portion is just a hard gradient stop driven by a custom property.\n */\n .color-fill {\n height: var(--scrubber-track-height--);\n border-radius: 1em;\n position: absolute;\n bottom: var(--scrubber-track-offset--);\n left: 2px;\n right: -2px;\n background: linear-gradient(\n to right,\n var(--scrubber-track-fill-color--) 0%,\n var(--scrubber-track-fill-color--) var(--fill-percent--),\n var(--scrubber-track-color--) var(--fill-percent--),\n var(--scrubber-track-color--) 100%\n );\n }\n\n .marker-container {\n position: absolute;\n left: var(--scrubber-marker-inset--);\n right: var(--scrubber-marker-inset--);\n height: 100%;\n }\n\n ia-section-marker {\n position: absolute;\n width: 2rem;\n height: var(--scrubber-track-height--);\n bottom: var(--scrubber-track-offset--);\n /*\n The left offset puts the marker where it belongs, but the divider runs\n down the middle of the marker, so it shifts back by half its own width\n to line the divider up with that point.\n */\n transform: translateX(-50%);\n }\n\n input[type='range'] {\n -webkit-appearance: none;\n appearance: none;\n height: var(--scrubber-bar-height--);\n padding: 0;\n width: 100%;\n background: none;\n outline: none;\n position: absolute;\n bottom: 0;\n }\n\n input[type='range']::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n box-sizing: content-box;\n margin-top: var(--scrubber-thumb-top-margin--);\n background-color: var(--scrubber-thumb-color--);\n height: var(--scrubber-thumb-diameter--);\n width: var(--scrubber-thumb-diameter--);\n border-radius: var(--scrubber-thumb-border-radius--);\n border: var(--scrubber-thumb-border--);\n cursor: pointer;\n }\n\n input[type='range']::-moz-range-thumb {\n background-color: var(--scrubber-thumb-color--);\n height: var(--scrubber-thumb-diameter--);\n width: var(--scrubber-thumb-diameter--);\n border-radius: var(--scrubber-thumb-border-radius--);\n border: var(--scrubber-thumb-border--);\n cursor: pointer;\n }\n\n input[type='range']::-webkit-slider-runnable-track {\n border: var(--scrubber-track-border--);\n height: var(--scrubber-track-height--);\n border-radius: var(--scrubber-track-border-radius--);\n }\n\n input[type='range']::-moz-range-track {\n border: var(--scrubber-track-border--);\n height: var(--scrubber-track-height--);\n border-radius: var(--scrubber-track-border-radius--);\n }\n\n input[type='range']::-moz-range-progress {\n height: var(--scrubber-track-height--);\n border-radius: var(--scrubber-track-border-radius--);\n }\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-scrubber-bar.js","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-scrubber-bar.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\n\nimport { SectionMarkerMode } from './models';\n\nimport './ia-section-marker';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n ValueChange: 'valuechange',\n UserInteractionStarted: 'userInteractionStarted',\n UserInteractionEnded: 'userInteractionEnded',\n};\n\n/**\n * The keys that move a range input.\n *\n * Only these count as scrubbing. Tab in particular must not, since it takes\n * focus away and its keyup lands on whatever it moved to, never here.\n */\nconst VALUE_KEYS = new Set([\n 'ArrowLeft',\n 'ArrowRight',\n 'ArrowUp',\n 'ArrowDown',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n]);\n\n/**\n * The section boundaries either side of the playhead.\n *\n * `undefined` where there is no boundary on that side, which is the case at\n * the very start and the very end of the track.\n */\ninterface SurroundingMarkers {\n lower?: number;\n upper?: number;\n}\n\n/**\n * A range slider styled as a playback scrubber, with optional section markers\n * laid over the track.\n */\n@customElement('ia-scrubber-bar')\nexport class IAScrubberBar extends LitElement {\n /** The current position along the track */\n @property({ type: Number }) value = 0;\n\n /** The lowest position the scrubber can reach */\n @property({ type: Number }) min = 0;\n\n /** The highest position the scrubber can reach */\n @property({ type: Number }) max = 100;\n\n /** How finely the scrubber can be moved */\n @property({ type: Number }) step = 0.1;\n\n /** Where to draw section boundaries, as percentages of the track */\n @property({ type: Array }) sectionMarkerPercentages: number[] = [];\n\n /** Whether the markers either side of the playhead point towards it */\n @property({ type: Boolean }) expandSectionMarkers = false;\n\n /** The accessible name for the slider */\n @property({ type: String }) label = msg('Playback position');\n\n /**\n * The position actually shown.\n *\n * `value` is driven from outside by whatever is playing the audio, but while\n * the listener is scrubbing their position wins. Keeping the two apart is\n * what stops playback updates fighting the drag.\n */\n @state() private currentValue = 0;\n\n private userIsInteracting = false;\n\n /** How far along the track the playhead is, as a percentage */\n get percentage(): number {\n const range = this.max - this.min;\n if (range === 0) return 0;\n\n return ((this.currentValue - this.min) / range) * 100;\n }\n\n render(): TemplateResult {\n const surrounding = this.surroundingMarkers;\n\n return html`\n <div class=\"container\" style=\"--fill-percent--: ${this.percentage}%\">\n <div class=\"color-fill\"></div>\n\n <div class=\"marker-container\">\n ${this.sectionMarkerPercentages.map(\n (markerPercent) => html`\n <ia-section-marker\n data-location=${markerPercent}\n style=\"left: ${markerPercent}%\"\n .markerMode=${this.markerModeFor(markerPercent, surrounding)}\n ></ia-section-marker>\n `,\n )}\n </div>\n\n <input\n id=\"slider\"\n type=\"range\"\n aria-label=${this.label}\n min=${this.min}\n max=${this.max}\n step=${this.step}\n .value=${String(this.currentValue)}\n @mousedown=${this.interactionStarted}\n @mouseup=${this.interactionEnded}\n @touchstart=${this.interactionStarted}\n @touchend=${this.interactionEnded}\n @touchcancel=${this.interactionEnded}\n @keydown=${this.handleKeyDown}\n @keyup=${this.handleKeyUp}\n @blur=${this.handleBlur}\n @input=${this.handleSlide}\n @change=${this.handleSlide}\n />\n </div>\n `;\n }\n\n updated(changedProperties: PropertyValues): void {\n if (this.userIsInteracting || !changedProperties.has('value')) return;\n\n this.currentValue = this.value;\n }\n\n /**\n * The section boundaries immediately below and above the playhead.\n *\n * Returns nothing when the markers aren't meant to react to the playhead, so\n * every marker falls back to its resting state.\n */\n private get surroundingMarkers(): SurroundingMarkers {\n if (!this.expandSectionMarkers) return {};\n\n const sorted = this.sortedMarkers;\n\n return {\n lower: sorted.filter((percent) => percent <= this.currentValue).pop(),\n upper: sorted.find((percent) => percent > this.currentValue),\n };\n }\n\n /**\n * The marker percentages in ascending numeric order.\n *\n * Sorted on a copy with an explicit comparator: the default `sort()` orders\n * lexicographically, which puts 100 before 9, and it sorts in place, which\n * would reorder the caller's own array.\n */\n private get sortedMarkers(): number[] {\n return [...this.sectionMarkerPercentages].sort((a, b) => a - b);\n }\n\n private markerModeFor(\n markerPercent: number,\n surrounding: SurroundingMarkers,\n ): SectionMarkerMode {\n if (markerPercent === surrounding.upper) return SectionMarkerMode.left;\n if (markerPercent === surrounding.lower) return SectionMarkerMode.right;\n\n return SectionMarkerMode.neither;\n }\n\n private handleSlide(e: Event): void {\n this.currentValue = parseFloat((e.target as HTMLInputElement).value);\n\n this.dispatchEvent(\n new CustomEvent<{ value: number }>(Events.ValueChange, {\n detail: { value: this.currentValue },\n }),\n );\n }\n\n private interactionStarted(): void {\n this.userIsInteracting = true;\n this.dispatchEvent(new Event(Events.UserInteractionStarted));\n }\n\n /**\n * Starts an interaction when the slider is scrubbed from the keyboard.\n *\n * Without this, arrowing along the bar sets the value but leaves\n * `userIsInteracting` false, so the next playback tick snaps the thumb back\n * to the playhead mid-scrub.\n *\n * Guarded against the auto-repeat that holding a key produces, which would\n * otherwise emit a fresh `userInteractionStarted` on every repeat.\n */\n private handleKeyDown(e: KeyboardEvent): void {\n if (!VALUE_KEYS.has(e.key) || this.userIsInteracting) return;\n\n this.interactionStarted();\n }\n\n private handleKeyUp(e: KeyboardEvent): void {\n if (!VALUE_KEYS.has(e.key)) return;\n\n this.interactionEnded();\n }\n\n /**\n * Releases an interaction that focus left behind.\n *\n * A keyup can go missing, e.g. focus moves while the key is still down, and\n * an interaction left latched on would ignore playback updates for good.\n */\n private handleBlur(): void {\n if (!this.userIsInteracting) return;\n\n this.interactionEnded();\n }\n\n /**\n * Ends the interaction.\n *\n * Bound to `touchcancel` as well as `touchend`, because a touch the system\n * takes over never delivers `touchend`, and an interaction left latched on\n * would ignore playback updates from then on.\n */\n private interactionEnded(): void {\n this.userIsInteracting = false;\n this.dispatchEvent(new Event(Events.UserInteractionEnded));\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --scrubber-bar-height--: var(--ia-theme-scrubber-bar-height, 20px);\n --scrubber-marker-inset--: var(--ia-theme-scrubber-marker-inset, 10px);\n\n --scrubber-thumb-color--: var(--ia-theme-scrubber-thumb-color, #fff);\n --scrubber-thumb-diameter--: var(\n --ia-theme-scrubber-thumb-diameter,\n 20px\n );\n --scrubber-thumb-border--: var(\n --ia-theme-scrubber-thumb-border,\n 1px solid #000\n );\n --scrubber-thumb-border-radius--: var(\n --ia-theme-scrubber-thumb-border-radius,\n 50%\n );\n /*\n Centres the thumb on the track. The thumb is content-box, so its\n border adds 1px above and below the diameter, hence the extra -1px.\n Comes out at -6px for the default track and thumb sizes.\n */\n --scrubber-thumb-top-margin--: var(\n --ia-theme-scrubber-thumb-top-margin,\n calc(\n (\n var(--scrubber-track-height--) - var(\n --scrubber-thumb-diameter--\n )\n ) /\n 2 - 1px\n )\n );\n\n --scrubber-track-height--: var(--ia-theme-scrubber-track-height, 10px);\n --scrubber-track-border--: var(\n --ia-theme-scrubber-track-border,\n 1px solid #fff\n );\n --scrubber-track-border-radius--: var(\n --ia-theme-scrubber-track-border-radius,\n 5px\n );\n --scrubber-track-color--: var(\n --ia-theme-scrubber-track-color,\n rgba(0, 0, 0, 0.1)\n );\n --scrubber-track-fill-color--: var(\n --ia-theme-scrubber-track-fill-color,\n #3272b6\n );\n\n /*\n How far off the bottom the track sits. The fill and the section\n markers both line up against this, so they follow the track when its\n height is themed. Comes out at 7px for the default sizes.\n */\n --scrubber-track-offset--: calc(\n (var(--scrubber-bar-height--) - var(--scrubber-track-height--)) / 2 +\n 2px\n );\n }\n\n .container {\n position: relative;\n height: var(--scrubber-bar-height--);\n }\n\n /*\n The fill is a plain element rather than a track pseudo-element, so the\n played portion is just a hard gradient stop driven by a custom property.\n */\n .color-fill {\n height: var(--scrubber-track-height--);\n border-radius: 1em;\n position: absolute;\n bottom: var(--scrubber-track-offset--);\n left: 2px;\n right: -2px;\n background: linear-gradient(\n to right,\n var(--scrubber-track-fill-color--) 0%,\n var(--scrubber-track-fill-color--) var(--fill-percent--),\n var(--scrubber-track-color--) var(--fill-percent--),\n var(--scrubber-track-color--) 100%\n );\n }\n\n .marker-container {\n position: absolute;\n left: var(--scrubber-marker-inset--);\n right: var(--scrubber-marker-inset--);\n height: 100%;\n }\n\n ia-section-marker {\n position: absolute;\n width: 2rem;\n height: var(--scrubber-track-height--);\n bottom: var(--scrubber-track-offset--);\n /*\n The left offset puts the marker where it belongs, but the divider runs\n down the middle of the marker, so it shifts back by half its own width\n to line the divider up with that point.\n */\n transform: translateX(-50%);\n }\n\n input[type='range'] {\n -webkit-appearance: none;\n appearance: none;\n height: var(--scrubber-bar-height--);\n padding: 0;\n width: 100%;\n background: none;\n outline: none;\n position: absolute;\n bottom: 0;\n }\n\n input[type='range']::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n box-sizing: content-box;\n margin-top: var(--scrubber-thumb-top-margin--);\n background-color: var(--scrubber-thumb-color--);\n height: var(--scrubber-thumb-diameter--);\n width: var(--scrubber-thumb-diameter--);\n border-radius: var(--scrubber-thumb-border-radius--);\n border: var(--scrubber-thumb-border--);\n cursor: pointer;\n }\n\n input[type='range']::-moz-range-thumb {\n background-color: var(--scrubber-thumb-color--);\n height: var(--scrubber-thumb-diameter--);\n width: var(--scrubber-thumb-diameter--);\n border-radius: var(--scrubber-thumb-border-radius--);\n border: var(--scrubber-thumb-border--);\n cursor: pointer;\n }\n\n input[type='range']::-webkit-slider-runnable-track {\n border: var(--scrubber-track-border--);\n height: var(--scrubber-track-height--);\n border-radius: var(--scrubber-track-border-radius--);\n }\n\n input[type='range']::-moz-range-track {\n border: var(--scrubber-track-border--);\n height: var(--scrubber-track-height--);\n border-radius: var(--scrubber-track-border-radius--);\n }\n\n input[type='range']::-moz-range-progress {\n height: var(--scrubber-track-height--);\n border-radius: var(--scrubber-track-border-radius--);\n }\n `;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-section-marker.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-section-marker.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAGb,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAK7C;;;;;;GAMG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,6BAA6B;IACD,UAAU,EAAE,iBAAiB,CAC7B;IAE5B,MAAM,IAAI,cAAc;IAUxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAuElC;CACF"}
1
+ {"version":3,"file":"ia-section-marker.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-section-marker.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAIb,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAK7C;;;;;;GAMG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,6BAA6B;IACD,UAAU,EAAE,iBAAiB,CAC7B;IAE5B,MAAM,IAAI,cAAc;IAUxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAuElC;CACF"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, } from 'lit';
3
- import { customElement, property } from 'lit/decorators.js';
3
+ import { property } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  import { SectionMarkerMode } from './models.js';
5
6
  import nextSectionIcon from './assets/next-section-marker.js';
6
7
  import previousSectionIcon from './assets/previous-section-marker.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ia-section-marker.js","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-section-marker.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EACH,IAAI,EACJ,UAAU,GAGX,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,eAAe,MAAM,8BAA8B,CAAC;AAC3D,OAAO,mBAAmB,MAAM,kCAAkC,CAAC;AAEnE;;;;;;GAMG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,UAAU;IAAxC;;QACL,6BAA6B;QACD,eAAU,GACpC,iBAAiB,CAAC,OAAO,CAAC;IAoF9B,CAAC;IAlFC,MAAM;QACJ,OAAO,IAAI,CAAA;mCACoB,IAAI,CAAC,UAAU;wCACV,eAAe;;yCAEd,mBAAmB;;KAEvD,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqET,CAAC;IACJ,CAAC;CACF,CAAA;AArF6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;mDACC;AAHjB,eAAe;IAD3B,aAAa,CAAC,mBAAmB,CAAC;GACtB,eAAe,CAuF3B","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { SectionMarkerMode } from './models';\n\nimport nextSectionIcon from './assets/next-section-marker';\nimport previousSectionIcon from './assets/previous-section-marker';\n\n/**\n * A single section boundary drawn on the scrubber bar.\n *\n * It's a vertical divider with an arrow either side. `markerMode` decides\n * which arrows show, so the two markers surrounding the playhead can point\n * towards the section the listener would land in.\n */\n@customElement('ia-section-marker')\nexport class IASectionMarker extends LitElement {\n /** Which arrows to reveal */\n @property({ type: String }) markerMode: SectionMarkerMode =\n SectionMarkerMode.neither;\n\n render(): TemplateResult {\n return html`\n <div class=\"container mode-${this.markerMode}\">\n <div class=\"left-arrow arrow\">${nextSectionIcon}</div>\n <div class=\"center-divider\"></div>\n <div class=\"right-arrow arrow\">${previousSectionIcon}</div>\n </div>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --section-marker-color--: var(--ia-theme-scrubber-marker-color, #fff);\n /*\n Relative to the marker, which the scrubber sizes to the track, so a\n collapsed divider is exactly as tall as the track it sits on and an\n expanded one stands proportionally above it. A fixed pixel height\n here only lines up at one track height.\n */\n --section-marker-height-collapsed--: var(\n --ia-theme-scrubber-marker-height-collapsed,\n 100%\n );\n --section-marker-height-expanded--: var(\n --ia-theme-scrubber-marker-height-expanded,\n 250%\n );\n --section-marker-animation-speed--: 0.1s;\n\n color: var(--section-marker-color--);\n }\n\n .container {\n display: flex;\n justify-content: center;\n height: 100%;\n }\n\n .arrow {\n padding-top: 10px;\n opacity: 1;\n /*\n The arrows are hidden in every mode. The mode rules below vary only\n opacity, which cannot reveal a hidden element, so nothing here brings\n them back. Reveal them by dropping this line, not by touching the\n mode rules.\n */\n visibility: hidden;\n transition:\n opacity var(--section-marker-animation-speed--) ease-out,\n padding-top var(--section-marker-animation-speed--) ease-out;\n }\n\n .container.mode-left .right-arrow {\n opacity: 0;\n }\n\n .container.mode-right .left-arrow {\n opacity: 0;\n }\n\n .container.mode-neither .left-arrow,\n .container.mode-neither .right-arrow {\n opacity: 0;\n padding-top: 75%;\n }\n\n .container.mode-neither .center-divider {\n height: var(--section-marker-height-collapsed--);\n }\n\n .center-divider {\n border-left: 1px solid currentColor;\n width: 1px;\n left: 50%;\n height: var(--section-marker-height-expanded--);\n align-self: flex-end;\n transition: height var(--section-marker-animation-speed--) ease-out;\n }\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-section-marker.js","sourceRoot":"","sources":["../../../../src/elements/ia-scrubber-bar/ia-section-marker.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EACH,IAAI,EACJ,UAAU,GAGX,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,eAAe,MAAM,8BAA8B,CAAC;AAC3D,OAAO,mBAAmB,MAAM,kCAAkC,CAAC;AAEnE;;;;;;GAMG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,UAAU;IAAxC;;QACL,6BAA6B;QACD,eAAU,GACpC,iBAAiB,CAAC,OAAO,CAAC;IAoF9B,CAAC;IAlFC,MAAM;QACJ,OAAO,IAAI,CAAA;mCACoB,IAAI,CAAC,UAAU;wCACV,eAAe;;yCAEd,mBAAmB;;KAEvD,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqET,CAAC;IACJ,CAAC;CACF,CAAA;AArF6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;mDACC;AAHjB,eAAe;IAD3B,aAAa,CAAC,mBAAmB,CAAC;GACtB,eAAe,CAuF3B","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type TemplateResult,\n} from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\n\nimport { SectionMarkerMode } from './models';\n\nimport nextSectionIcon from './assets/next-section-marker';\nimport previousSectionIcon from './assets/previous-section-marker';\n\n/**\n * A single section boundary drawn on the scrubber bar.\n *\n * It's a vertical divider with an arrow either side. `markerMode` decides\n * which arrows show, so the two markers surrounding the playhead can point\n * towards the section the listener would land in.\n */\n@customElement('ia-section-marker')\nexport class IASectionMarker extends LitElement {\n /** Which arrows to reveal */\n @property({ type: String }) markerMode: SectionMarkerMode =\n SectionMarkerMode.neither;\n\n render(): TemplateResult {\n return html`\n <div class=\"container mode-${this.markerMode}\">\n <div class=\"left-arrow arrow\">${nextSectionIcon}</div>\n <div class=\"center-divider\"></div>\n <div class=\"right-arrow arrow\">${previousSectionIcon}</div>\n </div>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --section-marker-color--: var(--ia-theme-scrubber-marker-color, #fff);\n /*\n Relative to the marker, which the scrubber sizes to the track, so a\n collapsed divider is exactly as tall as the track it sits on and an\n expanded one stands proportionally above it. A fixed pixel height\n here only lines up at one track height.\n */\n --section-marker-height-collapsed--: var(\n --ia-theme-scrubber-marker-height-collapsed,\n 100%\n );\n --section-marker-height-expanded--: var(\n --ia-theme-scrubber-marker-height-expanded,\n 250%\n );\n --section-marker-animation-speed--: 0.1s;\n\n color: var(--section-marker-color--);\n }\n\n .container {\n display: flex;\n justify-content: center;\n height: 100%;\n }\n\n .arrow {\n padding-top: 10px;\n opacity: 1;\n /*\n The arrows are hidden in every mode. The mode rules below vary only\n opacity, which cannot reveal a hidden element, so nothing here brings\n them back. Reveal them by dropping this line, not by touching the\n mode rules.\n */\n visibility: hidden;\n transition:\n opacity var(--section-marker-animation-speed--) ease-out,\n padding-top var(--section-marker-animation-speed--) ease-out;\n }\n\n .container.mode-left .right-arrow {\n opacity: 0;\n }\n\n .container.mode-right .left-arrow {\n opacity: 0;\n }\n\n .container.mode-neither .left-arrow,\n .container.mode-neither .right-arrow {\n opacity: 0;\n padding-top: 75%;\n }\n\n .container.mode-neither .center-divider {\n height: var(--section-marker-height-collapsed--);\n }\n\n .center-divider {\n border-left: 1px solid currentColor;\n width: 1px;\n left: 50%;\n height: var(--section-marker-height-expanded--);\n align-self: flex-end;\n transition: height var(--section-marker-animation-speed--) ease-out;\n }\n `;\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement } from 'lit';
3
- import { customElement } from 'lit/decorators.js';
3
+ import { customElement } from '../../util/custom-element.js';
4
4
  import themeStyles from '../../themes/theme-styles.js';
5
5
  /**
6
6
  * Wraps any slotted elements in a `span` element that hides them visually but keeps them available for screen readers.
@@ -1 +1 @@
1
- {"version":3,"file":"ia-sr-only-text.js","sourceRoot":"","sources":["../../../../src/elements/ia-sr-only-text/ia-sr-only-text.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAkB,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,WAAW,MAAM,0BAA0B,CAAC;AAEnD;;;GAGG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAC1C,MAAM;QACJ,OAAO,IAAI,CAAA;;;;KAIV,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO;YACL,WAAW;YACX,GAAG,CAAA;;;;;;;;;;;;;;;OAeF;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA9BY,YAAY;IADxB,aAAa,CAAC,iBAAiB,CAAC;GACpB,YAAY,CA8BxB","sourcesContent":["import { css, CSSResultGroup, html, LitElement, TemplateResult } from 'lit';\nimport { customElement } from 'lit/decorators.js';\n\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * Wraps any slotted elements in a `span` element that hides them visually but keeps them available for screen readers.\n * Useful for rendering any additional explanatory text that is only necessary for screen readers.\n */\n@customElement('ia-sr-only-text')\nexport class IASrOnlyText extends LitElement {\n render(): TemplateResult {\n return html`\n <span class=\"sr-only\">\n <slot></slot>\n </span>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n .sr-only {\n position: absolute !important;\n width: 1px !important;\n height: 1px !important;\n margin: -1px !important;\n padding: 0 !important;\n border: 0 !important;\n overflow: hidden !important;\n white-space: nowrap !important;\n clip: rect(1px, 1px, 1px, 1px) !important;\n -webkit-clip-path: inset(50%) !important;\n clip-path: inset(50%) !important;\n user-select: none !important;\n }\n `,\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"ia-sr-only-text.js","sourceRoot":"","sources":["../../../../src/elements/ia-sr-only-text/ia-sr-only-text.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAkB,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,WAAW,MAAM,0BAA0B,CAAC;AAEnD;;;GAGG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAC1C,MAAM;QACJ,OAAO,IAAI,CAAA;;;;KAIV,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO;YACL,WAAW;YACX,GAAG,CAAA;;;;;;;;;;;;;;;OAeF;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA9BY,YAAY;IADxB,aAAa,CAAC,iBAAiB,CAAC;GACpB,YAAY,CA8BxB","sourcesContent":["import { css, CSSResultGroup, html, LitElement, TemplateResult } from 'lit';\nimport { customElement } from '@src/util/custom-element';\n\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * Wraps any slotted elements in a `span` element that hides them visually but keeps them available for screen readers.\n * Useful for rendering any additional explanatory text that is only necessary for screen readers.\n */\n@customElement('ia-sr-only-text')\nexport class IASrOnlyText extends LitElement {\n render(): TemplateResult {\n return html`\n <span class=\"sr-only\">\n <slot></slot>\n </span>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n .sr-only {\n position: absolute !important;\n width: 1px !important;\n height: 1px !important;\n margin: -1px !important;\n padding: 0 !important;\n border: 0 !important;\n overflow: hidden !important;\n white-space: nowrap !important;\n clip: rect(1px, 1px, 1px, 1px) !important;\n -webkit-clip-path: inset(50%) !important;\n clip-path: inset(50%) !important;\n user-select: none !important;\n }\n `,\n ];\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-status-indicator.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EAEd,UAAU,EAIV,cAAc,EACf,MAAM,KAAK,CAAC;AAmBb,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,IAAI,GACJ,OAAO,GACP,KAAK,CAAC;AAeV;;;;;;;;GAQG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAEnB,YAAY,SAAqB;IAGjC,YAAY,SAAkB;IAG9B,UAAU,SAAgB;IAG1B,IAAI,EAAE,aAAa,CAAa;IAGhC,SAAS,CAAC,EAAE,aAAa,CAAC;IAGzB,QAAQ,UAAS;IAGrC,OAAO,CAAC,cAAc,CAAS;IAExC,MAAM,IAAI,cAAc;IASxB;;;OAGG;IACH,OAAO,KAAK,mBAAmB,GAE9B;IAED;;;;;OAKG;IACH,OAAO,KAAK,gBAAgB,GAG3B;IAED,6EAA6E;IAC7E,OAAO,KAAK,aAAa,GAExB;IAED;;;;;;OAMG;IACH,OAAO,KAAK,wBAAwB,GAYnC;IAED,oEAAoE;IACpE,OAAO,KAAK,aAAa,GA4BxB;IAED,8DAA8D;IAC9D,OAAO,KAAK,WAAW,GAoBtB;IAED;;;OAGG;IACH,OAAO,KAAK,qBAAqB,GAKhC;IAED,OAAO,CAAC,oBAAoB;IAK5B,wCAAwC;IACxC,OAAO,KAAK,wBAAwB,GAyBnC;IAED,gCAAgC;IAChC,OAAO,KAAK,sBAAsB,GAkBjC;IAED,MAAM,KAAK,MAAM,IAAI,cAAc,CA4HlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,iBAAiB,CAAC;KAC1C;CACF"}
1
+ {"version":3,"file":"ia-status-indicator.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EAEd,UAAU,EAIV,cAAc,EACf,MAAM,KAAK,CAAC;AAoBb,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,IAAI,GACJ,OAAO,GACP,KAAK,CAAC;AAeV;;;;;;;;GAQG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAEnB,YAAY,SAAqB;IAGjC,YAAY,SAAkB;IAG9B,UAAU,SAAgB;IAG1B,IAAI,EAAE,aAAa,CAAa;IAGhC,SAAS,CAAC,EAAE,aAAa,CAAC;IAGzB,QAAQ,UAAS;IAGrC,OAAO,CAAC,cAAc,CAAS;IAExC,MAAM,IAAI,cAAc;IASxB;;;OAGG;IACH,OAAO,KAAK,mBAAmB,GAE9B;IAED;;;;;OAKG;IACH,OAAO,KAAK,gBAAgB,GAG3B;IAED,6EAA6E;IAC7E,OAAO,KAAK,aAAa,GAExB;IAED;;;;;;OAMG;IACH,OAAO,KAAK,wBAAwB,GAYnC;IAED,oEAAoE;IACpE,OAAO,KAAK,aAAa,GA4BxB;IAED,8DAA8D;IAC9D,OAAO,KAAK,WAAW,GAoBtB;IAED;;;OAGG;IACH,OAAO,KAAK,qBAAqB,GAKhC;IAED,OAAO,CAAC,oBAAoB;IAK5B,wCAAwC;IACxC,OAAO,KAAK,wBAAwB,GAyBnC;IAED,gCAAgC;IAChC,OAAO,KAAK,sBAAsB,GAkBjC;IAED,MAAM,KAAK,MAAM,IAAI,cAAc,CA4HlC;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,iBAAiB,CAAC;KAC1C;CACF"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, nothing, svg, } from 'lit';
3
- import { customElement, property, state } from 'lit/decorators.js';
3
+ import { property, state } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  import { msg } from '@lit/localize';
5
6
  import { choose } from 'lit/directives/choose.js';
6
7
  import themeStyles from '../../themes/theme-styles.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ia-status-indicator.js","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n nothing,\n svg,\n SVGTemplateResult,\n TemplateResult,\n} from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { msg } from '@lit/localize';\nimport { choose } from 'lit/directives/choose.js';\n\nimport themeStyles from '@src/themes/theme-styles';\nimport { maskedIcon } from '@src/util/masked-icon';\n\nimport audioIcon from './icons/audio.svg';\nimport collectionIcon from './icons/collection.svg';\nimport etreeIcon from './icons/etree.svg';\nimport imagesIcon from './icons/images.svg';\nimport searchIcon from './icons/search.svg';\nimport softwareIcon from './icons/software.svg';\nimport textsIcon from './icons/texts.svg';\nimport tvIcon from './icons/tv.svg';\nimport videoIcon from './icons/video.svg';\nimport webIcon from './icons/web.svg';\n\nexport type LoadingStatus = 'ready' | 'loading' | 'success' | 'error';\n\n/**\n * The mediatype glyphs this element ships. These are *icon* names, which do not\n * map one-to-one onto archive.org mediatype values — a consumer holding a\n * `MediaType` translates at its own call site (e.g. `movies` -> `video`).\n */\nexport type MediaTypeIcon =\n | 'audio'\n | 'collection'\n | 'etree'\n | 'images'\n | 'search'\n | 'software'\n | 'texts'\n | 'tv'\n | 'video'\n | 'web';\n\nconst MEDIATYPE_ICONS: Record<MediaTypeIcon, string> = {\n audio: audioIcon,\n collection: collectionIcon,\n etree: etreeIcon,\n images: imagesIcon,\n search: searchIcon,\n software: softwareIcon,\n texts: textsIcon,\n tv: tvIcon,\n video: videoIcon,\n web: webIcon,\n};\n\n/**\n * Renders an SVG indicator, which defaults to an animated circular indicator.\n *\n * In `loading` mode the middle of the ring resolves in this order:\n * 1. slotted `icon` content\n * 2. the `mediatype` glyph\n * 3. nothing, when `hideDots` is set\n * 4. three animated dots (the default)\n */\n@customElement('ia-status-indicator')\nexport class IAStatusIndicator extends LitElement {\n /* An optional title to use for the loading state of the indicator. Will be used for screen readers. */\n @property({ type: String }) loadingTitle = msg('Loading...');\n\n /* An optional title to use for the success state of the indicator. Will be used for screen readers. */\n @property({ type: String }) successTitle = msg('Success');\n\n /* An optional title to use for the error state of the indicator. Will be used for screen readers. */\n @property({ type: String }) errorTitle = msg('Error');\n\n /* The state of the indicator that should be shown */\n @property({ type: String }) mode: LoadingStatus = 'loading';\n\n /* An optional mediatype glyph to render in the middle of the loading ring */\n @property({ type: String }) mediatype?: MediaTypeIcon;\n\n /* Renders a bare ring, with no dots in the middle. Ignored when a center icon is present. */\n @property({ type: Boolean }) hideDots = false;\n\n /* Whether a consumer has slotted their own center icon */\n @state() private hasSlottedIcon = false;\n\n render(): TemplateResult {\n return html`${choose(this.mode, [\n ['ready', () => this.placeholderTemplate],\n ['loading', () => this.loadingIndicatorTemplate],\n ['success', () => this.successIndicatorTemplate],\n ['error', () => this.errorIndicatorTemplate],\n ])}`;\n }\n\n /**\n * The `ready` state: reserves the indicator's space without drawing, so a\n * consumer's layout doesn't shift once the indicator appears.\n */\n private get placeholderTemplate(): TemplateResult {\n return html`<div class=\"placeholder\"></div>`;\n }\n\n /**\n * The asset URL for the current mediatype, if it maps to a glyph we ship.\n *\n * Unmapped values (e.g. archive.org's `account` or `data`) resolve to\n * undefined and degrade to the default dots rather than a broken mask.\n */\n private get mediatypeIconUrl(): string | undefined {\n if (!this.mediatype) return undefined;\n return MEDIATYPE_ICONS[this.mediatype];\n }\n\n /** Whether the middle of the ring is occupied by a glyph rather than dots */\n private get hasCenterIcon(): boolean {\n return this.hasSlottedIcon || !!this.mediatypeIconUrl;\n }\n\n /**\n * A circular loading indicator to render when processing.\n *\n * Two ring geometries are kept deliberately: the original 120x120 ring is\n * tuned for the dots, and the roomier 100x100 ring leaves space for a center\n * glyph. Keeping both means existing consumers see no visual change.\n */\n private get loadingIndicatorTemplate(): TemplateResult {\n const hasCenterIcon = this.hasCenterIcon;\n return html`\n <div class=\"indicator\">\n ${hasCenterIcon ? this.iconRingSvg : this.dottedRingSvg}\n <span class=\"center\" ?hidden=${!hasCenterIcon}>\n <slot name=\"icon\" @slotchange=${this.handleIconSlotChange}>\n ${this.mediatypeIconTemplate}\n </slot>\n </span>\n </div>\n `;\n }\n\n /** The original ring, with the three animated dots in the middle */\n private get dottedRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n d=\"M60,10 C69.8019971,10 78.9452178,12.8205573 86.6623125,17.6943223 L76.4086287,27.9484118 C71.4880919,25.4243078 65.9103784,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 C96,53.3014663 94.1704984,47.0302355 90.9839104,41.6587228 L101.110332,31.5326452 C106.715332,39.6116982 110,49.4222615 110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <g\n class=\"loading-dots ${this.hideDots ? 'hidden' : ''}\"\n transform=\"translate(40.000000, 55.000000)\"\n >\n <circle id=\"left-dot\" cx=\"5\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"middle-dot\" cx=\"20\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"right-dot\" cx=\"35\" cy=\"5\" r=\"5\"></circle>\n </g>\n </g>\n </svg>\n `;\n }\n\n /** The roomier ring, used when a glyph occupies the middle */\n private get iconRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator icon-ring\"\n viewBox=\"0 0 100 100\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n fill-rule=\"nonzero\"\n d=\"m17.8618849 11.6970233c18.5864635-15.59603144 45.6875867-15.59603102 64.2740497.000001 1.9271446 1.6170806 2.1785128 4.4902567.5614466 6.4174186-1.6170661 1.9271618-4.4902166 2.1785323-6.4173612.5614517-15.1996922-12.75416882-37.3625282-12.75416916-52.5622206-.000001-15.19969387 12.7541707-19.04823077 34.5805019-9.1273354 51.7641499 9.9208955 17.183646 30.7471499 24.7638499 49.3923323 17.9774983 18.6451823-6.7863521 29.7266014-25.9801026 26.2811129-45.5206248-.436848-2.4775114 1.2174186-4.8400696 3.6949079-5.2769215 2.4774893-.4368518 4.8400264 1.2174296 5.2768744 3.694941 4.2132065 23.8945096-9.3373563 47.3649806-32.137028 55.6634567-22.799672 8.2984758-48.2663986-.9707372-60.39785211-21.9832155-12.1314534-21.012481-7.42539173-47.7021198 11.16107351-63.2981544z\"\n ></path>\n </g>\n </svg>\n `;\n }\n\n /**\n * The bundled mediatype glyph. `maskedIcon` supplies the mask geometry and\n * the decorative `aria-hidden`; this component supplies the size and paint.\n */\n private get mediatypeIconTemplate(): TemplateResult | typeof nothing {\n const url = this.mediatypeIconUrl;\n if (!url) return nothing;\n\n return maskedIcon(url);\n }\n\n private handleIconSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this.hasSlottedIcon = slot.assignedNodes({ flatten: false }).length > 0;\n }\n\n /** A check mark to render on success */\n private get successIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"success-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.successTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"success-icon\"\n d=\"M60,10 C70.5816709,10 80.3955961,13.2871104 88.4763646,18.8959201 L78.3502633,29.0214223 C72.9767592,25.8315427 66.7022695,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 L95.995,59.46 L108.327675,47.128668 C109.350926,50.9806166 109.925886,55.015198 109.993301,59.1731586 L110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <polygon\n class=\"success-icon\"\n transform=\"translate(75.000000, 41.500000) rotate(44.000000) translate(-75.000000, -41.500000) \"\n points=\"96 85 54 85 54 65 76 64.999 76 -2 96 -2\"\n ></polygon>\n </g>\n </svg>\n `;\n }\n\n /** An \"!\" to render on error */\n private get errorIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"error-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.errorTitle}</title>\n <path\n class=\"error-icon\"\n d=\"m56.4612493 8.80450354 41.8901185 75.94632926c1.7706782 2.8433173 2.1150372 5.2623412 1.0330766 7.2570716-1.0819604 1.9947304-3.26978 2.9920956-6.5634587 2.9920956h-85.69973905c-3.29367873 0-5.46954894-.9973652-6.52761065-2.9920956-1.0580617-1.9947304-.70175345-4.4137543 1.06892476-7.2570716l41.89011844-75.12308969c1.8184757-2.84331737 3.9693609-4.37738627 6.4526556-4.60220671s4.6341799 1.03483527 6.4526556 3.77896714zm28.5387507 75.19549646-35.037482-62-34.962518 62zm-31-34.7484359v-10.2515641h-8v10.2515641l2.089172 14.7484359h3.8184713zm-8 19.7484359v8h8v-8z\"\n />\n </svg>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --indicator-width--: var(--icon-width);\n\n /* Loading */\n --loading-ring-color--: var(--primary-text-color);\n --loading-dot-color--: var(--primary-text-color);\n --loading-icon-color--: var(--primary-text-color);\n\n /* Success */\n --success-icon-color--: var(--color-success);\n\n /* Error */\n --error-icon-color--: var(--color-danger);\n\n display: inline-block;\n width: var(--indicator-width--);\n }\n\n .placeholder {\n height: var(--indicator-width--);\n }\n\n /* Stacks the center glyph over the ring */\n .indicator {\n position: relative;\n display: block;\n }\n\n .indicator svg {\n display: block;\n width: 100%;\n height: auto;\n }\n\n .center {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n }\n\n .center[hidden] {\n display: none;\n }\n\n /*\n * Sized to fit within the icon ring's inner diameter. maskedIcon sets\n * the mask itself; background-color is what paints the glyph, so it\n * recolors with the ring.\n */\n .ia-icon {\n width: 50%;\n height: 50%;\n background-color: var(--loading-icon-color--);\n }\n\n .success-icon {\n fill: var(--success-icon-color--);\n }\n\n .error-icon {\n fill: var(--error-icon-color--);\n }\n\n .loading-ring {\n fill: var(--loading-ring-color--);\n animation: rotate 1.3s infinite linear;\n transform-origin: 50px 50px;\n transform-box: fill-box;\n }\n\n .loading-dots {\n fill: var(--loading-dot-color--);\n transition: opacity 0.25s ease-out;\n }\n\n .loading-dots.hidden {\n display: none;\n }\n\n .loading-dots > * {\n opacity: 0;\n animation: dot 1.3s infinite;\n }\n\n .loading-dots #left-dot {\n animation-delay: 0.2s;\n }\n\n .loading-dots #middle-dot {\n animation-delay: 0.4s;\n }\n\n .loading-dots #right-dot {\n animation-delay: 0.6s;\n }\n\n @keyframes rotate {\n 0% {\n transform: rotate(-360deg);\n }\n 100% {\n /* This frame is supposed to be inferred, but Safari doesn't rotate it unless we're explicit */\n transform: rotate(0deg);\n }\n }\n\n @keyframes dot {\n 0% {\n opacity: 0;\n }\n 25% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-status-indicator': IAStatusIndicator;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-status-indicator.js","sourceRoot":"","sources":["../../../../src/elements/ia-status-indicator/ia-status-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n nothing,\n svg,\n SVGTemplateResult,\n TemplateResult,\n} from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\nimport { choose } from 'lit/directives/choose.js';\n\nimport themeStyles from '@src/themes/theme-styles';\nimport { maskedIcon } from '@src/util/masked-icon';\n\nimport audioIcon from './icons/audio.svg';\nimport collectionIcon from './icons/collection.svg';\nimport etreeIcon from './icons/etree.svg';\nimport imagesIcon from './icons/images.svg';\nimport searchIcon from './icons/search.svg';\nimport softwareIcon from './icons/software.svg';\nimport textsIcon from './icons/texts.svg';\nimport tvIcon from './icons/tv.svg';\nimport videoIcon from './icons/video.svg';\nimport webIcon from './icons/web.svg';\n\nexport type LoadingStatus = 'ready' | 'loading' | 'success' | 'error';\n\n/**\n * The mediatype glyphs this element ships. These are *icon* names, which do not\n * map one-to-one onto archive.org mediatype values — a consumer holding a\n * `MediaType` translates at its own call site (e.g. `movies` -> `video`).\n */\nexport type MediaTypeIcon =\n | 'audio'\n | 'collection'\n | 'etree'\n | 'images'\n | 'search'\n | 'software'\n | 'texts'\n | 'tv'\n | 'video'\n | 'web';\n\nconst MEDIATYPE_ICONS: Record<MediaTypeIcon, string> = {\n audio: audioIcon,\n collection: collectionIcon,\n etree: etreeIcon,\n images: imagesIcon,\n search: searchIcon,\n software: softwareIcon,\n texts: textsIcon,\n tv: tvIcon,\n video: videoIcon,\n web: webIcon,\n};\n\n/**\n * Renders an SVG indicator, which defaults to an animated circular indicator.\n *\n * In `loading` mode the middle of the ring resolves in this order:\n * 1. slotted `icon` content\n * 2. the `mediatype` glyph\n * 3. nothing, when `hideDots` is set\n * 4. three animated dots (the default)\n */\n@customElement('ia-status-indicator')\nexport class IAStatusIndicator extends LitElement {\n /* An optional title to use for the loading state of the indicator. Will be used for screen readers. */\n @property({ type: String }) loadingTitle = msg('Loading...');\n\n /* An optional title to use for the success state of the indicator. Will be used for screen readers. */\n @property({ type: String }) successTitle = msg('Success');\n\n /* An optional title to use for the error state of the indicator. Will be used for screen readers. */\n @property({ type: String }) errorTitle = msg('Error');\n\n /* The state of the indicator that should be shown */\n @property({ type: String }) mode: LoadingStatus = 'loading';\n\n /* An optional mediatype glyph to render in the middle of the loading ring */\n @property({ type: String }) mediatype?: MediaTypeIcon;\n\n /* Renders a bare ring, with no dots in the middle. Ignored when a center icon is present. */\n @property({ type: Boolean }) hideDots = false;\n\n /* Whether a consumer has slotted their own center icon */\n @state() private hasSlottedIcon = false;\n\n render(): TemplateResult {\n return html`${choose(this.mode, [\n ['ready', () => this.placeholderTemplate],\n ['loading', () => this.loadingIndicatorTemplate],\n ['success', () => this.successIndicatorTemplate],\n ['error', () => this.errorIndicatorTemplate],\n ])}`;\n }\n\n /**\n * The `ready` state: reserves the indicator's space without drawing, so a\n * consumer's layout doesn't shift once the indicator appears.\n */\n private get placeholderTemplate(): TemplateResult {\n return html`<div class=\"placeholder\"></div>`;\n }\n\n /**\n * The asset URL for the current mediatype, if it maps to a glyph we ship.\n *\n * Unmapped values (e.g. archive.org's `account` or `data`) resolve to\n * undefined and degrade to the default dots rather than a broken mask.\n */\n private get mediatypeIconUrl(): string | undefined {\n if (!this.mediatype) return undefined;\n return MEDIATYPE_ICONS[this.mediatype];\n }\n\n /** Whether the middle of the ring is occupied by a glyph rather than dots */\n private get hasCenterIcon(): boolean {\n return this.hasSlottedIcon || !!this.mediatypeIconUrl;\n }\n\n /**\n * A circular loading indicator to render when processing.\n *\n * Two ring geometries are kept deliberately: the original 120x120 ring is\n * tuned for the dots, and the roomier 100x100 ring leaves space for a center\n * glyph. Keeping both means existing consumers see no visual change.\n */\n private get loadingIndicatorTemplate(): TemplateResult {\n const hasCenterIcon = this.hasCenterIcon;\n return html`\n <div class=\"indicator\">\n ${hasCenterIcon ? this.iconRingSvg : this.dottedRingSvg}\n <span class=\"center\" ?hidden=${!hasCenterIcon}>\n <slot name=\"icon\" @slotchange=${this.handleIconSlotChange}>\n ${this.mediatypeIconTemplate}\n </slot>\n </span>\n </div>\n `;\n }\n\n /** The original ring, with the three animated dots in the middle */\n private get dottedRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n d=\"M60,10 C69.8019971,10 78.9452178,12.8205573 86.6623125,17.6943223 L76.4086287,27.9484118 C71.4880919,25.4243078 65.9103784,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 C96,53.3014663 94.1704984,47.0302355 90.9839104,41.6587228 L101.110332,31.5326452 C106.715332,39.6116982 110,49.4222615 110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <g\n class=\"loading-dots ${this.hideDots ? 'hidden' : ''}\"\n transform=\"translate(40.000000, 55.000000)\"\n >\n <circle id=\"left-dot\" cx=\"5\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"middle-dot\" cx=\"20\" cy=\"5\" r=\"5\"></circle>\n <circle id=\"right-dot\" cx=\"35\" cy=\"5\" r=\"5\"></circle>\n </g>\n </g>\n </svg>\n `;\n }\n\n /** The roomier ring, used when a glyph occupies the middle */\n private get iconRingSvg(): SVGTemplateResult {\n return svg`\n <svg\n class=\"loading-indicator icon-ring\"\n viewBox=\"0 0 100 100\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.loadingTitle}</title>\n <g fill-rule=\"evenodd\">\n <path\n class=\"loading-ring\"\n fill-rule=\"nonzero\"\n d=\"m17.8618849 11.6970233c18.5864635-15.59603144 45.6875867-15.59603102 64.2740497.000001 1.9271446 1.6170806 2.1785128 4.4902567.5614466 6.4174186-1.6170661 1.9271618-4.4902166 2.1785323-6.4173612.5614517-15.1996922-12.75416882-37.3625282-12.75416916-52.5622206-.000001-15.19969387 12.7541707-19.04823077 34.5805019-9.1273354 51.7641499 9.9208955 17.183646 30.7471499 24.7638499 49.3923323 17.9774983 18.6451823-6.7863521 29.7266014-25.9801026 26.2811129-45.5206248-.436848-2.4775114 1.2174186-4.8400696 3.6949079-5.2769215 2.4774893-.4368518 4.8400264 1.2174296 5.2768744 3.694941 4.2132065 23.8945096-9.3373563 47.3649806-32.137028 55.6634567-22.799672 8.2984758-48.2663986-.9707372-60.39785211-21.9832155-12.1314534-21.012481-7.42539173-47.7021198 11.16107351-63.2981544z\"\n ></path>\n </g>\n </svg>\n `;\n }\n\n /**\n * The bundled mediatype glyph. `maskedIcon` supplies the mask geometry and\n * the decorative `aria-hidden`; this component supplies the size and paint.\n */\n private get mediatypeIconTemplate(): TemplateResult | typeof nothing {\n const url = this.mediatypeIconUrl;\n if (!url) return nothing;\n\n return maskedIcon(url);\n }\n\n private handleIconSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this.hasSlottedIcon = slot.assignedNodes({ flatten: false }).length > 0;\n }\n\n /** A check mark to render on success */\n private get successIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"success-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.successTitle}</title>\n <g stroke=\"none\" stroke-width=\"1\" fill-rule=\"evenodd\">\n <path\n class=\"success-icon\"\n d=\"M60,10 C70.5816709,10 80.3955961,13.2871104 88.4763646,18.8959201 L78.3502633,29.0214223 C72.9767592,25.8315427 66.7022695,24 60,24 C40.117749,24 24,40.117749 24,60 C24,79.882251 40.117749,96 60,96 C79.882251,96 96,79.882251 96,60 L95.995,59.46 L108.327675,47.128668 C109.350926,50.9806166 109.925886,55.015198 109.993301,59.1731586 L110,60 C110,87.6142375 87.6142375,110 60,110 C32.3857625,110 10,87.6142375 10,60 C10,32.3857625 32.3857625,10 60,10 Z\"\n ></path>\n <polygon\n class=\"success-icon\"\n transform=\"translate(75.000000, 41.500000) rotate(44.000000) translate(-75.000000, -41.500000) \"\n points=\"96 85 54 85 54 65 76 64.999 76 -2 96 -2\"\n ></polygon>\n </g>\n </svg>\n `;\n }\n\n /** An \"!\" to render on error */\n private get errorIndicatorTemplate(): TemplateResult {\n return html`\n <svg\n class=\"error-indicator\"\n viewBox=\"0 0 120 120\"\n preserveAspectRatio=\"none\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n role=\"status\"\n >\n <title>${this.errorTitle}</title>\n <path\n class=\"error-icon\"\n d=\"m56.4612493 8.80450354 41.8901185 75.94632926c1.7706782 2.8433173 2.1150372 5.2623412 1.0330766 7.2570716-1.0819604 1.9947304-3.26978 2.9920956-6.5634587 2.9920956h-85.69973905c-3.29367873 0-5.46954894-.9973652-6.52761065-2.9920956-1.0580617-1.9947304-.70175345-4.4137543 1.06892476-7.2570716l41.89011844-75.12308969c1.8184757-2.84331737 3.9693609-4.37738627 6.4526556-4.60220671s4.6341799 1.03483527 6.4526556 3.77896714zm28.5387507 75.19549646-35.037482-62-34.962518 62zm-31-34.7484359v-10.2515641h-8v10.2515641l2.089172 14.7484359h3.8184713zm-8 19.7484359v8h8v-8z\"\n />\n </svg>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --indicator-width--: var(--icon-width);\n\n /* Loading */\n --loading-ring-color--: var(--primary-text-color);\n --loading-dot-color--: var(--primary-text-color);\n --loading-icon-color--: var(--primary-text-color);\n\n /* Success */\n --success-icon-color--: var(--color-success);\n\n /* Error */\n --error-icon-color--: var(--color-danger);\n\n display: inline-block;\n width: var(--indicator-width--);\n }\n\n .placeholder {\n height: var(--indicator-width--);\n }\n\n /* Stacks the center glyph over the ring */\n .indicator {\n position: relative;\n display: block;\n }\n\n .indicator svg {\n display: block;\n width: 100%;\n height: auto;\n }\n\n .center {\n position: absolute;\n inset: 0;\n display: grid;\n place-items: center;\n }\n\n .center[hidden] {\n display: none;\n }\n\n /*\n * Sized to fit within the icon ring's inner diameter. maskedIcon sets\n * the mask itself; background-color is what paints the glyph, so it\n * recolors with the ring.\n */\n .ia-icon {\n width: 50%;\n height: 50%;\n background-color: var(--loading-icon-color--);\n }\n\n .success-icon {\n fill: var(--success-icon-color--);\n }\n\n .error-icon {\n fill: var(--error-icon-color--);\n }\n\n .loading-ring {\n fill: var(--loading-ring-color--);\n animation: rotate 1.3s infinite linear;\n transform-origin: 50px 50px;\n transform-box: fill-box;\n }\n\n .loading-dots {\n fill: var(--loading-dot-color--);\n transition: opacity 0.25s ease-out;\n }\n\n .loading-dots.hidden {\n display: none;\n }\n\n .loading-dots > * {\n opacity: 0;\n animation: dot 1.3s infinite;\n }\n\n .loading-dots #left-dot {\n animation-delay: 0.2s;\n }\n\n .loading-dots #middle-dot {\n animation-delay: 0.4s;\n }\n\n .loading-dots #right-dot {\n animation-delay: 0.6s;\n }\n\n @keyframes rotate {\n 0% {\n transform: rotate(-360deg);\n }\n 100% {\n /* This frame is supposed to be inferred, but Safari doesn't rotate it unless we're explicit */\n transform: rotate(0deg);\n }\n }\n\n @keyframes dot {\n 0% {\n opacity: 0;\n }\n 25% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n `,\n ];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ia-status-indicator': IAStatusIndicator;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-transcript-entry.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAG5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEtD;;;;;;GAMG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAC/C,0BAA0B;IACE,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAE1D,sDAAsD;IACV,QAAQ,UAAS;IAE7D,kEAAkE;IACtB,UAAU,UAAS;IAE/D,gDAAgD;IACJ,WAAW,UAAS;IAEhE,oDAAoD;IACR,cAAc,UAAS;IAEnE,kEAAkE;IACtB,YAAY,UAAS;IAEjE,MAAM,IAAI,cAAc;CAGzB"}
1
+ {"version":3,"file":"ia-transcript-entry.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAI5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEtD;;;;;;GAMG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAC/C,0BAA0B;IACE,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAE1D,sDAAsD;IACV,QAAQ,UAAS;IAE7D,kEAAkE;IACtB,UAAU,UAAS;IAE/D,gDAAgD;IACJ,WAAW,UAAS;IAEhE,oDAAoD;IACR,cAAc,UAAS;IAEnE,kEAAkE;IACtB,YAAY,UAAS;IAEjE,MAAM,IAAI,cAAc;CAGzB"}
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { html, LitElement } from 'lit';
3
- import { customElement, property } from 'lit/decorators.js';
3
+ import { property } from 'lit/decorators.js';
4
+ import { customElement } from '../../util/custom-element.js';
4
5
  /**
5
6
  * One line of the transcript.
6
7
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ia-transcript-entry.js","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-entry.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAuB,MAAM,KAAK,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI5D;;;;;;GAMG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,UAAU;IAA1C;;QAIL,sDAAsD;QACV,aAAQ,GAAG,KAAK,CAAC;QAE7D,kEAAkE;QACtB,eAAU,GAAG,KAAK,CAAC;QAE/D,gDAAgD;QACJ,gBAAW,GAAG,KAAK,CAAC;QAEhE,oDAAoD;QACR,mBAAc,GAAG,KAAK,CAAC;QAEnE,kEAAkE;QACtB,iBAAY,GAAG,KAAK,CAAC;IAKnE,CAAC;IAHC,MAAM;QACJ,OAAO,IAAI,CAAA,GAAG,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,EAAE,EAAE,CAAC;IAChD,CAAC;CACF,CAAA;AApB6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAA+B;AAGd;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;mDAAkB;AAGjB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;qDAAoB;AAGnB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;sDAAqB;AAGpB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;yDAAwB;AAGvB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;uDAAsB;AAjBtD,iBAAiB;IAD7B,aAAa,CAAC,qBAAqB,CAAC;GACxB,iBAAiB,CAsB7B","sourcesContent":["import { html, LitElement, type TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport type { TranscriptEntryConfig } from './models';\n\n/**\n * One line of the transcript.\n *\n * Carries no styles of its own. Every flag reflects to an attribute so the\n * transcript view around it can style entries from a single stylesheet rather\n * than pushing styles down into each one.\n */\n@customElement('ia-transcript-entry')\nexport class IATranscriptEntry extends LitElement {\n /** The entry to render */\n @property({ type: Object }) entry?: TranscriptEntryConfig;\n\n /** Whether playback is currently inside this entry */\n @property({ type: Boolean, reflect: true }) isActive = false;\n\n /** Whether this is the search result currently being looked at */\n @property({ type: Boolean, reflect: true }) isSelected = false;\n\n /** Whether clicking this entry does anything */\n @property({ type: Boolean, reflect: true }) isClickable = false;\n\n /** Whether this entry matched the current search */\n @property({ type: Boolean, reflect: true }) isSearchResult = false;\n\n /** Whether this entry is a stretch of music rather than speech */\n @property({ type: Boolean, reflect: true }) isMusicEntry = false;\n\n render(): TemplateResult {\n return html`${this.entry?.displayText ?? ''}`;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-transcript-entry.js","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-entry.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAuB,MAAM,KAAK,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIzD;;;;;;GAMG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,UAAU;IAA1C;;QAIL,sDAAsD;QACV,aAAQ,GAAG,KAAK,CAAC;QAE7D,kEAAkE;QACtB,eAAU,GAAG,KAAK,CAAC;QAE/D,gDAAgD;QACJ,gBAAW,GAAG,KAAK,CAAC;QAEhE,oDAAoD;QACR,mBAAc,GAAG,KAAK,CAAC;QAEnE,kEAAkE;QACtB,iBAAY,GAAG,KAAK,CAAC;IAKnE,CAAC;IAHC,MAAM;QACJ,OAAO,IAAI,CAAA,GAAG,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,EAAE,EAAE,CAAC;IAChD,CAAC;CACF,CAAA;AApB6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAA+B;AAGd;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;mDAAkB;AAGjB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;qDAAoB;AAGnB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;sDAAqB;AAGpB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;yDAAwB;AAGvB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;uDAAsB;AAjBtD,iBAAiB;IAD7B,aAAa,CAAC,qBAAqB,CAAC;GACxB,iBAAiB,CAsB7B","sourcesContent":["import { html, LitElement, type TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\n\nimport type { TranscriptEntryConfig } from './models';\n\n/**\n * One line of the transcript.\n *\n * Carries no styles of its own. Every flag reflects to an attribute so the\n * transcript view around it can style entries from a single stylesheet rather\n * than pushing styles down into each one.\n */\n@customElement('ia-transcript-entry')\nexport class IATranscriptEntry extends LitElement {\n /** The entry to render */\n @property({ type: Object }) entry?: TranscriptEntryConfig;\n\n /** Whether playback is currently inside this entry */\n @property({ type: Boolean, reflect: true }) isActive = false;\n\n /** Whether this is the search result currently being looked at */\n @property({ type: Boolean, reflect: true }) isSelected = false;\n\n /** Whether clicking this entry does anything */\n @property({ type: Boolean, reflect: true }) isClickable = false;\n\n /** Whether this entry matched the current search */\n @property({ type: Boolean, reflect: true }) isSearchResult = false;\n\n /** Whether this entry is a stretch of music rather than speech */\n @property({ type: Boolean, reflect: true }) isMusicEntry = false;\n\n render(): TemplateResult {\n return html`${this.entry?.displayText ?? ''}`;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-transcript-view.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAMb,OAAO,KAAK,EAAE,gBAAgB,EAAyB,MAAM,UAAU,CAAC;AAGxE,OAAO,uBAAuB,CAAC;AAc/B;;;;;GAKG;AACH,qBACa,gBAAiB,SAAQ,UAAU;IAC9C,+BAA+B;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAEtD,mDAAmD;IACvB,WAAW,SAAK;IAE5C,qEAAqE;IACzC,gBAAgB,SAAM;IAElD,qEAAqE;IACzC,mBAAmB,SAAM;IAErD,8CAA8C;IACjB,UAAU,UAAQ;IAE/C,uDAAuD;IAC3B,yBAAyB,SAAK;IAE1D,yEAAyE;IAC5C,gBAAgB,UAAS;IAEtD,6EAA6E;IACjD,gBAAgB,SAAS;IAE5C,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,cAAc,CAA+B;IAElC,OAAO,CAAC,UAAU,CAAC,CAAqB;IAEpE,OAAO,CAAC,mBAAmB,CAAC,CAAgC;IAE5D,OAAO,CAAC,iBAAiB,CAAC,CAAS;IAEnC,oBAAoB,IAAI,IAAI;IAM5B,MAAM,IAAI,cAAc;IAwBxB,oDAAoD;IACpD,4BAA4B,IAAI,IAAI;IAQpC,6EAA6E;IAC7E,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkBzD,OAAO,KAAK,wBAAwB,GAUnC;IAED,OAAO,KAAK,mBAAmB,GAM9B;IAED,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,KAAK,oBAAoB,GAW/B;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAsBhD,OAAO,CAAC,uBAAuB;IAiB/B;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAY/B,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,oBAAoB;IAQ5B;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAWjB,8EAA8E;IAC9E,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,KAAK,qBAAqB,GAIhC;IAED,OAAO,KAAK,oBAAoB,GAM/B;IAED,OAAO,KAAK,yBAAyB,GAIpC;IAED,OAAO,CAAC,oBAAoB;IAO5B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,kBAAkB;IAY1B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,qBAAqB;IAO7B,MAAM,KAAK,MAAM,IAAI,cAAc,CAyMlC;CACF"}
1
+ {"version":3,"file":"ia-transcript-view.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAOb,OAAO,KAAK,EAAE,gBAAgB,EAAyB,MAAM,UAAU,CAAC;AAGxE,OAAO,uBAAuB,CAAC;AAc/B;;;;;GAKG;AACH,qBACa,gBAAiB,SAAQ,UAAU;IAC9C,+BAA+B;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAEtD,mDAAmD;IACvB,WAAW,SAAK;IAE5C,qEAAqE;IACzC,gBAAgB,SAAM;IAElD,qEAAqE;IACzC,mBAAmB,SAAM;IAErD,8CAA8C;IACjB,UAAU,UAAQ;IAE/C,uDAAuD;IAC3B,yBAAyB,SAAK;IAE1D,yEAAyE;IAC5C,gBAAgB,UAAS;IAEtD,6EAA6E;IACjD,gBAAgB,SAAS;IAE5C,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,cAAc,CAA+B;IAElC,OAAO,CAAC,UAAU,CAAC,CAAqB;IAEpE,OAAO,CAAC,mBAAmB,CAAC,CAAgC;IAE5D,OAAO,CAAC,iBAAiB,CAAC,CAAS;IAEnC,oBAAoB,IAAI,IAAI;IAM5B,MAAM,IAAI,cAAc;IAwBxB,oDAAoD;IACpD,4BAA4B,IAAI,IAAI;IAQpC,6EAA6E;IAC7E,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkBzD,OAAO,KAAK,wBAAwB,GAUnC;IAED,OAAO,KAAK,mBAAmB,GAM9B;IAED,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,KAAK,oBAAoB,GAW/B;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAED,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAsBhD,OAAO,CAAC,uBAAuB;IAiB/B;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAY/B,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,oBAAoB;IAQ5B;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAWjB,8EAA8E;IAC9E,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,KAAK,qBAAqB,GAIhC;IAED,OAAO,KAAK,oBAAoB,GAM/B;IAED,OAAO,KAAK,yBAAyB,GAIpC;IAED,OAAO,CAAC,oBAAoB;IAO5B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,kBAAkB;IAY1B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,qBAAqB;IAO7B,MAAM,KAAK,MAAM,IAAI,cAAc,CAyMlC;CACF"}
@@ -1,7 +1,8 @@
1
1
  var IATranscriptView_1;
2
2
  import { __decorate } from "tslib";
3
3
  import { css, html, LitElement, nothing, } from 'lit';
4
- import { customElement, property, query, state } from 'lit/decorators.js';
4
+ import { property, query, state } from 'lit/decorators.js';
5
+ import { customElement } from '../../util/custom-element.js';
5
6
  import { ifDefined } from 'lit/directives/if-defined.js';
6
7
  import { msg } from '@lit/localize';
7
8
  import { formatDuration } from './duration-formatter.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ia-transcript-view.js","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-view.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n nothing,\n type CSSResultGroup,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { msg } from '@lit/localize';\n\nimport { formatDuration } from './duration-formatter';\nimport type { TranscriptConfig, TranscriptEntryConfig } from './models';\nimport type { IATranscriptEntry } from './ia-transcript-entry';\n\nimport './ia-transcript-entry';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n TranscriptEntrySelected: 'transcriptEntrySelected',\n CurrentEntriesUpdated: 'currentEntriesUpdated',\n AutoScrollChanged: 'autoScrollChanged',\n};\n\n/** How long a scroll animation runs, in seconds */\nconst SCROLL_DURATION_SECONDS = 1;\n\n/**\n * A scrolling transcript that follows playback.\n *\n * It keeps itself scrolled to whatever is being spoken, steps aside when the\n * listener scrolls by hand, and picks the job back up once they've stopped.\n */\n@customElement('ia-transcript-view')\nexport class IATranscriptView extends LitElement {\n /** The transcript to render */\n @property({ type: Object }) config?: TranscriptConfig;\n\n /** Playback position, in seconds into the track */\n @property({ type: Number }) currentTime = 0;\n\n /** How much room to leave above the entry being spoken, in pixels */\n @property({ type: Number }) topContextHeight = 50;\n\n /** How much room to leave below the entry being spoken, in pixels */\n @property({ type: Number }) bottomContextHeight = 50;\n\n /** Whether the transcript follows playback */\n @property({ type: Boolean }) autoScroll = true;\n\n /** Which search result is currently being looked at */\n @property({ type: Number }) selectedSearchResultIndex = 0;\n\n /** Whether to outline the context zones, for working on the scrolling */\n @property({ type: Boolean }) showContextZones = false;\n\n /** How long to wait after a manual scroll before following playback again */\n @property({ type: Number }) scrollTimerDelay = 15000;\n\n @state() private timeScrollTop = 0;\n\n @state() private currentEntries: TranscriptEntryConfig[] = [];\n\n @query('#scroll-container') private scrollView?: HTMLElement | null;\n\n private scrollResumeTimerId?: ReturnType<typeof setTimeout>;\n\n private scrollAnimationId?: number;\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n clearTimeout(this.scrollResumeTimerId);\n this.cancelScrollAnimation();\n }\n\n render(): TemplateResult {\n return html`\n <div class=\"container\">\n ${this.showContextZones ? this.contextZoneTemplates : nothing}\n\n <div\n class=\"scroll-container\"\n id=\"scroll-container\"\n @wheel=${this.didScroll}\n @touchmove=${this.didScroll}\n >\n <div class=\"col time\">${this.timeDisplayTemplate}</div>\n\n <div class=\"col\">\n ${this.autoScrollButtonTemplate}\n ${this.transcriptEntries.map((entry) =>\n this.transcriptEntryTemplate(entry),\n )}\n </div>\n </div>\n </div>\n `;\n }\n\n /** Scrolls the selected search result into view. */\n scrollToSelectedSearchResult(): void {\n const { selectedSearchResult } = this;\n if (!selectedSearchResult) return;\n\n this.autoScroll = false;\n this.scrollToElement(selectedSearchResult);\n }\n\n /** The id of the entry starting closest to a given time, if there is one. */\n entryIdentifierClosestToTime(time: number): number | null {\n const entries = this.transcriptEntries;\n if (entries.length === 0) return null;\n\n let closest = entries[0];\n let smallestDelta = Math.abs(time - closest.start);\n\n for (const entry of entries) {\n const delta = Math.abs(time - entry.start);\n if (delta < smallestDelta) {\n smallestDelta = delta;\n closest = entry;\n }\n }\n\n return closest.id;\n }\n\n private get autoScrollButtonTemplate(): TemplateResult {\n return html`\n <button\n type=\"button\"\n class=\"auto-scroll-button ${this.autoScroll ? 'hidden' : ''}\"\n @click=${this.enableAutoScroll}\n >\n ${msg('Scroll text with audio')}\n </button>\n `;\n }\n\n private get timeDisplayTemplate(): TemplateResult {\n return html`\n <div class=\"time-display\" style=\"top: ${this.timeScrollTop}px\">\n ${formatDuration(this.currentTime)}\n </div>\n `;\n }\n\n private transcriptEntryTemplate(\n entry: TranscriptEntryConfig,\n ): TemplateResult {\n const isActive = this.currentEntries.some(\n (currentEntry) => currentEntry.id === entry.id,\n );\n\n return html`\n <ia-transcript-entry\n .entry=${entry}\n ?isActive=${isActive}\n ?isSelected=${entry.searchMatchIndex === this.selectedSearchResultIndex}\n ?isSearchResult=${entry.searchMatchIndex !== undefined}\n ?isMusicEntry=${entry.isMusic}\n isClickable\n data-search-result-index=${ifDefined(entry.searchMatchIndex)}\n data-identifier=${entry.id}\n @click=${this.transcriptEntrySelected}\n ></ia-transcript-entry>\n `;\n }\n\n private get contextZoneTemplates(): TemplateResult {\n return html`\n <div\n class=\"top context-overlay\"\n style=\"height: ${this.topContextHeight}px\"\n ></div>\n <div\n class=\"bottom context-overlay\"\n style=\"height: ${this.bottomContextHeight}px\"\n ></div>\n `;\n }\n\n private get transcriptEntries(): TranscriptEntryConfig[] {\n return this.config?.entries ?? [];\n }\n\n updated(changedProperties: PropertyValues): void {\n if (changedProperties.has('currentTime')) this.handleCurrentTimeChange();\n if (changedProperties.has('selectedSearchResultIndex')) {\n this.scrollToSelectedSearchResult();\n }\n if (changedProperties.has('currentEntries')) {\n this.scrollToClosestEntry();\n this.updateTimePosition();\n }\n if (changedProperties.has('autoScroll')) {\n this.dispatchEvent(\n new CustomEvent<{ autoScroll: boolean }>(Events.AutoScrollChanged, {\n detail: { autoScroll: this.autoScroll },\n }),\n );\n }\n if (changedProperties.has('config')) {\n this.selectedSearchResultIndex = 0;\n this.scrollToSelectedSearchResult();\n }\n }\n\n private transcriptEntrySelected(e: Event): void {\n const { entry } = e.currentTarget as IATranscriptEntry;\n if (!entry) return;\n\n this.dispatchEvent(\n new CustomEvent<{ entry: TranscriptEntryConfig }>(\n Events.TranscriptEntrySelected,\n { detail: { entry } },\n ),\n );\n\n if (entry.searchMatchIndex !== undefined) {\n this.selectedSearchResultIndex = entry.searchMatchIndex;\n }\n this.autoScroll = false;\n }\n\n /**\n * Works out which entries are being spoken now.\n *\n * Runs on every time update, several times a second, so it only touches the\n * rendered state when the set of entries has actually changed.\n */\n private handleCurrentTimeChange(): void {\n const entries = this.transcriptEntries;\n if (entries.length === 0) return;\n\n const activeEntries = entries.filter(\n (entry) =>\n this.currentTime >= entry.start && this.currentTime <= entry.end,\n );\n\n if (IATranscriptView.entryArraysMatch(activeEntries, this.currentEntries)) {\n return;\n }\n\n this.dispatchEvent(new Event(Events.CurrentEntriesUpdated));\n this.currentEntries = activeEntries;\n }\n\n private static entryArraysMatch(\n a: TranscriptEntryConfig[],\n b: TranscriptEntryConfig[],\n ): boolean {\n if (a.length !== b.length) return false;\n\n const aIds = a.map((entry) => entry.id).sort((x, y) => x - y);\n const bIds = b.map((entry) => entry.id).sort((x, y) => x - y);\n\n return aIds.every((id, index) => bIds[index] === id);\n }\n\n private elementClosestToTime(time: number): HTMLElement | null {\n const closestIdentifier = this.entryIdentifierClosestToTime(time);\n // Compared against null rather than tested for truthiness, so an entry\n // whose id is 0 is still found.\n if (closestIdentifier === null) return null;\n\n return this.elementForIdentifier(closestIdentifier);\n }\n\n private elementForIdentifier(identifier: number): HTMLElement | null {\n return (\n this.shadowRoot?.querySelector(\n `ia-transcript-entry[data-identifier=\"${identifier}\"]`,\n ) ?? null\n );\n }\n\n /**\n * Steps auto-scroll aside when the listener scrolls by hand, and arranges to\n * pick it back up once they've left it alone for a while.\n *\n * A wheel that the transcript cannot act on, such as a wheel-up when it is\n * already at the top, is ignored: the listener sees nothing move, so taking\n * auto-scroll away from them reads as the page misbehaving.\n */\n private didScroll(event: Event): void {\n if (event instanceof WheelEvent && !this.canScrollBy(event.deltaY)) return;\n\n this.autoScroll = false;\n\n clearTimeout(this.scrollResumeTimerId);\n this.scrollResumeTimerId = setTimeout(() => {\n this.autoScroll = true;\n }, this.scrollTimerDelay);\n }\n\n /** Whether the transcript has anywhere left to go in `deltaY`'s direction. */\n private canScrollBy(deltaY: number): boolean {\n const { scrollView } = this;\n if (!scrollView) return false;\n\n const { scrollTop, scrollHeight, clientHeight } = scrollView;\n if (deltaY < 0) return scrollTop > 0;\n if (deltaY > 0) return Math.ceil(scrollTop + clientHeight) < scrollHeight;\n return false;\n }\n\n private enableAutoScroll(): void {\n this.autoScroll = true;\n this.scrollToClosestEntry();\n }\n\n private get activeTranscriptEntry(): HTMLElement | null {\n return (\n this.shadowRoot?.querySelector('ia-transcript-entry[isActive]') ?? null\n );\n }\n\n private get selectedSearchResult(): HTMLElement | null {\n return (\n this.shadowRoot?.querySelector(\n `ia-transcript-entry[data-search-result-index=\"${this.selectedSearchResultIndex}\"]`,\n ) ?? null\n );\n }\n\n private get closestEntryToCurrentTime(): HTMLElement | null {\n return (\n this.activeTranscriptEntry ?? this.elementClosestToTime(this.currentTime)\n );\n }\n\n private scrollToClosestEntry(): void {\n if (!this.autoScroll) return;\n\n const closestEntry = this.closestEntryToCurrentTime;\n if (closestEntry) this.scrollToElement(closestEntry);\n }\n\n /**\n * Scrolls an entry to the top of the focus area, if it isn't in there\n * already.\n */\n private scrollToElement(element: HTMLElement): void {\n const { scrollView } = this;\n if (!scrollView) return;\n\n const containerRect = scrollView.getBoundingClientRect();\n const entryRect = element.getBoundingClientRect();\n const focusBottom = containerRect.height - this.bottomContextHeight;\n\n const isBelowFocusArea = entryRect.bottom > containerRect.top + focusBottom;\n const isAboveFocusArea = entryRect.top < containerRect.top;\n if (!isBelowFocusArea && !isAboveFocusArea) return;\n\n this.scrollToOffset(\n entryRect.top -\n containerRect.top +\n scrollView.scrollTop -\n this.topContextHeight,\n );\n }\n\n private updateTimePosition(): void {\n const scrollToEntry = this.closestEntryToCurrentTime;\n if (!scrollToEntry) return;\n\n const parent = scrollToEntry.parentNode as HTMLElement | null;\n if (!parent) return;\n\n this.timeScrollTop =\n scrollToEntry.getBoundingClientRect().top -\n parent.getBoundingClientRect().top;\n }\n\n /**\n * Eases the scroll container to an offset.\n *\n * Only one animation runs at a time: playback ticks arrive faster than an\n * animation finishes, and two loops writing `scrollTop` fight each other.\n */\n private scrollToOffset(offset: number): void {\n const { scrollView } = this;\n if (!scrollView) return;\n\n this.cancelScrollAnimation();\n\n const start = scrollView.scrollTop;\n const change = offset - start;\n const startTime = performance.now();\n\n const easeInOutQuad = (time: number): number =>\n time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time;\n\n const animate = (): void => {\n const elapsed = (performance.now() - startTime) / 1000;\n // Clamped so the last frame lands exactly on the target rather than\n // overshooting past it.\n const progress = Math.min(elapsed / SCROLL_DURATION_SECONDS, 1);\n\n scrollView.scrollTop = start + change * easeInOutQuad(progress);\n\n if (progress < 1) {\n this.scrollAnimationId = requestAnimationFrame(animate);\n } else {\n this.scrollAnimationId = undefined;\n }\n };\n\n animate();\n }\n\n private cancelScrollAnimation(): void {\n if (this.scrollAnimationId === undefined) return;\n\n cancelAnimationFrame(this.scrollAnimationId);\n this.scrollAnimationId = undefined;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --transcript-height--: var(--ia-theme-transcript-height, 200px);\n\n --transcript-normal-text-color--: var(\n --ia-theme-transcript-normal-text-color,\n gray\n );\n --transcript-active-text-color--: var(\n --ia-theme-transcript-active-text-color,\n white\n );\n --transcript-hover-text-color--: var(\n --ia-theme-transcript-hover-text-color,\n silver\n );\n\n --transcript-music-normal-text-color--: var(\n --ia-theme-transcript-music-normal-text-color,\n gray\n );\n --transcript-music-active-text-color--: var(\n --ia-theme-transcript-music-active-text-color,\n white\n );\n --transcript-music-hover-text-color--: var(\n --ia-theme-transcript-music-hover-text-color,\n silver\n );\n\n --transcript-search-result-inactive-border-color--: var(\n --ia-theme-transcript-search-result-inactive-border-color,\n gray\n );\n --transcript-search-result-active-border-color--: var(\n --ia-theme-transcript-search-result-active-border-color,\n green\n );\n\n --transcript-time-color--: var(--ia-theme-transcript-time-color, white);\n --transcript-time-column-width--: var(\n --ia-theme-transcript-time-column-width,\n 3rem\n );\n --transcript-time-font-size--: var(\n --ia-theme-transcript-time-font-size,\n 1em\n );\n --transcript-time-line-height--: var(\n --ia-theme-transcript-time-line-height,\n 1em\n );\n --transcript-time-display--: var(\n --ia-theme-transcript-time-display,\n block\n );\n\n --transcript-auto-scroll-button-color--: var(\n --ia-theme-transcript-auto-scroll-button-color,\n black\n );\n --transcript-auto-scroll-button-background--: var(\n --ia-theme-transcript-auto-scroll-button-background,\n white\n );\n --transcript-auto-scroll-button-width--: var(\n --ia-theme-transcript-auto-scroll-button-width,\n 12rem\n );\n --transcript-auto-scroll-button-font-size--: var(\n --ia-theme-transcript-auto-scroll-button-font-size,\n 1em\n );\n\n color: var(--transcript-normal-text-color--);\n }\n\n .container {\n position: relative;\n }\n\n .auto-scroll-button {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 1rem;\n margin: auto;\n width: var(--transcript-auto-scroll-button-width--);\n border-radius: 1em;\n border: 0;\n display: inline-block;\n color: var(--transcript-auto-scroll-button-color--);\n background-color: var(--transcript-auto-scroll-button-background--);\n font-size: var(--transcript-auto-scroll-button-font-size--);\n cursor: pointer;\n z-index: 10;\n }\n\n .auto-scroll-button.hidden {\n display: none;\n }\n\n .context-overlay {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n /* Purely a guide. It sits over the top and bottom of the scroll area,\n so without this it would swallow the wheel and the entry clicks\n there, breaking the scrolling it exists to help you look at. */\n pointer-events: none;\n }\n\n .context-overlay.top {\n top: 0;\n border-bottom: 1px solid green;\n }\n\n .context-overlay.bottom {\n bottom: 0;\n border-top: 1px solid green;\n }\n\n .time {\n display: var(--transcript-time-display--);\n flex: 0 0 var(--transcript-time-column-width--);\n color: var(--transcript-time-color--);\n position: relative;\n }\n\n .time-display {\n position: absolute;\n top: 0;\n font-size: var(--transcript-time-font-size--);\n line-height: var(--transcript-time-line-height--);\n transition: top 1s;\n }\n\n .scroll-container {\n display: flex;\n overflow-y: auto;\n -ms-overflow-style: none;\n scrollbar-width: none;\n height: var(--transcript-height--);\n }\n\n .scroll-container::-webkit-scrollbar {\n display: none;\n }\n\n ia-transcript-entry {\n cursor: pointer;\n }\n\n ia-transcript-entry:hover {\n color: var(--transcript-hover-text-color--);\n }\n\n ia-transcript-entry[ismusicentry] {\n color: var(--transcript-music-normal-text-color--);\n display: block;\n font-style: italic;\n }\n\n ia-transcript-entry[ismusicentry]:hover {\n color: var(--transcript-music-hover-text-color--);\n }\n\n ia-transcript-entry[ismusicentry][isactive] {\n color: var(--transcript-music-active-text-color--);\n }\n\n ia-transcript-entry[isactive] {\n color: var(--transcript-active-text-color--);\n }\n\n ia-transcript-entry[issearchresult] {\n /* Inline-block, or the outline adds a space to the right of the text */\n display: inline-block;\n padding: 0 5px;\n position: relative;\n }\n\n ia-transcript-entry[issearchresult]:after {\n content: '';\n display: block;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n border: 2px solid\n var(--transcript-search-result-inactive-border-color--);\n border-radius: 5px;\n }\n\n ia-transcript-entry[issearchresult][isselected]:after {\n border: 2px solid var(--transcript-search-result-active-border-color--);\n }\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"ia-transcript-view.js","sourceRoot":"","sources":["../../../../src/elements/ia-transcript-view/ia-transcript-view.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n nothing,\n type CSSResultGroup,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { msg } from '@lit/localize';\n\nimport { formatDuration } from './duration-formatter';\nimport type { TranscriptConfig, TranscriptEntryConfig } from './models';\nimport type { IATranscriptEntry } from './ia-transcript-entry';\n\nimport './ia-transcript-entry';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n TranscriptEntrySelected: 'transcriptEntrySelected',\n CurrentEntriesUpdated: 'currentEntriesUpdated',\n AutoScrollChanged: 'autoScrollChanged',\n};\n\n/** How long a scroll animation runs, in seconds */\nconst SCROLL_DURATION_SECONDS = 1;\n\n/**\n * A scrolling transcript that follows playback.\n *\n * It keeps itself scrolled to whatever is being spoken, steps aside when the\n * listener scrolls by hand, and picks the job back up once they've stopped.\n */\n@customElement('ia-transcript-view')\nexport class IATranscriptView extends LitElement {\n /** The transcript to render */\n @property({ type: Object }) config?: TranscriptConfig;\n\n /** Playback position, in seconds into the track */\n @property({ type: Number }) currentTime = 0;\n\n /** How much room to leave above the entry being spoken, in pixels */\n @property({ type: Number }) topContextHeight = 50;\n\n /** How much room to leave below the entry being spoken, in pixels */\n @property({ type: Number }) bottomContextHeight = 50;\n\n /** Whether the transcript follows playback */\n @property({ type: Boolean }) autoScroll = true;\n\n /** Which search result is currently being looked at */\n @property({ type: Number }) selectedSearchResultIndex = 0;\n\n /** Whether to outline the context zones, for working on the scrolling */\n @property({ type: Boolean }) showContextZones = false;\n\n /** How long to wait after a manual scroll before following playback again */\n @property({ type: Number }) scrollTimerDelay = 15000;\n\n @state() private timeScrollTop = 0;\n\n @state() private currentEntries: TranscriptEntryConfig[] = [];\n\n @query('#scroll-container') private scrollView?: HTMLElement | null;\n\n private scrollResumeTimerId?: ReturnType<typeof setTimeout>;\n\n private scrollAnimationId?: number;\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n clearTimeout(this.scrollResumeTimerId);\n this.cancelScrollAnimation();\n }\n\n render(): TemplateResult {\n return html`\n <div class=\"container\">\n ${this.showContextZones ? this.contextZoneTemplates : nothing}\n\n <div\n class=\"scroll-container\"\n id=\"scroll-container\"\n @wheel=${this.didScroll}\n @touchmove=${this.didScroll}\n >\n <div class=\"col time\">${this.timeDisplayTemplate}</div>\n\n <div class=\"col\">\n ${this.autoScrollButtonTemplate}\n ${this.transcriptEntries.map((entry) =>\n this.transcriptEntryTemplate(entry),\n )}\n </div>\n </div>\n </div>\n `;\n }\n\n /** Scrolls the selected search result into view. */\n scrollToSelectedSearchResult(): void {\n const { selectedSearchResult } = this;\n if (!selectedSearchResult) return;\n\n this.autoScroll = false;\n this.scrollToElement(selectedSearchResult);\n }\n\n /** The id of the entry starting closest to a given time, if there is one. */\n entryIdentifierClosestToTime(time: number): number | null {\n const entries = this.transcriptEntries;\n if (entries.length === 0) return null;\n\n let closest = entries[0];\n let smallestDelta = Math.abs(time - closest.start);\n\n for (const entry of entries) {\n const delta = Math.abs(time - entry.start);\n if (delta < smallestDelta) {\n smallestDelta = delta;\n closest = entry;\n }\n }\n\n return closest.id;\n }\n\n private get autoScrollButtonTemplate(): TemplateResult {\n return html`\n <button\n type=\"button\"\n class=\"auto-scroll-button ${this.autoScroll ? 'hidden' : ''}\"\n @click=${this.enableAutoScroll}\n >\n ${msg('Scroll text with audio')}\n </button>\n `;\n }\n\n private get timeDisplayTemplate(): TemplateResult {\n return html`\n <div class=\"time-display\" style=\"top: ${this.timeScrollTop}px\">\n ${formatDuration(this.currentTime)}\n </div>\n `;\n }\n\n private transcriptEntryTemplate(\n entry: TranscriptEntryConfig,\n ): TemplateResult {\n const isActive = this.currentEntries.some(\n (currentEntry) => currentEntry.id === entry.id,\n );\n\n return html`\n <ia-transcript-entry\n .entry=${entry}\n ?isActive=${isActive}\n ?isSelected=${entry.searchMatchIndex === this.selectedSearchResultIndex}\n ?isSearchResult=${entry.searchMatchIndex !== undefined}\n ?isMusicEntry=${entry.isMusic}\n isClickable\n data-search-result-index=${ifDefined(entry.searchMatchIndex)}\n data-identifier=${entry.id}\n @click=${this.transcriptEntrySelected}\n ></ia-transcript-entry>\n `;\n }\n\n private get contextZoneTemplates(): TemplateResult {\n return html`\n <div\n class=\"top context-overlay\"\n style=\"height: ${this.topContextHeight}px\"\n ></div>\n <div\n class=\"bottom context-overlay\"\n style=\"height: ${this.bottomContextHeight}px\"\n ></div>\n `;\n }\n\n private get transcriptEntries(): TranscriptEntryConfig[] {\n return this.config?.entries ?? [];\n }\n\n updated(changedProperties: PropertyValues): void {\n if (changedProperties.has('currentTime')) this.handleCurrentTimeChange();\n if (changedProperties.has('selectedSearchResultIndex')) {\n this.scrollToSelectedSearchResult();\n }\n if (changedProperties.has('currentEntries')) {\n this.scrollToClosestEntry();\n this.updateTimePosition();\n }\n if (changedProperties.has('autoScroll')) {\n this.dispatchEvent(\n new CustomEvent<{ autoScroll: boolean }>(Events.AutoScrollChanged, {\n detail: { autoScroll: this.autoScroll },\n }),\n );\n }\n if (changedProperties.has('config')) {\n this.selectedSearchResultIndex = 0;\n this.scrollToSelectedSearchResult();\n }\n }\n\n private transcriptEntrySelected(e: Event): void {\n const { entry } = e.currentTarget as IATranscriptEntry;\n if (!entry) return;\n\n this.dispatchEvent(\n new CustomEvent<{ entry: TranscriptEntryConfig }>(\n Events.TranscriptEntrySelected,\n { detail: { entry } },\n ),\n );\n\n if (entry.searchMatchIndex !== undefined) {\n this.selectedSearchResultIndex = entry.searchMatchIndex;\n }\n this.autoScroll = false;\n }\n\n /**\n * Works out which entries are being spoken now.\n *\n * Runs on every time update, several times a second, so it only touches the\n * rendered state when the set of entries has actually changed.\n */\n private handleCurrentTimeChange(): void {\n const entries = this.transcriptEntries;\n if (entries.length === 0) return;\n\n const activeEntries = entries.filter(\n (entry) =>\n this.currentTime >= entry.start && this.currentTime <= entry.end,\n );\n\n if (IATranscriptView.entryArraysMatch(activeEntries, this.currentEntries)) {\n return;\n }\n\n this.dispatchEvent(new Event(Events.CurrentEntriesUpdated));\n this.currentEntries = activeEntries;\n }\n\n private static entryArraysMatch(\n a: TranscriptEntryConfig[],\n b: TranscriptEntryConfig[],\n ): boolean {\n if (a.length !== b.length) return false;\n\n const aIds = a.map((entry) => entry.id).sort((x, y) => x - y);\n const bIds = b.map((entry) => entry.id).sort((x, y) => x - y);\n\n return aIds.every((id, index) => bIds[index] === id);\n }\n\n private elementClosestToTime(time: number): HTMLElement | null {\n const closestIdentifier = this.entryIdentifierClosestToTime(time);\n // Compared against null rather than tested for truthiness, so an entry\n // whose id is 0 is still found.\n if (closestIdentifier === null) return null;\n\n return this.elementForIdentifier(closestIdentifier);\n }\n\n private elementForIdentifier(identifier: number): HTMLElement | null {\n return (\n this.shadowRoot?.querySelector(\n `ia-transcript-entry[data-identifier=\"${identifier}\"]`,\n ) ?? null\n );\n }\n\n /**\n * Steps auto-scroll aside when the listener scrolls by hand, and arranges to\n * pick it back up once they've left it alone for a while.\n *\n * A wheel that the transcript cannot act on, such as a wheel-up when it is\n * already at the top, is ignored: the listener sees nothing move, so taking\n * auto-scroll away from them reads as the page misbehaving.\n */\n private didScroll(event: Event): void {\n if (event instanceof WheelEvent && !this.canScrollBy(event.deltaY)) return;\n\n this.autoScroll = false;\n\n clearTimeout(this.scrollResumeTimerId);\n this.scrollResumeTimerId = setTimeout(() => {\n this.autoScroll = true;\n }, this.scrollTimerDelay);\n }\n\n /** Whether the transcript has anywhere left to go in `deltaY`'s direction. */\n private canScrollBy(deltaY: number): boolean {\n const { scrollView } = this;\n if (!scrollView) return false;\n\n const { scrollTop, scrollHeight, clientHeight } = scrollView;\n if (deltaY < 0) return scrollTop > 0;\n if (deltaY > 0) return Math.ceil(scrollTop + clientHeight) < scrollHeight;\n return false;\n }\n\n private enableAutoScroll(): void {\n this.autoScroll = true;\n this.scrollToClosestEntry();\n }\n\n private get activeTranscriptEntry(): HTMLElement | null {\n return (\n this.shadowRoot?.querySelector('ia-transcript-entry[isActive]') ?? null\n );\n }\n\n private get selectedSearchResult(): HTMLElement | null {\n return (\n this.shadowRoot?.querySelector(\n `ia-transcript-entry[data-search-result-index=\"${this.selectedSearchResultIndex}\"]`,\n ) ?? null\n );\n }\n\n private get closestEntryToCurrentTime(): HTMLElement | null {\n return (\n this.activeTranscriptEntry ?? this.elementClosestToTime(this.currentTime)\n );\n }\n\n private scrollToClosestEntry(): void {\n if (!this.autoScroll) return;\n\n const closestEntry = this.closestEntryToCurrentTime;\n if (closestEntry) this.scrollToElement(closestEntry);\n }\n\n /**\n * Scrolls an entry to the top of the focus area, if it isn't in there\n * already.\n */\n private scrollToElement(element: HTMLElement): void {\n const { scrollView } = this;\n if (!scrollView) return;\n\n const containerRect = scrollView.getBoundingClientRect();\n const entryRect = element.getBoundingClientRect();\n const focusBottom = containerRect.height - this.bottomContextHeight;\n\n const isBelowFocusArea = entryRect.bottom > containerRect.top + focusBottom;\n const isAboveFocusArea = entryRect.top < containerRect.top;\n if (!isBelowFocusArea && !isAboveFocusArea) return;\n\n this.scrollToOffset(\n entryRect.top -\n containerRect.top +\n scrollView.scrollTop -\n this.topContextHeight,\n );\n }\n\n private updateTimePosition(): void {\n const scrollToEntry = this.closestEntryToCurrentTime;\n if (!scrollToEntry) return;\n\n const parent = scrollToEntry.parentNode as HTMLElement | null;\n if (!parent) return;\n\n this.timeScrollTop =\n scrollToEntry.getBoundingClientRect().top -\n parent.getBoundingClientRect().top;\n }\n\n /**\n * Eases the scroll container to an offset.\n *\n * Only one animation runs at a time: playback ticks arrive faster than an\n * animation finishes, and two loops writing `scrollTop` fight each other.\n */\n private scrollToOffset(offset: number): void {\n const { scrollView } = this;\n if (!scrollView) return;\n\n this.cancelScrollAnimation();\n\n const start = scrollView.scrollTop;\n const change = offset - start;\n const startTime = performance.now();\n\n const easeInOutQuad = (time: number): number =>\n time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time;\n\n const animate = (): void => {\n const elapsed = (performance.now() - startTime) / 1000;\n // Clamped so the last frame lands exactly on the target rather than\n // overshooting past it.\n const progress = Math.min(elapsed / SCROLL_DURATION_SECONDS, 1);\n\n scrollView.scrollTop = start + change * easeInOutQuad(progress);\n\n if (progress < 1) {\n this.scrollAnimationId = requestAnimationFrame(animate);\n } else {\n this.scrollAnimationId = undefined;\n }\n };\n\n animate();\n }\n\n private cancelScrollAnimation(): void {\n if (this.scrollAnimationId === undefined) return;\n\n cancelAnimationFrame(this.scrollAnimationId);\n this.scrollAnimationId = undefined;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --transcript-height--: var(--ia-theme-transcript-height, 200px);\n\n --transcript-normal-text-color--: var(\n --ia-theme-transcript-normal-text-color,\n gray\n );\n --transcript-active-text-color--: var(\n --ia-theme-transcript-active-text-color,\n white\n );\n --transcript-hover-text-color--: var(\n --ia-theme-transcript-hover-text-color,\n silver\n );\n\n --transcript-music-normal-text-color--: var(\n --ia-theme-transcript-music-normal-text-color,\n gray\n );\n --transcript-music-active-text-color--: var(\n --ia-theme-transcript-music-active-text-color,\n white\n );\n --transcript-music-hover-text-color--: var(\n --ia-theme-transcript-music-hover-text-color,\n silver\n );\n\n --transcript-search-result-inactive-border-color--: var(\n --ia-theme-transcript-search-result-inactive-border-color,\n gray\n );\n --transcript-search-result-active-border-color--: var(\n --ia-theme-transcript-search-result-active-border-color,\n green\n );\n\n --transcript-time-color--: var(--ia-theme-transcript-time-color, white);\n --transcript-time-column-width--: var(\n --ia-theme-transcript-time-column-width,\n 3rem\n );\n --transcript-time-font-size--: var(\n --ia-theme-transcript-time-font-size,\n 1em\n );\n --transcript-time-line-height--: var(\n --ia-theme-transcript-time-line-height,\n 1em\n );\n --transcript-time-display--: var(\n --ia-theme-transcript-time-display,\n block\n );\n\n --transcript-auto-scroll-button-color--: var(\n --ia-theme-transcript-auto-scroll-button-color,\n black\n );\n --transcript-auto-scroll-button-background--: var(\n --ia-theme-transcript-auto-scroll-button-background,\n white\n );\n --transcript-auto-scroll-button-width--: var(\n --ia-theme-transcript-auto-scroll-button-width,\n 12rem\n );\n --transcript-auto-scroll-button-font-size--: var(\n --ia-theme-transcript-auto-scroll-button-font-size,\n 1em\n );\n\n color: var(--transcript-normal-text-color--);\n }\n\n .container {\n position: relative;\n }\n\n .auto-scroll-button {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 1rem;\n margin: auto;\n width: var(--transcript-auto-scroll-button-width--);\n border-radius: 1em;\n border: 0;\n display: inline-block;\n color: var(--transcript-auto-scroll-button-color--);\n background-color: var(--transcript-auto-scroll-button-background--);\n font-size: var(--transcript-auto-scroll-button-font-size--);\n cursor: pointer;\n z-index: 10;\n }\n\n .auto-scroll-button.hidden {\n display: none;\n }\n\n .context-overlay {\n position: absolute;\n left: 0;\n width: 100%;\n height: 0;\n /* Purely a guide. It sits over the top and bottom of the scroll area,\n so without this it would swallow the wheel and the entry clicks\n there, breaking the scrolling it exists to help you look at. */\n pointer-events: none;\n }\n\n .context-overlay.top {\n top: 0;\n border-bottom: 1px solid green;\n }\n\n .context-overlay.bottom {\n bottom: 0;\n border-top: 1px solid green;\n }\n\n .time {\n display: var(--transcript-time-display--);\n flex: 0 0 var(--transcript-time-column-width--);\n color: var(--transcript-time-color--);\n position: relative;\n }\n\n .time-display {\n position: absolute;\n top: 0;\n font-size: var(--transcript-time-font-size--);\n line-height: var(--transcript-time-line-height--);\n transition: top 1s;\n }\n\n .scroll-container {\n display: flex;\n overflow-y: auto;\n -ms-overflow-style: none;\n scrollbar-width: none;\n height: var(--transcript-height--);\n }\n\n .scroll-container::-webkit-scrollbar {\n display: none;\n }\n\n ia-transcript-entry {\n cursor: pointer;\n }\n\n ia-transcript-entry:hover {\n color: var(--transcript-hover-text-color--);\n }\n\n ia-transcript-entry[ismusicentry] {\n color: var(--transcript-music-normal-text-color--);\n display: block;\n font-style: italic;\n }\n\n ia-transcript-entry[ismusicentry]:hover {\n color: var(--transcript-music-hover-text-color--);\n }\n\n ia-transcript-entry[ismusicentry][isactive] {\n color: var(--transcript-music-active-text-color--);\n }\n\n ia-transcript-entry[isactive] {\n color: var(--transcript-active-text-color--);\n }\n\n ia-transcript-entry[issearchresult] {\n /* Inline-block, or the outline adds a space to the right of the text */\n display: inline-block;\n padding: 0 5px;\n position: relative;\n }\n\n ia-transcript-entry[issearchresult]:after {\n content: '';\n display: block;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n border: 2px solid\n var(--transcript-search-result-inactive-border-color--);\n border-radius: 5px;\n }\n\n ia-transcript-entry[issearchresult][isselected]:after {\n border: 2px solid var(--transcript-search-result-active-border-color--);\n }\n `;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ia-waveform-progress.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-waveform-progress/ia-waveform-progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAGb,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAS9C;;;;;;GAMG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IAChD,wEAAwE;IAC5C,eAAe,SAAK;IAEhD,0CAA0C;IACd,WAAW,SAAM;IAE7C,4DAA4D;IAC/B,WAAW,UAAS;IAEjD,oEAAoE;IACzC,cAAc,EAAE,aAAa,EAAE,CAAM;IAEhE;;;;;;;OAOG;IACM,OAAO,CAAC,gBAAgB,CAAK;IAEtC,OAAO,CAAC,iBAAiB,CAAS;IAEb,OAAO,CAAC,SAAS,CAAC,CAAqB;IAE5D,MAAM,IAAI,cAAc;IAWxB,OAAO,KAAK,sBAAsB,GAYjC;IAED,OAAO,KAAK,wBAAwB,GAcnC;IAED,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAQhD,OAAO,CAAC,IAAI;IAKZ;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAOjB;;;;;;OAMG;IACH,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,sBAAsB;IAqB9B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAKxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAsDlC;CACF"}
1
+ {"version":3,"file":"ia-waveform-progress.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-waveform-progress/ia-waveform-progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAIb,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAS9C;;;;;;GAMG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IAChD,wEAAwE;IAC5C,eAAe,SAAK;IAEhD,0CAA0C;IACd,WAAW,SAAM;IAE7C,4DAA4D;IAC/B,WAAW,UAAS;IAEjD,oEAAoE;IACzC,cAAc,EAAE,aAAa,EAAE,CAAM;IAEhE;;;;;;;OAOG;IACM,OAAO,CAAC,gBAAgB,CAAK;IAEtC,OAAO,CAAC,iBAAiB,CAAS;IAEb,OAAO,CAAC,SAAS,CAAC,CAAqB;IAE5D,MAAM,IAAI,cAAc;IAWxB,OAAO,KAAK,sBAAsB,GAYjC;IAED,OAAO,KAAK,wBAAwB,GAcnC;IAED,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAQhD,OAAO,CAAC,IAAI;IAKZ;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAOjB;;;;;;OAMG;IACH,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,sBAAsB;IAqB9B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAKxB,MAAM,KAAK,MAAM,IAAI,cAAc,CAsDlC;CACF"}
@@ -1,7 +1,8 @@
1
1
  var IAWaveformProgress_1;
2
2
  import { __decorate } from "tslib";
3
3
  import { css, html, LitElement, nothing, } from 'lit';
4
- import { customElement, property, query, state } from 'lit/decorators.js';
4
+ import { property, query, state } from 'lit/decorators.js';
5
+ import { customElement } from '../../util/custom-element.js';
5
6
  /**
6
7
  * Event names emitted by this component
7
8
  */