diff --git a/src/elements/drag-area.ts b/src/elements/drag-area.ts index 0316cd8..7743cc9 100644 --- a/src/elements/drag-area.ts +++ b/src/elements/drag-area.ts @@ -1,7 +1,7 @@ -import { css, CSSResult, html, LitElement, type TemplateResult } from 'lit' -import { customElement } from 'lit/decorators.js' -import { cssReset } from '../utils/css-reset.js' -import { DragLine } from './drag-line.js' +import {css, CSSResult, html, LitElement, type TemplateResult} from 'lit' +import {customElement} from 'lit/decorators.js' +import {cssReset} from '../utils/css-reset.js' +import {DragLine} from './drag-line.js' declare global { interface HTMLElementEventMap { @@ -39,17 +39,17 @@ export class DragArea extends LitElement { #gesture: | { - /** Set on significant duration or movement. */ - drag?: true - /** Most recent event intercepted. */ - ev: PointerEvent - /** Origin of the opening pointer down event. */ - readonly start: Readonly<{ x: number; y: number }> - /** Re-target all drag events in the gesture. */ - readonly target: HTMLElement - /** Synthetic drag event interval timer. */ - readonly timer: ReturnType - } + /** Set on significant duration or movement. */ + drag?: true + /** Most recent event intercepted. */ + ev: PointerEvent + /** Origin of the opening pointer down event. */ + readonly start: Readonly<{x: number; y: number}> + /** Re-target all drag events in the gesture. */ + readonly target: HTMLElement + /** Synthetic drag event interval timer. */ + readonly timer: ReturnType + } | undefined // to-do: Disable mobile long press? @@ -74,7 +74,7 @@ export class DragArea extends LitElement { #onPointerDown = (ev: PointerEvent): void => { if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey) return if (!ev.isPrimary || ev.buttons !== 1) return - if (!ev.composedPath().some((target) => target instanceof DragLine)) return + if (!ev.composedPath().some(target => target instanceof DragLine)) return const target = ev.composedPath()[0] if (!(target instanceof HTMLElement)) return if (target.isContentEditable && target.matches(':focus')) return // Editing text. @@ -82,9 +82,9 @@ export class DragArea extends LitElement { ev.preventDefault() this.#gesture = { ev, - start: { x: ev.clientX, y: ev.clientY }, + start: {x: ev.clientX, y: ev.clientY}, target, - timer: setInterval(() => this.#onPointerMove(this.#gesture!.ev), 10), + timer: setInterval(() => this.#onPointerMove(this.#gesture!.ev), 10) } } diff --git a/src/elements/drag-line.ts b/src/elements/drag-line.ts index 88f7bba..66676c4 100644 --- a/src/elements/drag-line.ts +++ b/src/elements/drag-line.ts @@ -1,18 +1,18 @@ -import { css, CSSResult, html, LitElement, type TemplateResult } from 'lit' -import { customElement } from 'lit/decorators.js' -import type { Group, Line, PositionLine } from '../tree/text-tree.js' -import { Bubble } from '../utils/bubble.js' -import { cssReset } from '../utils/css-reset.js' +import {css, CSSResult, html, LitElement, type TemplateResult} from 'lit' +import {customElement} from 'lit/decorators.js' +import type {Group, Line, PositionLine} from '../tree/text-tree.js' +import {Bubble} from '../utils/bubble.js' +import {cssReset} from '../utils/css-reset.js' import { blurActiveElement, composedAncestorElement, composedClosest, composedClosestScrollable, composedElementFromPoint, - scrollTowardsEdge, + scrollTowardsEdge } from '../utils/element-util.js' -import type { LineElement } from './line-element.js' -import { LineList } from './line-list.js' +import type {LineElement} from './line-element.js' +import {LineList} from './line-list.js' export type DragEnd = { readonly from: Readonly @@ -53,14 +53,14 @@ export class DragLine extends LitElement { #drag: | { - /** Cursor position relative this. */ - readonly cursor: Readonly<{ x: number; y: number }> - /** A clone of this modified to follow the cursor. */ - readonly ghost: DragLine - readonly line: Readonly - over?: { at: PositionLine; line: Readonly } - parent: Element - } + /** Cursor position relative this. */ + readonly cursor: Readonly<{x: number; y: number}> + /** A clone of this modified to follow the cursor. */ + readonly ghost: DragLine + readonly line: Readonly + over?: {at: PositionLine; line: Readonly} + parent: Element + } | undefined constructor() { @@ -87,8 +87,8 @@ export class DragLine extends LitElement { Bubble('drag-line-end', { from: this.#drag.line, to: this.#drag.over.line, - at: this.#drag.over.at, - }), + at: this.#drag.over.at + }) ) // Lit components track children rendered from the model. Manually adding // or removing a child may cause a duplicate or missing child on model @@ -96,11 +96,9 @@ export class DragLine extends LitElement { // parent lists it was associated with. this.#drag.parent.dispatchEvent( - Bubble('drag-line-invalidate', undefined), - ) - this.dispatchEvent( - Bubble('drag-line-invalidate', undefined), + Bubble('drag-line-invalidate', undefined) ) + this.dispatchEvent(Bubble('drag-line-invalidate', undefined)) this.remove() this.#drag = undefined } @@ -116,19 +114,18 @@ export class DragLine extends LitElement { this.#moveGhostToCursor(scrollable, ev) if (scrollable) { - scrollTowardsEdge(scrollable, { x: ev.clientX, y: ev.clientY }, 32, 4) + scrollTowardsEdge(scrollable, {x: ev.clientX, y: ev.clientY}, 32, 4) } const el = composedElementFromPoint(ev.pageX, ev.pageY) if (!el) return - const over = ( + const over = ( composedClosest('drag-line, line-list', el) ) if (!over) return - const overLine = over instanceof DragLine - ? queryLineElement(over)?.line - : undefined // to-do: fix for list + const overLine = + over instanceof DragLine ? queryLineElement(over)?.line : undefined // to-do: fix for list if (!overLine) return let op = computeDragOp(ev, this, over) @@ -157,7 +154,7 @@ export class DragLine extends LitElement { op satisfies 'none' return } - this.#drag.over = { at, line: overLine } + this.#drag.over = {at, line: overLine} } #onDragStart = (ev: DragEvent): void => { @@ -172,18 +169,17 @@ export class DragLine extends LitElement { if (!parent) throw Error('missing parent') this.#drag = { - cursor: { x: ev.offsetX, y: ev.offsetY }, - ghost: this.cloneNode(true), // Before add('picked') and follow. + cursor: {x: ev.offsetX, y: ev.offsetY}, + ghost: this.cloneNode(true), // Before add('picked') and follow. line: lineEl.line, - parent: parent, + parent: parent } this.classList.add('picked') lineEl.classList.add('picked') if (this.#drag.ghost.children[0]) { - ;( this.#drag.ghost.children[0]).line = - lineEl.line + ;(this.#drag.ghost.children[0]).line = lineEl.line this.#drag.ghost.children[0].classList.add('ghost') // setTimeout(() => this.#drag.ghost.children[0].classList.add('ghost'), 10) } @@ -202,15 +198,15 @@ export class DragLine extends LitElement { 0, Math.min( scrollable.scrollLeft + ev.pageX - this.#drag.cursor.x, - scrollable.scrollWidth - rect.width - 1, - ), + scrollable.scrollWidth - rect.width - 1 + ) ) const y = Math.max( 0, Math.min( scrollable.scrollTop + ev.pageY - this.#drag.cursor.y, - scrollable.scrollHeight - rect.height - 1, - ), + scrollable.scrollHeight - rect.height - 1 + ) ) this.#drag.ghost.style.translate = `${x}px ${y}px` } @@ -223,7 +219,7 @@ export class DragLine extends LitElement { function computeDragOp( ev: DragEvent, picked: DragLine, - over: DragLine | LineList, + over: DragLine | LineList ): 'none' | 'after' | 'append' | 'before' | 'prepend' { if (over.contains(picked)) return 'none' // Pivoting over picked may oscillate. if (over instanceof LineList) return 'append' @@ -232,7 +228,7 @@ function computeDragOp( if (!lineEl) return 'none' const rect = lineEl.rect - const offset = { x: ev.pageX - rect.x, y: ev.pageY - rect.y } + const offset = {x: ev.pageX - rect.x, y: ev.pageY - rect.y} const above = offset.y / rect.height < 0.5 const inside = offset.x / rect.width >= 0.5 @@ -246,6 +242,5 @@ function computeDragOp( } function queryLineElement(el: LitElement): LineElement | undefined { - return el.renderRoot.querySelector('slot')! - .assignedElements()[0] + return el.renderRoot.querySelector('slot')!.assignedElements()[0] } diff --git a/src/elements/line-element.ts b/src/elements/line-element.ts index 0793cba..9a91089 100644 --- a/src/elements/line-element.ts +++ b/src/elements/line-element.ts @@ -1,5 +1,5 @@ -import type { LitElement } from 'lit' -import type { Line } from '../tree/text-tree.js' +import type {LitElement} from 'lit' +import type {Line} from '../tree/text-tree.js' export type LineElement = LitElement & { line?: Readonly | undefined diff --git a/src/elements/linear-text/linear-text-vars.ts b/src/elements/linear-text/linear-text-vars.ts index 6489c3a..74ded64 100644 --- a/src/elements/linear-text/linear-text-vars.ts +++ b/src/elements/linear-text/linear-text-vars.ts @@ -1,4 +1,4 @@ -import { css, type CSSResult } from 'lit' +import {css, type CSSResult} from 'lit' export const linearTextVars: CSSResult = css` :host { diff --git a/src/io/file.ts b/src/io/file.ts index 685b751..d57d7e4 100644 --- a/src/io/file.ts +++ b/src/io/file.ts @@ -1,4 +1,4 @@ -import { fileOpen, fileSave } from 'browser-fs-access' +import {fileOpen, fileSave} from 'browser-fs-access' export type FileAndHandle = { file: File @@ -15,45 +15,45 @@ export async function openFile(): Promise { file = await fileOpen({ mimeTypes: [defaultMimeType], extensions: [...defaultExtensions], - description: 'Plain Text Files', + description: 'Plain Text Files' }) } catch (err) { if (isCanceledByUser(err)) return throw err } - return { file, handle: file.handle } + return {file, handle: file.handle} } export async function reopenFile( - fileAndHandle: FileAndHandle, + fileAndHandle: FileAndHandle ): Promise { if (!fileAndHandle.handle) return fileAndHandle return { file: await fileAndHandle.handle.getFile(), - handle: fileAndHandle.handle, + handle: fileAndHandle.handle } } export function isFileModified( before: Readonly, - after: Readonly, + after: Readonly ): boolean { return before.file.lastModified < after.file.lastModified } export async function saveFile( fileAndHandle: FileAndHandle | undefined, - text: string, + text: string ): Promise { let handle try { handle = await fileSave( - new Blob([text], { type: defaultMimeType }), + new Blob([text], {type: defaultMimeType}), { fileName: fileAndHandle?.file.name ?? `untitled${defaultExtension}`, - extensions: [...defaultExtensions], + extensions: [...defaultExtensions] }, - fileAndHandle?.handle, + fileAndHandle?.handle ) } catch (err) { if (isCanceledByUser(err)) { @@ -63,7 +63,7 @@ export async function saveFile( throw err } if (!handle) return fileAndHandle - return { file: await handle.getFile(), handle } + return {file: await handle.getFile(), handle} } function isCanceledByUser(err: unknown): boolean { diff --git a/src/io/storage.ts b/src/io/storage.ts index 51eff3f..cf6ee93 100644 --- a/src/io/storage.ts +++ b/src/io/storage.ts @@ -1,4 +1,4 @@ -import { TextTree } from '../tree/text-tree.js' +import {TextTree} from '../tree/text-tree.js' export type Autosave = { /** Filename last saved as. */ @@ -18,13 +18,13 @@ const autosave: string = 'linearText' export function saveStorage( filename: string | undefined, saved: boolean, - tree: Readonly, + tree: Readonly ): void { const save: Autosave = { filename, saved, text: TextTree.toString(tree), - version: 1, + version: 1 } localStorage.setItem(autosave, JSON.stringify(save)) } diff --git a/src/manifest.json b/src/manifest.json index 9e12da9..2f6f966 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -4,21 +4,13 @@ "display": "standalone", "homepage_url": "https://lineartext.com", "icons": [ - { "src": "favicon/favicon.png", "sizes": "16x16", "type": "image/png" }, - { "src": "favicon/favicon32.png", "sizes": "32x32", "type": "image/png" }, - { "src": "favicon/favicon48.png", "sizes": "48x48", "type": "image/png" }, - { "src": "favicon/favicon64.png", "sizes": "64x64", "type": "image/png" }, - { - "src": "favicon/favicon192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "favicon/favicon512.png", - "sizes": "512x512", - "type": "image/png" - }, - { "src": "favicon/favicon.svg", "sizes": "any", "type": "image/svg+xml" } + {"src": "favicon/favicon.png", "sizes": "16x16", "type": "image/png"}, + {"src": "favicon/favicon32.png", "sizes": "32x32", "type": "image/png"}, + {"src": "favicon/favicon48.png", "sizes": "48x48", "type": "image/png"}, + {"src": "favicon/favicon64.png", "sizes": "64x64", "type": "image/png"}, + {"src": "favicon/favicon192.png", "sizes": "192x192", "type": "image/png"}, + {"src": "favicon/favicon512.png", "sizes": "512x512", "type": "image/png"}, + {"src": "favicon/favicon.svg", "sizes": "any", "type": "image/svg+xml"} ], "manifest_version": 3, "name": "Linear Text", diff --git a/src/tree/line-type.ts b/src/tree/line-type.ts index 63081db..810991a 100644 --- a/src/tree/line-type.ts +++ b/src/tree/line-type.ts @@ -2,9 +2,9 @@ import { isDataImageURIStr, isDataURIStr, isFileURIStr, - isHTTPURIStr, + isHTTPURIStr } from '../uri-parser/uri-parser.js' -import { isNumeric } from '../utils/string-util.js' +import {isNumeric} from '../utils/string-util.js' /** String-encoded data type of the text value. */ export type LineType = @@ -61,11 +61,11 @@ const imageExtensions = Object.freeze([ '.ico', '.cur', '.tif', - '.tiff', + '.tiff' ]) function endsWithImageExtension(text: string): boolean { - const extIndex = imageExtensions.find((ext) => text.endsWith(ext)) + const extIndex = imageExtensions.find(ext => text.endsWith(ext)) if (extIndex == null) return false // Require not just an extension but a filename stem too. return text.length > extIndex.length diff --git a/src/tree/text-tree.test.ts b/src/tree/text-tree.test.ts index f5e46ec..0e8bb8c 100644 --- a/src/tree/text-tree.test.ts +++ b/src/tree/text-tree.test.ts @@ -479,9 +479,8 @@ test('multi-line group (2)', () => } `)) test('multi-line groups (3)', () => - expect( - TextTree('a\nb\nc\n\nd\ne\nf\n\ng\nh\ni', 2, IDFactory()) - ).toMatchInlineSnapshot(` + expect(TextTree('a\nb\nc\n\nd\ne\nf\n\ng\nh\ni', 2, IDFactory())) + .toMatchInlineSnapshot(` { "down": [ { @@ -1085,9 +1084,7 @@ test('an empty line before a group is added to the preceding group (2)', () => } `)) test('an empty line before a group is added to the preceding group (3)', () => - expect( - TextTree('a\n\n\n\n\n\nb\n\n', 2, IDFactory()) - ).toMatchInlineSnapshot(` + expect(TextTree('a\n\n\n\n\n\nb\n\n', 2, IDFactory())).toMatchInlineSnapshot(` { "down": [ { diff --git a/src/tree/text-tree.ts b/src/tree/text-tree.ts index 270e0a6..2f71d1f 100644 --- a/src/tree/text-tree.ts +++ b/src/tree/text-tree.ts @@ -1,4 +1,4 @@ -import { treeAdd, treeRemove, treeRoot, treeTouch } from './tree.js' +import {treeAdd, treeRemove, treeRoot, treeTouch} from './tree.js' /** * End of line; an empty line ("\n" or "\r\n"). These voids are tracked to allow @@ -88,17 +88,17 @@ const factory: IDFactory = IDFactory() export function TextTree( str: string, indentW: IndentW, - id: IDFactory = factory, + id: IDFactory = factory ): TextTree { - const tree: TextTree = { down: [], id: id(), indentW, type: 'TextTree' } + const tree: TextTree = {down: [], id: id(), indentW, type: 'TextTree'} let prev: Line | undefined - for (const { start, text, end } of split(str)) { + for (const {start, text, end} of split(str)) { if (!text && !start) { // EOL. Create group if none exists. - const group = tree.down.at(-1) ?? - treeAdd({ id: id(), type: 'Group' }, tree, -1) - treeAdd({ id: id(), end, type: 'EOL' }, group, -1) + const group = + tree.down.at(-1) ?? treeAdd({id: id(), type: 'Group'}, tree, -1) + treeAdd({id: id(), end, type: 'EOL'}, group, -1) continue } @@ -115,12 +115,12 @@ export function TextTree( end: eol.end, expand: false, id: eol.id, - indent: prev ? (prev.indent + 1) : 0, + indent: prev ? prev.indent + 1 : 0, text: '', - type: 'Line', + type: 'Line' }, prev ?? eol.up, - -1, + -1 ) } @@ -129,11 +129,11 @@ export function TextTree( tree.down.at(-1)!.down.at(-1)?.type === 'EOL' ) { // No group or last line was EOL. - const group = treeAdd({ id: id(), type: 'Group' }, tree, -1) + const group = treeAdd({id: id(), type: 'Group'}, tree, -1) prev = treeAdd( - { end, expand: false, id: id(), indent: 0, text, type: 'Line' }, + {end, expand: false, id: id(), indent: 0, text, type: 'Line'}, group, - -1, + -1 ) continue } @@ -152,13 +152,13 @@ export function TextTree( id: id(), indent: lineIndent, text, - type: 'Line', + type: 'Line' }, // Indent matches a previous depth or previous depth was too deep? lineIndent <= prev!.indent ? prev!.up // Peer of line. : prev!, // Child of line. - -1, + -1 ) } @@ -169,7 +169,7 @@ TextTree.addLine = ( to: Line | Group, at: PositionLine, end: LineEnding, - id: IDFactory = factory, + id: IDFactory = factory ): TextTree => { let i let indent @@ -187,9 +187,9 @@ TextTree.addLine = ( } const line = treeAdd( - { end, expand: false, id: id(), indent, text: '', type: 'Line' }, + {end, expand: false, id: id(), indent, text: '', type: 'Line'}, up, - i, + i ) return treeRoot(treeTouch(line)) @@ -199,10 +199,10 @@ TextTree.breakLine = ( line: Line, at: number, end: LineEnding, - id: IDFactory = factory, -): { root: TextTree; new: Line } => { + id: IDFactory = factory +): {root: TextTree; new: Line} => { if (at < 0 || at > line.text.length) { - return { root: treeRoot(line), new: line } + return {root: treeRoot(line), new: line} } const lhs = line.text.slice(0, at) const rhs = line.text.slice(at) @@ -217,18 +217,18 @@ TextTree.breakLine = ( id: id(), indent: line.indent, text: rhs, - type: 'Line', + type: 'Line' }, line.up, - line.up.down.indexOf(line) + 1, + line.up.down.indexOf(line) + 1 ) - return { root: treeRoot(next), new: next } + return {root: treeRoot(next), new: next} } TextTree.moveLine = ( from: Line, to: Line | Group, - at: PositionLine, + at: PositionLine ): TextTree => { if (from === to) return treeRoot(from) @@ -298,7 +298,7 @@ function measureIndent(str: string, indentW: IndentW): number { function nodesToString( nodes: readonly Readonly[], - indentW: IndentW, + indentW: IndentW ): string { let str = '' for (const node of nodes) { @@ -307,14 +307,12 @@ function nodesToString( else if (node.type === 'Group') str += nodesToString(node.down, indentW) else if (node.type === 'Line') { const indent = (indentW === 'Tab' ? '\t' : ' '.repeat(indentW)).repeat( - node.indent, + node.indent ) - str += `${indent}${node.text}${endToString(node.end)}${ - nodesToString( - node.down, - indentW, - ) - }` + str += `${indent}${node.text}${endToString(node.end)}${nodesToString( + node.down, + indentW + )}` } else node satisfies never } return str @@ -326,8 +324,8 @@ function setIndent(line: Line, indent: number): void { } function* split( - str: string, -): Generator<{ start: string; text: string; end: LineEnding | '' }> { + str: string +): Generator<{start: string; text: string; end: LineEnding | ''}> { let start = '' let text = '' let end: LineEnding | '' = '' @@ -338,17 +336,17 @@ function* split( end = 'CRLF' text = text.slice(0, -1) } else end = 'LF' - yield { start, text, end } + yield {start, text, end} start = text = end = '' } else text += char } else { if (char === ' ' || char === '\t') start += char else if (char === '\n') { end = 'LF' - yield { start, text, end } + yield {start, text, end} start = text = end = '' } else text += char } } - if (start || text || end) yield { start, text, end } + if (start || text || end) yield {start, text, end} } diff --git a/src/tree/tree.test.ts b/src/tree/tree.test.ts index a10a46c..a7fd37c 100644 --- a/src/tree/tree.test.ts +++ b/src/tree/tree.test.ts @@ -15,7 +15,6 @@ test('touch root', () => { // 4 5 // | // 6 - // deno-fmt-ignore const i: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] i[0]!.down = [i[1]!, i[2]!, i[3]!] @@ -55,7 +54,6 @@ test('touch mid', () => { // 4 5 // | // 6 - // deno-fmt-ignore const i: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] i[0]!.down = [i[1]!, i[2]!, i[3]!] @@ -96,7 +94,6 @@ test('touch leaf', () => { // 4 5 // | // 6 - // deno-fmt-ignore const i: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] i[0]!.down = [i[1]!, i[2]!, i[3]!] @@ -139,7 +136,6 @@ test('remove', () => { // 4 5 // | // 6 - // deno-fmt-ignore const i: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] i[0]!.down = [i[1]!, i[2]!, i[3]!] @@ -161,7 +157,6 @@ test('remove', () => { // 1 2 3 // | // 5 - // deno-fmt-ignore const e: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] e[0]!.down = [e[1]!, e[2]!, e[3]!] @@ -186,7 +181,6 @@ test('add', () => { // 5 4 // | // 6 - // deno-fmt-ignore const i: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] i[0]!.down = [i[1]!, i[2]!, i[3]!] @@ -208,7 +202,6 @@ test('add', () => { // 5 4 // | // 6 - // deno-fmt-ignore const e: NumTree[] = [{n: 0}, {n: 1}, {n: 2}, {n: 3}, {n: 4}, {n: 5}, {n: 6}] e[0]!.down = [e[1]!, e[2]!, e[3]!] diff --git a/src/tree/tree.ts b/src/tree/tree.ts index d6007f9..aae4667 100644 --- a/src/tree/tree.ts +++ b/src/tree/tree.ts @@ -1,5 +1,5 @@ /** n-ary tree. Subtypes may specify nonnullish linkage if treeAdd() is used. */ -export type Tree = { down?: undefined | Tree[]; up?: Tree | undefined } +export type Tree = {down?: undefined | Tree[]; up?: Tree | undefined} /** Tree subtype with optional linkage. */ export type OptTree = Omit & Tree @@ -10,14 +10,14 @@ export type OptTree = Omit & Tree export function treeAdd( node: OptTree, up: T['up'], - at: number, + at: number ): T { node.up = up node.down ??= [] // Allow nonnullish linkage. - if (!up) return node + if (!up) return node up.down ??= [] up.down.splice(at < 0 ? up.down.length + 1 + at : at, 0, node) - return node + return node } /** Disconnect node from up. Return node. */ @@ -31,7 +31,7 @@ export function treeRemove(node: T): T { export function treeRoot(node: Tree): T { while (node.up) node = node.up - return node + return node } /** @@ -41,12 +41,12 @@ export function treeRoot(node: Tree): T { * an immutable down tree would replace every up node. */ export function treeTouch(node: Readonly>): T { - const touched = { ...node } + const touched = {...node} for (const down of node.down ?? []) down.up = touched - if (!node.up) return touched + if (!node.up) return touched const i = node.up.down?.indexOf(node) ?? -1 if (i === -1) throw Error('up missing down tree') node.up.down![i] = touched treeTouch(node.up) - return touched + return touched } diff --git a/src/uri-parser/uri-parser.ts b/src/uri-parser/uri-parser.ts index 4543150..76e9514 100644 --- a/src/uri-parser/uri-parser.ts +++ b/src/uri-parser/uri-parser.ts @@ -1,4 +1,4 @@ -import type { DataURI } from './data-uri.js' +import type {DataURI} from './data-uri.js' export function isDataURIStr(str: string): boolean { return str.startsWith('data:') @@ -26,19 +26,19 @@ export function parseObjectURL(uri: string): string { } export function parseDataURIBlob(str: string): Blob | undefined { - const { data, encoding, mediaType } = parseDataURI(str) ?? {} + const {data, encoding, mediaType} = parseDataURI(str) ?? {} if (data == null) return if (encoding !== 'base64') return const encoder = new TextEncoder() const buffer = encoder.encode(data) - return new Blob([buffer], mediaType == null ? undefined : { type: mediaType }) + return new Blob([buffer], mediaType == null ? undefined : {type: mediaType}) } const dataURIRegex = /^(?data):(?(?[^,;]+)(?(;[^=,;]+=[^=,;]+)*))?(;(?base64))?,(?.*)$/i export function parseDataURI(str: string): DataURI | undefined { - const { groups } = dataURIRegex.exec(str) ?? {} + const {groups} = dataURIRegex.exec(str) ?? {} if (groups == null) return if (groups.scheme !== 'data') return if (groups.encoding != null && groups.encoding !== 'base64') return @@ -50,9 +50,9 @@ export function parseDataURI(str: string): DataURI | undefined { groups.params ?.split(';') .slice(1) // Params start with `';'`. Skip the leading empty division. - .map((param) => param.split('=')) ?? [], + .map(param => param.split('=')) ?? [] ), encoding: groups.encoding, - data: groups.data ?? '', + data: groups.data ?? '' } } diff --git a/src/utils/bubble.ts b/src/utils/bubble.ts index e9f9933..fc0fe14 100644 --- a/src/utils/bubble.ts +++ b/src/utils/bubble.ts @@ -1,4 +1,4 @@ export function Bubble(type: string, detail: T): CustomEvent { // Composed bubbles through shadow DOM. - return new CustomEvent(type, { bubbles: true, composed: true, detail }) + return new CustomEvent(type, {bubbles: true, composed: true, detail}) } diff --git a/src/utils/css-reset.ts b/src/utils/css-reset.ts index 03ce9d1..5508f03 100644 --- a/src/utils/css-reset.ts +++ b/src/utils/css-reset.ts @@ -1,7 +1,9 @@ -import { css, type CSSResult } from 'lit' +import {css, type CSSResult} from 'lit' export const cssReset: CSSResult = css` - *, *::after, *::before { + *, + *::after, + *::before { box-sizing: border-box; /* Dimensions include any border and padding. */ } ` diff --git a/src/utils/element-util.ts b/src/utils/element-util.ts index 3c040c5..a111768 100644 --- a/src/utils/element-util.ts +++ b/src/utils/element-util.ts @@ -14,7 +14,7 @@ export function composedAncestorElement(el: Element): Element | undefined { /** Composed Element.closest(). */ export function composedClosest( selector: string, - el: Element, + el: Element ): Element | undefined { const closest = el.closest(selector) if (closest) return closest @@ -31,7 +31,7 @@ export function composedClosestScrollable(el: Element): Element | undefined { /** Composed Document.elementFromPoint(). */ export function composedElementFromPoint(x: number, y: number): Element | null { - for (let el = document.elementFromPoint(x, y);;) { + for (let el = document.elementFromPoint(x, y); ; ) { const next = el?.shadowRoot?.elementFromPoint(x, y) if (!next || el === next) return el el = next @@ -41,9 +41,9 @@ export function composedElementFromPoint(x: number, y: number): Element | null { /** @arg xy Target in viewport client coordinates. */ export function scrollTowardsEdge( el: Element, - xy: Readonly<{ x: number; y: number }>, + xy: Readonly<{x: number; y: number}>, threshold: number, - by: number, + by: number ): void { const sx = xy.x < threshold ? -1 : xy.x > el.clientWidth - threshold ? 1 : 0 const sy = xy.y < threshold ? -1 : xy.y > el.clientHeight - threshold ? 1 : 0 diff --git a/src/utils/string-util.ts b/src/utils/string-util.ts index 53a2394..3e51779 100644 --- a/src/utils/string-util.ts +++ b/src/utils/string-util.ts @@ -1,5 +1,5 @@ /** Evaluate whether str is a finite number. */ export function isNumeric(str: string): boolean { // https://stackoverflow.com/a/1830844/970346 - return !isNaN(parseFloat(str)) && isFinite( ( str)) + return !isNaN(parseFloat(str)) && isFinite((str)) }