@internetarchive/elements 1.1.0 → 1.1.2-webdev-9192.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.
- package/dist/src/elements/ia-image-viewer/ia-image-viewer.d.ts.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-image-viewer.js +0 -7
- package/dist/src/elements/ia-image-viewer/ia-image-viewer.js.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.d.ts +11 -4
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.d.ts.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js +39 -23
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js.map +1 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts +2 -0
- package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts.map +1 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.js +6 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-image-viewer.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-image-viewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAEnB,UAAU,EACV,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAUb,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAY,MAAM,UAAU,CAAC;AAE3E,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAK/B;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,aAAc,SAAQ,UAAU;IAChB,MAAM,EAAE,gBAAgB,EAAE,CAAM;IAE3D;;;OAGG;IACyB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAEtD,uEAAuE;IACjD,SAAS,CAAC,EAAE,WAAW,CAAC;IAE9C,yEAAyE;IAClD,UAAU,CAAC,EAAE,WAAW,CAAC;IAEhD,gFAAgF;IACvE,YAAY,SAAK;IAEjB,OAAO,CAAC,SAAS,CAAS;IAEnC;;;;OAIG;IACM,OAAO,CAAC,eAAe,CAAK;IAErC,kEAAkE;IACzD,OAAO,CAAC,QAAQ,CAAyB;IAElD;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,WAAW,CAAuB;IAE1C,OAAO,CAAC,cAAc,CAA+B;IAErD,OAAO,CAAC,QAAQ,CAAiC;IAEjD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,sDAAsD;IACtD,IAAI,YAAY,IAAI,gBAAgB,GAAG,SAAS,CAE/C;IAED,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAenD;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IAyBnB,MAAM,IAAI,cAAc,GAAG,OAAO,OAAO;IA6EzC,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,KAAK,oBAAoB,GAW/B;IAED;;;;OAIG;IACH,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,aAAa;IASrB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;;;OAKG;IACH,gBAAgB,IAAI,IAAI;IAgBxB,gBAAgB,IAAI,IAAI;IAOxB,OAAO,CAAC,eAAe;IASvB,QAAQ,IAAI,IAAI;IAKhB,YAAY,IAAI,IAAI;IAQpB;;;;OAIG;IACH,OAAO,CAAC,MAAM;IAmBd;;;OAGG;IACH,UAAU,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI;IAc3C;;;;OAIG;IACH,iBAAiB,IAAI,IAAI;IAMzB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,UAAU;IAMlB,8CAA8C;IAC9C,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,gBAAgB;IAUxB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;;;;;;;;OASG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAUvC,MAAM,KAAK,MAAM,IAAI,cAAc,
|
|
1
|
+
{"version":3,"file":"ia-image-viewer.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-image-viewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAEnB,UAAU,EACV,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAUb,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAY,MAAM,UAAU,CAAC;AAE3E,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAK/B;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,aAAc,SAAQ,UAAU;IAChB,MAAM,EAAE,gBAAgB,EAAE,CAAM;IAE3D;;;OAGG;IACyB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAEtD,uEAAuE;IACjD,SAAS,CAAC,EAAE,WAAW,CAAC;IAE9C,yEAAyE;IAClD,UAAU,CAAC,EAAE,WAAW,CAAC;IAEhD,gFAAgF;IACvE,YAAY,SAAK;IAEjB,OAAO,CAAC,SAAS,CAAS;IAEnC;;;;OAIG;IACM,OAAO,CAAC,eAAe,CAAK;IAErC,kEAAkE;IACzD,OAAO,CAAC,QAAQ,CAAyB;IAElD;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,WAAW,CAAuB;IAE1C,OAAO,CAAC,cAAc,CAA+B;IAErD,OAAO,CAAC,QAAQ,CAAiC;IAEjD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,sDAAsD;IACtD,IAAI,YAAY,IAAI,gBAAgB,GAAG,SAAS,CAE/C;IAED,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAenD;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IAyBnB,MAAM,IAAI,cAAc,GAAG,OAAO,OAAO;IA6EzC,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,KAAK,oBAAoB,GAW/B;IAED;;;;OAIG;IACH,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,aAAa;IASrB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;;;;OAKG;IACH,gBAAgB,IAAI,IAAI;IAgBxB,gBAAgB,IAAI,IAAI;IAOxB,OAAO,CAAC,eAAe;IASvB,QAAQ,IAAI,IAAI;IAKhB,YAAY,IAAI,IAAI;IAQpB;;;;OAIG;IACH,OAAO,CAAC,MAAM;IAmBd;;;OAGG;IACH,UAAU,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI;IAc3C;;;;OAIG;IACH,iBAAiB,IAAI,IAAI;IAMzB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,UAAU;IAMlB,8CAA8C;IAC9C,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,gBAAgB;IAUxB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;;;;;;;;OASG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAUvC,MAAM,KAAK,MAAM,IAAI,cAAc,CAyIlC;CACF"}
|
|
@@ -370,13 +370,6 @@ let IAImageViewer = class IAImageViewer extends LitElement {
|
|
|
370
370
|
--image-viewer-glow-color,
|
|
371
371
|
rgba(255, 255, 255, 0.25)
|
|
372
372
|
);
|
|
373
|
-
/*
|
|
374
|
-
* The breakpoint the controls query against. Named so the query in
|
|
375
|
-
* ia-imgview-controls resolves to this host rather than to whatever
|
|
376
|
-
* container the consumer happens to have further up.
|
|
377
|
-
*/
|
|
378
|
-
container: image-viewer / inline-size;
|
|
379
|
-
|
|
380
373
|
/*
|
|
381
374
|
* Size and placement are the host's business, set with ordinary CSS
|
|
382
375
|
* on the element. These are only defaults for a host that sets
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-image-viewer.js","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-image-viewer.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n type CSSResultGroup,\n html,\n LitElement,\n nothing,\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 { classMap } from 'lit/directives/class-map.js';\nimport { keyed } from 'lit/directives/keyed.js';\nimport { msg, str } from '@lit/localize';\n\nimport themeStyles from '@src/themes/theme-styles';\nimport { prefersReducedMotion } from '@src/util/prefers-reduced-motion';\nimport { ImageViewerGestures } from './image-viewer-gestures';\nimport type { ImageViewerImage, SlideDirection, WrapEdge } from './models';\nimport type { IAImageViewerSlide } from './ia-imgview-slide';\nimport './ia-imgview-slide';\nimport './ia-imgview-controls';\n\n/** Detail carried by the load and failure events a slide reports. */\ntype SlideImageEvent = CustomEvent<{ image: ImageViewerImage }>;\n\n/**\n * A swipeable image carousel.\n *\n * Shows one image at a time from a list, with previous/next buttons, a\n * counter, keyboard arrows, horizontal wheel scrolling and touch swipes.\n * Clicking an image opens it in a new tab.\n *\n * The viewer holds no opinion about where the images came from: it takes a\n * plain list of names and URLs, and reports the image it lands on through\n * `imageChanged` so a host can mirror that into its own URL or analytics.\n *\n * @fires imageChanged - The viewer settled on a new image.\n * @fires imageLoaded - An image the viewer showed finished loading.\n * @fires imageLoadFailed - An image the viewer showed could not be loaded.\n * Fires once per image until it loads successfully or the set changes.\n * @fires imageActivated - An image was clicked. Cancelable: preventing it\n * stops the default of opening the image in a new tab.\n */\n@customElement('ia-image-viewer')\nexport class IAImageViewer extends LitElement {\n @property({ type: Array }) images: ImageViewerImage[] = [];\n\n /**\n * Name of the image to show. Changing it jumps straight to that image\n * without animating. An unknown name shows the first image.\n */\n @property({ type: String }) currentImageName?: string;\n\n /** Read by the gesture controller, which tracks touches against it. */\n @query('.image-area') imageArea?: HTMLElement;\n\n /** Read by the gesture controller, which translates it during a drag. */\n @query('.slide-track') slideTrack?: HTMLElement;\n\n /** Read by the gesture controller to navigate relative to the current image. */\n @state() currentIndex = 0;\n\n @state() private animating = false;\n\n /**\n * Incremented when an animation is interrupted to force the track element to\n * be recreated via the `keyed()` directive, which guarantees the CSS\n * animation restarts even if the direction is the same.\n */\n @state() private slideGeneration = 0;\n\n /** Which edge just wrapped, if any. Drives the glow indicator. */\n @state() private wrapEdge: WrapEdge | null = null;\n\n /**\n * Images already reported as failed, so a broken image isn't counted again\n * every time the viewer passes over it. Navigating back re-fires `error` on\n * the recreated element, and the neighbouring slides staged during an\n * animation or a drag load the same image too, so without this a single\n * broken derivative reports several times a session.\n *\n * Cleared when the image set changes, which is the point a name stops\n * standing for the same file.\n */\n private reportedFailures = new Set<string>();\n\n private slideTarget: number | null = null;\n\n private slideDirection: SlideDirection | null = null;\n\n private gestures = new ImageViewerGestures(this);\n\n get imageCount(): number {\n return this.images.length;\n }\n\n /** The image currently on screen, if there is one. */\n get currentImage(): ImageViewerImage | undefined {\n return this.images[this.currentIndex];\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.has('images') || changed.has('currentImageName')) {\n const previous = changed.get('images') as ImageViewerImage[] | undefined;\n this.currentIndex = this.indexToShow(changed, previous);\n\n this.animating = false;\n this.slideGeneration = 0;\n this.slideTarget = null;\n this.slideDirection = null;\n this.wrapEdge = null;\n this.reportedFailures.clear();\n this.preloadAdjacentImages();\n }\n }\n\n /**\n * Where to land when the images or the requested name change.\n *\n * A new `currentImageName` is the host asking for a particular image, so it\n * wins. A new `images` array on its own isn't: a host that builds its list\n * in a getter hands over a fresh array on every render, which says nothing\n * about the images having changed. So the viewer holds its place by name and\n * only goes back to the start when the image it was showing is really gone.\n */\n private indexToShow(\n changed: PropertyValues,\n previousImages: ImageViewerImage[] | undefined,\n ): number {\n if (changed.has('currentImageName') && this.currentImageName) {\n const requested = this.images.findIndex(\n (image) => image.name === this.currentImageName,\n );\n if (requested >= 0) return requested;\n }\n\n const showing = previousImages?.[this.currentIndex]?.name;\n if (showing) {\n const stillThere = this.images.findIndex(\n (image) => image.name === showing,\n );\n if (stillThere >= 0) return stillThere;\n }\n\n const named = this.currentImageName\n ? this.images.findIndex((image) => image.name === this.currentImageName)\n : -1;\n return named >= 0 ? named : 0;\n }\n\n render(): TemplateResult | typeof nothing {\n if (this.images.length === 0) return nothing;\n\n const { dragging } = this.gestures;\n const current = this.images[this.currentIndex];\n const showControls = this.images.length > 1;\n\n const trackClasses = {\n 'slide-track': true,\n 'sliding-next':\n this.animating && !dragging && this.slideDirection === 'next',\n 'sliding-prev':\n this.animating && !dragging && this.slideDirection === 'prev',\n dragging,\n };\n\n const prevIndex =\n (this.currentIndex - 1 + this.images.length) % this.images.length;\n const nextIndex = (this.currentIndex + 1) % this.images.length;\n\n const slideTarget =\n this.animating && !dragging && this.slideTarget !== null\n ? this.images[this.slideTarget]\n : null;\n const prevImage = dragging ? this.images[prevIndex] : slideTarget;\n const nextImage = dragging ? this.images[nextIndex] : slideTarget;\n const showPrev =\n dragging || (slideTarget !== null && this.slideDirection === 'prev');\n const showNext =\n dragging || (slideTarget !== null && this.slideDirection === 'next');\n\n const displayIndex =\n this.animating && this.slideTarget !== null\n ? this.slideTarget\n : this.currentIndex;\n\n return html`\n <div class=\"viewer\">\n <div class=\"image-area\">\n ${this.wrapEdge\n ? html`<div\n class=\"wrap-glow ${this.wrapEdge === 'start'\n ? 'glow-start'\n : 'glow-end'}\"\n @animationend=${this.onWrapGlowEnd}\n ></div>`\n : nothing}\n ${keyed(\n this.slideGeneration,\n html`<div\n class=${classMap(trackClasses)}\n @animationend=${this.onSlideEnd}\n @imageLoaded=${this.onImageLoaded}\n @imageFailed=${this.onImageFailed}\n @imageActivated=${this.onImageActivated}\n >\n ${showPrev && prevImage ? this.slideTemplate(prevImage) : nothing}\n ${this.slideTemplate(current)}\n ${showNext && nextImage ? this.slideTemplate(nextImage) : nothing}\n </div>`,\n )}\n </div>\n ${showControls\n ? html`\n <ia-imgview-controls\n .currentIndex=${displayIndex}\n .totalImages=${this.images.length}\n @showPrevious=${this.showPrevious}\n @showNext=${this.showNext}\n ></ia-imgview-controls>\n `\n : nothing}\n ${this.announcementTemplate}\n </div>\n `;\n }\n\n private slideTemplate(image: ImageViewerImage): TemplateResult {\n return html`<ia-imgview-slide .image=${image}></ia-imgview-slide>`;\n }\n\n /**\n * Announces the image to a screen reader, which otherwise gets nothing when\n * the counter and the picture change under it.\n */\n private get announcementTemplate(): TemplateResult {\n const current = this.images[this.currentIndex];\n const position = msg(\n str`Image ${this.currentIndex + 1} of ${this.images.length}`,\n );\n const label = current?.title ?? current?.name;\n return html`\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n ${label ? `${position}: ${label}` : position}\n </div>\n `;\n }\n\n /**\n * Passes a slide's load result on to the host, which is where reporting\n * belongs. The slide's own events stop at this shadow root, so they're\n * re-dispatched rather than allowed to escape.\n */\n private onImageLoaded(e: SlideImageEvent): void {\n // A load that succeeds clears the failure, so an image that breaks again\n // later is reported again rather than swallowed as a repeat.\n this.reportedFailures.delete(e.detail.image.name);\n this.dispatchEvent(\n new CustomEvent('imageLoaded', { detail: { image: e.detail.image } }),\n );\n }\n\n private onImageFailed(e: SlideImageEvent): void {\n const { image } = e.detail;\n if (this.reportedFailures.has(image.name)) return;\n this.reportedFailures.add(image.name);\n this.dispatchEvent(\n new CustomEvent('imageLoadFailed', { detail: { image } }),\n );\n }\n\n /**\n * Decides whether a click on a slide opens the image.\n *\n * Two things can stop it: the click is the tail end of a swipe, or the host\n * cancels the event to show the image its own way. The slide's event doesn't\n * cross this shadow root, so it's re-raised here for the host to see, and a\n * veto is passed back down to cancel the click.\n */\n private onImageActivated(e: SlideImageEvent): void {\n if (this.gestures.consumeSwipeTap()) {\n e.preventDefault();\n return;\n }\n const allowed = this.dispatchEvent(\n new CustomEvent('imageActivated', {\n detail: { image: e.detail.image },\n cancelable: true,\n }),\n );\n if (!allowed) e.preventDefault();\n }\n\n /**\n * Inserts the neighbouring slides around the current one so the touch target\n * element stays in the DOM (avoiding touchcancel). These aren't rendered\n * from the template, so they're marked for the gesture controller to clean\n * up. The dragging class shifts the track to centre on the middle slide.\n */\n insertDragSlides(): void {\n const track = this.slideTrack;\n if (!track) return;\n const prevIdx =\n (this.currentIndex - 1 + this.images.length) % this.images.length;\n const nextIdx = (this.currentIndex + 1) % this.images.length;\n\n track.insertBefore(\n this.createDragSlide(this.images[prevIdx]),\n track.firstChild,\n );\n track.appendChild(this.createDragSlide(this.images[nextIdx]));\n\n track.classList.add('dragging');\n }\n\n removeDragSlides(): void {\n const track = this.slideTrack;\n if (!track) return;\n track.querySelectorAll('[data-drag-slide]').forEach((el) => el.remove());\n track.classList.remove('dragging');\n }\n\n private createDragSlide(image: ImageViewerImage): IAImageViewerSlide {\n const slide = document.createElement(\n 'ia-imgview-slide',\n ) as IAImageViewerSlide;\n slide.image = image;\n slide.dataset.dragSlide = '';\n return slide;\n }\n\n showNext(): void {\n this.settleIfAnimating();\n this.moveTo((this.currentIndex + 1) % this.images.length, 'next');\n }\n\n showPrevious(): void {\n this.settleIfAnimating();\n this.moveTo(\n (this.currentIndex - 1 + this.images.length) % this.images.length,\n 'prev',\n );\n }\n\n /**\n * Starts the move to another image. With reduced motion there's no animation\n * to wait on, so the move lands immediately: nothing would fire the\n * `animationend` that otherwise commits it.\n */\n private moveTo(target: number, direction: SlideDirection): void {\n const wraps =\n direction === 'next'\n ? this.currentIndex === this.images.length - 1\n : this.currentIndex === 0;\n this.preloadAroundIndex(target);\n\n if (prefersReducedMotion()) {\n this.currentIndex = target;\n this.settleAtCurrentIndex();\n return;\n }\n\n this.slideTarget = target;\n this.slideDirection = direction;\n this.animating = true;\n this.wrapEdge = wraps ? (direction === 'next' ? 'end' : 'start') : null;\n }\n\n /**\n * Moves to the image a completed drag landed on. The drag has already\n * animated the track there, so this only updates state.\n */\n commitDrag(direction: SlideDirection): void {\n const wraps =\n direction === 'next'\n ? this.currentIndex === this.images.length - 1\n : this.currentIndex === 0;\n const step = direction === 'next' ? 1 : -1;\n this.currentIndex =\n (this.currentIndex + step + this.images.length) % this.images.length;\n if (wraps && !prefersReducedMotion()) {\n this.wrapEdge = direction === 'next' ? 'end' : 'start';\n }\n this.emitImageChanged();\n }\n\n /**\n * If an animation is in progress, immediately commit its target so the next\n * animation starts from the right position. Bumps the generation key to\n * force the track element to be recreated, which restarts the CSS animation.\n */\n settleIfAnimating(): void {\n if (!this.animating || this.slideTarget === null) return;\n this.currentIndex = this.slideTarget;\n this.slideGeneration++;\n }\n\n private onWrapGlowEnd(): void {\n this.wrapEdge = null;\n }\n\n private onSlideEnd(): void {\n if (this.slideTarget === null) return;\n this.currentIndex = this.slideTarget;\n this.settleAtCurrentIndex();\n }\n\n /** Finishes a move, however it was driven. */\n private settleAtCurrentIndex(): void {\n this.slideTarget = null;\n this.slideDirection = null;\n this.animating = false;\n this.gestures.animationSettled();\n this.emitImageChanged();\n this.preloadAdjacentImages();\n }\n\n private emitImageChanged(): void {\n const image = this.images[this.currentIndex];\n if (!image) return;\n this.dispatchEvent(\n new CustomEvent('imageChanged', {\n detail: { image, index: this.currentIndex },\n }),\n );\n }\n\n /**\n * Preloads the next and previous images around `currentIndex` so the first\n * navigation feels instant.\n */\n private preloadAdjacentImages(): void {\n this.preloadAroundIndex(this.currentIndex);\n }\n\n /**\n * Preloads images adjacent to the given index. Called both at rest (around\n * `currentIndex`) and at the start of a move (around the target) so rapid\n * navigation stays ahead of the browser cache.\n *\n * A preload that fails is deliberately not reported. These requests are\n * speculative and the viewer may never show them, so counting them would\n * inflate the failure rate with images nobody looked at. Navigating to a\n * broken image renders a real slide, whose `error` reports it then.\n */\n preloadAroundIndex(index: number): void {\n if (this.images.length <= 1) return;\n const next = (index + 1) % this.images.length;\n const prev = (index - 1 + this.images.length) % this.images.length;\n for (const idx of [next, prev]) {\n const img = new Image();\n img.src = this.images[idx].url;\n }\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --image-viewer-slide-duration--: var(\n --image-viewer-slide-duration,\n 500ms\n );\n --image-viewer-glow-color--: var(\n --image-viewer-glow-color,\n rgba(255, 255, 255, 0.25)\n );\n /*\n * The breakpoint the controls query against. Named so the query in\n * ia-imgview-controls resolves to this host rather than to whatever\n * container the consumer happens to have further up.\n */\n container: image-viewer / inline-size;\n\n /*\n * Size and placement are the host's business, set with ordinary CSS\n * on the element. These are only defaults for a host that sets\n * neither; a rule in the outer tree beats them.\n */\n display: block;\n height: 100%;\n margin: 0 auto;\n }\n\n .viewer {\n position: relative;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n }\n\n .image-area {\n position: relative;\n flex: 1;\n min-height: 0;\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n touch-action: pan-y pinch-zoom;\n }\n\n .wrap-glow {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 100px;\n pointer-events: none;\n z-index: 2;\n animation: glow-fade 700ms ease-out both;\n }\n\n .glow-start {\n left: 0;\n background: linear-gradient(\n to right,\n var(--image-viewer-glow-color--),\n transparent\n );\n }\n\n .glow-end {\n right: 0;\n background: linear-gradient(\n to left,\n var(--image-viewer-glow-color--),\n transparent\n );\n }\n\n @keyframes glow-fade {\n 0% {\n opacity: 0;\n }\n 20% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n\n .slide-track {\n display: flex;\n width: 100%;\n height: 100%;\n flex-shrink: 0;\n }\n\n @keyframes slide-next {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-100%);\n }\n }\n\n @keyframes slide-prev {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n }\n\n .slide-track.dragging {\n transform: translateX(-100%);\n }\n\n .slide-track.sliding-next {\n animation: slide-next var(--image-viewer-slide-duration--) ease-in-out\n both;\n }\n\n .slide-track.sliding-prev {\n animation: slide-prev var(--image-viewer-slide-duration--) ease-in-out\n both;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n overflow: hidden;\n white-space: nowrap;\n clip-path: inset(50%);\n }\n `,\n ];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ia-image-viewer.js","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-image-viewer.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n type CSSResultGroup,\n html,\n LitElement,\n nothing,\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 { classMap } from 'lit/directives/class-map.js';\nimport { keyed } from 'lit/directives/keyed.js';\nimport { msg, str } from '@lit/localize';\n\nimport themeStyles from '@src/themes/theme-styles';\nimport { prefersReducedMotion } from '@src/util/prefers-reduced-motion';\nimport { ImageViewerGestures } from './image-viewer-gestures';\nimport type { ImageViewerImage, SlideDirection, WrapEdge } from './models';\nimport type { IAImageViewerSlide } from './ia-imgview-slide';\nimport './ia-imgview-slide';\nimport './ia-imgview-controls';\n\n/** Detail carried by the load and failure events a slide reports. */\ntype SlideImageEvent = CustomEvent<{ image: ImageViewerImage }>;\n\n/**\n * A swipeable image carousel.\n *\n * Shows one image at a time from a list, with previous/next buttons, a\n * counter, keyboard arrows, horizontal wheel scrolling and touch swipes.\n * Clicking an image opens it in a new tab.\n *\n * The viewer holds no opinion about where the images came from: it takes a\n * plain list of names and URLs, and reports the image it lands on through\n * `imageChanged` so a host can mirror that into its own URL or analytics.\n *\n * @fires imageChanged - The viewer settled on a new image.\n * @fires imageLoaded - An image the viewer showed finished loading.\n * @fires imageLoadFailed - An image the viewer showed could not be loaded.\n * Fires once per image until it loads successfully or the set changes.\n * @fires imageActivated - An image was clicked. Cancelable: preventing it\n * stops the default of opening the image in a new tab.\n */\n@customElement('ia-image-viewer')\nexport class IAImageViewer extends LitElement {\n @property({ type: Array }) images: ImageViewerImage[] = [];\n\n /**\n * Name of the image to show. Changing it jumps straight to that image\n * without animating. An unknown name shows the first image.\n */\n @property({ type: String }) currentImageName?: string;\n\n /** Read by the gesture controller, which tracks touches against it. */\n @query('.image-area') imageArea?: HTMLElement;\n\n /** Read by the gesture controller, which translates it during a drag. */\n @query('.slide-track') slideTrack?: HTMLElement;\n\n /** Read by the gesture controller to navigate relative to the current image. */\n @state() currentIndex = 0;\n\n @state() private animating = false;\n\n /**\n * Incremented when an animation is interrupted to force the track element to\n * be recreated via the `keyed()` directive, which guarantees the CSS\n * animation restarts even if the direction is the same.\n */\n @state() private slideGeneration = 0;\n\n /** Which edge just wrapped, if any. Drives the glow indicator. */\n @state() private wrapEdge: WrapEdge | null = null;\n\n /**\n * Images already reported as failed, so a broken image isn't counted again\n * every time the viewer passes over it. Navigating back re-fires `error` on\n * the recreated element, and the neighbouring slides staged during an\n * animation or a drag load the same image too, so without this a single\n * broken derivative reports several times a session.\n *\n * Cleared when the image set changes, which is the point a name stops\n * standing for the same file.\n */\n private reportedFailures = new Set<string>();\n\n private slideTarget: number | null = null;\n\n private slideDirection: SlideDirection | null = null;\n\n private gestures = new ImageViewerGestures(this);\n\n get imageCount(): number {\n return this.images.length;\n }\n\n /** The image currently on screen, if there is one. */\n get currentImage(): ImageViewerImage | undefined {\n return this.images[this.currentIndex];\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.has('images') || changed.has('currentImageName')) {\n const previous = changed.get('images') as ImageViewerImage[] | undefined;\n this.currentIndex = this.indexToShow(changed, previous);\n\n this.animating = false;\n this.slideGeneration = 0;\n this.slideTarget = null;\n this.slideDirection = null;\n this.wrapEdge = null;\n this.reportedFailures.clear();\n this.preloadAdjacentImages();\n }\n }\n\n /**\n * Where to land when the images or the requested name change.\n *\n * A new `currentImageName` is the host asking for a particular image, so it\n * wins. A new `images` array on its own isn't: a host that builds its list\n * in a getter hands over a fresh array on every render, which says nothing\n * about the images having changed. So the viewer holds its place by name and\n * only goes back to the start when the image it was showing is really gone.\n */\n private indexToShow(\n changed: PropertyValues,\n previousImages: ImageViewerImage[] | undefined,\n ): number {\n if (changed.has('currentImageName') && this.currentImageName) {\n const requested = this.images.findIndex(\n (image) => image.name === this.currentImageName,\n );\n if (requested >= 0) return requested;\n }\n\n const showing = previousImages?.[this.currentIndex]?.name;\n if (showing) {\n const stillThere = this.images.findIndex(\n (image) => image.name === showing,\n );\n if (stillThere >= 0) return stillThere;\n }\n\n const named = this.currentImageName\n ? this.images.findIndex((image) => image.name === this.currentImageName)\n : -1;\n return named >= 0 ? named : 0;\n }\n\n render(): TemplateResult | typeof nothing {\n if (this.images.length === 0) return nothing;\n\n const { dragging } = this.gestures;\n const current = this.images[this.currentIndex];\n const showControls = this.images.length > 1;\n\n const trackClasses = {\n 'slide-track': true,\n 'sliding-next':\n this.animating && !dragging && this.slideDirection === 'next',\n 'sliding-prev':\n this.animating && !dragging && this.slideDirection === 'prev',\n dragging,\n };\n\n const prevIndex =\n (this.currentIndex - 1 + this.images.length) % this.images.length;\n const nextIndex = (this.currentIndex + 1) % this.images.length;\n\n const slideTarget =\n this.animating && !dragging && this.slideTarget !== null\n ? this.images[this.slideTarget]\n : null;\n const prevImage = dragging ? this.images[prevIndex] : slideTarget;\n const nextImage = dragging ? this.images[nextIndex] : slideTarget;\n const showPrev =\n dragging || (slideTarget !== null && this.slideDirection === 'prev');\n const showNext =\n dragging || (slideTarget !== null && this.slideDirection === 'next');\n\n const displayIndex =\n this.animating && this.slideTarget !== null\n ? this.slideTarget\n : this.currentIndex;\n\n return html`\n <div class=\"viewer\">\n <div class=\"image-area\">\n ${this.wrapEdge\n ? html`<div\n class=\"wrap-glow ${this.wrapEdge === 'start'\n ? 'glow-start'\n : 'glow-end'}\"\n @animationend=${this.onWrapGlowEnd}\n ></div>`\n : nothing}\n ${keyed(\n this.slideGeneration,\n html`<div\n class=${classMap(trackClasses)}\n @animationend=${this.onSlideEnd}\n @imageLoaded=${this.onImageLoaded}\n @imageFailed=${this.onImageFailed}\n @imageActivated=${this.onImageActivated}\n >\n ${showPrev && prevImage ? this.slideTemplate(prevImage) : nothing}\n ${this.slideTemplate(current)}\n ${showNext && nextImage ? this.slideTemplate(nextImage) : nothing}\n </div>`,\n )}\n </div>\n ${showControls\n ? html`\n <ia-imgview-controls\n .currentIndex=${displayIndex}\n .totalImages=${this.images.length}\n @showPrevious=${this.showPrevious}\n @showNext=${this.showNext}\n ></ia-imgview-controls>\n `\n : nothing}\n ${this.announcementTemplate}\n </div>\n `;\n }\n\n private slideTemplate(image: ImageViewerImage): TemplateResult {\n return html`<ia-imgview-slide .image=${image}></ia-imgview-slide>`;\n }\n\n /**\n * Announces the image to a screen reader, which otherwise gets nothing when\n * the counter and the picture change under it.\n */\n private get announcementTemplate(): TemplateResult {\n const current = this.images[this.currentIndex];\n const position = msg(\n str`Image ${this.currentIndex + 1} of ${this.images.length}`,\n );\n const label = current?.title ?? current?.name;\n return html`\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n ${label ? `${position}: ${label}` : position}\n </div>\n `;\n }\n\n /**\n * Passes a slide's load result on to the host, which is where reporting\n * belongs. The slide's own events stop at this shadow root, so they're\n * re-dispatched rather than allowed to escape.\n */\n private onImageLoaded(e: SlideImageEvent): void {\n // A load that succeeds clears the failure, so an image that breaks again\n // later is reported again rather than swallowed as a repeat.\n this.reportedFailures.delete(e.detail.image.name);\n this.dispatchEvent(\n new CustomEvent('imageLoaded', { detail: { image: e.detail.image } }),\n );\n }\n\n private onImageFailed(e: SlideImageEvent): void {\n const { image } = e.detail;\n if (this.reportedFailures.has(image.name)) return;\n this.reportedFailures.add(image.name);\n this.dispatchEvent(\n new CustomEvent('imageLoadFailed', { detail: { image } }),\n );\n }\n\n /**\n * Decides whether a click on a slide opens the image.\n *\n * Two things can stop it: the click is the tail end of a swipe, or the host\n * cancels the event to show the image its own way. The slide's event doesn't\n * cross this shadow root, so it's re-raised here for the host to see, and a\n * veto is passed back down to cancel the click.\n */\n private onImageActivated(e: SlideImageEvent): void {\n if (this.gestures.consumeSwipeTap()) {\n e.preventDefault();\n return;\n }\n const allowed = this.dispatchEvent(\n new CustomEvent('imageActivated', {\n detail: { image: e.detail.image },\n cancelable: true,\n }),\n );\n if (!allowed) e.preventDefault();\n }\n\n /**\n * Inserts the neighbouring slides around the current one so the touch target\n * element stays in the DOM (avoiding touchcancel). These aren't rendered\n * from the template, so they're marked for the gesture controller to clean\n * up. The dragging class shifts the track to centre on the middle slide.\n */\n insertDragSlides(): void {\n const track = this.slideTrack;\n if (!track) return;\n const prevIdx =\n (this.currentIndex - 1 + this.images.length) % this.images.length;\n const nextIdx = (this.currentIndex + 1) % this.images.length;\n\n track.insertBefore(\n this.createDragSlide(this.images[prevIdx]),\n track.firstChild,\n );\n track.appendChild(this.createDragSlide(this.images[nextIdx]));\n\n track.classList.add('dragging');\n }\n\n removeDragSlides(): void {\n const track = this.slideTrack;\n if (!track) return;\n track.querySelectorAll('[data-drag-slide]').forEach((el) => el.remove());\n track.classList.remove('dragging');\n }\n\n private createDragSlide(image: ImageViewerImage): IAImageViewerSlide {\n const slide = document.createElement(\n 'ia-imgview-slide',\n ) as IAImageViewerSlide;\n slide.image = image;\n slide.dataset.dragSlide = '';\n return slide;\n }\n\n showNext(): void {\n this.settleIfAnimating();\n this.moveTo((this.currentIndex + 1) % this.images.length, 'next');\n }\n\n showPrevious(): void {\n this.settleIfAnimating();\n this.moveTo(\n (this.currentIndex - 1 + this.images.length) % this.images.length,\n 'prev',\n );\n }\n\n /**\n * Starts the move to another image. With reduced motion there's no animation\n * to wait on, so the move lands immediately: nothing would fire the\n * `animationend` that otherwise commits it.\n */\n private moveTo(target: number, direction: SlideDirection): void {\n const wraps =\n direction === 'next'\n ? this.currentIndex === this.images.length - 1\n : this.currentIndex === 0;\n this.preloadAroundIndex(target);\n\n if (prefersReducedMotion()) {\n this.currentIndex = target;\n this.settleAtCurrentIndex();\n return;\n }\n\n this.slideTarget = target;\n this.slideDirection = direction;\n this.animating = true;\n this.wrapEdge = wraps ? (direction === 'next' ? 'end' : 'start') : null;\n }\n\n /**\n * Moves to the image a completed drag landed on. The drag has already\n * animated the track there, so this only updates state.\n */\n commitDrag(direction: SlideDirection): void {\n const wraps =\n direction === 'next'\n ? this.currentIndex === this.images.length - 1\n : this.currentIndex === 0;\n const step = direction === 'next' ? 1 : -1;\n this.currentIndex =\n (this.currentIndex + step + this.images.length) % this.images.length;\n if (wraps && !prefersReducedMotion()) {\n this.wrapEdge = direction === 'next' ? 'end' : 'start';\n }\n this.emitImageChanged();\n }\n\n /**\n * If an animation is in progress, immediately commit its target so the next\n * animation starts from the right position. Bumps the generation key to\n * force the track element to be recreated, which restarts the CSS animation.\n */\n settleIfAnimating(): void {\n if (!this.animating || this.slideTarget === null) return;\n this.currentIndex = this.slideTarget;\n this.slideGeneration++;\n }\n\n private onWrapGlowEnd(): void {\n this.wrapEdge = null;\n }\n\n private onSlideEnd(): void {\n if (this.slideTarget === null) return;\n this.currentIndex = this.slideTarget;\n this.settleAtCurrentIndex();\n }\n\n /** Finishes a move, however it was driven. */\n private settleAtCurrentIndex(): void {\n this.slideTarget = null;\n this.slideDirection = null;\n this.animating = false;\n this.gestures.animationSettled();\n this.emitImageChanged();\n this.preloadAdjacentImages();\n }\n\n private emitImageChanged(): void {\n const image = this.images[this.currentIndex];\n if (!image) return;\n this.dispatchEvent(\n new CustomEvent('imageChanged', {\n detail: { image, index: this.currentIndex },\n }),\n );\n }\n\n /**\n * Preloads the next and previous images around `currentIndex` so the first\n * navigation feels instant.\n */\n private preloadAdjacentImages(): void {\n this.preloadAroundIndex(this.currentIndex);\n }\n\n /**\n * Preloads images adjacent to the given index. Called both at rest (around\n * `currentIndex`) and at the start of a move (around the target) so rapid\n * navigation stays ahead of the browser cache.\n *\n * A preload that fails is deliberately not reported. These requests are\n * speculative and the viewer may never show them, so counting them would\n * inflate the failure rate with images nobody looked at. Navigating to a\n * broken image renders a real slide, whose `error` reports it then.\n */\n preloadAroundIndex(index: number): void {\n if (this.images.length <= 1) return;\n const next = (index + 1) % this.images.length;\n const prev = (index - 1 + this.images.length) % this.images.length;\n for (const idx of [next, prev]) {\n const img = new Image();\n img.src = this.images[idx].url;\n }\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --image-viewer-slide-duration--: var(\n --image-viewer-slide-duration,\n 500ms\n );\n --image-viewer-glow-color--: var(\n --image-viewer-glow-color,\n rgba(255, 255, 255, 0.25)\n );\n /*\n * Size and placement are the host's business, set with ordinary CSS\n * on the element. These are only defaults for a host that sets\n * neither; a rule in the outer tree beats them.\n */\n display: block;\n height: 100%;\n margin: 0 auto;\n }\n\n .viewer {\n position: relative;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n }\n\n .image-area {\n position: relative;\n flex: 1;\n min-height: 0;\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n touch-action: pan-y pinch-zoom;\n }\n\n .wrap-glow {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 100px;\n pointer-events: none;\n z-index: 2;\n animation: glow-fade 700ms ease-out both;\n }\n\n .glow-start {\n left: 0;\n background: linear-gradient(\n to right,\n var(--image-viewer-glow-color--),\n transparent\n );\n }\n\n .glow-end {\n right: 0;\n background: linear-gradient(\n to left,\n var(--image-viewer-glow-color--),\n transparent\n );\n }\n\n @keyframes glow-fade {\n 0% {\n opacity: 0;\n }\n 20% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n\n .slide-track {\n display: flex;\n width: 100%;\n height: 100%;\n flex-shrink: 0;\n }\n\n @keyframes slide-next {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-100%);\n }\n }\n\n @keyframes slide-prev {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n }\n\n .slide-track.dragging {\n transform: translateX(-100%);\n }\n\n .slide-track.sliding-next {\n animation: slide-next var(--image-viewer-slide-duration--) ease-in-out\n both;\n }\n\n .slide-track.sliding-prev {\n animation: slide-prev var(--image-viewer-slide-duration--) ease-in-out\n both;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n overflow: hidden;\n white-space: nowrap;\n clip-path: inset(50%);\n }\n `,\n ];\n }\n}\n"]}
|
|
@@ -5,10 +5,17 @@ import { type CSSResultGroup, LitElement, type TemplateResult } from 'lit';
|
|
|
5
5
|
* Past the wide breakpoint the buttons position themselves over the image
|
|
6
6
|
* area, which lives in the viewer's shadow root. That works because an
|
|
7
7
|
* absolutely positioned element finds its containing block through the flat
|
|
8
|
-
* tree, so the viewer's frame is still the reference as long as this
|
|
9
|
-
*
|
|
10
|
-
* container
|
|
11
|
-
*
|
|
8
|
+
* tree, so the viewer's frame is still the reference as long as this host
|
|
9
|
+
* stays unpositioned. The breakpoint itself queries this host's own
|
|
10
|
+
* (unnamed) container from `.controls`, a genuine descendant inside this
|
|
11
|
+
* element's own shadow root, rather than a named container on the
|
|
12
|
+
* `ia-image-viewer` ancestor — Safari doesn't reliably resolve a named
|
|
13
|
+
* container query across a shadow-tree boundary, so querying across from
|
|
14
|
+
* here left the wide layout permanently off in Safari. `:host` stays full
|
|
15
|
+
* width the whole time; once the buttons come out of flow, `.controls` only
|
|
16
|
+
* has the counter left to lay out, so switching its `justify-content` to
|
|
17
|
+
* `center` puts the counter in the middle of the image without needing
|
|
18
|
+
* anything to shrink-wrap.
|
|
12
19
|
*/
|
|
13
20
|
export declare class IAImageViewerControls extends LitElement {
|
|
14
21
|
/** Zero-based index of the image being shown, for the counter. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-imgview-controls.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-imgview-controls.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAEnB,UAAU,EACV,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAOb
|
|
1
|
+
{"version":3,"file":"ia-imgview-controls.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-imgview-controls.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAEnB,UAAU,EACV,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAOb;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,qBAAsB,SAAQ,UAAU;IACnD,kEAAkE;IACtC,YAAY,SAAK;IAEjB,WAAW,SAAK;IAE5C,MAAM,IAAI,cAAc;IAwBxB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,MAAM;IAId,MAAM,KAAK,MAAM,IAAI,cAAc,CAyFlC;CACF"}
|
|
@@ -10,10 +10,17 @@ import themeStyles from '../../themes/theme-styles.js';
|
|
|
10
10
|
* Past the wide breakpoint the buttons position themselves over the image
|
|
11
11
|
* area, which lives in the viewer's shadow root. That works because an
|
|
12
12
|
* absolutely positioned element finds its containing block through the flat
|
|
13
|
-
* tree, so the viewer's frame is still the reference as long as this
|
|
14
|
-
*
|
|
15
|
-
* container
|
|
16
|
-
*
|
|
13
|
+
* tree, so the viewer's frame is still the reference as long as this host
|
|
14
|
+
* stays unpositioned. The breakpoint itself queries this host's own
|
|
15
|
+
* (unnamed) container from `.controls`, a genuine descendant inside this
|
|
16
|
+
* element's own shadow root, rather than a named container on the
|
|
17
|
+
* `ia-image-viewer` ancestor — Safari doesn't reliably resolve a named
|
|
18
|
+
* container query across a shadow-tree boundary, so querying across from
|
|
19
|
+
* here left the wide layout permanently off in Safari. `:host` stays full
|
|
20
|
+
* width the whole time; once the buttons come out of flow, `.controls` only
|
|
21
|
+
* has the counter left to lay out, so switching its `justify-content` to
|
|
22
|
+
* `center` puts the counter in the middle of the image without needing
|
|
23
|
+
* anything to shrink-wrap.
|
|
17
24
|
*/
|
|
18
25
|
let IAImageViewerControls = class IAImageViewerControls extends LitElement {
|
|
19
26
|
constructor() {
|
|
@@ -24,21 +31,25 @@ let IAImageViewerControls = class IAImageViewerControls extends LitElement {
|
|
|
24
31
|
}
|
|
25
32
|
render() {
|
|
26
33
|
return html `
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
<div class="controls">
|
|
35
|
+
<button
|
|
36
|
+
class="nav-btn prev"
|
|
37
|
+
aria-label=${msg('Previous image')}
|
|
38
|
+
@click=${this.onPrevious}
|
|
39
|
+
>
|
|
40
|
+
‹
|
|
41
|
+
</button>
|
|
42
|
+
<div class="counter">
|
|
43
|
+
${this.currentIndex + 1} / ${this.totalImages}
|
|
44
|
+
</div>
|
|
45
|
+
<button
|
|
46
|
+
class="nav-btn next"
|
|
47
|
+
aria-label=${msg('Next image')}
|
|
48
|
+
@click=${this.onNext}
|
|
49
|
+
>
|
|
50
|
+
›
|
|
51
|
+
</button>
|
|
52
|
+
</div>
|
|
42
53
|
`;
|
|
43
54
|
}
|
|
44
55
|
onPrevious() {
|
|
@@ -57,6 +68,12 @@ let IAImageViewerControls = class IAImageViewerControls extends LitElement {
|
|
|
57
68
|
var(--true-white)
|
|
58
69
|
);
|
|
59
70
|
|
|
71
|
+
display: block;
|
|
72
|
+
width: 100%;
|
|
73
|
+
container-type: inline-size;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.controls {
|
|
60
77
|
display: flex;
|
|
61
78
|
align-items: center;
|
|
62
79
|
justify-content: space-between;
|
|
@@ -101,10 +118,9 @@ let IAImageViewerControls = class IAImageViewerControls extends LitElement {
|
|
|
101
118
|
}
|
|
102
119
|
}
|
|
103
120
|
|
|
104
|
-
@container
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
width: auto;
|
|
121
|
+
@container (min-width: 890px) {
|
|
122
|
+
.controls {
|
|
123
|
+
justify-content: center;
|
|
108
124
|
margin-top: 0;
|
|
109
125
|
}
|
|
110
126
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-imgview-controls.js","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-imgview-controls.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EAEH,IAAI,EACJ,UAAU,GAEX,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,OAAO,WAAW,MAAM,0BAA0B,CAAC;AAEnD
|
|
1
|
+
{"version":3,"file":"ia-imgview-controls.js","sourceRoot":"","sources":["../../../../src/elements/ia-image-viewer/ia-imgview-controls.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EAEH,IAAI,EACJ,UAAU,GAEX,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,OAAO,WAAW,MAAM,0BAA0B,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,UAAU;IAA9C;;QACL,kEAAkE;QACtC,iBAAY,GAAG,CAAC,CAAC;QAEjB,gBAAW,GAAG,CAAC,CAAC;IA4H9C,CAAC;IA1HC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;uBAIQ,GAAG,CAAC,gBAAgB,CAAC;mBACzB,IAAI,CAAC,UAAU;;;;;YAKtB,IAAI,CAAC,YAAY,GAAG,CAAC,MAAM,IAAI,CAAC,WAAW;;;;uBAIhC,GAAG,CAAC,YAAY,CAAC;mBACrB,IAAI,CAAC,MAAM;;;;;KAKzB,CAAC;IACJ,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;IACtD,CAAC;IAEO,MAAM;QACZ,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO;YACL,WAAW;YACX,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoFF;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA9H6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2DAAkB;AAEjB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0DAAiB;AAJjC,qBAAqB;IADjC,aAAa,CAAC,qBAAqB,CAAC;GACxB,qBAAqB,CAgIjC","sourcesContent":["import {\n css,\n type CSSResultGroup,\n html,\n LitElement,\n type TemplateResult,\n} from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\n\nimport themeStyles from '@src/themes/theme-styles';\n\n/**\n * The image viewer's previous / next buttons and the \"n / total\" counter.\n *\n * Past the wide breakpoint the buttons position themselves over the image\n * area, which lives in the viewer's shadow root. That works because an\n * absolutely positioned element finds its containing block through the flat\n * tree, so the viewer's frame is still the reference as long as this host\n * stays unpositioned. The breakpoint itself queries this host's own\n * (unnamed) container from `.controls`, a genuine descendant inside this\n * element's own shadow root, rather than a named container on the\n * `ia-image-viewer` ancestor — Safari doesn't reliably resolve a named\n * container query across a shadow-tree boundary, so querying across from\n * here left the wide layout permanently off in Safari. `:host` stays full\n * width the whole time; once the buttons come out of flow, `.controls` only\n * has the counter left to lay out, so switching its `justify-content` to\n * `center` puts the counter in the middle of the image without needing\n * anything to shrink-wrap.\n */\n@customElement('ia-imgview-controls')\nexport class IAImageViewerControls extends LitElement {\n /** Zero-based index of the image being shown, for the counter. */\n @property({ type: Number }) currentIndex = 0;\n\n @property({ type: Number }) totalImages = 0;\n\n render(): TemplateResult {\n return html`\n <div class=\"controls\">\n <button\n class=\"nav-btn prev\"\n aria-label=${msg('Previous image')}\n @click=${this.onPrevious}\n >\n ‹\n </button>\n <div class=\"counter\">\n ${this.currentIndex + 1} / ${this.totalImages}\n </div>\n <button\n class=\"nav-btn next\"\n aria-label=${msg('Next image')}\n @click=${this.onNext}\n >\n ›\n </button>\n </div>\n `;\n }\n\n private onPrevious(): void {\n this.dispatchEvent(new CustomEvent('showPrevious'));\n }\n\n private onNext(): void {\n this.dispatchEvent(new CustomEvent('showNext'));\n }\n\n static get styles(): CSSResultGroup {\n return [\n themeStyles,\n css`\n :host {\n --imgview-controls-text-color--: var(\n --image-viewer-text-color,\n var(--true-white)\n );\n\n display: block;\n width: 100%;\n container-type: inline-size;\n }\n\n .controls {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n margin-top: 0.8rem;\n }\n\n .nav-btn {\n width: 40px;\n background: transparent;\n color: var(--imgview-controls-text-color--);\n border: none;\n cursor: pointer;\n font-size: 30px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.5;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n transition: opacity 0.15s;\n }\n\n .nav-btn:hover {\n opacity: 1;\n }\n\n .nav-btn:focus-visible {\n outline: 2px solid rgba(255, 255, 255, 0.8);\n outline-offset: -2px;\n }\n\n .counter {\n color: var(--imgview-controls-text-color--);\n font-size: 14px;\n font-weight: 200;\n letter-spacing: 0.05em;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .nav-btn {\n transition: none;\n }\n }\n\n @container (min-width: 890px) {\n .controls {\n justify-content: center;\n margin-top: 0;\n }\n\n .nav-btn {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 60px;\n font-size: 60px;\n z-index: 1;\n }\n\n .prev {\n left: 0;\n }\n\n .next {\n right: 0;\n }\n\n .counter {\n margin-top: 0.8rem;\n }\n }\n `,\n ];\n }\n}\n"]}
|
|
@@ -32,6 +32,8 @@ export declare class IARadioPlayer extends LitElement {
|
|
|
32
32
|
searchTerm: string;
|
|
33
33
|
/** Whether to skip past the music sections rather than play them */
|
|
34
34
|
skipMusicSections: boolean;
|
|
35
|
+
/** Whether to shade the music sections on the waveform */
|
|
36
|
+
showMusicZones: boolean;
|
|
35
37
|
private percentComplete;
|
|
36
38
|
private isPlaying;
|
|
37
39
|
private duration;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-radio-player.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAQb,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,yCAAyC,CAAC;AAKjD,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGtE,OAAO,iDAAiD,CAAC;AACzD,OAAO,iEAAiE,CAAC;AACzE,OAAO,yDAAyD,CAAC;AACjE,OAAO,+CAA+C,CAAC;AACvD,OAAO,uDAAuD,CAAC;AAC/D,OAAO,qDAAqD,CAAC;AAC7D,OAAO,yDAAyD,CAAC;AACjE,OAAO,8BAA8B,CAAC;AAqCtC;;;;;;GAMG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,sDAAsD;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAEvD,mEAAmE;IACvC,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAEnE,uDAAuD;IAC3B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEhE,0EAA0E;IAC9C,uBAAuB,CAAC,EAAE,gBAAgB,CAAC;IAEvE,oCAAoC;IACR,WAAW,SAAK;IAE5C,0CAA0C;IACd,UAAU,SAAM;IAE5C,oEAAoE;IACvC,iBAAiB,UAAS;
|
|
1
|
+
{"version":3,"file":"ia-radio-player.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.ts"],"names":[],"mappings":"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"}
|
|
@@ -59,6 +59,8 @@ let IARadioPlayer = class IARadioPlayer extends LitElement {
|
|
|
59
59
|
this.searchTerm = '';
|
|
60
60
|
/** Whether to skip past the music sections rather than play them */
|
|
61
61
|
this.skipMusicSections = false;
|
|
62
|
+
/** Whether to shade the music sections on the waveform */
|
|
63
|
+
this.showMusicZones = false;
|
|
62
64
|
this.percentComplete = 0;
|
|
63
65
|
this.isPlaying = false;
|
|
64
66
|
this.duration = 0;
|
|
@@ -154,7 +156,7 @@ let IARadioPlayer = class IARadioPlayer extends LitElement {
|
|
|
154
156
|
interactive
|
|
155
157
|
.waveformUrl=${waveformUrl}
|
|
156
158
|
.percentComplete=${this.percentComplete}
|
|
157
|
-
.zonesOfSilence=${this.zonesOfSilence}
|
|
159
|
+
.zonesOfSilence=${this.showMusicZones ? this.zonesOfSilence : []}
|
|
158
160
|
@valuechange=${this.handleScrub}
|
|
159
161
|
></ia-waveform-progress>
|
|
160
162
|
`;
|
|
@@ -715,6 +717,9 @@ __decorate([
|
|
|
715
717
|
__decorate([
|
|
716
718
|
property({ type: Boolean })
|
|
717
719
|
], IARadioPlayer.prototype, "skipMusicSections", void 0);
|
|
720
|
+
__decorate([
|
|
721
|
+
property({ type: Boolean })
|
|
722
|
+
], IARadioPlayer.prototype, "showMusicZones", void 0);
|
|
718
723
|
__decorate([
|
|
719
724
|
state()
|
|
720
725
|
], IARadioPlayer.prototype, "percentComplete", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-radio-player.js","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.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 { msg, str } from '@lit/localize';\n\nimport type { AudioSource } from '@src/elements/ia-audio-element/models';\nimport type { QuickSearchEntry } from '@src/elements/ia-expandable-search-bar/models';\nimport { PlaybackMode } from '@src/elements/ia-playback-controls/models';\nimport type {\n TranscriptConfig,\n TranscriptEntryConfig,\n} from '@src/elements/ia-transcript-view/models';\nimport type { IAAudioElement } from '@src/elements/ia-audio-element/ia-audio-element';\nimport type { IATranscriptView } from '@src/elements/ia-transcript-view/ia-transcript-view';\nimport type { ZoneOfSilence } from '@src/elements/ia-waveform-progress/models';\n\nimport type { MusicZone, RadioPlayerConfig } from './models';\nimport type { SearchHandlerInterface } from './search/search-handler';\nimport type { IASearchResultsSwitcher } from './ia-search-results-switcher';\n\nimport '@src/elements/ia-audio-element/ia-audio-element';\nimport '@src/elements/ia-expandable-search-bar/ia-expandable-search-bar';\nimport '@src/elements/ia-playback-controls/ia-playback-controls';\nimport '@src/elements/ia-scrubber-bar/ia-scrubber-bar';\nimport '@src/elements/ia-status-indicator/ia-status-indicator';\nimport '@src/elements/ia-transcript-view/ia-transcript-view';\nimport '@src/elements/ia-waveform-progress/ia-waveform-progress';\nimport './ia-search-results-switcher';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n CanPlay: 'canplay',\n CurrentTimeChanged: 'currentTimeChanged',\n HighlightedSearchResultChanged: 'highlightedSearchResultChanged',\n JumpBackButtonPressed: 'jumpBackButtonPressed',\n JumpForwardButtonPressed: 'jumpForwardButtonPressed',\n NextSectionButtonPressed: 'nextSectionButtonPressed',\n PlaybackPaused: 'playbackPaused',\n PlaybackRateChanged: 'playbackRateChanged',\n PlaybackStarted: 'playbackStarted',\n PlayPauseButtonPressed: 'playPauseButtonPressed',\n PrevSectionButtonPressed: 'prevSectionButtonPressed',\n SearchCleared: 'searchCleared',\n SearchExecuted: 'searchExecuted',\n SearchFailed: 'searchFailed',\n SearchTermChanged: 'searchTermChanged',\n TimeChangedFromScrub: 'timeChangedFromScrub',\n TranscriptEntrySelected: 'transcriptEntrySelected',\n};\n\n/** How far the skip buttons move, in seconds */\nconst SKIP_SECONDS = 10;\n\n/** Shortest term worth searching for */\nconst MIN_SEARCH_LENGTH = 2;\n\n/**\n * Nudge past a section boundary when jumping to it, so playback lands inside\n * the next section rather than exactly on its edge.\n */\nconst SECTION_SEEK_NUDGE = 0.1;\n\n/**\n * A player for transcribed radio broadcasts.\n *\n * It owns no playback or search logic of its own. It wires the audio element,\n * transport controls, waveform, scrubber, search bar and transcript together,\n * and hands searching off to whatever `searchHandler` it is given.\n */\n@customElement('ia-radio-player')\nexport class IARadioPlayer extends LitElement {\n /** What is being played, and what to show about it */\n @property({ type: Object }) config?: RadioPlayerConfig;\n\n /** Where searches go. Without one, the search bar does nothing. */\n @property({ type: Object }) searchHandler?: SearchHandlerInterface;\n\n /** The transcript to show when no search is running */\n @property({ type: Object }) transcriptConfig?: TranscriptConfig;\n\n /** The transcript marked up with search results, shown while searching */\n @property({ type: Object }) searchResultsTranscript?: TranscriptConfig;\n\n /** Playback position, in seconds */\n @property({ type: Number }) currentTime = 0;\n\n /** What is currently in the search bar */\n @property({ type: String }) searchTerm = '';\n\n /** Whether to skip past the music sections rather than play them */\n @property({ type: Boolean }) skipMusicSections = false;\n\n @state() private percentComplete = 0;\n\n @state() private isPlaying = false;\n\n @state() private duration = 0;\n\n @state() private playbackRate = 1;\n\n @state() private volume = 1;\n\n @state() private isSearching = false;\n\n /** Numbers each search so a stale one can be told from the current one. */\n private latestSearchId = 0;\n\n @query('ia-audio-element') private audioElement?: IAAudioElement | null;\n\n @query('ia-transcript-view') private transcriptView?: IATranscriptView | null;\n\n @query('ia-search-results-switcher')\n private searchResultsSwitcher?: IASearchResultsSwitcher | null;\n\n render(): TemplateResult {\n return html`\n ${this.audioElementTemplate}\n <section role=\"main\">\n ${this.titleDateTemplate} ${this.collectionLogoTemplate}\n ${this.playbackControlsTemplate}\n <div class=\"waveform-scrubber-container\">\n ${this.waveformProgressTemplate} ${this.scrubberBarTemplate}\n </div>\n ${this.searchSectionTemplate} ${this.transcriptViewTemplate}\n </section>\n `;\n }\n\n /** Starts playback */\n play(): void {\n this.audioElement?.play();\n }\n\n /** Pauses playback */\n pause(): void {\n this.audioElement?.pause();\n }\n\n /** Jumps to a position in the track, in seconds */\n seekTo(seconds: number): void {\n this.audioElement?.seekTo(seconds);\n }\n\n private get audioElementTemplate(): TemplateResult {\n return html`\n <ia-audio-element\n .sources=${this.audioSources}\n .playbackRate=${this.playbackRate}\n .volume=${this.volume}\n @timeupdate=${this.handleTimeChange}\n @durationchange=${this.handleDurationChange}\n @playbackStarted=${this.playbackStarted}\n @playbackPaused=${this.playbackPaused}\n @canplay=${this.canPlay}\n ></ia-audio-element>\n `;\n }\n\n private get titleDateTemplate(): TemplateResult {\n return html`\n <div class=\"title-date\">\n <div class=\"title\">${this.config?.title ?? ''}</div>\n <div class=\"date\">${this.config?.date ?? ''}</div>\n </div>\n `;\n }\n\n private get collectionLogoTemplate(): TemplateResult | typeof nothing {\n const logoUrl = this.config?.logoUrl;\n if (!logoUrl) return nothing;\n\n return html`\n <img\n class=\"collection-logo\"\n src=${logoUrl}\n alt=${msg('Collection logo')}\n />\n `;\n }\n\n private get playbackControlsTemplate(): TemplateResult {\n return html`\n <ia-playback-controls\n .playbackMode=${this.isPlaying\n ? PlaybackMode.playing\n : PlaybackMode.paused}\n .playbackRate=${this.playbackRate}\n .volume=${this.volume}\n @back-button-pressed=${this.handleBackButton}\n @play-pause-button-pressed=${this.handlePlayPauseButton}\n @forward-button-pressed=${this.handleForwardButton}\n @volumeChange=${this.handleVolumeChange}\n @playbackRateChange=${this.handlePlaybackRateChange}\n @next-section-button-pressed=${this.handleNextSectionButton}\n @prev-section-button-pressed=${this.handlePrevSectionButton}\n ></ia-playback-controls>\n `;\n }\n\n private get waveformProgressTemplate(): TemplateResult | typeof nothing {\n const waveformUrl = this.config?.waveformUrl;\n if (!waveformUrl) return nothing;\n\n return html`\n <ia-waveform-progress\n interactive\n .waveformUrl=${waveformUrl}\n .percentComplete=${this.percentComplete}\n .zonesOfSilence=${this.zonesOfSilence}\n @valuechange=${this.handleScrub}\n ></ia-waveform-progress>\n `;\n }\n\n private get scrubberBarTemplate(): TemplateResult {\n return html`\n <ia-scrubber-bar\n .sectionMarkerPercentages=${this.sectionMarkerPercentages}\n .value=${this.percentComplete}\n @valuechange=${this.handleScrub}\n ></ia-scrubber-bar>\n `;\n }\n\n private get transcriptViewTemplate(): TemplateResult {\n return html`\n <div class=\"transcript-container\">\n <ia-transcript-view\n .config=${this.currentTranscript}\n .currentTime=${this.currentTime}\n @transcriptEntrySelected=${this.handleTranscriptEntrySelected}\n ></ia-transcript-view>\n </div>\n `;\n }\n\n private get searchSectionTemplate(): TemplateResult {\n return html`\n <div class=\"search-section\">\n <ia-expandable-search-bar\n .searchTerm=${this.searchTerm}\n .quickSearches=${this.quickSearches}\n ?showsDisclosure=${this.quickSearches.length > 0}\n @inputchange=${this.handleSearchInput}\n @enterKeyPressed=${this.handleSearchSubmitted}\n @quickSearchSelected=${this.handleQuickSearchSelected}\n @searchCleared=${this.handleSearchCleared}\n ></ia-expandable-search-bar>\n\n <div class=\"search-results-info\">\n <!--\n Always rendered, so a screen reader is already watching it by the\n time the text changes. A live region added to the page with its\n text already in place is not announced.\n -->\n <div class=\"sr-only\" role=\"status\">${this.searchStatusMessage}</div>\n\n ${this.isSearching\n ? html`<ia-status-indicator\n mode=\"loading\"\n loadingTitle=${msg('Searching the transcript')}\n ></ia-status-indicator>`\n : this.searchOutcomeTemplate}\n </div>\n </div>\n `;\n }\n\n /** What to show once a search has come back: a counter, or nothing found. */\n private get searchOutcomeTemplate(): TemplateResult | typeof nothing {\n if (this.searchTerm.length === 0 || !this.searchResultsTranscript) {\n return nothing;\n }\n\n const resultCount = this.searchResults.length;\n if (resultCount === 0) {\n return html`\n <div class=\"no-search-results-message\" aria-hidden=\"true\">\n ${msg('No search results.')}\n </div>\n `;\n }\n\n return html`\n <ia-search-results-switcher\n .numberOfResults=${resultCount}\n @searchResultIndexChanged=${this.handleSearchResultIndexChanged}\n ></ia-search-results-switcher>\n `;\n }\n\n /** What the live region announces as a search runs and comes back. */\n private get searchStatusMessage(): string {\n if (this.isSearching) return msg('Searching the transcript');\n if (this.searchTerm.length === 0 || !this.searchResultsTranscript)\n return '';\n\n const count = this.searchResults.length;\n if (count === 0) return msg('No search results.');\n\n return msg(str`${count} search results`);\n }\n\n private get currentTranscript(): TranscriptConfig | undefined {\n return this.searchResultsTranscript ?? this.transcriptConfig;\n }\n\n private get transcriptEntries(): TranscriptEntryConfig[] {\n return this.currentTranscript?.entries ?? [];\n }\n\n private get searchResults(): TranscriptEntryConfig[] {\n return this.searchResultsTranscript?.searchResults ?? [];\n }\n\n private get audioSources(): AudioSource[] {\n return this.config?.audioSources ?? [];\n }\n\n private get quickSearches(): QuickSearchEntry[] {\n return (this.config?.quickSearches ?? []).map((displayText) => ({\n displayText,\n }));\n }\n\n private get musicEntries(): TranscriptEntryConfig[] {\n return this.transcriptEntries.filter((entry) => entry.isMusic);\n }\n\n /** The music stretches, as percentages, for marking on the waveform. */\n private get zonesOfSilence(): ZoneOfSilence[] {\n if (this.duration === 0) return [];\n\n return this.musicEntries.map((entry) => ({\n startPercent: (entry.start / this.duration) * 100,\n endPercent: (entry.end / this.duration) * 100,\n }));\n }\n\n /** The music stretches in seconds, for skipping past them. */\n private get musicZones(): MusicZone[] {\n return this.musicEntries.map((entry) => ({\n start: entry.start,\n end: entry.end,\n }));\n }\n\n /**\n * Every section boundary as a percentage, including the two ends.\n *\n * The section skip buttons step between these, and the scrubber draws a\n * marker at each.\n */\n private get sectionMarkerPercentages(): number[] {\n const percentages = [0];\n\n this.zonesOfSilence.forEach((zone) => {\n percentages.push(zone.startPercent, zone.endPercent);\n });\n percentages.push(100);\n\n return percentages;\n }\n\n updated(changedProperties: PropertyValues): void {\n if (changedProperties.has('searchResultsTranscript')) {\n this.resetSearchResultPosition();\n }\n\n if (changedProperties.has('searchHandler') && this.searchTerm) {\n this.executeSearch(this.searchTerm);\n }\n\n if (changedProperties.has('currentTime')) {\n this.dispatchEvent(\n new CustomEvent<{ currentTime: number }>(Events.CurrentTimeChanged, {\n detail: { currentTime: this.currentTime },\n }),\n );\n\n if (this.skipMusicSections) this.skipMusicZone();\n }\n }\n\n private handleTimeChange(e: CustomEvent<{ currentTime: number }>): void {\n const { currentTime } = e.detail;\n if (currentTime === undefined) return;\n\n this.currentTime = currentTime;\n // A duration of 0 means nothing has loaded yet, and dividing by it would\n // put NaN into the scrubber and the waveform.\n this.percentComplete =\n this.duration > 0 ? (currentTime / this.duration) * 100 : 0;\n }\n\n private handleDurationChange(e: CustomEvent<{ duration: number }>): void {\n const { duration } = e.detail;\n // A stream reports Infinity, and metadata that hasn't loaded reports NaN.\n if (!Number.isFinite(duration)) return;\n\n this.duration = duration;\n }\n\n private handlePlaybackRateChange(\n e: CustomEvent<{ playbackRate: number }>,\n ): void {\n const { playbackRate } = e.detail;\n if (playbackRate === undefined) return;\n\n this.playbackRate = playbackRate;\n this.dispatchEvent(\n new CustomEvent<{ playbackRate: number }>(Events.PlaybackRateChanged, {\n detail: { playbackRate },\n }),\n );\n }\n\n private handleVolumeChange(e: CustomEvent<{ volume: number }>): void {\n const { volume } = e.detail;\n if (volume === undefined) return;\n\n this.volume = volume;\n this.dispatchEvent(\n new CustomEvent<{ volume: number }>('volumeChanged', {\n detail: { volume },\n }),\n );\n }\n\n private handleBackButton(): void {\n this.audioElement?.seekBy(-SKIP_SECONDS);\n this.dispatchEvent(new Event(Events.JumpBackButtonPressed));\n }\n\n private handleForwardButton(): void {\n this.audioElement?.seekBy(SKIP_SECONDS);\n this.dispatchEvent(new Event(Events.JumpForwardButtonPressed));\n }\n\n private handlePlayPauseButton(): void {\n this.isPlaying = !this.isPlaying;\n\n if (this.isPlaying) this.audioElement?.play();\n else this.audioElement?.pause();\n\n this.dispatchEvent(\n new CustomEvent<{ isPlaying: boolean }>(Events.PlayPauseButtonPressed, {\n detail: { isPlaying: this.isPlaying },\n }),\n );\n }\n\n private handleNextSectionButton(): void {\n const ahead = this.sectionMarkerPercentages.filter(\n (percent) => percent > this.percentComplete + SECTION_SEEK_NUDGE,\n );\n this.seekToSectionBoundary(ahead, Math.min, SECTION_SEEK_NUDGE);\n\n this.dispatchEvent(new Event(Events.NextSectionButtonPressed));\n }\n\n private handlePrevSectionButton(): void {\n const behind = this.sectionMarkerPercentages.filter(\n (percent) => percent < this.percentComplete - SECTION_SEEK_NUDGE,\n );\n this.seekToSectionBoundary(behind, Math.max, -SECTION_SEEK_NUDGE);\n\n this.dispatchEvent(new Event(Events.PrevSectionButtonPressed));\n }\n\n /**\n * Seeks to the nearest of a set of boundaries.\n *\n * Does nothing when the set is empty, since `Math.min` of nothing is\n * `Infinity` and `Math.max` of nothing is `-Infinity`, either of which would\n * be handed straight to the audio element as a position.\n */\n private seekToSectionBoundary(\n percentages: number[],\n pick: (...values: number[]) => number,\n nudge: number,\n ): void {\n if (percentages.length === 0) return;\n\n const boundary = pick(...percentages);\n this.audioElement?.seekTo(this.duration * (boundary / 100) + nudge);\n }\n\n private handleScrub(e: CustomEvent<{ value: number }>): void {\n const percentage = e.detail.value;\n if (percentage === undefined) return;\n\n const newTime = this.duration * (percentage / 100);\n this.currentTime = newTime;\n this.percentComplete = percentage;\n this.audioElement?.seekTo(newTime);\n\n this.dispatchEvent(\n new CustomEvent<{ newTime: number }>(Events.TimeChangedFromScrub, {\n detail: { newTime },\n }),\n );\n }\n\n private handleTranscriptEntrySelected(\n e: CustomEvent<{ entry: TranscriptEntryConfig }>,\n ): void {\n const { entry } = e.detail;\n if (!entry) return;\n\n this.currentTime = entry.start;\n this.audioElement?.seekTo(entry.start);\n this.audioElement?.play();\n\n this.dispatchEvent(\n new CustomEvent<{ newTime: number }>(Events.TranscriptEntrySelected, {\n detail: { newTime: entry.start },\n }),\n );\n }\n\n private handleSearchInput(e: CustomEvent<{ value: string }>): void {\n const { value } = e.detail;\n if (value === undefined) return;\n\n this.searchTerm = value;\n\n // An empty box has nothing to show results for. The counter already hides\n // itself on an empty term, so without dropping the results too the\n // transcript keeps its outlines and offers no way to step between them.\n if (value.length === 0) {\n this.searchResultsTranscript = undefined;\n // Abandons whatever is in flight, so its results can't land afterwards.\n this.latestSearchId += 1;\n this.isSearching = false;\n this.resetSearchResultPosition();\n }\n\n this.emitSearchTermChanged(value);\n }\n\n private handleSearchSubmitted(e: CustomEvent<{ value: string }>): void {\n const { value } = e.detail;\n if (!value) return;\n\n this.executeSearch(value);\n }\n\n private handleQuickSearchSelected(\n e: CustomEvent<{ quickSearchEntry: QuickSearchEntry }>,\n ): void {\n const term = e.detail.quickSearchEntry?.displayText;\n if (!term) return;\n\n this.emitSearchTermChanged(term);\n this.executeSearch(term);\n }\n\n private handleSearchCleared(): void {\n this.searchTerm = '';\n this.searchResultsTranscript = undefined;\n // Abandons whatever is in flight, so its results can't arrive after this.\n this.latestSearchId += 1;\n this.isSearching = false;\n\n this.dispatchEvent(new Event(Events.SearchCleared));\n this.emitSearchTermChanged('');\n this.resetSearchResultPosition();\n }\n\n /**\n * Runs a search and shows its results.\n *\n * Each run is numbered, and only the newest one is allowed to report back.\n * Searches go over the network, so a slow one started earlier can land after\n * a fast one started later, and without this the older results would end up\n * on screen under the newer term.\n *\n * A failed search has to put the spinner away as surely as a successful one,\n * hence the `finally`. Leaving it up would hide the search UI for as long as\n * the page lives.\n */\n private async executeSearch(term: string): Promise<void> {\n if (!this.searchHandler || term.length < MIN_SEARCH_LENGTH) {\n this.searchResultsTranscript = undefined;\n return;\n }\n\n this.searchTerm = term;\n this.isSearching = true;\n this.dispatchEvent(new Event(Events.SearchExecuted));\n\n this.latestSearchId += 1;\n const searchId = this.latestSearchId;\n\n try {\n const results = await this.searchHandler.search(term);\n if (searchId !== this.latestSearchId) return;\n\n this.searchResultsTranscript = results;\n } catch {\n if (searchId !== this.latestSearchId) return;\n\n this.searchResultsTranscript = undefined;\n this.dispatchEvent(new Event(Events.SearchFailed));\n } finally {\n if (searchId === this.latestSearchId) this.isSearching = false;\n }\n }\n\n private handleSearchResultIndexChanged(\n e: CustomEvent<{ searchResultIndex: number }>,\n ): void {\n const { searchResultIndex } = e.detail;\n if (searchResultIndex === undefined || !this.transcriptView) return;\n\n this.transcriptView.selectedSearchResultIndex = searchResultIndex;\n this.transcriptView.scrollToSelectedSearchResult();\n\n this.dispatchEvent(\n new CustomEvent<{ searchResultIndex: number }>(\n Events.HighlightedSearchResultChanged,\n { detail: { searchResultIndex } },\n ),\n );\n }\n\n /** Puts both the transcript and the switcher back to the first result. */\n private resetSearchResultPosition(): void {\n if (this.transcriptView) this.transcriptView.selectedSearchResultIndex = 0;\n if (this.searchResultsSwitcher) {\n this.searchResultsSwitcher.currentResultIndex = 0;\n }\n }\n\n private emitSearchTermChanged(searchTerm: string): void {\n this.dispatchEvent(\n new CustomEvent<{ searchTerm: string }>(Events.SearchTermChanged, {\n detail: { searchTerm },\n }),\n );\n }\n\n private playbackPaused(): void {\n this.isPlaying = false;\n this.dispatchEvent(new Event(Events.PlaybackPaused));\n }\n\n private playbackStarted(): void {\n this.isPlaying = true;\n this.dispatchEvent(new Event(Events.PlaybackStarted));\n }\n\n private canPlay(): void {\n this.dispatchEvent(new Event(Events.CanPlay));\n }\n\n /** Jumps past a music stretch if playback has wandered into one. */\n private skipMusicZone(): void {\n const activeZone = this.musicZones.find(\n (zone) => this.currentTime > zone.start && this.currentTime < zone.end,\n );\n if (!activeZone) return;\n\n this.audioElement?.seekTo(activeZone.end + SECTION_SEEK_NUDGE);\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --radio-player-title-color--: var(\n --ia-theme-radio-player-title-color,\n #fff\n );\n --radio-player-title-font--: var(\n --ia-theme-radio-player-title-font,\n 1.5em sans-serif\n );\n --radio-player-date-color--: var(\n --ia-theme-radio-player-date-color,\n #fff\n );\n --radio-player-date-font--: var(\n --ia-theme-radio-player-date-font,\n 1em sans-serif\n );\n --radio-player-logo-max-height--: var(\n --ia-theme-radio-player-logo-max-height,\n 8rem\n );\n --radio-player-waveform-height--: var(\n --ia-theme-radio-player-waveform-height,\n 5rem\n );\n }\n\n section[role='main'] {\n display: grid;\n grid-gap: 0.5rem;\n }\n\n ia-status-indicator {\n --ia-theme-icon-width: 1.5em;\n --ia-theme-primary-text-color: #999;\n\n display: block;\n margin: auto;\n }\n\n /* mobile view */\n @media (max-width: 770px) {\n section[role='main'] {\n grid-template-columns: 25% 1fr;\n grid-template-areas:\n 'collection-logo title-date'\n 'waveform-scrubber waveform-scrubber'\n 'playback-controls playback-controls'\n 'search-section search-section'\n 'transcript-container transcript-container';\n }\n\n .date {\n text-align: left;\n }\n\n ia-transcript-view {\n --ia-theme-transcript-time-display: none;\n }\n\n ia-playback-controls {\n width: 75%;\n margin: auto;\n }\n\n .search-section {\n width: 75%;\n margin: auto;\n }\n }\n\n /* wide view */\n @media (min-width: 770px) {\n section[role='main'] {\n grid-template-columns: 192px 0 250px 1fr;\n grid-template-areas:\n 'title-date title-date title-date title-date'\n 'collection-logo . playback-controls waveform-scrubber'\n 'search-section transcript-container transcript-container transcript-container';\n }\n\n .title-date {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n }\n\n ia-transcript-view {\n --ia-theme-transcript-time-display: block;\n }\n }\n\n .title-date {\n grid-area: title-date;\n }\n\n .title {\n color: var(--radio-player-title-color--);\n font: var(--radio-player-title-font--);\n }\n\n .date {\n color: var(--radio-player-date-color--);\n font: var(--radio-player-date-font--);\n }\n\n ia-waveform-progress {\n width: 100%;\n height: var(--radio-player-waveform-height--);\n }\n\n ia-playback-controls {\n grid-area: playback-controls;\n }\n\n .transcript-container {\n grid-area: transcript-container;\n }\n\n ia-transcript-view {\n max-width: 600px;\n display: block;\n }\n\n .collection-logo {\n width: 100%;\n max-height: var(--radio-player-logo-max-height--);\n object-fit: contain;\n grid-area: collection-logo;\n align-self: center;\n }\n\n .waveform-scrubber-container {\n width: 100%;\n height: 100%;\n grid-area: waveform-scrubber;\n }\n\n .search-section {\n grid-area: search-section;\n }\n\n .search-results-info {\n margin-top: 0.5em;\n }\n\n ia-expandable-search-bar {\n display: block;\n margin: auto;\n }\n\n .no-search-results-message {\n text-align: center;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ia-radio-player.js","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.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 { msg, str } from '@lit/localize';\n\nimport type { AudioSource } from '@src/elements/ia-audio-element/models';\nimport type { QuickSearchEntry } from '@src/elements/ia-expandable-search-bar/models';\nimport { PlaybackMode } from '@src/elements/ia-playback-controls/models';\nimport type {\n TranscriptConfig,\n TranscriptEntryConfig,\n} from '@src/elements/ia-transcript-view/models';\nimport type { IAAudioElement } from '@src/elements/ia-audio-element/ia-audio-element';\nimport type { IATranscriptView } from '@src/elements/ia-transcript-view/ia-transcript-view';\nimport type { ZoneOfSilence } from '@src/elements/ia-waveform-progress/models';\n\nimport type { MusicZone, RadioPlayerConfig } from './models';\nimport type { SearchHandlerInterface } from './search/search-handler';\nimport type { IASearchResultsSwitcher } from './ia-search-results-switcher';\n\nimport '@src/elements/ia-audio-element/ia-audio-element';\nimport '@src/elements/ia-expandable-search-bar/ia-expandable-search-bar';\nimport '@src/elements/ia-playback-controls/ia-playback-controls';\nimport '@src/elements/ia-scrubber-bar/ia-scrubber-bar';\nimport '@src/elements/ia-status-indicator/ia-status-indicator';\nimport '@src/elements/ia-transcript-view/ia-transcript-view';\nimport '@src/elements/ia-waveform-progress/ia-waveform-progress';\nimport './ia-search-results-switcher';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n CanPlay: 'canplay',\n CurrentTimeChanged: 'currentTimeChanged',\n HighlightedSearchResultChanged: 'highlightedSearchResultChanged',\n JumpBackButtonPressed: 'jumpBackButtonPressed',\n JumpForwardButtonPressed: 'jumpForwardButtonPressed',\n NextSectionButtonPressed: 'nextSectionButtonPressed',\n PlaybackPaused: 'playbackPaused',\n PlaybackRateChanged: 'playbackRateChanged',\n PlaybackStarted: 'playbackStarted',\n PlayPauseButtonPressed: 'playPauseButtonPressed',\n PrevSectionButtonPressed: 'prevSectionButtonPressed',\n SearchCleared: 'searchCleared',\n SearchExecuted: 'searchExecuted',\n SearchFailed: 'searchFailed',\n SearchTermChanged: 'searchTermChanged',\n TimeChangedFromScrub: 'timeChangedFromScrub',\n TranscriptEntrySelected: 'transcriptEntrySelected',\n};\n\n/** How far the skip buttons move, in seconds */\nconst SKIP_SECONDS = 10;\n\n/** Shortest term worth searching for */\nconst MIN_SEARCH_LENGTH = 2;\n\n/**\n * Nudge past a section boundary when jumping to it, so playback lands inside\n * the next section rather than exactly on its edge.\n */\nconst SECTION_SEEK_NUDGE = 0.1;\n\n/**\n * A player for transcribed radio broadcasts.\n *\n * It owns no playback or search logic of its own. It wires the audio element,\n * transport controls, waveform, scrubber, search bar and transcript together,\n * and hands searching off to whatever `searchHandler` it is given.\n */\n@customElement('ia-radio-player')\nexport class IARadioPlayer extends LitElement {\n /** What is being played, and what to show about it */\n @property({ type: Object }) config?: RadioPlayerConfig;\n\n /** Where searches go. Without one, the search bar does nothing. */\n @property({ type: Object }) searchHandler?: SearchHandlerInterface;\n\n /** The transcript to show when no search is running */\n @property({ type: Object }) transcriptConfig?: TranscriptConfig;\n\n /** The transcript marked up with search results, shown while searching */\n @property({ type: Object }) searchResultsTranscript?: TranscriptConfig;\n\n /** Playback position, in seconds */\n @property({ type: Number }) currentTime = 0;\n\n /** What is currently in the search bar */\n @property({ type: String }) searchTerm = '';\n\n /** Whether to skip past the music sections rather than play them */\n @property({ type: Boolean }) skipMusicSections = false;\n\n /** Whether to shade the music sections on the waveform */\n @property({ type: Boolean }) showMusicZones = false;\n\n @state() private percentComplete = 0;\n\n @state() private isPlaying = false;\n\n @state() private duration = 0;\n\n @state() private playbackRate = 1;\n\n @state() private volume = 1;\n\n @state() private isSearching = false;\n\n /** Numbers each search so a stale one can be told from the current one. */\n private latestSearchId = 0;\n\n @query('ia-audio-element') private audioElement?: IAAudioElement | null;\n\n @query('ia-transcript-view') private transcriptView?: IATranscriptView | null;\n\n @query('ia-search-results-switcher')\n private searchResultsSwitcher?: IASearchResultsSwitcher | null;\n\n render(): TemplateResult {\n return html`\n ${this.audioElementTemplate}\n <section role=\"main\">\n ${this.titleDateTemplate} ${this.collectionLogoTemplate}\n ${this.playbackControlsTemplate}\n <div class=\"waveform-scrubber-container\">\n ${this.waveformProgressTemplate} ${this.scrubberBarTemplate}\n </div>\n ${this.searchSectionTemplate} ${this.transcriptViewTemplate}\n </section>\n `;\n }\n\n /** Starts playback */\n play(): void {\n this.audioElement?.play();\n }\n\n /** Pauses playback */\n pause(): void {\n this.audioElement?.pause();\n }\n\n /** Jumps to a position in the track, in seconds */\n seekTo(seconds: number): void {\n this.audioElement?.seekTo(seconds);\n }\n\n private get audioElementTemplate(): TemplateResult {\n return html`\n <ia-audio-element\n .sources=${this.audioSources}\n .playbackRate=${this.playbackRate}\n .volume=${this.volume}\n @timeupdate=${this.handleTimeChange}\n @durationchange=${this.handleDurationChange}\n @playbackStarted=${this.playbackStarted}\n @playbackPaused=${this.playbackPaused}\n @canplay=${this.canPlay}\n ></ia-audio-element>\n `;\n }\n\n private get titleDateTemplate(): TemplateResult {\n return html`\n <div class=\"title-date\">\n <div class=\"title\">${this.config?.title ?? ''}</div>\n <div class=\"date\">${this.config?.date ?? ''}</div>\n </div>\n `;\n }\n\n private get collectionLogoTemplate(): TemplateResult | typeof nothing {\n const logoUrl = this.config?.logoUrl;\n if (!logoUrl) return nothing;\n\n return html`\n <img\n class=\"collection-logo\"\n src=${logoUrl}\n alt=${msg('Collection logo')}\n />\n `;\n }\n\n private get playbackControlsTemplate(): TemplateResult {\n return html`\n <ia-playback-controls\n .playbackMode=${this.isPlaying\n ? PlaybackMode.playing\n : PlaybackMode.paused}\n .playbackRate=${this.playbackRate}\n .volume=${this.volume}\n @back-button-pressed=${this.handleBackButton}\n @play-pause-button-pressed=${this.handlePlayPauseButton}\n @forward-button-pressed=${this.handleForwardButton}\n @volumeChange=${this.handleVolumeChange}\n @playbackRateChange=${this.handlePlaybackRateChange}\n @next-section-button-pressed=${this.handleNextSectionButton}\n @prev-section-button-pressed=${this.handlePrevSectionButton}\n ></ia-playback-controls>\n `;\n }\n\n private get waveformProgressTemplate(): TemplateResult | typeof nothing {\n const waveformUrl = this.config?.waveformUrl;\n if (!waveformUrl) return nothing;\n\n return html`\n <ia-waveform-progress\n interactive\n .waveformUrl=${waveformUrl}\n .percentComplete=${this.percentComplete}\n .zonesOfSilence=${this.showMusicZones ? this.zonesOfSilence : []}\n @valuechange=${this.handleScrub}\n ></ia-waveform-progress>\n `;\n }\n\n private get scrubberBarTemplate(): TemplateResult {\n return html`\n <ia-scrubber-bar\n .sectionMarkerPercentages=${this.sectionMarkerPercentages}\n .value=${this.percentComplete}\n @valuechange=${this.handleScrub}\n ></ia-scrubber-bar>\n `;\n }\n\n private get transcriptViewTemplate(): TemplateResult {\n return html`\n <div class=\"transcript-container\">\n <ia-transcript-view\n .config=${this.currentTranscript}\n .currentTime=${this.currentTime}\n @transcriptEntrySelected=${this.handleTranscriptEntrySelected}\n ></ia-transcript-view>\n </div>\n `;\n }\n\n private get searchSectionTemplate(): TemplateResult {\n return html`\n <div class=\"search-section\">\n <ia-expandable-search-bar\n .searchTerm=${this.searchTerm}\n .quickSearches=${this.quickSearches}\n ?showsDisclosure=${this.quickSearches.length > 0}\n @inputchange=${this.handleSearchInput}\n @enterKeyPressed=${this.handleSearchSubmitted}\n @quickSearchSelected=${this.handleQuickSearchSelected}\n @searchCleared=${this.handleSearchCleared}\n ></ia-expandable-search-bar>\n\n <div class=\"search-results-info\">\n <!--\n Always rendered, so a screen reader is already watching it by the\n time the text changes. A live region added to the page with its\n text already in place is not announced.\n -->\n <div class=\"sr-only\" role=\"status\">${this.searchStatusMessage}</div>\n\n ${this.isSearching\n ? html`<ia-status-indicator\n mode=\"loading\"\n loadingTitle=${msg('Searching the transcript')}\n ></ia-status-indicator>`\n : this.searchOutcomeTemplate}\n </div>\n </div>\n `;\n }\n\n /** What to show once a search has come back: a counter, or nothing found. */\n private get searchOutcomeTemplate(): TemplateResult | typeof nothing {\n if (this.searchTerm.length === 0 || !this.searchResultsTranscript) {\n return nothing;\n }\n\n const resultCount = this.searchResults.length;\n if (resultCount === 0) {\n return html`\n <div class=\"no-search-results-message\" aria-hidden=\"true\">\n ${msg('No search results.')}\n </div>\n `;\n }\n\n return html`\n <ia-search-results-switcher\n .numberOfResults=${resultCount}\n @searchResultIndexChanged=${this.handleSearchResultIndexChanged}\n ></ia-search-results-switcher>\n `;\n }\n\n /** What the live region announces as a search runs and comes back. */\n private get searchStatusMessage(): string {\n if (this.isSearching) return msg('Searching the transcript');\n if (this.searchTerm.length === 0 || !this.searchResultsTranscript)\n return '';\n\n const count = this.searchResults.length;\n if (count === 0) return msg('No search results.');\n\n return msg(str`${count} search results`);\n }\n\n private get currentTranscript(): TranscriptConfig | undefined {\n return this.searchResultsTranscript ?? this.transcriptConfig;\n }\n\n private get transcriptEntries(): TranscriptEntryConfig[] {\n return this.currentTranscript?.entries ?? [];\n }\n\n private get searchResults(): TranscriptEntryConfig[] {\n return this.searchResultsTranscript?.searchResults ?? [];\n }\n\n private get audioSources(): AudioSource[] {\n return this.config?.audioSources ?? [];\n }\n\n private get quickSearches(): QuickSearchEntry[] {\n return (this.config?.quickSearches ?? []).map((displayText) => ({\n displayText,\n }));\n }\n\n private get musicEntries(): TranscriptEntryConfig[] {\n return this.transcriptEntries.filter((entry) => entry.isMusic);\n }\n\n /** The music stretches, as percentages, for marking on the waveform. */\n private get zonesOfSilence(): ZoneOfSilence[] {\n if (this.duration === 0) return [];\n\n return this.musicEntries.map((entry) => ({\n startPercent: (entry.start / this.duration) * 100,\n endPercent: (entry.end / this.duration) * 100,\n }));\n }\n\n /** The music stretches in seconds, for skipping past them. */\n private get musicZones(): MusicZone[] {\n return this.musicEntries.map((entry) => ({\n start: entry.start,\n end: entry.end,\n }));\n }\n\n /**\n * Every section boundary as a percentage, including the two ends.\n *\n * The section skip buttons step between these, and the scrubber draws a\n * marker at each.\n */\n private get sectionMarkerPercentages(): number[] {\n const percentages = [0];\n\n this.zonesOfSilence.forEach((zone) => {\n percentages.push(zone.startPercent, zone.endPercent);\n });\n percentages.push(100);\n\n return percentages;\n }\n\n updated(changedProperties: PropertyValues): void {\n if (changedProperties.has('searchResultsTranscript')) {\n this.resetSearchResultPosition();\n }\n\n if (changedProperties.has('searchHandler') && this.searchTerm) {\n this.executeSearch(this.searchTerm);\n }\n\n if (changedProperties.has('currentTime')) {\n this.dispatchEvent(\n new CustomEvent<{ currentTime: number }>(Events.CurrentTimeChanged, {\n detail: { currentTime: this.currentTime },\n }),\n );\n\n if (this.skipMusicSections) this.skipMusicZone();\n }\n }\n\n private handleTimeChange(e: CustomEvent<{ currentTime: number }>): void {\n const { currentTime } = e.detail;\n if (currentTime === undefined) return;\n\n this.currentTime = currentTime;\n // A duration of 0 means nothing has loaded yet, and dividing by it would\n // put NaN into the scrubber and the waveform.\n this.percentComplete =\n this.duration > 0 ? (currentTime / this.duration) * 100 : 0;\n }\n\n private handleDurationChange(e: CustomEvent<{ duration: number }>): void {\n const { duration } = e.detail;\n // A stream reports Infinity, and metadata that hasn't loaded reports NaN.\n if (!Number.isFinite(duration)) return;\n\n this.duration = duration;\n }\n\n private handlePlaybackRateChange(\n e: CustomEvent<{ playbackRate: number }>,\n ): void {\n const { playbackRate } = e.detail;\n if (playbackRate === undefined) return;\n\n this.playbackRate = playbackRate;\n this.dispatchEvent(\n new CustomEvent<{ playbackRate: number }>(Events.PlaybackRateChanged, {\n detail: { playbackRate },\n }),\n );\n }\n\n private handleVolumeChange(e: CustomEvent<{ volume: number }>): void {\n const { volume } = e.detail;\n if (volume === undefined) return;\n\n this.volume = volume;\n this.dispatchEvent(\n new CustomEvent<{ volume: number }>('volumeChanged', {\n detail: { volume },\n }),\n );\n }\n\n private handleBackButton(): void {\n this.audioElement?.seekBy(-SKIP_SECONDS);\n this.dispatchEvent(new Event(Events.JumpBackButtonPressed));\n }\n\n private handleForwardButton(): void {\n this.audioElement?.seekBy(SKIP_SECONDS);\n this.dispatchEvent(new Event(Events.JumpForwardButtonPressed));\n }\n\n private handlePlayPauseButton(): void {\n this.isPlaying = !this.isPlaying;\n\n if (this.isPlaying) this.audioElement?.play();\n else this.audioElement?.pause();\n\n this.dispatchEvent(\n new CustomEvent<{ isPlaying: boolean }>(Events.PlayPauseButtonPressed, {\n detail: { isPlaying: this.isPlaying },\n }),\n );\n }\n\n private handleNextSectionButton(): void {\n const ahead = this.sectionMarkerPercentages.filter(\n (percent) => percent > this.percentComplete + SECTION_SEEK_NUDGE,\n );\n this.seekToSectionBoundary(ahead, Math.min, SECTION_SEEK_NUDGE);\n\n this.dispatchEvent(new Event(Events.NextSectionButtonPressed));\n }\n\n private handlePrevSectionButton(): void {\n const behind = this.sectionMarkerPercentages.filter(\n (percent) => percent < this.percentComplete - SECTION_SEEK_NUDGE,\n );\n this.seekToSectionBoundary(behind, Math.max, -SECTION_SEEK_NUDGE);\n\n this.dispatchEvent(new Event(Events.PrevSectionButtonPressed));\n }\n\n /**\n * Seeks to the nearest of a set of boundaries.\n *\n * Does nothing when the set is empty, since `Math.min` of nothing is\n * `Infinity` and `Math.max` of nothing is `-Infinity`, either of which would\n * be handed straight to the audio element as a position.\n */\n private seekToSectionBoundary(\n percentages: number[],\n pick: (...values: number[]) => number,\n nudge: number,\n ): void {\n if (percentages.length === 0) return;\n\n const boundary = pick(...percentages);\n this.audioElement?.seekTo(this.duration * (boundary / 100) + nudge);\n }\n\n private handleScrub(e: CustomEvent<{ value: number }>): void {\n const percentage = e.detail.value;\n if (percentage === undefined) return;\n\n const newTime = this.duration * (percentage / 100);\n this.currentTime = newTime;\n this.percentComplete = percentage;\n this.audioElement?.seekTo(newTime);\n\n this.dispatchEvent(\n new CustomEvent<{ newTime: number }>(Events.TimeChangedFromScrub, {\n detail: { newTime },\n }),\n );\n }\n\n private handleTranscriptEntrySelected(\n e: CustomEvent<{ entry: TranscriptEntryConfig }>,\n ): void {\n const { entry } = e.detail;\n if (!entry) return;\n\n this.currentTime = entry.start;\n this.audioElement?.seekTo(entry.start);\n this.audioElement?.play();\n\n this.dispatchEvent(\n new CustomEvent<{ newTime: number }>(Events.TranscriptEntrySelected, {\n detail: { newTime: entry.start },\n }),\n );\n }\n\n private handleSearchInput(e: CustomEvent<{ value: string }>): void {\n const { value } = e.detail;\n if (value === undefined) return;\n\n this.searchTerm = value;\n\n // An empty box has nothing to show results for. The counter already hides\n // itself on an empty term, so without dropping the results too the\n // transcript keeps its outlines and offers no way to step between them.\n if (value.length === 0) {\n this.searchResultsTranscript = undefined;\n // Abandons whatever is in flight, so its results can't land afterwards.\n this.latestSearchId += 1;\n this.isSearching = false;\n this.resetSearchResultPosition();\n }\n\n this.emitSearchTermChanged(value);\n }\n\n private handleSearchSubmitted(e: CustomEvent<{ value: string }>): void {\n const { value } = e.detail;\n if (!value) return;\n\n this.executeSearch(value);\n }\n\n private handleQuickSearchSelected(\n e: CustomEvent<{ quickSearchEntry: QuickSearchEntry }>,\n ): void {\n const term = e.detail.quickSearchEntry?.displayText;\n if (!term) return;\n\n this.emitSearchTermChanged(term);\n this.executeSearch(term);\n }\n\n private handleSearchCleared(): void {\n this.searchTerm = '';\n this.searchResultsTranscript = undefined;\n // Abandons whatever is in flight, so its results can't arrive after this.\n this.latestSearchId += 1;\n this.isSearching = false;\n\n this.dispatchEvent(new Event(Events.SearchCleared));\n this.emitSearchTermChanged('');\n this.resetSearchResultPosition();\n }\n\n /**\n * Runs a search and shows its results.\n *\n * Each run is numbered, and only the newest one is allowed to report back.\n * Searches go over the network, so a slow one started earlier can land after\n * a fast one started later, and without this the older results would end up\n * on screen under the newer term.\n *\n * A failed search has to put the spinner away as surely as a successful one,\n * hence the `finally`. Leaving it up would hide the search UI for as long as\n * the page lives.\n */\n private async executeSearch(term: string): Promise<void> {\n if (!this.searchHandler || term.length < MIN_SEARCH_LENGTH) {\n this.searchResultsTranscript = undefined;\n return;\n }\n\n this.searchTerm = term;\n this.isSearching = true;\n this.dispatchEvent(new Event(Events.SearchExecuted));\n\n this.latestSearchId += 1;\n const searchId = this.latestSearchId;\n\n try {\n const results = await this.searchHandler.search(term);\n if (searchId !== this.latestSearchId) return;\n\n this.searchResultsTranscript = results;\n } catch {\n if (searchId !== this.latestSearchId) return;\n\n this.searchResultsTranscript = undefined;\n this.dispatchEvent(new Event(Events.SearchFailed));\n } finally {\n if (searchId === this.latestSearchId) this.isSearching = false;\n }\n }\n\n private handleSearchResultIndexChanged(\n e: CustomEvent<{ searchResultIndex: number }>,\n ): void {\n const { searchResultIndex } = e.detail;\n if (searchResultIndex === undefined || !this.transcriptView) return;\n\n this.transcriptView.selectedSearchResultIndex = searchResultIndex;\n this.transcriptView.scrollToSelectedSearchResult();\n\n this.dispatchEvent(\n new CustomEvent<{ searchResultIndex: number }>(\n Events.HighlightedSearchResultChanged,\n { detail: { searchResultIndex } },\n ),\n );\n }\n\n /** Puts both the transcript and the switcher back to the first result. */\n private resetSearchResultPosition(): void {\n if (this.transcriptView) this.transcriptView.selectedSearchResultIndex = 0;\n if (this.searchResultsSwitcher) {\n this.searchResultsSwitcher.currentResultIndex = 0;\n }\n }\n\n private emitSearchTermChanged(searchTerm: string): void {\n this.dispatchEvent(\n new CustomEvent<{ searchTerm: string }>(Events.SearchTermChanged, {\n detail: { searchTerm },\n }),\n );\n }\n\n private playbackPaused(): void {\n this.isPlaying = false;\n this.dispatchEvent(new Event(Events.PlaybackPaused));\n }\n\n private playbackStarted(): void {\n this.isPlaying = true;\n this.dispatchEvent(new Event(Events.PlaybackStarted));\n }\n\n private canPlay(): void {\n this.dispatchEvent(new Event(Events.CanPlay));\n }\n\n /** Jumps past a music stretch if playback has wandered into one. */\n private skipMusicZone(): void {\n const activeZone = this.musicZones.find(\n (zone) => this.currentTime > zone.start && this.currentTime < zone.end,\n );\n if (!activeZone) return;\n\n this.audioElement?.seekTo(activeZone.end + SECTION_SEEK_NUDGE);\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --radio-player-title-color--: var(\n --ia-theme-radio-player-title-color,\n #fff\n );\n --radio-player-title-font--: var(\n --ia-theme-radio-player-title-font,\n 1.5em sans-serif\n );\n --radio-player-date-color--: var(\n --ia-theme-radio-player-date-color,\n #fff\n );\n --radio-player-date-font--: var(\n --ia-theme-radio-player-date-font,\n 1em sans-serif\n );\n --radio-player-logo-max-height--: var(\n --ia-theme-radio-player-logo-max-height,\n 8rem\n );\n --radio-player-waveform-height--: var(\n --ia-theme-radio-player-waveform-height,\n 5rem\n );\n }\n\n section[role='main'] {\n display: grid;\n grid-gap: 0.5rem;\n }\n\n ia-status-indicator {\n --ia-theme-icon-width: 1.5em;\n --ia-theme-primary-text-color: #999;\n\n display: block;\n margin: auto;\n }\n\n /* mobile view */\n @media (max-width: 770px) {\n section[role='main'] {\n grid-template-columns: 25% 1fr;\n grid-template-areas:\n 'collection-logo title-date'\n 'waveform-scrubber waveform-scrubber'\n 'playback-controls playback-controls'\n 'search-section search-section'\n 'transcript-container transcript-container';\n }\n\n .date {\n text-align: left;\n }\n\n ia-transcript-view {\n --ia-theme-transcript-time-display: none;\n }\n\n ia-playback-controls {\n width: 75%;\n margin: auto;\n }\n\n .search-section {\n width: 75%;\n margin: auto;\n }\n }\n\n /* wide view */\n @media (min-width: 770px) {\n section[role='main'] {\n grid-template-columns: 192px 0 250px 1fr;\n grid-template-areas:\n 'title-date title-date title-date title-date'\n 'collection-logo . playback-controls waveform-scrubber'\n 'search-section transcript-container transcript-container transcript-container';\n }\n\n .title-date {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n }\n\n ia-transcript-view {\n --ia-theme-transcript-time-display: block;\n }\n }\n\n .title-date {\n grid-area: title-date;\n }\n\n .title {\n color: var(--radio-player-title-color--);\n font: var(--radio-player-title-font--);\n }\n\n .date {\n color: var(--radio-player-date-color--);\n font: var(--radio-player-date-font--);\n }\n\n ia-waveform-progress {\n width: 100%;\n height: var(--radio-player-waveform-height--);\n }\n\n ia-playback-controls {\n grid-area: playback-controls;\n }\n\n .transcript-container {\n grid-area: transcript-container;\n }\n\n ia-transcript-view {\n max-width: 600px;\n display: block;\n }\n\n .collection-logo {\n width: 100%;\n max-height: var(--radio-player-logo-max-height--);\n object-fit: contain;\n grid-area: collection-logo;\n align-self: center;\n }\n\n .waveform-scrubber-container {\n width: 100%;\n height: 100%;\n grid-area: waveform-scrubber;\n }\n\n .search-section {\n grid-area: search-section;\n }\n\n .search-results-info {\n margin-top: 0.5em;\n }\n\n ia-expandable-search-bar {\n display: block;\n margin: auto;\n }\n\n .no-search-results-message {\n text-align: center;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `;\n }\n}\n"]}
|
package/package.json
CHANGED