Last active
April 21, 2024 12:14
-
-
Save fsubal/9188e111d0a557c8230f2401223677eb to your computer and use it in GitHub Desktop.
<tora-viewer> Web Components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import toraViewer, { type Viewer } from '@toralab/tora-viewer'; | |
function finiteInteger<R extends number | null | undefined>(value: string | null, defaultValue: R = 0): R { | |
if (!value) { | |
return defaultValue | |
} | |
const parsed = parseInt(value) | |
if (!Number.isFinite(parsed)) { | |
throw new RangeError(`${value} cannot be parsed to finite number`) | |
} | |
return parsed | |
} | |
/** | |
* @example | |
* ```html | |
* <tora-viewer title="漫画のタイトル" page-style="auto"> | |
* <tora-viewer-page url="..." /> | |
* <tora-viewer-page url="..." /> | |
* <tora-viewer-page url="..." /> | |
* <tora-viewer-page url="..." /> | |
* <tora-viewer-lastpage> | |
* <button>高評価 +1</button> | |
* </tora-viewer-lastpage> | |
* </tora-viewer> | |
* ``` | |
*/ | |
export class ToraViewer extends HTMLElement { | |
static { customElements.define('tora-viewer', this) } | |
readonly pages = this.querySelectorAll<ToraViewerPage>('tora-viewer-page') | |
#viewer?: Viewer | |
#lastPageElement = this.querySelector('tora-viewer-lastpage') | |
get currentIndex() { | |
return this.#viewer?.currentIndex | |
} | |
get isLastPage() { | |
return this.#viewer?.isLastPage | |
} | |
get workTitle() { | |
return this.getAttribute('title') ?? undefined | |
} | |
get direction() { | |
return this.getAttribute('direction') ?? 'horizontal-rtl' | |
} | |
get pageStyle() { | |
return this.getAttribute('page-style') | |
} | |
get controlShowTime() { | |
return finiteInteger(this.getAttribute('control-show-time')) | |
} | |
get width() { | |
return finiteInteger(this.getAttribute('width'), undefined) | |
} | |
get height() { | |
return finiteInteger(this.getAttribute('height'), undefined) | |
} | |
get images() { | |
return Array.from(this.pages).map(page => page.toImage()) | |
} | |
get embed() { | |
return this.hasAttribute('embed') | |
} | |
constructor() { | |
super() | |
this.attachShadow({ mode: 'open' }) | |
} | |
connectedCallback() { | |
this.#viewer = toraViewer(this.images, { | |
title: this.title, | |
pageSize: { | |
width: this.width, | |
height: this.height, | |
}, | |
pageStyle: this.pageStyle, | |
direction: this.direction, | |
controlShowTime: this.controlShowTime, | |
lastPageElement: this.#lastPageElement, | |
insertTarget: this.embed ? this.shadowRoot! : undefined | |
}) | |
} | |
disconnectedCallback() { | |
this.#viewer?.dispose() | |
} | |
goNext() { | |
this.#viewer?.goNext() | |
} | |
goPrev() { | |
this.#viewer?.goPrev() | |
} | |
goLeft() { | |
this.#viewer?.goLeft() | |
} | |
goRight() { | |
this.#viewer?.goRight() | |
} | |
goTo(next: number) { | |
this.#viewer?.goTo(next) | |
} | |
openSettings() { | |
this.#viewer?.openSettings() | |
} | |
closeSettings() { | |
this.#viewer?.closeSettings() | |
} | |
onCurrentIndexChanged(callback: (index: number) => void) { | |
this.#viewer?.onCurrentIndexChanged(callback) | |
} | |
} | |
export class ToraViewerPage extends HTMLElement { | |
static { customElements.define('tora-viewer-page', this) } | |
get url() { | |
const url = this.getAttribute('url') | |
if (!url) { | |
throw new Error('<tora-viewer-page url="..."> is required') | |
} | |
return url | |
} | |
get thumbnailUrl() { | |
return this.getAttribute('thumbnail-url') | |
} | |
toImage() { | |
const { url, thumbnailUrl } = this | |
if (thumbnailUrl) { | |
return { url, thumbnailUrl } | |
} else { | |
return url | |
} | |
} | |
} | |
export class ToraViewerLastPage extends HTMLElement { | |
static { customElements.define('tora-viewer-lastpage', this) } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment