@sehv-oss/basketball-upload 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basketball-upload.js","names":["resolve","layers","tokens","reset","layout","hoop","card","list","states","motion"],"sources":["../src/game/config.ts","../src/game/court.ts","../src/upload/accept.ts","../src/file-types/defaults.ts","../src/file-types/registry.ts","../src/upload/event-emitter.ts","../src/upload/upload-queue.ts","../src/game/simulate.ts","../src/game/vector.ts","../src/game/slingshot.ts","../src/element/motion.ts","../src/element/controllers/shot-controller.ts","../src/element/dom.ts","../src/element/messages.ts","../src/element/styles/card.css?text","../src/element/styles/hoop.css?text","../src/element/styles/layers.css?text","../src/element/styles/layout.css?text","../src/element/styles/list.css?text","../src/element/styles/motion.css?text","../src/element/styles/reset.css?text","../src/element/styles/states.css?text","../src/element/styles/tokens.css?text","../src/element/styles/styles.ts","../src/element/views/card.ts","../src/element/views/header.ts","../src/element/views/hoop.ts","../src/element/views/live-region.ts","../src/element/views/trajectory.ts","../src/upload/format.ts","../src/element/views/upload-list.ts","../src/element/basketball-upload-element.ts","../src/element/register.ts","../src/upload/xhr.ts"],"sourcesContent":["/**\n * Physics constants. Lengths are in rim units (`u`, the rim width in pixels)\n * and times in seconds, so a shot behaves the same at any rendered size.\n *\n * Calibrated against the reference design: its aiming dots are 1/15 s apart,\n * advance ≈0.116 u horizontally and lose ≈0.095 u of rise per dot.\n */\nexport const PHYSICS = {\n /**\n * Fixed simulation step. Preview and flight both advance by exactly this.\n */\n step: 1 / 120,\n\n /**\n * Downward acceleration, u/s².\n */\n gravity: 21,\n\n /**\n * Launch speed per unit of pull, 1/s. Raised per layout by `launchPower`.\n */\n power: 12,\n\n /**\n * Headroom of a full pull over the speed of the assisted shot.\n */\n powerHeadroom: 1.4,\n\n /**\n * Longest pull that still adds speed, u.\n */\n maxPull: 1,\n\n /**\n * Shorter pulls cancel the shot instead of firing it, u.\n */\n minPull: 0.12,\n\n /**\n * Pull beyond the maximum keeps moving the card, damped by this factor.\n */\n pullStretch: 0.15,\n\n /**\n * Time between two aiming dots, s.\n */\n dotInterval: 1 / 15,\n\n /**\n * The preview stops after this long when nothing is hit, s.\n */\n maxPreviewTime: 2,\n\n /**\n * A shot still in the air after this long counts as a miss, s.\n */\n maxFlightTime: 5,\n\n /**\n * Collision radius of the card around the rim, u.\n */\n hitRadius: 0.17,\n\n /**\n * Half the thickness of the rim, u.\n */\n rimRadius: 0.02,\n\n /**\n * Distance from the card center to the floor and walls, u.\n */\n floorRadius: 0.35,\n\n /**\n * Card scale when it reaches the hoop: it travels away from the viewer.\n */\n depthScale: 0.7,\n\n /**\n * A card rising faster than this (u/s) is still in front of the hoop:\n * the board and the rim only stop cards around the top of their arc or falling.\n */\n hoopDepthRise: 1.5,\n\n /**\n * Velocity kept after touching the board (the orange square).\n */\n board: { x: 0.25, y: 0.3 },\n\n restitution: { rim: 0.45, floor: 0.35, wall: 0.5 },\n\n /**\n * Horizontal velocity kept on each floor bounce.\n */\n floorFriction: 0.8,\n\n /**\n * A missed card stops bouncing after this many floor contacts.\n */\n maxFloorBounces: 2,\n\n /**\n * Assisted shots peak this far above the top of the square, u.\n */\n assistApex: 0.5,\n\n /**\n * Spin in degrees per second, per u/s of horizontal speed.\n */\n spin: { factor: 160, min: 180, max: 540 },\n} as const;\n","import type { Vector } from './vector.ts';\n\nexport interface Rectangle {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\nexport interface Rim {\n readonly left: number;\n\n readonly right: number;\n\n /**\n * Height of the rim plane.\n */\n readonly y: number;\n}\n\n/**\n * The layout as the simulation sees it, in pixels relative to the element.\n * CSS owns the layout; the game only measures it (see `courtFromRectangles`).\n */\nexport interface Court {\n /**\n * Rim width in pixels: the `u` the physics constants are expressed in.\n */\n readonly unit: number;\n\n /**\n * Play area: walls, ceiling and floor.\n */\n readonly bounds: Rectangle;\n\n /**\n * The dropzone, which doubles as the backboard.\n */\n readonly board: Rectangle;\n\n /**\n * The orange target square on the board.\n */\n readonly square: Rectangle;\n\n readonly rim: Rim;\n\n /**\n * Bottom edge of the net, where scored cards come to rest.\n */\n readonly netBottom: number;\n\n /**\n * Center of a staged card.\n */\n readonly rest: Vector;\n}\n\nexport interface CourtRectangles {\n readonly host: Rectangle;\n\n readonly board: Rectangle;\n\n readonly square: Rectangle;\n\n /**\n * Bounding box of the rim drawing: the rim plane is its vertical center.\n */\n readonly rim: Rectangle;\n\n readonly net: Rectangle;\n\n /**\n * Box a staged card rests in.\n */\n readonly spot: Rectangle;\n}\n\nfunction relative(rectangle: Rectangle, origin: Rectangle): Rectangle {\n return {\n x: rectangle.x - origin.x,\n y: rectangle.y - origin.y,\n width: rectangle.width,\n height: rectangle.height,\n };\n}\n\n/**\n * Builds a court from client rectangles (`getBoundingClientRect`).\n */\nexport function courtFromRectangles(rectangles: CourtRectangles): Court {\n const { host } = rectangles;\n const rim = relative(rectangles.rim, host);\n const net = relative(rectangles.net, host);\n const spot = relative(rectangles.spot, host);\n\n return {\n unit: rim.width,\n bounds: { x: 0, y: 0, width: host.width, height: host.height },\n board: relative(rectangles.board, host),\n square: relative(rectangles.square, host),\n rim: { left: rim.x, right: rim.x + rim.width, y: rim.y + rim.height / 2 },\n netBottom: net.y + net.height,\n rest: { x: spot.x + spot.width / 2, y: spot.y + spot.height / 2 },\n };\n}\n\n/**\n * Middle of the rim, on the rim plane.\n */\nexport function rimCenter(court: Court): Vector {\n return { x: (court.rim.left + court.rim.right) / 2, y: court.rim.y };\n}\n\n/**\n * Whether `point` is inside `rectangle`, edges included.\n */\nexport function contains(rectangle: Rectangle, point: Vector): boolean {\n return (\n point.x >= rectangle.x &&\n point.x <= rectangle.x + rectangle.width &&\n point.y >= rectangle.y &&\n point.y <= rectangle.y + rectangle.height\n );\n}\n","/**\n * The parts of a `File` that `matchesAccept` reads.\n */\nexport interface FileLike {\n readonly name: string;\n readonly type: string;\n}\n\n/**\n * Whether a file matches an `accept` string, with the semantics of\n * `<input type=\"file\" accept>`: comma separated extensions (`.pdf`), MIME\n * types (`application/pdf`) and wildcards (`image/*`). Empty accepts all.\n */\nexport function matchesAccept(\n file: FileLike,\n accept: string | null | undefined\n): boolean {\n const tokens = (accept ?? '')\n .split(',')\n .map((token) => token.trim().toLowerCase())\n .filter(Boolean);\n if (tokens.length === 0) return true;\n\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return tokens.some((token) => {\n if (token === '*' || token === '*/*') return true;\n\n if (token.startsWith('.')) return name.endsWith(token);\n\n if (token.endsWith('/*')) return type.startsWith(token.slice(0, -1));\n\n return type === token;\n });\n}\n\n/**\n * Lowercase extension without the dot, or an empty string.\n */\nexport function fileExtension(name: string): string {\n const dot = name.lastIndexOf('.');\n return dot > 0 && dot < name.length - 1\n ? name.slice(dot + 1).toLowerCase()\n : '';\n}\n","import type { FileType } from './types.ts';\n\n/**\n * Built-in file types, checked after the ones you register.\n */\nexport const defaultFileTypes: readonly FileType[] = [\n {\n kind: 'pdf',\n match: '.pdf,application/pdf',\n label: 'PDF',\n color: '#d8374e',\n },\n {\n kind: 'image',\n match: 'image/*,.png,.jpg,.jpeg,.gif,.webp,.avif,.svg',\n color: '#2f7cf6',\n artwork: 'thumbnail',\n },\n { kind: 'video', match: 'video/*', color: '#8b5cf6' },\n { kind: 'audio', match: 'audio/*', color: '#e39a0b' },\n {\n kind: 'sheet',\n match: '.csv,.tsv,.xls,.xlsx,.ods,.numbers,text/csv',\n color: '#1f9d55',\n },\n {\n kind: 'doc',\n match: '.doc,.docx,.odt,.rtf,.md,.txt,.pages,text/plain,text/markdown',\n color: '#2563eb',\n },\n { kind: 'slides', match: '.ppt,.pptx,.key,.odp', color: '#ea580c' },\n {\n kind: 'archive',\n match: '.zip,.rar,.7z,.tar,.gz,.tgz,.bz2,application/zip',\n label: (file) =>\n file.name.toLowerCase().endsWith('.tar.gz')\n ? 'TGZ'\n : extensionLabel(file.name, 'ZIP'),\n color: '#6b7280',\n },\n {\n kind: 'code',\n match:\n '.json,.js,.mjs,.cjs,.ts,.tsx,.jsx,.html,.css,.xml,.yaml,.yml,.py,.go,.rs,.java,.c,.cpp,.sh',\n color: '#475569',\n },\n];\n\n/**\n * The extension in capitals, at most 4 characters, or `fallback`.\n */\nexport function extensionLabel(name: string, fallback: string): string {\n const dot = name.lastIndexOf('.');\n const extension = dot > 0 ? name.slice(dot + 1) : '';\n\n return (extension || fallback).slice(0, 4).toUpperCase();\n}\n","import { matchesAccept } from '../upload/accept.ts';\nimport { defaultFileTypes, extensionLabel } from './defaults.ts';\nimport type { FileType, ResolvedFileType } from './types.ts';\n\nconst KIND = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Registered globally, most recent first.\n */\nconst registered: FileType[] = [];\n\n/**\n * Throws when a file type cannot be used: its kind ends up in part names.\n */\nexport function assertFileType(type: FileType): void {\n if (!KIND.test(type.kind)) {\n throw new TypeError(\n `Invalid file type kind \"${type.kind}\": use lowercase letters, digits and dashes, starting with a letter.`\n );\n }\n}\n\n/**\n * Adds a file type for every `<basketball-upload>` on the page. It wins over the\n * built-in types and over the ones registered before it; types set on an\n * element (`fileTypes`) still win over it. Returns a function that removes it.\n */\nexport function registerFileType(type: FileType): () => void {\n assertFileType(type);\n registered.unshift(type);\n return () => {\n const index = registered.indexOf(type);\n if (index !== -1) registered.splice(index, 1);\n };\n}\n\nfunction matches(type: FileType, file: File): boolean {\n return typeof type.match === 'function'\n ? type.match(file)\n : matchesAccept(file, type.match);\n}\n\nfunction resolve(type: FileType, file: File): ResolvedFileType {\n const label =\n typeof type.label === 'function'\n ? type.label(file)\n : (type.label ?? extensionLabel(file.name, type.kind));\n return {\n kind: type.kind,\n label,\n color: type.color ?? null,\n artwork: type.artwork ?? 'lines',\n };\n}\n\n/**\n * The look of a file: the first match among `instanceTypes`, then the\n * registered types, then the built-in ones, then a neutral `file`.\n */\nexport function resolveFileType(\n file: File,\n instanceTypes: readonly FileType[] = []\n): ResolvedFileType {\n for (const types of [instanceTypes, registered, defaultFileTypes]) {\n for (const type of types) {\n if (matches(type, file)) return resolve(type, file);\n }\n }\n return {\n kind: 'file',\n label: extensionLabel(file.name, 'FILE'),\n color: null,\n artwork: 'lines',\n };\n}\n","/**\n * Gets the payload of an event.\n */\nexport type Listener<TDetail> = (detail: TDetail) => void;\n\n/**\n * Minimal typed emitter. Listeners run synchronously, in subscription order.\n */\nexport class EventEmitter<TEvents extends object> {\n readonly #listeners = new Map<keyof TEvents, Set<Listener<never>>>();\n\n /**\n * Subscribes to an event. Returns a function that unsubscribes.\n */\n on<TType extends keyof TEvents>(\n type: TType,\n listener: Listener<TEvents[TType]>\n ): () => void {\n let listeners = this.#listeners.get(type);\n if (!listeners) {\n listeners = new Set();\n this.#listeners.set(type, listeners);\n }\n listeners.add(listener as Listener<never>);\n return () => {\n listeners.delete(listener as Listener<never>);\n };\n }\n\n /**\n * Calls the listeners of an event with its payload.\n */\n emit<TType extends keyof TEvents>(type: TType, detail: TEvents[TType]): void {\n const listeners = this.#listeners.get(type);\n if (!listeners) return;\n for (const listener of [...listeners]) {\n (listener as Listener<TEvents[TType]>)(detail);\n }\n }\n}\n","import { EventEmitter } from './event-emitter.ts';\nimport type { UploadItem, Uploader } from './types.ts';\n\n/**\n * Events of `UploadQueue`, with the payload their listeners get.\n */\nexport interface UploadQueueEvents {\n /**\n * Any change to the list or to an item, including progress.\n */\n change: readonly UploadItem[];\n\n /**\n * The uploader was called for the item.\n */\n start: UploadItem;\n\n /**\n * The uploader reported progress.\n */\n progress: UploadItem;\n\n /**\n * The upload resolved. Not emitted once the item was removed.\n */\n success: UploadItem;\n\n /**\n * The upload rejected. Not emitted once the item was removed.\n */\n error: UploadItem;\n}\n\nexport interface UploadQueueOptions {\n /**\n * Sends each file. Without one, files are `ready`.\n */\n uploader?: Uploader | null | undefined;\n\n /**\n * Uploads running at the same time. Defaults to 3.\n */\n concurrency?: number | undefined;\n}\n\n/**\n * Uploads running at the same time when no valid `concurrency` is given.\n */\nexport const DEFAULT_CONCURRENCY = 3;\n\n/**\n * Files accepted by the hoop, and their uploads. Items are immutable\n * snapshots; every change replaces the item and emits `change`.\n */\nexport class UploadQueue extends EventEmitter<UploadQueueEvents> {\n /**\n * Used for the files added from now on. Without one, files are `ready`.\n */\n uploader: Uploader | null;\n\n #concurrency: number;\n #items: readonly UploadItem[] = [];\n readonly #controllers = new Map<string, AbortController>();\n #nextId = 0;\n\n constructor(options: UploadQueueOptions = {}) {\n super();\n this.uploader = options.uploader ?? null;\n this.#concurrency = normalizeConcurrency(options.concurrency);\n }\n\n /**\n * Every item, in the order the files were added.\n */\n get items(): readonly UploadItem[] {\n return this.#items;\n }\n\n /**\n * Uploads running at the same time: a whole number from 1, otherwise\n * `DEFAULT_CONCURRENCY`. Raising it starts queued uploads at once.\n */\n get concurrency(): number {\n return this.#concurrency;\n }\n\n set concurrency(value: number) {\n this.#concurrency = normalizeConcurrency(value);\n this.#pump();\n }\n\n /**\n * The current snapshot of an item.\n */\n get(id: string): UploadItem | undefined {\n return this.#items.find((item) => item.id === id);\n }\n\n /**\n * Adds a file: `queued` with an uploader, which starts as soon as a slot is\n * free, otherwise `ready`. Returns the item as it is once added, possibly\n * already `uploading`.\n */\n add(file: File): UploadItem {\n this.#nextId += 1;\n const id = `upload-${this.#nextId}`;\n const item: UploadItem = {\n id,\n file,\n status: this.uploader ? 'queued' : 'ready',\n progress: this.uploader ? 0 : 1,\n response: undefined,\n error: undefined,\n };\n this.#items = [...this.#items, item];\n this.emit('change', this.#items);\n this.#pump();\n return this.get(id) ?? item;\n }\n\n /**\n * Uploads a failed item again. Returns whether there was one to retry.\n */\n retry(id: string): boolean {\n const item = this.get(id);\n if (!item || item.status !== 'error' || !this.uploader) return false;\n this.#update(id, { status: 'queued', progress: 0, error: undefined });\n this.#pump();\n return true;\n }\n\n /**\n * Removes an item, aborting its upload.\n */\n remove(id: string): boolean {\n if (!this.get(id)) return false;\n this.#controllers.get(id)?.abort();\n this.#controllers.delete(id);\n this.#items = this.#items.filter((item) => item.id !== id);\n this.emit('change', this.#items);\n this.#pump();\n return true;\n }\n\n /**\n * Removes every item, aborting the uploads in flight.\n */\n clear(): void {\n for (const controller of this.#controllers.values()) controller.abort();\n this.#controllers.clear();\n if (this.#items.length === 0) return;\n this.#items = [];\n this.emit('change', this.#items);\n }\n\n #pump(): void {\n if (!this.uploader) return;\n let active = this.#items.filter(\n (item) => item.status === 'uploading'\n ).length;\n for (const item of this.#items) {\n if (active >= this.#concurrency) return;\n if (item.status !== 'queued') continue;\n this.#start(item, this.uploader);\n active += 1;\n }\n }\n\n #start(item: UploadItem, uploader: Uploader): void {\n const { id, file } = item;\n const controller = new AbortController();\n const { signal } = controller;\n this.#controllers.set(id, controller);\n this.#update(id, { status: 'uploading', progress: 0 });\n this.#emitItem('start', id);\n\n const onProgress = (loaded: number, total: number = file.size): void => {\n if (signal.aborted) return;\n const progress = total > 0 ? Math.min(1, Math.max(0, loaded / total)) : 0;\n this.#update(id, { progress });\n this.#emitItem('progress', id);\n };\n\n let upload: Promise<unknown>;\n try {\n upload = Promise.resolve(uploader(file, { signal, onProgress }));\n } catch (error) {\n upload = Promise.reject(error);\n }\n\n upload.then(\n (response) => {\n if (signal.aborted) return;\n this.#controllers.delete(id);\n this.#update(id, { status: 'uploaded', progress: 1, response });\n this.#emitItem('success', id);\n this.#pump();\n },\n (error: unknown) => {\n if (signal.aborted) return;\n this.#controllers.delete(id);\n this.#update(id, { status: 'error', error });\n this.#emitItem('error', id);\n this.#pump();\n }\n );\n }\n\n #update(id: string, patch: Partial<Omit<UploadItem, 'id' | 'file'>>): void {\n this.#items = this.#items.map((item) =>\n item.id === id ? { ...item, ...patch } : item\n );\n this.emit('change', this.#items);\n }\n\n #emitItem(\n type: 'start' | 'progress' | 'success' | 'error',\n id: string\n ): void {\n const item = this.get(id);\n if (item) this.emit(type, item);\n }\n}\n\nfunction normalizeConcurrency(value: number | undefined): number {\n return value !== undefined && Number.isFinite(value) && value >= 1\n ? Math.floor(value)\n : DEFAULT_CONCURRENCY;\n}\n","import { PHYSICS } from './config.ts';\nimport { contains, rimCenter, type Court } from './court.ts';\nimport type { Vector } from './vector.ts';\n\n/**\n * State of a card in the air. Plain data: the same body always steps the same way.\n */\nexport interface Body {\n readonly x: number;\n\n readonly y: number;\n\n readonly velocityX: number;\n\n readonly velocityY: number;\n\n /**\n * Number of steps taken since launch. Time is `steps * PHYSICS.step`.\n */\n readonly steps: number;\n\n /**\n * The board (orange square) absorbs the energy of a shot once.\n */\n readonly boarded: boolean;\n}\n\n/**\n * - `board`: the card reached the orange square and lost most of its speed.\n * - `rim`: it bounced off an end of the rim.\n * - `score`: it went down through the rim. The body stops on the rim plane.\n * - `floor` / `wall`: it bounced off the edges of the element.\n */\nexport type ShotEvent = 'board' | 'rim' | 'score' | 'floor' | 'wall';\n\n/**\n * One step of the simulation.\n */\nexport interface StepResult {\n /**\n * The body after the step.\n */\n readonly body: Body;\n\n /**\n * What happened during the step, in the order it was resolved. Usually\n * empty.\n */\n readonly events: readonly ShotEvent[];\n}\n\n/**\n * A body at `position`, leaving at `velocity` (pixels per second).\n */\nexport function launch(position: Vector, velocity: Vector): Body {\n return {\n x: position.x,\n y: position.y,\n velocityX: velocity.x,\n velocityY: velocity.y,\n steps: 0,\n boarded: false,\n };\n}\n\n/**\n * Seconds since launch.\n */\nexport function timeOf(body: Body): number {\n return body.steps * PHYSICS.step;\n}\n\n/**\n * Advances a body by one fixed step (`PHYSICS.step`).\n */\nexport function step(body: Body, court: Court): StepResult {\n const timeStep = PHYSICS.step;\n const { unit } = court;\n const events: ShotEvent[] = [];\n\n let velocityX = body.velocityX;\n let velocityY = body.velocityY + PHYSICS.gravity * unit * timeStep;\n let x = body.x + velocityX * timeStep;\n let y = body.y + velocityY * timeStep;\n let boarded = body.boarded;\n const steps = body.steps + 1;\n\n const { left, right, y: rimY } = court.rim;\n const center = rimCenter(court).x;\n const hit = PHYSICS.hitRadius * unit;\n\n const atHoopDepth = body.velocityY > -PHYSICS.hoopDepthRise * unit;\n\n if (body.y < rimY && y >= rimY) {\n const fraction = (rimY - body.y) / (y - body.y);\n const crossX = body.x + (x - body.x) * fraction;\n if (Math.abs(crossX - center) < (right - left) / 2 - hit * 0.6) {\n return {\n body: { x: crossX, y: rimY, velocityX, velocityY, steps, boarded },\n events: ['score'],\n };\n }\n }\n\n const reach = hit + PHYSICS.rimRadius * unit;\n for (const end of atHoopDepth ? [left, right] : []) {\n const offsetX = x - end;\n const offsetY = y - rimY;\n const distance = Math.hypot(offsetX, offsetY);\n if (distance >= reach || distance === 0) continue;\n\n const normalX = offsetX / distance;\n const normalY = offsetY / distance;\n x = end + normalX * reach;\n y = rimY + normalY * reach;\n const along = velocityX * normalX + velocityY * normalY;\n if (along < 0) {\n velocityX -= (1 + PHYSICS.restitution.rim) * along * normalX;\n velocityY -= (1 + PHYSICS.restitution.rim) * along * normalY;\n }\n events.push('rim');\n }\n\n if (!boarded && atHoopDepth && contains(court.square, { x, y })) {\n boarded = true;\n velocityX *= PHYSICS.board.x;\n velocityY *= PHYSICS.board.y;\n events.push('board');\n }\n\n const { bounds } = court;\n const edge = PHYSICS.floorRadius * unit;\n const floor = bounds.y + bounds.height - edge;\n if (y > floor) {\n y = floor;\n if (velocityY > 0) velocityY = -velocityY * PHYSICS.restitution.floor;\n velocityX *= PHYSICS.floorFriction;\n events.push('floor');\n }\n if (x < bounds.x + edge) {\n x = bounds.x + edge;\n velocityX = Math.abs(velocityX) * PHYSICS.restitution.wall;\n events.push('wall');\n } else if (x > bounds.x + bounds.width - edge) {\n x = bounds.x + bounds.width - edge;\n velocityX = -Math.abs(velocityX) * PHYSICS.restitution.wall;\n events.push('wall');\n }\n if (y < bounds.y + edge && velocityY < 0) {\n y = bounds.y + edge;\n velocityY = Math.abs(velocityY) * PHYSICS.restitution.wall;\n events.push('wall');\n }\n\n return { body: { x, y, velocityX, velocityY, steps, boarded }, events };\n}\n\nexport interface PreviewDot {\n readonly x: number;\n\n readonly y: number;\n\n /**\n * Steps since launch: the dot is behind the card once the card has taken this many.\n */\n readonly steps: number;\n}\n\nexport interface Preview {\n /**\n * Where the card will be every `PHYSICS.dotInterval`, then where it meets `end`, which is the last dot.\n */\n readonly dots: readonly PreviewDot[];\n\n /**\n * First thing the card will hit, or `null` when the preview ran out of time.\n */\n readonly end: ShotEvent | null;\n\n /**\n * Steps until `end` (or until the preview gave up).\n */\n readonly steps: number;\n}\n\n/**\n * Runs the very simulation the flight will run, until its first event.\n * The dots are therefore exactly where the card is going to be.\n */\nexport function previewPath(start: Body, court: Court): Preview {\n const every = Math.round(PHYSICS.dotInterval / PHYSICS.step);\n const limit = Math.round(PHYSICS.maxPreviewTime / PHYSICS.step);\n const dots: PreviewDot[] = [];\n\n let body = start;\n while (body.steps < limit) {\n const result = step(body, court);\n body = result.body;\n const [event] = result.events;\n if (event) {\n dots.push({ x: body.x, y: body.y, steps: body.steps });\n return { dots, end: event, steps: body.steps };\n }\n if (body.steps % every === 0) {\n dots.push({ x: body.x, y: body.y, steps: body.steps });\n }\n }\n\n return { dots, end: null, steps: body.steps };\n}\n","export interface Vector {\n readonly x: number;\n readonly y: number;\n}\n\nexport function scale(vector: Vector, factor: number): Vector {\n return { x: vector.x * factor, y: vector.y * factor };\n}\n\nexport function length(vector: Vector): number {\n return Math.hypot(vector.x, vector.y);\n}\n\n/**\n * `vector` turned by `degrees`, clockwise on screen (y points down).\n */\nexport function rotate(vector: Vector, degrees: number): Vector {\n const radians = (degrees * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return {\n x: vector.x * cos - vector.y * sin,\n y: vector.x * sin + vector.y * cos,\n };\n}\n\n/**\n * `vector` shortened to `max` when longer; unchanged otherwise.\n */\nexport function limit(vector: Vector, max: number): Vector {\n const size = length(vector);\n return size > max ? scale(vector, max / size) : vector;\n}\n","import { PHYSICS } from './config.ts';\nimport { rimCenter, type Court } from './court.ts';\nimport { length, limit, rotate, scale, type Vector } from './vector.ts';\n\n/**\n * Where the card is drawn while pulled: it follows the pointer up to the\n * maximum pull, then only by a fraction of the extra distance.\n */\nexport function stretchPull(pull: Vector, unit: number): Vector {\n const max = PHYSICS.maxPull * unit;\n const size = length(pull);\n if (size <= max) return pull;\n return scale(pull, (max + (size - max) * PHYSICS.pullStretch) / size);\n}\n\n/**\n * Pulls shorter than this cancel the shot.\n */\nexport function isPullEnough(pull: Vector, unit: number): boolean {\n return length(pull) >= PHYSICS.minPull * unit;\n}\n\n/**\n * Launch velocity of a pull, in px/s: opposite to the pull, like a slingshot.\n */\nexport function pullToVelocity(\n pull: Vector,\n unit: number,\n power: number\n): Vector {\n return scale(limit(pull, PHYSICS.maxPull * unit), -power);\n}\n\n/**\n * Aiming with the keyboard: `pull` turned by `degrees` (clockwise on screen)\n * and lengthened by `extra` rim units, between the shortest and the longest pull.\n */\nexport function steerPull(\n pull: Vector,\n degrees: number,\n extra: number,\n unit: number\n): Vector {\n const size = length(pull);\n const steered = Math.min(\n PHYSICS.maxPull * unit,\n Math.max(PHYSICS.minPull * unit, size + extra * unit)\n );\n\n return scale(rotate(pull, degrees), steered / size);\n}\n\n/**\n * Velocity, in px/s, of a shot from `start` that peaks above the square and\n * comes down on the center of the rim. Used for keyboard shots, and to size\n * the slingshot to the layout.\n */\nexport function solveAssistedShot(start: Vector, court: Court): Vector {\n const gravity = PHYSICS.gravity * court.unit;\n const target = rimCenter(court);\n const apex =\n Math.min(start.y, court.square.y) - PHYSICS.assistApex * court.unit;\n\n const rise = start.y - apex;\n const fall = target.y - apex;\n const time =\n Math.sqrt((2 * rise) / gravity) + Math.sqrt((2 * fall) / gravity);\n\n return {\n x: (target.x - start.x) / time,\n y: -Math.sqrt(2 * gravity * rise),\n };\n}\n\n/**\n * The pull that launches the assisted shot from where cards rest.\n */\nexport function assistedPull(court: Court): Vector {\n return scale(solveAssistedShot(court.rest, court), -1 / launchPower(court));\n}\n\n/**\n * Speed per unit of pull for this layout: at least the default, and enough\n * for a full pull to comfortably reach the hoop from where cards rest.\n */\nexport function launchPower(court: Court): number {\n const needed = length(solveAssistedShot(court.rest, court));\n return Math.max(\n PHYSICS.power,\n (needed * PHYSICS.powerHeadroom) / (PHYSICS.maxPull * court.unit)\n );\n}\n\n/**\n * Spin in degrees per second for a launch velocity in px/s.\n */\nexport function spinFor(velocity: Vector, unit: number): number {\n const speed = (Math.abs(velocity.x) / unit) * PHYSICS.spin.factor;\n const spin = Math.min(PHYSICS.spin.max, Math.max(PHYSICS.spin.min, speed));\n return velocity.x < 0 ? -spin : spin;\n}\n","/**\n * Where a card is drawn: its center, rotation and scale, in layer pixels.\n */\nexport interface Pose {\n readonly x: number;\n readonly y: number;\n readonly rotation: number;\n readonly scale: number;\n}\n\n/**\n * Whether the user asked for reduced motion. `false` where `matchMedia` is\n * missing.\n */\nexport function prefersReducedMotion(): boolean {\n return (\n typeof matchMedia === 'function' &&\n matchMedia('(prefers-reduced-motion: reduce)').matches\n );\n}\n\n/**\n * The individual transform properties of a pose, for a box of the given size.\n */\nexport function poseStyle(\n pose: Pose,\n width: number,\n height: number\n): { translate: string; rotate: string; scale: string } {\n return {\n translate: `${pose.x - width / 2}px ${pose.y - height / 2}px`,\n rotate: `${pose.rotation}deg`,\n scale: String(pose.scale),\n };\n}\n\n/**\n * Timing of `play()`, plus `commit`.\n */\nexport interface PlayOptions extends KeyframeAnimationOptions {\n /**\n * Keep the last keyframe as inline style once the animation ends.\n */\n commit?: boolean;\n}\n\n/**\n * Runs a Web Animation and resolves when it ends or is cancelled.\n * Resolves at once where the Web Animations API is missing.\n */\nexport async function play(\n element: Element,\n keyframes: Keyframe[],\n options: PlayOptions = {}\n): Promise<void> {\n if (typeof element.animate !== 'function') return;\n const { commit = false, ...timing } = options;\n const animation = element.animate(\n keyframes,\n commit ? { ...timing, fill: 'forwards' } : timing\n );\n\n try {\n await animation.finished;\n } catch {\n return;\n }\n\n if (!commit) return;\n\n try {\n animation.commitStyles();\n } catch {\n // Not rendered (display: none): there is nothing to keep.\n }\n\n animation.cancel();\n}\n\n/**\n * The nearest whole turn, so a spinning card settles upright without unwinding.\n */\nexport function uprightOf(rotation: number): number {\n return Math.round(rotation / 360) * 360;\n}\n","import { PHYSICS } from '../../game/config.ts';\nimport { contains, type Court } from '../../game/court.ts';\nimport {\n launch,\n previewPath,\n step,\n timeOf,\n type Body,\n} from '../../game/simulate.ts';\nimport {\n assistedPull,\n isPullEnough,\n launchPower,\n pullToVelocity,\n solveAssistedShot,\n spinFor,\n steerPull,\n stretchPull,\n} from '../../game/slingshot.ts';\nimport type { Vector } from '../../game/vector.ts';\nimport { play, poseStyle, prefersReducedMotion, type Pose } from '../motion.ts';\nimport type { CardView } from '../views/card.ts';\nimport type { TrajectoryView } from '../views/trajectory.ts';\n\n/**\n * Rotation of a card resting on the court. Keep in sync with `card.css`.\n */\nexport const REST_ROTATION = -6;\n\n/**\n * Cards lift a little while held.\n */\nconst GRAB_SCALE = 1.04;\n\n/**\n * Tilt while pulling, in degrees per rim unit of horizontal pull.\n */\nconst PULL_TILT = 14;\n\n/**\n * Degrees a press of the left or right arrow turns the keyboard aim by.\n */\nconst TURN_STEP = 2;\n\n/**\n * Rim units a press of the up or down arrow lengthens or shortens the pull by.\n */\nconst PULL_STEP = 0.05;\n\n/**\n * What each arrow does to the keyboard aim: degrees to turn it by, and rim\n * units to lengthen its pull by.\n */\nconst STEERING: Readonly<Record<string, readonly [number, number]>> = {\n ArrowLeft: [-TURN_STEP, 0],\n ArrowRight: [TURN_STEP, 0],\n ArrowUp: [0, PULL_STEP],\n ArrowDown: [0, -PULL_STEP],\n};\n\n/**\n * Rotation of a card pulled by `pull`: it leans back against the pull.\n */\nfunction tiltOf(pull: Vector, unit: number): number {\n return Math.max(-1, Math.min(1, pull.x / unit)) * PULL_TILT;\n}\n\n/**\n * An aim in progress: the card is held, showing the shot of its pull.\n */\ninterface Aim {\n /**\n * Aborted once the aim ends.\n */\n readonly signal: AbortSignal;\n\n /**\n * Draws the card and its shot for `pull`.\n */\n aim(pull: Vector): void;\n\n /**\n * Shoots, when `shoot` and the pull is long enough; otherwise the card goes\n * back to the court.\n */\n end(shoot: boolean): void;\n}\n\n/**\n * What `ShotController` needs from the element: the views it draws on, and\n * callbacks for what happens to the card.\n */\nexport interface ShotHost {\n /**\n * Shows the arc of the shot while aiming and in flight.\n */\n readonly trajectory: TrajectoryView;\n\n /**\n * The court as currently laid out, or `null` when not rendered.\n */\n measure(): Court | null;\n\n /**\n * Whether a card is pulled back: the `aiming` state.\n */\n setAiming(aiming: boolean): void;\n\n /**\n * Whether a card is in the air: the `flying` state.\n */\n setFlying(flying: boolean): void;\n\n /**\n * Whether the flying card is in front of the dropzone.\n */\n setOverBoard(over: boolean): void;\n\n /**\n * The card left the court: it is no longer staged.\n */\n launched(card: CardView): void;\n\n /**\n * The card went through the rim, drawn at `pose`.\n */\n scored(card: CardView, pose: Pose, court: Court): void;\n\n /**\n * The card missed and is back on the court.\n */\n missed(card: CardView): void;\n}\n\n/**\n * Aiming with the pointer or the keyboard, assisted shots, and the flight of\n * the card.\n */\nexport class ShotController {\n readonly #host: ShotHost;\n #card: CardView | null = null;\n #frame = 0;\n #endAim: (() => void) | null = null;\n\n constructor(host: ShotHost) {\n this.#host = host;\n }\n\n /**\n * Starts aiming: the card follows the pointer like a slingshot pouch.\n */\n grab(card: CardView, event: PointerEvent): void {\n if (this.#card || event.button !== 0) return;\n const court = this.#host.measure();\n if (!court) return;\n\n event.preventDefault();\n const { element } = card;\n try {\n element.setPointerCapture(event.pointerId);\n } catch {\n // Not an active pointer (synthetic events): the card still gets its own.\n }\n const { signal, aim, end } = this.#takeAim(card, court, { follow: true });\n signal.addEventListener('abort', () => {\n if (element.hasPointerCapture(event.pointerId)) {\n element.releasePointerCapture(event.pointerId);\n }\n });\n\n const origin: Vector = { x: event.clientX, y: event.clientY };\n element.addEventListener(\n 'pointermove',\n (moved) => {\n if (moved.pointerId !== event.pointerId) return;\n\n aim({ x: moved.clientX - origin.x, y: moved.clientY - origin.y });\n },\n { signal }\n );\n element.addEventListener(\n 'pointerup',\n (released) => {\n if (released.pointerId === event.pointerId) {\n end(true);\n }\n },\n { signal }\n );\n element.addEventListener(\n 'pointercancel',\n (cancelled) => {\n if (cancelled.pointerId === event.pointerId) {\n end(false);\n }\n },\n { signal }\n );\n element.addEventListener(\n 'lostpointercapture',\n (lost) => {\n if (lost.pointerId === event.pointerId) {\n end(false);\n }\n },\n { signal }\n );\n }\n\n /**\n * Starts aiming from the keyboard, at the assisted shot: the arrows turn it\n * and change its strength, and releasing the key that started it shoots.\n */\n hold(card: CardView, event: KeyboardEvent): void {\n if (this.#card || event.repeat) return;\n const court = this.#host.measure();\n if (!court) return;\n\n const { element } = card;\n const { signal, aim, end } = this.#takeAim(card, court, { follow: false });\n let pull = assistedPull(court);\n aim(pull);\n\n element.addEventListener(\n 'keydown',\n (pressed) => {\n const steering = STEERING[pressed.key];\n if (!steering) return;\n\n pressed.preventDefault();\n pull = steerPull(pull, steering[0], steering[1], court.unit);\n aim(pull);\n },\n { signal }\n );\n element.addEventListener(\n 'keyup',\n (released) => {\n if (released.key === event.key) end(true);\n },\n { signal }\n );\n element.addEventListener('blur', () => end(false), { signal });\n }\n\n /**\n * Drops the current aim; the card goes back to the court.\n */\n cancelAim(): void {\n this.#endAim?.();\n }\n\n /**\n * A perfect shot from the court, for `shoot()`.\n */\n shoot(card: CardView): boolean {\n if (this.#card) return false;\n\n const court = this.#host.measure();\n if (!court) return false;\n\n this.#card = card;\n const pose: Pose = { ...court.rest, rotation: REST_ROTATION, scale: 1 };\n card.place(pose);\n const body = launch(pose, solveAssistedShot(court.rest, court));\n this.#host.trajectory.show(previewPath(body, court).dots, court.unit);\n this.#host.launched(card);\n this.#fly(card, body, pose.rotation, court);\n\n return true;\n }\n\n /**\n * Stops whatever is going on, leaving the card where it is.\n */\n stop(): CardView | null {\n this.#endAim?.();\n cancelAnimationFrame(this.#frame);\n this.#frame = 0;\n const card = this.#card;\n this.#card = null;\n this.#host.trajectory.clear();\n this.#host.setFlying(false);\n this.#host.setOverBoard(false);\n\n return card;\n }\n\n #fly(card: CardView, start: Body, rotation: number, court: Court): void {\n if (prefersReducedMotion()) {\n this.#card = null;\n this.#host.trajectory.clear();\n this.#host.scored(\n card,\n { x: start.x, y: start.y, rotation, scale: 1 },\n court\n );\n return;\n }\n\n this.#host.setFlying(true);\n const preview = previewPath(start, court);\n const reachesHoop =\n preview.end === 'board' ||\n preview.end === 'rim' ||\n preview.end === 'score';\n const depthSteps = reachesHoop\n ? Math.max(1, preview.steps)\n : Math.round(0.6 / PHYSICS.step);\n\n let body = start;\n let angle = rotation;\n let spin = spinFor({ x: start.velocityX, y: start.velocityY }, court.unit);\n let bounces = 0;\n let carry = 0;\n let last = performance.now();\n\n const pose = (): Pose => ({\n x: body.x,\n y: body.y,\n rotation: angle,\n scale:\n 1 - (1 - PHYSICS.depthScale) * Math.min(1, body.steps / depthSteps),\n });\n\n const finish = (scored: boolean): void => {\n this.#frame = 0;\n this.#host.trajectory.clear();\n this.#host.setFlying(false);\n this.#host.setOverBoard(false);\n const final = pose();\n card.place(final);\n if (scored) {\n this.#card = null;\n this.#host.scored(card, final, court);\n return;\n }\n void this.#returnToRest(card, final, court).then(() => {\n this.#card = null;\n this.#host.missed(card);\n });\n };\n\n const frame = (now: number): void => {\n carry += Math.min(0.1, Math.max(0, (now - last) / 1000));\n last = now;\n while (carry >= PHYSICS.step) {\n carry -= PHYSICS.step;\n const result = step(body, court);\n body = result.body;\n angle += spin * PHYSICS.step;\n\n if (result.events.includes('score')) {\n finish(true);\n return;\n }\n\n if (result.events.includes('board') || result.events.includes('rim')) {\n spin *= 0.6;\n }\n\n if (result.events.includes('floor')) {\n bounces += 1;\n spin *= 0.5;\n }\n\n if (\n bounces > PHYSICS.maxFloorBounces ||\n timeOf(body) > PHYSICS.maxFlightTime\n ) {\n finish(false);\n return;\n }\n }\n\n card.place(pose());\n this.#host.trajectory.hideBefore(body.steps);\n this.#host.setOverBoard(contains(court.board, body));\n this.#frame = requestAnimationFrame(frame);\n };\n this.#frame = requestAnimationFrame(frame);\n }\n\n /**\n * Holds `card` and draws the shot of each pull it is given, until the aim\n * ends. With `follow`, the card moves with the pull; otherwise it stays on\n * its spot.\n */\n #takeAim(card: CardView, court: Court, { follow }: { follow: boolean }): Aim {\n this.#card = card;\n this.#host.setAiming(true);\n\n const power = launchPower(court);\n const listeners = new AbortController();\n let pull: Vector = { x: 0, y: 0 };\n let pose: Pose = {\n ...court.rest,\n rotation: REST_ROTATION,\n scale: GRAB_SCALE,\n };\n card.place(pose);\n\n const aim = (to: Vector): void => {\n pull = to;\n const shown = stretchPull(pull, court.unit);\n pose = {\n x: court.rest.x + (follow ? shown.x : 0),\n y: court.rest.y + (follow ? shown.y : 0),\n rotation: REST_ROTATION + tiltOf(shown, court.unit),\n scale: GRAB_SCALE,\n };\n card.place(pose);\n if (isPullEnough(pull, court.unit)) {\n const body = launch(pose, pullToVelocity(pull, court.unit, power));\n this.#host.trajectory.show(previewPath(body, court).dots, court.unit);\n } else {\n this.#host.trajectory.clear();\n }\n };\n\n const end = (shoot: boolean): void => {\n listeners.abort();\n this.#endAim = null;\n this.#host.setAiming(false);\n\n if (shoot && isPullEnough(pull, court.unit)) {\n const body = launch(pose, pullToVelocity(pull, court.unit, power));\n this.#host.launched(card);\n this.#fly(card, body, pose.rotation, court);\n return;\n }\n this.#host.trajectory.clear();\n void this.#returnToRest(card, pose, court).then(() => {\n this.#card = null;\n });\n };\n this.#endAim = () => end(false);\n\n return { signal: listeners.signal, aim, end };\n }\n\n async #returnToRest(card: CardView, from: Pose, court: Court): Promise<void> {\n const rest: Pose = { ...court.rest, rotation: REST_ROTATION, scale: 1 };\n const { width, height } = card.size();\n await play(\n card.element,\n [poseStyle(from, width, height), poseStyle(rest, width, height)],\n {\n duration: prefersReducedMotion() ? 0 : 520,\n easing: 'cubic-bezier(0.34, 1.4, 0.64, 1)',\n commit: true,\n }\n );\n card.release();\n }\n}\n","/**\n * An HTML element with its attributes and children.\n */\nexport function createElement<TTagName extends keyof HTMLElementTagNameMap>(\n tag: TTagName,\n attributes: Record<string, string> = {},\n children: readonly (Node | string)[] = []\n): HTMLElementTagNameMap[TTagName] {\n const element = document.createElement(tag);\n for (const [name, value] of Object.entries(attributes)) {\n element.setAttribute(name, value);\n }\n element.append(...children);\n return element;\n}\n\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n\n/**\n * An SVG element with its attributes and children, in the SVG namespace.\n */\nexport function createSvgElement<TTagName extends keyof SVGElementTagNameMap>(\n tag: TTagName,\n attributes: Record<string, string | number> = {},\n children: readonly SVGElement[] = []\n): SVGElementTagNameMap[TTagName] {\n const element = document.createElementNS(SVG_NAMESPACE, tag);\n for (const [name, value] of Object.entries(attributes)) {\n element.setAttribute(name, String(value));\n }\n element.append(...children);\n return element;\n}\n\nconst icons = {\n upload:\n 'M12 15V4.5m0 0L8 8.5m4-4 4 4M5 14v3.5A2.5 2.5 0 0 0 7.5 20h9a2.5 2.5 0 0 0 2.5-2.5V14',\n check: 'M7.5 12.5l3 3 6-6.5',\n retry: 'M19.5 12a7.5 7.5 0 1 1-2.2-5.3M19.5 4.5v4h-4',\n} as const;\n\n/**\n * Icons drawn by `icon()`.\n */\nexport type IconName = keyof typeof icons;\n\n/**\n * A 24×24 stroked icon, hidden from assistive technology.\n */\nexport function icon(\n name: IconName,\n attributes: Record<string, string> = {}\n): SVGSVGElement {\n return createSvgElement(\n 'svg',\n {\n viewBox: '0 0 24 24',\n 'aria-hidden': 'true',\n focusable: 'false',\n class: 'icon',\n ...attributes,\n },\n [createSvgElement('path', { d: icons[name] })]\n );\n}\n\n/**\n * Replaces the children of a slot: its fallback content.\n */\nexport function setFallback(slot: HTMLSlotElement, text: string): void {\n if (slot.textContent !== text) slot.textContent = text;\n}\n","/**\n * Why a file was turned away:\n * - `type`: it does not match `accept`.\n * - `size`: it is larger than `max-size`.\n * - `count`: it is one file more than `max-files` allows, or than one without\n * `multiple`.\n */\nexport type RejectReason = 'type' | 'size' | 'count';\n\n/**\n * Visible copy and accessible names. The defaults are the copy of the\n * reference design; override any of them with the `messages` property, or the\n * first four with slots.\n */\nexport interface Messages {\n /**\n * Heading of the element. The `title` slot replaces it.\n */\n title: string;\n\n /**\n * Line under the heading. The `description` slot replaces it.\n */\n description: string;\n\n /**\n * Main text of the dropzone. The `prompt` slot replaces it.\n */\n prompt: string;\n\n /**\n * Text under the prompt. The `hint` slot replaces it.\n */\n hint: string;\n\n /**\n * Accessible name of the dropzone button.\n */\n dropzone: string;\n\n /**\n * Label of the pill that counts the files in the basket.\n */\n counter: string;\n\n /**\n * Accessible name of a card waiting on the court.\n */\n shoot: (name: string) => string;\n\n /**\n * Status of a file in the basket when there is no uploader.\n */\n ready: string;\n\n /**\n * Status of a file waiting for a free upload slot.\n */\n queued: string;\n\n /**\n * Status of a file being uploaded.\n */\n uploading: string;\n\n /**\n * Status of a file the uploader stored.\n */\n uploaded: string;\n\n /**\n * Status of a file whose upload failed.\n */\n failed: string;\n\n /**\n * Accessible name and tooltip of the retry button of a row.\n */\n retry: (name: string) => string;\n\n /**\n * Accessible name of the progress bar of a row.\n */\n progress: (name: string) => string;\n\n /**\n * Validation message when `required` and empty.\n */\n required: string;\n\n /**\n * Announced when a file goes through the net.\n */\n scored: (name: string) => string;\n\n /**\n * Announced when a shot misses.\n */\n missed: (name: string) => string;\n\n /**\n * Announced when a file is turned away.\n */\n rejected: (name: string, reason: RejectReason) => string;\n\n /**\n * Announced when an upload succeeds.\n */\n complete: (name: string) => string;\n\n /**\n * Announced when an upload fails.\n */\n error: (name: string) => string;\n}\n\n/**\n * The copy of the reference design, in English.\n */\nexport const defaultMessages: Messages = {\n title: 'Upload files',\n description: 'Drag and drop, or take the shot.',\n prompt: 'Drop files here',\n hint: 'or take the shot',\n dropzone: 'Choose files to upload',\n counter: 'Uploaded',\n shoot: (name) => `Shoot ${name}`,\n ready: 'Ready',\n queued: 'Waiting…',\n uploading: 'Uploading…',\n uploaded: 'Uploaded',\n failed: 'Upload failed',\n retry: (name) => `Retry ${name}`,\n progress: (name) => `${name} upload progress`,\n required: 'Add at least one file.',\n scored: (name) => `${name}: nothing but net.`,\n missed: (name) => `Missed ${name}. Take the shot again.`,\n rejected: (name, reason) =>\n reason === 'type'\n ? `${name} is not an accepted file type.`\n : reason === 'size'\n ? `${name} is too large.`\n : `${name} is one file too many.`,\n complete: (name) => `${name} uploaded.`,\n error: (name) => `${name} failed to upload.`,\n};\n","export default \"@layer components {\\n .card {\\n --_depth: 0;\\n --_fold: calc(var(--_card-width) * 0.2);\\n\\n position: absolute;\\n top: 0;\\n left: 0;\\n inline-size: var(--_card-width);\\n block-size: var(--_card-height);\\n translate: calc(var(--_rest-x, 0px) - 50% - var(--_depth) * 0.45rem)\\n calc(var(--_rest-y, 0px) - 50% + var(--_depth) * 0.2rem);\\n /* Keep -6deg in sync with REST_ROTATION in shot-controller.ts. */\\n rotate: calc(-6deg - var(--_depth) * 7deg);\\n pointer-events: auto;\\n touch-action: none;\\n user-select: none;\\n -webkit-user-drag: none;\\n cursor: grab;\\n filter: drop-shadow(0 0.5rem 0.75rem rgb(15 17 21 / 0.13));\\n\\n &[data-depth='1'] {\\n --_depth: 1;\\n }\\n\\n &[data-depth='2'] {\\n --_depth: 2;\\n }\\n\\n &[data-depth='hidden'] {\\n visibility: hidden;\\n }\\n\\n &:focus-visible {\\n outline: var(--_focus-ring);\\n outline-offset: 4px;\\n border-radius: calc(var(--_card-width) * 0.1);\\n }\\n }\\n\\n .card-paper {\\n position: absolute;\\n inset: 0;\\n border-radius: calc(var(--_card-width) * 0.1);\\n background: var(--_file-surface);\\n clip-path: polygon(\\n 0 0,\\n calc(100% - var(--_fold)) 0,\\n 100% var(--_fold),\\n 100% 100%,\\n 0 100%\\n );\\n\\n &::after {\\n content: '';\\n position: absolute;\\n top: 0;\\n right: 0;\\n inline-size: var(--_fold);\\n block-size: var(--_fold);\\n border-end-start-radius: calc(var(--_fold) * 0.22);\\n background: linear-gradient(\\n to bottom left,\\n transparent 50%,\\n var(--_file-fold) 50%\\n );\\n }\\n }\\n\\n .card-artwork {\\n position: absolute;\\n inset: 22% 18% 40% 14%;\\n display: flex;\\n flex-direction: column;\\n justify-content: flex-start;\\n gap: calc(var(--_card-height) * 0.06);\\n\\n &[data-artwork='thumbnail'] {\\n inset: 12% 12% 34% 12%;\\n }\\n }\\n\\n .line {\\n display: block;\\n block-size: calc(var(--_card-height) * 0.05);\\n border-radius: 999px;\\n background: var(--_file-line);\\n\\n &:nth-child(2) {\\n inline-size: 82%;\\n }\\n\\n &:nth-child(3) {\\n inline-size: 92%;\\n }\\n }\\n\\n .thumbnail {\\n inline-size: 100%;\\n block-size: 100%;\\n object-fit: cover;\\n border-radius: calc(var(--_card-width) * 0.05);\\n }\\n\\n .card-badge {\\n position: absolute;\\n inset-inline-start: 12%;\\n inset-block-end: 12.5%;\\n padding: 0.18em 0.55em;\\n border-radius: 0.32em;\\n font-size: calc(var(--_card-width) * 0.12);\\n font-weight: 700;\\n line-height: 1.35;\\n letter-spacing: 0.02em;\\n color: #ffffff;\\n background: var(--_file-color, var(--_file-badge));\\n white-space: nowrap;\\n }\\n\\n .trajectory {\\n position: absolute;\\n inset: 0;\\n inline-size: 100%;\\n block-size: 100%;\\n z-index: 0;\\n overflow: visible;\\n }\\n\\n .dot {\\n fill: var(--_trajectory);\\n }\\n}\\n\";","export default \"@layer components {\\n .title {\\n font-size: clamp(1.5rem, 3cqi + 1rem, 2rem);\\n font-weight: 700;\\n line-height: 1.25;\\n letter-spacing: -0.015em;\\n text-wrap: balance;\\n }\\n\\n .description {\\n margin-block-start: 0.1875rem;\\n font-size: clamp(1rem, 1cqi + 0.85rem, 1.125rem);\\n color: var(--_muted-foreground);\\n text-wrap: balance;\\n }\\n\\n .counter {\\n display: inline-flex;\\n flex: none;\\n margin-block-start: 0.375rem;\\n align-items: center;\\n gap: 0.625rem;\\n padding: 0.3125rem 0.875rem;\\n border-radius: 999px;\\n background: var(--_counter-background);\\n white-space: nowrap;\\n }\\n\\n .counter-label {\\n font-size: 0.84375rem;\\n color: var(--_muted-foreground);\\n }\\n\\n .counter-value {\\n display: inline-block;\\n min-inline-size: 1ch;\\n font-size: 1.0625rem;\\n font-weight: 600;\\n font-variant-numeric: tabular-nums;\\n text-align: center;\\n }\\n\\n .dropzone {\\n position: absolute;\\n inset: 0;\\n z-index: 0;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n padding-block-start: 7.5%;\\n border-radius: var(--_radius);\\n color: var(--_muted-foreground);\\n background: var(--_surface);\\n transition: background-color 180ms ease;\\n\\n &:focus-visible {\\n outline: var(--_focus-ring);\\n outline-offset: 4px;\\n }\\n\\n &:disabled {\\n cursor: not-allowed;\\n }\\n }\\n\\n .dropzone-outline {\\n position: absolute;\\n inset: 0;\\n inline-size: 100%;\\n block-size: 100%;\\n pointer-events: none;\\n\\n & rect {\\n fill: none;\\n stroke: var(--_border);\\n stroke-width: 1.5;\\n stroke-dasharray: 8 6;\\n transition: stroke 180ms ease;\\n }\\n }\\n\\n .dropzone-icon {\\n inline-size: 2.125rem;\\n block-size: 2.125rem;\\n stroke-width: 1.6;\\n }\\n\\n .prompt {\\n margin-block-start: 0.6875rem;\\n font-size: clamp(1.125rem, 2cqi + 0.8rem, 1.375rem);\\n font-weight: 500;\\n line-height: 1.25;\\n letter-spacing: -0.01em;\\n color: var(--_foreground);\\n }\\n\\n .hint {\\n margin-block-start: 0.25rem;\\n font-size: 0.9375rem;\\n color: var(--_subtle-foreground);\\n }\\n\\n .square {\\n position: absolute;\\n inset-inline-start: 33%;\\n inset-block-start: 64.6%;\\n z-index: 0;\\n inline-size: 34%;\\n block-size: 29.9%;\\n border: 3px solid var(--_accent);\\n border-radius: 3px;\\n pointer-events: none;\\n }\\n\\n .rim {\\n position: absolute;\\n inset-inline-start: 29.5%;\\n inset-block-start: 100%;\\n inline-size: 41%;\\n translate: 0 -55%;\\n pointer-events: none;\\n }\\n\\n .rim-arc {\\n fill: none;\\n stroke-width: 5.5;\\n stroke-linecap: round;\\n }\\n\\n .rim-back {\\n z-index: 1;\\n\\n & .rim-arc {\\n stroke: color-mix(in oklab, var(--_accent) 40%, var(--_accent-strong));\\n }\\n }\\n\\n .rim-bracket {\\n fill: var(--_accent-strong);\\n }\\n\\n .rim-front {\\n z-index: 3;\\n\\n & .rim-arc {\\n stroke: var(--_accent);\\n }\\n }\\n\\n .net {\\n position: absolute;\\n inset-inline-start: 29.5%;\\n inset-block-start: 101.5%;\\n z-index: 3;\\n inline-size: 41%;\\n aspect-ratio: 164 / 104;\\n transform-origin: 50% 0;\\n pointer-events: none;\\n\\n & line {\\n stroke: var(--_net);\\n stroke-width: 1.75;\\n stroke-linecap: round;\\n vector-effect: non-scaling-stroke;\\n }\\n }\\n\\n .score-pop {\\n position: absolute;\\n inset-inline-start: 68%;\\n inset-block-start: 59.5%;\\n z-index: 4;\\n font-size: calc(var(--_hoop-size) * 0.08);\\n font-weight: 800;\\n line-height: 1;\\n letter-spacing: -0.02em;\\n color: var(--_accent);\\n opacity: 0;\\n pointer-events: none;\\n }\\n}\\n\";","export default \"@layer tokens, reset, layout, components, states, motion;\\n\";","export default \"@layer layout {\\n :host {\\n display: flex;\\n flex-direction: column;\\n position: relative;\\n container-type: inline-size;\\n min-block-size: 36rem;\\n font-family: var(--_font-family);\\n font-size: 1rem;\\n line-height: 1.4;\\n color: var(--_foreground);\\n background: var(--_background);\\n -webkit-font-smoothing: antialiased;\\n -moz-osx-font-smoothing: grayscale;\\n }\\n\\n :host([hidden]) {\\n display: none;\\n }\\n\\n .frame {\\n position: relative;\\n display: flex;\\n flex: 1 1 auto;\\n flex-direction: column;\\n padding: var(--_gutter);\\n }\\n\\n .header {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: flex-start;\\n justify-content: space-between;\\n gap: 0.75rem 1rem;\\n }\\n\\n .hoop {\\n position: relative;\\n flex: none;\\n align-self: center;\\n inline-size: var(--_hoop-size);\\n aspect-ratio: 400 / 268;\\n margin-block-start: calc(var(--_hoop-size) * 0.1125);\\n }\\n\\n .court {\\n position: relative;\\n flex: 1 1 auto;\\n min-block-size: calc(var(--_hoop-size) * 0.96);\\n }\\n\\n .frame:has(.list:not([hidden])) {\\n padding-block-end: calc(var(--_gutter) * 0.65);\\n\\n & .court {\\n min-block-size: calc(var(--_hoop-size) * 0.8);\\n }\\n }\\n\\n .spot {\\n position: absolute;\\n inset-inline-start: calc(var(--_hoop-size) * 0.13);\\n inset-block-end: calc(var(--_hoop-size) * 0.3);\\n inline-size: var(--_card-width);\\n block-size: var(--_card-height);\\n pointer-events: none;\\n }\\n\\n .list {\\n display: grid;\\n flex: none;\\n gap: 0.75rem;\\n }\\n\\n .layer {\\n position: absolute;\\n inset: 0;\\n z-index: 2;\\n pointer-events: none;\\n }\\n}\\n\";","export default \"@layer components {\\n .item {\\n display: grid;\\n grid-template-columns: auto minmax(0, 1fr) minmax(5rem, 11.25rem) 1.875rem;\\n align-items: center;\\n gap: 0.5rem 0.9375rem;\\n padding: 1.0625rem 1.25rem 1.0625rem 1.375rem;\\n border-radius: 1rem;\\n background: var(--_surface);\\n box-shadow: var(--_shadow);\\n transition:\\n opacity 320ms ease,\\n translate 320ms cubic-bezier(0.22, 1, 0.36, 1);\\n\\n @starting-style {\\n opacity: 0;\\n translate: 0 0.75rem;\\n }\\n }\\n\\n @container (inline-size < 30rem) {\\n .item {\\n grid-template-columns: auto minmax(0, 1fr) 1.875rem;\\n }\\n\\n .item-progress {\\n grid-column: 1 / -1;\\n grid-row: 2;\\n }\\n\\n .item-end {\\n grid-column: 3;\\n grid-row: 1;\\n }\\n }\\n\\n .item-icon {\\n --_card-width: 1.8125rem;\\n --_card-height: 2.375rem;\\n --_fold: 0.5625rem;\\n\\n position: relative;\\n inline-size: var(--_card-width);\\n block-size: var(--_card-height);\\n filter: drop-shadow(0 1px 1px rgb(15 17 21 / 0.08));\\n }\\n\\n .item-paper {\\n position: absolute;\\n inset: 0;\\n border-radius: 0.1875rem;\\n background: color-mix(\\n in oklab,\\n var(--_file-line) 45%,\\n var(--_file-surface)\\n );\\n clip-path: polygon(\\n 0 0,\\n calc(100% - var(--_fold)) 0,\\n 100% var(--_fold),\\n 100% 100%,\\n 0 100%\\n );\\n\\n &::after {\\n content: '';\\n position: absolute;\\n top: 0;\\n right: 0;\\n inline-size: var(--_fold);\\n block-size: var(--_fold);\\n background: linear-gradient(\\n to bottom left,\\n transparent 50%,\\n var(--_file-line) 50%\\n );\\n }\\n }\\n\\n .item-artwork {\\n position: absolute;\\n inset: 24% 16% 42% 16%;\\n display: flex;\\n flex-direction: column;\\n gap: 0.125rem;\\n\\n & .line {\\n block-size: 0.125rem;\\n background: var(--_file-line);\\n }\\n\\n &[data-artwork='thumbnail'] {\\n inset: 8% 8% 36% 8%;\\n }\\n }\\n\\n .item-badge {\\n position: absolute;\\n inset-inline-start: 12%;\\n inset-block-end: 12%;\\n padding: 0 0.25em;\\n border-radius: 0.2em;\\n font-size: 0.375rem;\\n font-weight: 700;\\n line-height: 1.5;\\n color: #ffffff;\\n background: var(--_file-color, var(--_file-badge));\\n }\\n\\n .item-meta {\\n display: grid;\\n gap: 0.125rem;\\n min-inline-size: 0;\\n }\\n\\n .item-name {\\n overflow: hidden;\\n font-size: clamp(1rem, 1.5cqi + 0.5rem, 1.1875rem);\\n font-weight: 600;\\n line-height: 1.3;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n }\\n\\n .item-size {\\n font-size: 0.875rem;\\n color: var(--_subtle-foreground);\\n font-variant-numeric: tabular-nums;\\n }\\n\\n .item-progress {\\n display: grid;\\n gap: 0.8125rem;\\n }\\n\\n .item-status {\\n font-size: 0.875rem;\\n line-height: 1.2;\\n color: var(--_subtle-foreground);\\n }\\n\\n .progress {\\n display: block;\\n block-size: 0.3125rem;\\n overflow: hidden;\\n border-radius: 999px;\\n background: var(--_track);\\n }\\n\\n .progress-bar {\\n display: block;\\n block-size: 100%;\\n border-radius: inherit;\\n background: var(--_accent);\\n transform-origin: 0 50%;\\n scale: 0 1;\\n transition:\\n scale 240ms ease-out,\\n background-color 240ms ease;\\n }\\n\\n .item-end {\\n display: grid;\\n place-items: center;\\n inline-size: 1.875rem;\\n block-size: 1.875rem;\\n }\\n\\n .item-check {\\n display: grid;\\n place-items: center;\\n inline-size: 1.875rem;\\n block-size: 1.875rem;\\n border-radius: 50%;\\n color: #ffffff;\\n background: var(--_success);\\n\\n & .icon {\\n inline-size: 1.3125rem;\\n block-size: 1.3125rem;\\n stroke-width: 2.75;\\n }\\n }\\n\\n .item-retry {\\n display: grid;\\n place-items: center;\\n inline-size: 1.875rem;\\n block-size: 1.875rem;\\n border-radius: 50%;\\n color: var(--_danger);\\n\\n &:hover {\\n background: color-mix(in oklab, var(--_danger) 12%, transparent);\\n }\\n\\n &:focus-visible {\\n outline: var(--_focus-ring);\\n outline-offset: 2px;\\n }\\n\\n & .icon {\\n inline-size: 1.25rem;\\n block-size: 1.25rem;\\n }\\n }\\n\\n .item[data-status='ready'] .progress-bar {\\n background: var(--_subtle-foreground);\\n }\\n\\n .item[data-status='uploaded'] {\\n & .item-status {\\n color: var(--_success);\\n }\\n\\n & .progress-bar {\\n background: var(--_success);\\n }\\n }\\n\\n .item[data-status='error'] {\\n & .item-status {\\n color: var(--_danger);\\n }\\n\\n & .progress-bar {\\n background: var(--_danger);\\n }\\n }\\n}\\n\";","export default \"@layer motion {\\n @keyframes basketball-upload-shake {\\n 0%,\\n 100% {\\n translate: 0 0;\\n }\\n 20% {\\n translate: -0.375rem 0;\\n }\\n 40% {\\n translate: 0.3125rem 0;\\n }\\n 60% {\\n translate: -0.1875rem 0;\\n }\\n 80% {\\n translate: 0.125rem 0;\\n }\\n }\\n\\n :host(:state(rejected)) .dropzone {\\n animation: basketball-upload-shake 420ms ease-in-out;\\n }\\n\\n @media (prefers-reduced-motion: reduce) {\\n :host(:state(rejected)) .dropzone {\\n animation: none;\\n }\\n\\n .item,\\n .progress-bar,\\n .dropzone,\\n .dropzone-outline rect {\\n transition: none;\\n }\\n }\\n}\\n\";","export default \"@layer reset {\\n *,\\n *::before,\\n *::after {\\n box-sizing: border-box;\\n }\\n\\n [hidden] {\\n display: none !important;\\n }\\n\\n h2,\\n p,\\n ul {\\n margin: 0;\\n padding: 0;\\n }\\n\\n ul {\\n list-style: none;\\n }\\n\\n button {\\n margin: 0;\\n padding: 0;\\n font: inherit;\\n color: inherit;\\n background: none;\\n border: 0;\\n cursor: pointer;\\n -webkit-tap-highlight-color: transparent;\\n }\\n\\n img {\\n display: block;\\n max-inline-size: 100%;\\n }\\n\\n svg {\\n display: block;\\n overflow: visible;\\n }\\n\\n .icon {\\n fill: none;\\n stroke: currentColor;\\n stroke-width: 1.75;\\n stroke-linecap: round;\\n stroke-linejoin: round;\\n }\\n\\n .visually-hidden {\\n position: absolute;\\n inline-size: 1px;\\n block-size: 1px;\\n overflow: hidden;\\n clip-path: inset(50%);\\n white-space: nowrap;\\n }\\n}\\n\";","export default \"@layer states {\\n :host(:state(drop-target)) .dropzone {\\n background: var(--_accent-surface);\\n\\n & .dropzone-outline rect {\\n stroke: var(--_accent);\\n }\\n }\\n\\n :host(:state(aiming)) {\\n cursor: grabbing;\\n\\n & .card {\\n cursor: grabbing;\\n }\\n }\\n\\n :host(:state(aiming)),\\n :host(:state(flying)) {\\n user-select: none;\\n }\\n\\n :host(:state(disabled)) {\\n & .frame {\\n cursor: not-allowed;\\n }\\n\\n & .dropzone,\\n & .card {\\n filter: grayscale(1);\\n opacity: 0.55;\\n }\\n }\\n}\\n\";","export default \"@layer tokens {\\n :host {\\n color-scheme: light dark;\\n\\n --_background: var(\\n --basketball-upload-background,\\n light-dark(#eff1f5, #0f1115)\\n );\\n --_foreground: var(\\n --basketball-upload-foreground,\\n light-dark(#0f1115, #f4f5f7)\\n );\\n --_muted-foreground: var(\\n --basketball-upload-muted-foreground,\\n light-dark(#6b6f78, #a3a8b2)\\n );\\n --_subtle-foreground: var(\\n --basketball-upload-subtle-foreground,\\n light-dark(#989a9f, #7c818b)\\n );\\n --_surface: var(--basketball-upload-surface, light-dark(#ffffff, #181b21));\\n --_border: var(--basketball-upload-border, light-dark(#cbccd1, #3a3f48));\\n --_radius: var(--basketball-upload-radius, 1.125rem);\\n\\n --_accent: var(--basketball-upload-accent, light-dark(#f0612e, #f26a39));\\n --_accent-strong: var(\\n --basketball-upload-accent-strong,\\n light-dark(#bd4d19, #c4521f)\\n );\\n --_accent-surface: var(\\n --basketball-upload-accent-surface,\\n light-dark(#fff4ef, color-mix(in oklab, #f26a39 14%, #181b21))\\n );\\n --_trajectory: var(\\n --basketball-upload-trajectory,\\n color-mix(in oklab, var(--_accent) 60%, transparent)\\n );\\n --_net: var(--basketball-upload-net, light-dark(#a9abb3, #6b717c));\\n\\n --_counter-background: var(\\n --basketball-upload-counter-background,\\n light-dark(#e3e7ed, #232730)\\n );\\n --_track: var(--basketball-upload-track, light-dark(#e6e8ec, #2a2e36));\\n --_success: var(--basketball-upload-success, light-dark(#2fb06d, #34c07a));\\n --_danger: var(--basketball-upload-danger, light-dark(#d8374e, #f0606f));\\n\\n --_file-surface: var(--basketball-upload-file-surface, #ffffff);\\n --_file-line: var(--basketball-upload-file-line, #e4e5e9);\\n --_file-fold: var(--basketball-upload-file-fold, #e9eaee);\\n --_file-badge: var(--basketball-upload-file-badge, #6b7280);\\n\\n --_shadow: var(\\n --basketball-upload-shadow,\\n 0 1px 2px rgb(15 17 21 / 0.04),\\n 0 0.5rem 1.5rem rgb(15 17 21 / 0.07)\\n );\\n --_focus-ring: var(\\n --basketball-upload-focus-ring,\\n 2px solid var(--_accent)\\n );\\n --_font-family: var(\\n --basketball-upload-font-family,\\n Inter,\\n ui-sans-serif,\\n system-ui,\\n sans-serif\\n );\\n\\n --_gutter: var(--basketball-upload-gutter, clamp(1.25rem, 8cqi, 3.75rem));\\n --_hoop-size: var(\\n --basketball-upload-hoop-size,\\n min(25rem, 100cqi - 2 * var(--_gutter))\\n );\\n --_card-width: calc(var(--_hoop-size) * 0.2375);\\n --_card-height: calc(var(--_hoop-size) * 0.2875);\\n }\\n\\n :host([theme='light']) {\\n color-scheme: light;\\n }\\n\\n :host([theme='dark']) {\\n color-scheme: dark;\\n }\\n}\\n\";","import card from './card.css';\nimport hoop from './hoop.css';\nimport layers from './layers.css';\nimport layout from './layout.css';\nimport list from './list.css';\nimport motion from './motion.css';\nimport reset from './reset.css';\nimport states from './states.css';\nimport tokens from './tokens.css';\n\nconst SOURCES = [\n layers,\n tokens,\n reset,\n layout,\n hoop,\n card,\n list,\n states,\n motion,\n];\n\nlet sheet: CSSStyleSheet | undefined;\n\n/**\n * One constructed stylesheet shared by every element, created on first use rather than at module evaluation:\n * the module must be importable where `CSSStyleSheet` does not exist (SSR).\n */\nexport function getStyleSheet(): CSSStyleSheet {\n if (!sheet) {\n sheet = new CSSStyleSheet();\n sheet.replaceSync(SOURCES.join('\\n'));\n }\n return sheet;\n}\n","import type { ResolvedFileType } from '../../file-types/types.ts';\nimport { createElement } from '../dom.ts';\nimport { poseStyle, type Pose } from '../motion.ts';\n\n/**\n * The CSS color of a file type: its token when set, its own color otherwise.\n */\nexport function fileColor(type: ResolvedFileType): string {\n return `var(--basketball-upload-file-${type.kind}, ${type.color ?? 'var(--_file-badge)'})`;\n}\n\nexport interface Artwork {\n readonly element: HTMLElement;\n dispose(): void;\n}\n\nfunction lines(): HTMLElement[] {\n return Array.from({ length: 3 }, () =>\n createElement('span', { class: 'line' })\n );\n}\n\n/**\n * The body of a file card: text lines, a thumbnail, or a node of your own.\n */\nexport function createArtwork(\n file: File,\n type: ResolvedFileType,\n attributes: Record<string, string>\n): Artwork {\n const element = createElement('span', attributes);\n let url: string | null = null;\n const revoke = (): void => {\n if (url) URL.revokeObjectURL(url);\n url = null;\n };\n\n if (\n type.artwork === 'thumbnail' &&\n typeof URL.createObjectURL === 'function'\n ) {\n url = URL.createObjectURL(file);\n const image = createElement('img', {\n class: 'thumbnail',\n alt: '',\n src: url,\n draggable: 'false',\n decoding: 'async',\n });\n image.addEventListener('load', revoke, { once: true });\n image.addEventListener(\n 'error',\n () => {\n revoke();\n element.dataset.artwork = 'lines';\n image.replaceWith(...lines());\n },\n { once: true }\n );\n element.dataset.artwork = 'thumbnail';\n element.append(image);\n } else if (typeof type.artwork === 'function') {\n element.dataset.artwork = 'custom';\n element.append(type.artwork(file));\n } else {\n element.dataset.artwork = 'lines';\n element.append(...lines());\n }\n\n return { element, dispose: revoke };\n}\n\nexport interface CardView {\n readonly element: HTMLButtonElement;\n readonly file: File;\n readonly type: ResolvedFileType;\n\n /**\n * Size before scaling, in pixels.\n */\n size(): { width: number; height: number };\n\n /**\n * Takes the card out of the CSS layout and draws it at `pose`.\n */\n place(pose: Pose): void;\n\n /**\n * Hands the card back to the CSS layout (its spot on the court).\n */\n release(): void;\n\n dispose(): void;\n}\n\nexport function createCard(\n file: File,\n type: ResolvedFileType,\n label: string\n): CardView {\n const artwork = createArtwork(file, type, {\n class: 'card-artwork',\n part: 'file-artwork',\n });\n const element = createElement(\n 'button',\n {\n type: 'button',\n class: 'card',\n part: `file file-${type.kind}`,\n 'data-kind': type.kind,\n 'aria-label': label,\n },\n [\n createElement('span', { class: 'card-paper' }, [\n artwork.element,\n createElement('span', { class: 'card-badge', part: 'file-badge' }, [\n type.label,\n ]),\n ]),\n ]\n );\n element.style.setProperty('--_file-color', fileColor(type));\n\n const size = (): { width: number; height: number } => ({\n width: element.offsetWidth,\n height: element.offsetHeight,\n });\n\n return {\n element,\n file,\n type,\n size,\n place(pose) {\n const { width, height } = size();\n const style = poseStyle(pose, width, height);\n element.style.translate = style.translate;\n element.style.rotate = style.rotate;\n element.style.scale = style.scale;\n },\n release() {\n element.style.removeProperty('translate');\n element.style.removeProperty('rotate');\n element.style.removeProperty('scale');\n element.style.removeProperty('opacity');\n },\n dispose() {\n artwork.dispose();\n element.remove();\n },\n };\n}\n","import { createElement, setFallback } from '../dom.ts';\nimport type { Messages } from '../messages.ts';\nimport { play } from '../motion.ts';\n\nexport interface HeaderView {\n readonly element: HTMLElement;\n update(messages: Messages): void;\n\n /**\n * Shows the number of files in the basket; `bump` animates an increase.\n */\n setCount(count: number, bump: boolean): void;\n}\n\nexport function createHeader(): HeaderView {\n const title = createElement('slot', { name: 'title' });\n const description = createElement('slot', { name: 'description' });\n const counterLabel = createElement('span', {\n class: 'counter-label',\n part: 'counter-label',\n });\n const counterValue = createElement(\n 'span',\n { class: 'counter-value', part: 'counter-value' },\n ['0']\n );\n\n const element = createElement('header', { class: 'header', part: 'header' }, [\n createElement('div', { class: 'heading' }, [\n createElement('h2', { class: 'title', part: 'title' }, [title]),\n createElement('p', { class: 'description', part: 'description' }, [\n description,\n ]),\n ]),\n createElement('p', { class: 'counter', part: 'counter' }, [\n counterLabel,\n counterValue,\n ]),\n ]);\n\n let count = 0;\n\n return {\n element,\n update(messages) {\n setFallback(title, messages.title);\n setFallback(description, messages.description);\n counterLabel.textContent = messages.counter;\n },\n setCount(value, bump) {\n if (value === count) return;\n const increased = value > count;\n count = value;\n counterValue.textContent = String(value);\n if (bump && increased) {\n void play(\n counterValue,\n [{ scale: '1' }, { scale: '1.35' }, { scale: '1' }],\n { duration: 360, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' }\n );\n }\n },\n };\n}\n","import { createElement, createSvgElement, icon, setFallback } from '../dom.ts';\nimport type { Messages } from '../messages.ts';\nimport { play } from '../motion.ts';\n\n/**\n * The hoop, drawn in layers so a card can pass between them: the dropzone is\n * the backboard, then the back of the rim, then (in the card layer above\n * this element) the cards, then the front of the rim and the net.\n */\nexport interface HoopView {\n readonly element: HTMLElement;\n\n readonly dropzone: HTMLButtonElement;\n\n readonly square: HTMLElement;\n\n /**\n * The front of the rim: its box is the rim the physics measures.\n */\n readonly rim: SVGSVGElement;\n\n readonly net: SVGSVGElement;\n\n update(messages: Messages): void;\n\n /**\n * The net swings as a card goes through.\n */\n swish(): void;\n\n /**\n * The \"+1\" over the square.\n */\n celebrate(reducedMotion: boolean): void;\n}\n\n/**\n * Net in a 164×104 box: the rim width on top, narrowing towards the bottom.\n */\nfunction netLines(): SVGElement[] {\n const top = [3, 29.3, 55.7, 82, 108.3, 134.7, 161];\n const bottom = [31, 48, 65, 82, 99, 116, 133];\n const [topY, bottomY] = [2, 102];\n const lines: SVGElement[] = [];\n\n const line = (\n fromX: number,\n fromY: number,\n toX: number,\n toY: number\n ): void => {\n lines.push(\n createSvgElement('line', { x1: fromX, y1: fromY, x2: toX, y2: toY })\n );\n };\n\n for (let index = 0; index < top.length; index += 1) {\n const x = top[index] ?? 0;\n const left = bottom[index - 1];\n const right = bottom[index + 1];\n if (left !== undefined) line(x, topY, left, bottomY);\n if (right !== undefined) line(x, topY, right, bottomY);\n }\n line(top[0] ?? 0, topY, bottom[0] ?? 0, bottomY);\n line(top[top.length - 1] ?? 0, topY, bottom[bottom.length - 1] ?? 0, bottomY);\n\n for (const y of [42, 70]) {\n const progress = (y - topY) / (bottomY - topY);\n const inset = (31 - 3) * progress;\n line(3 + inset, y, 161 - inset, y);\n }\n return lines;\n}\n\nexport function createHoop(): HoopView {\n const prompt = createElement('slot', { name: 'prompt' });\n const hint = createElement('slot', { name: 'hint' });\n\n const outline = createSvgElement(\n 'svg',\n { class: 'dropzone-outline', 'aria-hidden': 'true' },\n [\n createSvgElement('rect', {\n x: 0,\n y: 0,\n width: '100%',\n height: '100%',\n rx: '4.5%',\n ry: '6.7%',\n }),\n ]\n );\n\n const dropzone = createElement(\n 'button',\n { type: 'button', class: 'dropzone', part: 'dropzone' },\n [\n outline,\n icon('upload', { class: 'icon dropzone-icon', part: 'dropzone-icon' }),\n createElement('span', { class: 'prompt', part: 'prompt' }, [prompt]),\n createElement('span', { class: 'hint', part: 'hint' }, [hint]),\n ]\n );\n\n const square = createElement('div', {\n class: 'square',\n part: 'backboard-square',\n });\n\n const rimBack = createSvgElement(\n 'svg',\n {\n class: 'rim rim-back',\n part: 'rim',\n viewBox: '0 0 164 18',\n 'aria-hidden': 'true',\n },\n [\n createSvgElement('path', {\n class: 'rim-arc',\n d: 'M3 10 A79 6.5 0 0 1 161 10',\n }),\n createSvgElement('rect', {\n class: 'rim-bracket',\n x: 70,\n y: 0.5,\n width: 24,\n height: 10,\n rx: 1.5,\n }),\n ]\n );\n const rim = createSvgElement(\n 'svg',\n {\n class: 'rim rim-front',\n part: 'rim',\n viewBox: '0 0 164 18',\n 'aria-hidden': 'true',\n },\n [\n createSvgElement('path', {\n class: 'rim-arc',\n d: 'M3 10 A79 6.5 0 0 0 161 10',\n }),\n ]\n );\n\n const net = createSvgElement(\n 'svg',\n {\n class: 'net',\n part: 'net',\n viewBox: '0 0 164 104',\n preserveAspectRatio: 'none',\n 'aria-hidden': 'true',\n },\n netLines()\n );\n\n const scorePop = createElement(\n 'span',\n { class: 'score-pop', part: 'score-pop', 'aria-hidden': 'true' },\n ['+1']\n );\n\n const element = createElement('div', { class: 'hoop', part: 'hoop' }, [\n dropzone,\n square,\n rimBack,\n rim,\n net,\n scorePop,\n ]);\n\n return {\n element,\n dropzone,\n square,\n rim,\n net,\n update(messages) {\n setFallback(prompt, messages.prompt);\n setFallback(hint, messages.hint);\n dropzone.setAttribute('aria-label', messages.dropzone);\n },\n celebrate(reducedMotion) {\n void play(\n scorePop,\n reducedMotion\n ? [\n { opacity: 0 },\n { opacity: 1, offset: 0.2 },\n { opacity: 1, offset: 0.7 },\n { opacity: 0 },\n ]\n : [\n { opacity: 0, translate: '0 0.3em', scale: '0.6' },\n { opacity: 1, translate: '0 0', scale: '1.1', offset: 0.12 },\n { opacity: 1, translate: '0 -0.1em', scale: '1', offset: 0.75 },\n { opacity: 0, translate: '0 -0.45em', scale: '1' },\n ],\n { duration: 1700, easing: 'ease-out' }\n );\n },\n swish() {\n void play(\n net,\n [\n { scale: '1 1' },\n { scale: '0.94 1.22', offset: 0.45 },\n { scale: '1.02 0.96', offset: 0.78 },\n { scale: '1 1' },\n ],\n { duration: 700, easing: 'ease-out' }\n );\n },\n };\n}\n","import { createElement } from '../dom.ts';\n\nexport interface LiveRegionView {\n readonly element: HTMLElement;\n announce(message: string): void;\n}\n\n/**\n * Polite announcements for what only shows as motion: scores, misses, uploads.\n */\nexport function createLiveRegion(): LiveRegionView {\n const element = createElement('div', {\n class: 'visually-hidden',\n role: 'status',\n 'aria-live': 'polite',\n });\n let frame = 0;\n\n return {\n element,\n announce(message) {\n element.textContent = '';\n if (typeof requestAnimationFrame !== 'function') {\n element.textContent = message;\n return;\n }\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => {\n element.textContent = message;\n });\n },\n };\n}\n","import type { PreviewDot } from '../../game/simulate.ts';\nimport { createSvgElement } from '../dom.ts';\n\n/**\n * Dot radius, in rim units: 3.6 px on the 164 px rim of the design.\n */\nconst DOT_RADIUS = 0.022;\n\nexport interface TrajectoryView {\n readonly element: SVGSVGElement;\n\n /**\n * Draws the dots of a preview. `unit` is the rim width in pixels.\n */\n show(dots: readonly PreviewDot[], unit: number): void;\n\n /**\n * Hides the dots the card has already passed.\n */\n hideBefore(steps: number): void;\n\n clear(): void;\n}\n\nexport function createTrajectory(): TrajectoryView {\n const element = createSvgElement('svg', {\n class: 'trajectory',\n part: 'trajectory',\n 'aria-hidden': 'true',\n });\n const circles: SVGCircleElement[] = [];\n let shown: readonly PreviewDot[] = [];\n\n return {\n element,\n show(dots, unit) {\n shown = dots;\n while (circles.length < dots.length) {\n const circle = createSvgElement('circle', { class: 'dot' });\n circles.push(circle);\n element.append(circle);\n }\n const radius = Math.max(1.5, unit * DOT_RADIUS).toFixed(2);\n circles.forEach((circle, index) => {\n const dot = dots[index];\n circle.toggleAttribute('hidden', !dot);\n if (!dot) return;\n circle.setAttribute('cx', dot.x.toFixed(1));\n circle.setAttribute('cy', dot.y.toFixed(1));\n circle.setAttribute('r', radius);\n });\n },\n hideBefore(steps) {\n shown.forEach((dot, index) => {\n if (dot.steps <= steps) circles[index]?.setAttribute('hidden', '');\n });\n },\n clear() {\n shown = [];\n for (const circle of circles) circle.setAttribute('hidden', '');\n },\n };\n}\n","const UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const;\n\n/**\n * Human readable size in decimal units, the way file managers show it: `2_400_000` → `2.4 MB`.\n * `locale` formats the number (`2,4 MB` in `de`); it defaults to the runtime's.\n */\nexport function formatBytes(bytes: number, locale?: string): string {\n let value = bytes > 0 ? bytes : 0;\n let unit = 0;\n while (value >= (unit === 0 ? 999.5 : 999.95) && unit < UNITS.length - 1) {\n value /= 1000;\n unit += 1;\n }\n const number = new Intl.NumberFormat(locale, {\n maximumFractionDigits: unit === 0 ? 0 : 1,\n }).format(value);\n\n return `${number} ${UNITS[unit]}`;\n}\n","import type { ResolvedFileType } from '../../file-types/types.ts';\nimport { formatBytes } from '../../upload/format.ts';\nimport type { UploadItem } from '../../upload/types.ts';\nimport { createElement, icon } from '../dom.ts';\nimport type { Messages } from '../messages.ts';\nimport { createArtwork, fileColor } from './card.ts';\n\nexport interface UploadListOptions {\n resolveType(file: File): ResolvedFileType;\n onRetry(id: string): void;\n locale(): string | undefined;\n}\n\nexport interface UploadListView {\n readonly element: HTMLUListElement;\n render(items: readonly UploadItem[], messages: Messages): void;\n dispose(): void;\n}\n\ninterface Row {\n readonly element: HTMLLIElement;\n update(item: UploadItem, messages: Messages): void;\n dispose(): void;\n}\n\nfunction statusText(item: UploadItem, messages: Messages): string {\n switch (item.status) {\n case 'ready':\n return messages.ready;\n case 'queued':\n return messages.queued;\n case 'uploading':\n return messages.uploading;\n case 'uploaded':\n return messages.uploaded;\n case 'error':\n return messages.failed;\n }\n}\n\nfunction createRow(\n item: UploadItem,\n type: ResolvedFileType,\n options: UploadListOptions\n): Row {\n const { file } = item;\n const artwork = createArtwork(file, type, { class: 'item-artwork' });\n const thumbnail = createElement(\n 'span',\n {\n class: 'item-icon',\n part: `item-icon item-icon-${type.kind}`,\n 'aria-hidden': 'true',\n },\n [\n createElement('span', { class: 'item-paper' }, [\n artwork.element,\n createElement('span', { class: 'item-badge' }, [type.label]),\n ]),\n ]\n );\n thumbnail.style.setProperty('--_file-color', fileColor(type));\n\n const status = createElement('span', {\n class: 'item-status',\n part: 'item-status',\n });\n const bar = createElement('span', { class: 'progress-bar' });\n const progress = createElement(\n 'span',\n {\n class: 'progress',\n part: 'progress',\n role: 'progressbar',\n 'aria-valuemin': '0',\n 'aria-valuemax': '100',\n },\n [bar]\n );\n const check = createElement(\n 'span',\n { class: 'item-check', 'aria-hidden': 'true' },\n [icon('check')]\n );\n const retry = createElement(\n 'button',\n { type: 'button', class: 'item-retry', part: 'retry' },\n [icon('retry')]\n );\n retry.addEventListener('click', () => options.onRetry(item.id));\n\n const element = createElement(\n 'li',\n { class: 'item', part: 'item', 'data-kind': type.kind },\n [\n thumbnail,\n createElement('span', { class: 'item-meta' }, [\n createElement('span', { class: 'item-name', part: 'item-name' }, [\n file.name,\n ]),\n createElement('span', { class: 'item-size', part: 'item-size' }, [\n formatBytes(file.size, options.locale()),\n ]),\n ]),\n createElement('span', { class: 'item-progress' }, [status, progress]),\n createElement('span', { class: 'item-end' }, [check, retry]),\n ]\n );\n\n return {\n element,\n update(next, messages) {\n element.dataset.status = next.status;\n status.textContent = statusText(next, messages);\n const percent = Math.round(next.progress * 100);\n progress.setAttribute('aria-valuenow', String(percent));\n progress.setAttribute('aria-label', messages.progress(file.name));\n bar.style.scale = `${next.progress} 1`;\n check.hidden = next.status !== 'uploaded';\n retry.hidden = next.status !== 'error';\n retry.setAttribute('aria-label', messages.retry(file.name));\n retry.title = messages.retry(file.name);\n },\n dispose() {\n artwork.dispose();\n element.remove();\n },\n };\n}\n\n/**\n * The list of files in the basket, with their upload progress.\n */\nexport function createUploadList(options: UploadListOptions): UploadListView {\n const element = createElement('ul', {\n class: 'list',\n part: 'list',\n role: 'list',\n });\n element.hidden = true;\n const rows = new Map<string, Row>();\n\n return {\n element,\n render(items, messages) {\n const present = new Set<string>();\n for (const item of items) {\n present.add(item.id);\n let row = rows.get(item.id);\n if (!row) {\n row = createRow(item, options.resolveType(item.file), options);\n rows.set(item.id, row);\n element.append(row.element);\n }\n row.update(item, messages);\n }\n for (const [id, row] of rows) {\n if (present.has(id)) continue;\n row.dispose();\n rows.delete(id);\n }\n element.hidden = items.length === 0;\n },\n dispose() {\n for (const row of rows.values()) row.dispose();\n rows.clear();\n },\n };\n}\n","import { PHYSICS } from '../game/config.ts';\nimport { courtFromRectangles, rimCenter, type Court } from '../game/court.ts';\nimport type { Vector } from '../game/vector.ts';\nimport { assertFileType, resolveFileType } from '../file-types/registry.ts';\nimport type { FileType, ResolvedFileType } from '../file-types/types.ts';\nimport { matchesAccept } from '../upload/accept.ts';\nimport { DEFAULT_CONCURRENCY, UploadQueue } from '../upload/upload-queue.ts';\nimport type { UploadItem, Uploader } from '../upload/types.ts';\nimport { ShotController } from './controllers/shot-controller.ts';\nimport { createElement } from './dom.ts';\nimport {\n defaultMessages,\n type Messages,\n type RejectReason,\n} from './messages.ts';\nimport {\n play,\n poseStyle,\n prefersReducedMotion,\n uprightOf,\n type Pose,\n} from './motion.ts';\nimport { getStyleSheet } from './styles/styles.ts';\nimport { createCard, type CardView } from './views/card.ts';\nimport { createHeader } from './views/header.ts';\nimport { createHoop } from './views/hoop.ts';\nimport { createLiveRegion } from './views/live-region.ts';\nimport { createTrajectory } from './views/trajectory.ts';\nimport { createUploadList, type UploadListView } from './views/upload-list.ts';\n\n/**\n * Color scheme of the element. `system` follows `prefers-color-scheme`.\n */\nexport type Theme = 'light' | 'dark' | 'system';\n\n/**\n * How a shot ended: through the net (a dunk included), or back on the court.\n */\nexport type ShotResult = 'score' | 'miss';\n\n/**\n * `CustomEvent`s dispatched by `<basketball-upload>`, keyed by event name. They bubble.\n */\nexport interface BasketballUploadEventMap {\n /**\n * A file did not pass `accept`, `max-size` or `max-files`, and stays out.\n */\n 'file-reject': CustomEvent<{ file: File; reason: RejectReason }>;\n\n /**\n * A card went through the net, dunks included, or a shot missed and the\n * card is back on the court.\n */\n shot: CustomEvent<{ file: File; result: ShotResult }>;\n\n /**\n * The uploader was called for an item.\n */\n 'upload-start': CustomEvent<{ item: UploadItem }>;\n\n /**\n * The uploader reported progress; `item.progress` has the new value.\n */\n 'upload-progress': CustomEvent<{ item: UploadItem }>;\n\n /**\n * An upload resolved; `item.response` has its value.\n */\n 'upload-success': CustomEvent<{ item: UploadItem }>;\n\n /**\n * An upload rejected; `item.error` has the reason. Aborted uploads (removed\n * items, `clear()`) do not fire it.\n */\n 'upload-error': CustomEvent<{ item: UploadItem }>;\n\n /**\n * Files entered or left the basket, or one changed status. Progress alone\n * does not fire it: `upload-progress` does.\n */\n change: CustomEvent<{ items: readonly UploadItem[] }>;\n}\n\ntype State =\n | 'dragging'\n | 'drop-target'\n | 'aiming'\n | 'flying'\n | 'scoring'\n | 'rejected'\n | 'disabled';\n\n/**\n * Cards drawn on the court: the top one and two underneath.\n */\nconst VISIBLE_STACK = 3;\n\n/**\n * Delay between the cards of a multi-file dunk, ms.\n */\nconst DUNK_STAGGER = 150;\n\n/**\n * `HTMLElement` is missing where there is no DOM (SSR). Extending a stand-in\n * keeps this module importable there; the class is only ever instantiated by\n * `customElements.define`, which those environments do not have either.\n */\nconst BaseElement: typeof HTMLElement =\n typeof HTMLElement === 'undefined'\n ? (class {} as unknown as typeof HTMLElement)\n : HTMLElement;\n\nfunction hasFiles(event: DragEvent): boolean {\n return event.dataTransfer?.types.includes('Files') ?? false;\n}\n\nfunction numberAttribute(value: string | null): number | null {\n if (value === null || value.trim() === '') return null;\n const number = Number(value);\n return Number.isFinite(number) && number >= 0 ? number : null;\n}\n\n/**\n * `<basketball-upload>`: a file upload where the dropzone is a backboard.\n * Drop files on it, or drop them on the court and take the shot.\n */\nexport class BasketballUploadElement extends BaseElement {\n static readonly formAssociated = true;\n static readonly observedAttributes = [\n 'concurrency',\n 'disabled',\n 'name',\n 'required',\n ] as const;\n\n readonly #internals: ElementInternals | null;\n readonly #queue = new UploadQueue();\n readonly #header = createHeader();\n readonly #hoop = createHoop();\n readonly #trajectory = createTrajectory();\n readonly #liveRegion = createLiveRegion();\n readonly #list: UploadListView;\n readonly #layer: HTMLElement;\n readonly #court: HTMLElement;\n readonly #spot: HTMLElement;\n readonly #input: HTMLInputElement;\n readonly #shots: ShotController;\n\n /**\n * Cards waiting on the court, bottom of the stack first.\n */\n #staged: CardView[] = [];\n\n /**\n * Cards on their way into the basket: dunks, shots in the air, scores.\n */\n readonly #inPlay = new Set<CardView>();\n\n /**\n * Scored cards fading out of the net: their files are already in the basket.\n */\n readonly #leaving = new Set<CardView>();\n #messages: Messages = defaultMessages;\n #fileTypes: readonly FileType[] = [];\n #resizeObserver: ResizeObserver | null = null;\n #formDisabled = false;\n #changeSignature = '';\n\n readonly #states = {\n dragging: false,\n dropOverBoard: false,\n flightOverBoard: false,\n scoring: 0,\n aiming: false,\n flying: false,\n rejected: false,\n };\n #rejectedTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n super();\n this.#internals =\n typeof this.attachInternals === 'function'\n ? this.attachInternals()\n : null;\n\n this.#list = createUploadList({\n resolveType: (file) => this.#resolveType(file),\n onRetry: (id) => this.retryItem(id),\n locale: () => this.closest('[lang]')?.getAttribute('lang') ?? undefined,\n });\n\n this.#spot = createElement('div', { class: 'spot', 'aria-hidden': 'true' });\n this.#court = createElement('div', { class: 'court' }, [this.#spot]);\n this.#layer = createElement('div', { class: 'layer' }, [\n this.#trajectory.element,\n ]);\n this.#input = createElement('input', {\n type: 'file',\n hidden: '',\n tabindex: '-1',\n 'aria-hidden': 'true',\n });\n\n const root = this.attachShadow({ mode: 'open' });\n root.adoptedStyleSheets = [getStyleSheet()];\n root.append(\n createElement('div', { class: 'frame', part: 'frame' }, [\n this.#header.element,\n this.#hoop.element,\n this.#court,\n this.#list.element,\n this.#layer,\n ]),\n this.#liveRegion.element,\n this.#input\n );\n\n this.#shots = new ShotController({\n trajectory: this.#trajectory,\n measure: () => this.#measure(),\n setAiming: (on) => this.#setState('aiming', on),\n setFlying: (on) => this.#setState('flying', on),\n setOverBoard: (on) => {\n this.#states.flightOverBoard = on;\n this.#syncStates();\n },\n launched: (card) => this.#launched(card),\n scored: (card, pose, court) => void this.#score(card, pose, court),\n missed: (card) => this.#missed(card),\n });\n\n this.#hoop.dropzone.addEventListener('click', () => this.openPicker());\n this.#input.addEventListener('change', () => {\n const files = [...(this.#input.files ?? [])];\n this.#input.value = '';\n if (this.instant) this.#dunk(files);\n else this.#stage(files);\n });\n\n this.addEventListener('dragenter', this.#handleDragOver);\n this.addEventListener('dragover', this.#handleDragOver);\n this.addEventListener('dragleave', this.#handleDragLeave);\n this.addEventListener('drop', this.#handleDrop);\n\n this.#queue.on('change', (items) => this.#handleItems(items));\n this.#queue.on('start', (item) => this.#emit('upload-start', { item }));\n this.#queue.on('progress', (item) =>\n this.#emit('upload-progress', { item })\n );\n this.#queue.on('success', (item) => {\n this.#emit('upload-success', { item });\n this.#liveRegion.announce(this.#messages.complete(item.file.name));\n });\n this.#queue.on('error', (item) => {\n this.#emit('upload-error', { item });\n this.#liveRegion.announce(this.#messages.error(item.file.name));\n });\n\n this.#applyMessages();\n this.#syncForm();\n }\n\n /**\n * `light`, `dark`, or `system` (the default) to follow `prefers-color-scheme`.\n */\n get theme(): Theme {\n const value = this.getAttribute('theme');\n return value === 'light' || value === 'dark' ? value : 'system';\n }\n\n set theme(value: Theme | null | undefined) {\n if (value === 'light' || value === 'dark')\n this.setAttribute('theme', value);\n else this.removeAttribute('theme');\n }\n\n /**\n * Accepted files, with the syntax of `<input type=\"file\" accept>`.\n */\n get accept(): string {\n return this.getAttribute('accept') ?? '';\n }\n\n set accept(value: string | null | undefined) {\n if (value) this.setAttribute('accept', value);\n else this.removeAttribute('accept');\n }\n\n /**\n * Several files at a time. Without it, a new file replaces the previous one.\n */\n get multiple(): boolean {\n return this.hasAttribute('multiple');\n }\n\n set multiple(value: boolean | null | undefined) {\n this.toggleAttribute('multiple', Boolean(value));\n }\n\n /**\n * Largest accepted file, in bytes.\n */\n get maxSize(): number | null {\n return numberAttribute(this.getAttribute('max-size'));\n }\n\n set maxSize(value: number | null | undefined) {\n if (value === null || value === undefined) this.removeAttribute('max-size');\n else this.setAttribute('max-size', String(value));\n }\n\n /**\n * Most files at once, staged and in the basket.\n */\n get maxFiles(): number | null {\n return numberAttribute(this.getAttribute('max-files'));\n }\n\n set maxFiles(value: number | null | undefined) {\n if (value === null || value === undefined)\n this.removeAttribute('max-files');\n else this.setAttribute('max-files', String(value));\n }\n\n /**\n * Form field the files are submitted under.\n */\n get name(): string {\n return this.getAttribute('name') ?? '';\n }\n\n set name(value: string | null | undefined) {\n if (value) this.setAttribute('name', value);\n else this.removeAttribute('name');\n }\n\n /**\n * The form is invalid while the basket is empty.\n */\n get required(): boolean {\n return this.hasAttribute('required');\n }\n\n set required(value: boolean | null | undefined) {\n this.toggleAttribute('required', Boolean(value));\n }\n\n /**\n * Ignores files and shots. A disabled `<fieldset>` does the same, without\n * changing this property.\n */\n get disabled(): boolean {\n return this.hasAttribute('disabled');\n }\n\n set disabled(value: boolean | null | undefined) {\n this.toggleAttribute('disabled', Boolean(value));\n }\n\n /**\n * No shooting: every file goes straight into the basket.\n */\n get instant(): boolean {\n return this.hasAttribute('instant');\n }\n\n set instant(value: boolean | null | undefined) {\n this.toggleAttribute('instant', Boolean(value));\n }\n\n /**\n * Uploads running at the same time.\n */\n get concurrency(): number {\n return this.#queue.concurrency;\n }\n\n set concurrency(value: number | null | undefined) {\n if (value === null || value === undefined)\n this.removeAttribute('concurrency');\n else this.setAttribute('concurrency', String(value));\n }\n\n /**\n * Sends each file in the basket. Without one, files only travel with their form.\n */\n get uploader(): Uploader | null {\n return this.#queue.uploader;\n }\n\n set uploader(value: Uploader | null | undefined) {\n this.#queue.uploader = value ?? null;\n }\n\n /**\n * Copy and accessible names. Assign a partial object to override some: it is\n * merged over the defaults, not over the previous value, and keys set to\n * `undefined` keep their default.\n */\n get messages(): Messages {\n return this.#messages;\n }\n\n set messages(value: Partial<Messages> | null | undefined) {\n const overrides = Object.fromEntries(\n Object.entries(value ?? {}).filter(([, message]) => message !== undefined)\n ) as Partial<Messages>;\n this.#messages = { ...defaultMessages, ...overrides };\n this.#applyMessages();\n }\n\n /**\n * File types for this element only, checked before the registered ones.\n */\n get fileTypes(): readonly FileType[] {\n return this.#fileTypes;\n }\n\n set fileTypes(value: readonly FileType[] | null | undefined) {\n const types = value ?? [];\n types.forEach(assertFileType);\n this.#fileTypes = types;\n }\n\n /**\n * Files in the basket and their uploads.\n */\n get items(): readonly UploadItem[] {\n return this.#queue.items;\n }\n\n /**\n * Files in the basket: the value submitted with the form.\n */\n get files(): readonly File[] {\n return this.#queue.items.map((item) => item.file);\n }\n\n /**\n * The `<form>` the element belongs to, or `null`.\n */\n get form(): HTMLFormElement | null {\n return this.#internals?.form ?? null;\n }\n\n /**\n * As on native controls: `valueMissing` while `required` and empty.\n * `undefined` where `ElementInternals` is missing.\n */\n get validity(): ValidityState | undefined {\n return this.#internals?.validity;\n }\n\n /**\n * `messages.required` while `required` and empty, otherwise empty.\n */\n get validationMessage(): string {\n return this.#internals?.validationMessage ?? '';\n }\n\n /**\n * Whether the form validates the element, as on native controls: not while\n * disabled.\n */\n get willValidate(): boolean {\n return this.#internals?.willValidate ?? false;\n }\n\n /**\n * Whether the element is valid, firing `invalid` when it is not. Always\n * valid where `ElementInternals` is missing.\n */\n checkValidity(): boolean {\n return this.#internals?.checkValidity() ?? true;\n }\n\n /**\n * Like `checkValidity()`, and shows the message on the dropzone when invalid.\n */\n reportValidity(): boolean {\n return this.#internals?.reportValidity() ?? true;\n }\n\n /**\n * Opens the file picker. The chosen files land on the court (or in the basket, with `instant`).\n */\n openPicker(): void {\n if (this.#isDisabled) return;\n this.#input.accept = this.accept;\n this.#input.multiple = this.multiple;\n this.#input.click();\n }\n\n /**\n * Puts files on the court, ready to be shot (with `instant`, straight into\n * the basket). Files that do not pass `accept`, `max-size` or `max-files`\n * fire `file-reject` instead.\n */\n stage(files: Iterable<File>): void {\n if (this.instant) this.#dunk([...files]);\n else this.#stage([...files]);\n }\n\n /**\n * Puts files straight into the basket. Files that do not pass `accept`,\n * `max-size` or `max-files` fire `file-reject` instead.\n */\n dunk(files: Iterable<File>): void {\n this.#dunk([...files]);\n }\n\n /**\n * Shoots the card on top of the court with a perfect shot. Returns `false`\n * when it cannot: no card on the court, disabled, another card held or in\n * the air, or the element not laid out.\n */\n shoot(): boolean {\n const card = this.#staged.at(-1);\n return card !== undefined && !this.#isDisabled && this.#shots.shoot(card);\n }\n\n /**\n * Uploads a failed file again. Returns `false` when `id` is not an item in\n * error, or there is no `uploader`.\n */\n retryItem(id: string): boolean {\n return this.#queue.retry(id);\n }\n\n /**\n * Takes a file out of the basket, aborting its upload. Returns `false` when\n * there is no item with this `id`.\n */\n removeItem(id: string): boolean {\n return this.#queue.remove(id);\n }\n\n /**\n * Empties the court and the basket, aborting uploads.\n */\n clear(): void {\n const card = this.#shots.stop();\n card?.dispose();\n for (const staged of this.#staged) staged.dispose();\n for (const playing of this.#inPlay) playing.dispose();\n for (const leaving of this.#leaving) leaving.dispose();\n this.#staged = [];\n this.#inPlay.clear();\n this.#leaving.clear();\n this.#states.scoring = 0;\n this.#syncStates();\n this.#queue.clear();\n }\n\n connectedCallback(): void {\n if (typeof ResizeObserver !== 'undefined') {\n this.#resizeObserver = new ResizeObserver(() => this.#syncRest());\n this.#resizeObserver.observe(this.#court);\n this.#resizeObserver.observe(this.#layer);\n }\n this.#syncRest();\n this.#applyDisabled();\n }\n\n disconnectedCallback(): void {\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n const card = this.#shots.stop();\n if (card && !this.#staged.includes(card)) {\n this.#inPlay.delete(card);\n card.release();\n this.#staged.push(card);\n this.#renderStack();\n }\n }\n\n attributeChangedCallback(\n name: string,\n _oldValue: string | null,\n value: string | null\n ): void {\n switch (name) {\n case 'concurrency':\n this.#queue.concurrency = numberAttribute(value) ?? DEFAULT_CONCURRENCY;\n break;\n case 'disabled':\n this.#applyDisabled();\n break;\n case 'name':\n case 'required':\n this.#syncForm();\n break;\n default:\n break;\n }\n }\n\n formResetCallback(): void {\n this.clear();\n }\n\n formDisabledCallback(disabled: boolean): void {\n this.#formDisabled = disabled;\n this.#applyDisabled();\n }\n\n get #isDisabled(): boolean {\n return this.disabled || this.#formDisabled;\n }\n\n #emit<TType extends keyof BasketballUploadEventMap>(\n type: TType,\n detail: BasketballUploadEventMap[TType]['detail']\n ): void {\n this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true }));\n }\n\n #resolveType(file: File): ResolvedFileType {\n return resolveFileType(file, this.#fileTypes);\n }\n\n #setState(name: 'aiming' | 'flying', on: boolean): void {\n this.#states[name] = on;\n this.#syncStates();\n }\n\n #toggleState(name: State, on: boolean): void {\n const states = this.#internals?.states;\n if (!states) return;\n\n try {\n if (on) {\n states.add(name);\n } else {\n states.delete(name);\n }\n } catch {\n // CustomStateSet without plain identifiers (Chrome < 125): styling only.\n }\n }\n\n #syncStates(): void {\n const states = this.#states;\n this.#toggleState('dragging', states.dragging);\n this.#toggleState(\n 'drop-target',\n (states.dragging && states.dropOverBoard) ||\n states.flightOverBoard ||\n states.scoring > 0\n );\n this.#toggleState('aiming', states.aiming);\n this.#toggleState('flying', states.flying);\n this.#toggleState('scoring', states.scoring > 0);\n this.#toggleState('rejected', states.rejected);\n this.#toggleState('disabled', this.#isDisabled);\n }\n\n #applyMessages(): void {\n this.#header.update(this.#messages);\n this.#hoop.update(this.#messages);\n this.#list.render(this.#queue.items, this.#messages);\n for (const card of this.#staged) {\n card.element.setAttribute(\n 'aria-label',\n this.#messages.shoot(card.file.name)\n );\n }\n this.#syncForm();\n }\n\n #applyDisabled(): void {\n const disabled = this.#isDisabled;\n this.#hoop.dropzone.disabled = disabled;\n if (this.#internals)\n this.#internals.ariaDisabled = disabled ? 'true' : null;\n if (disabled) this.#shots.cancelAim();\n this.#renderStack();\n this.#syncStates();\n }\n\n /**\n * Validates incoming files; rejected ones are reported, accepted ones returned.\n */\n #admit(files: readonly File[]): File[] {\n if (this.#isDisabled) return [];\n const max = this.multiple ? (this.maxFiles ?? Infinity) : 1;\n const used = this.multiple\n ? this.#queue.items.length + this.#staged.length + this.#inPlay.size\n : 0;\n const maxSize = this.maxSize;\n const accepted: File[] = [];\n\n for (const file of files) {\n let reason: RejectReason | null = null;\n if (!matchesAccept(file, this.accept)) reason = 'type';\n else if (maxSize !== null && file.size > maxSize) reason = 'size';\n else if (used + accepted.length >= max) reason = 'count';\n\n if (reason) this.#reject(file, reason);\n else accepted.push(file);\n }\n\n if (!this.multiple && accepted.length > 0) this.clear();\n return accepted;\n }\n\n #reject(file: File, reason: RejectReason): void {\n this.#emit('file-reject', { file, reason });\n this.#liveRegion.announce(this.#messages.rejected(file.name, reason));\n this.#states.rejected = true;\n this.#syncStates();\n clearTimeout(this.#rejectedTimer);\n this.#rejectedTimer = setTimeout(() => {\n this.#states.rejected = false;\n this.#syncStates();\n }, 450);\n }\n\n #createCard(file: File): CardView {\n const card = createCard(\n file,\n this.#resolveType(file),\n this.#messages.shoot(file.name)\n );\n const { element } = card;\n element.addEventListener('pointerdown', (event) => {\n if (this.#isDisabled || !this.#staged.includes(card)) return;\n this.#shots.grab(card, event);\n });\n element.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') {\n this.#shots.cancelAim();\n return;\n }\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n if (!this.#isDisabled && this.#staged.at(-1) === card)\n this.#shots.hold(card, event);\n });\n element.addEventListener('click', (event) => event.preventDefault());\n\n return card;\n }\n\n #stage(files: readonly File[], clientPoint?: Vector): void {\n const accepted = this.#admit(files);\n if (accepted.length === 0) return;\n\n const origin = clientPoint ? this.#toLayer(clientPoint) : null;\n for (const file of accepted) {\n const card = this.#createCard(file);\n this.#staged.push(card);\n this.#layer.append(card.element);\n }\n this.#renderStack();\n\n if (!origin || prefersReducedMotion()) return;\n\n for (const card of this.#staged.slice(-accepted.length)) {\n const rest = card.element.getBoundingClientRect();\n const layer = this.#layer.getBoundingClientRect();\n const offsetX = origin.x - (rest.left - layer.left + rest.width / 2);\n const offsetY = origin.y - (rest.top - layer.top + rest.height / 2);\n void play(\n card.element,\n [\n { transform: `translate(${offsetX}px, ${offsetY}px)` },\n { transform: 'none' },\n ],\n { duration: 380, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' }\n );\n }\n }\n\n #dunk(files: readonly File[], clientPoint?: Vector): void {\n const accepted = this.#admit(files);\n accepted.forEach((file, index) => {\n const card = this.#createCard(file);\n card.element.tabIndex = -1;\n card.element.inert = true;\n this.#inPlay.add(card);\n this.#layer.append(card.element);\n setTimeout(\n () => void this.#runDunk(card, clientPoint),\n index * DUNK_STAGGER\n );\n });\n }\n\n async #runDunk(card: CardView, clientPoint?: Vector): Promise<void> {\n if (!this.#inPlay.has(card)) return;\n const court = this.#measure();\n if (!court) {\n this.#inPlay.delete(card);\n card.dispose();\n this.#queue.add(card.file);\n return;\n }\n\n const center = rimCenter(court);\n const start = clientPoint\n ? this.#toLayer(clientPoint)\n : { x: center.x, y: court.board.y + court.board.height * 0.3 };\n const from: Pose = { ...start, rotation: -10, scale: 0.9 };\n const above: Pose = {\n x: center.x,\n y: court.square.y + court.square.height * 0.35,\n rotation: 6,\n scale: PHYSICS.depthScale,\n };\n card.place(from);\n this.#states.scoring += 1;\n this.#syncStates();\n\n if (!prefersReducedMotion()) {\n const { width, height } = card.size();\n await play(\n card.element,\n [poseStyle(from, width, height), poseStyle(above, width, height)],\n {\n duration: 320,\n easing: 'cubic-bezier(0.22, 1, 0.36, 1)',\n commit: true,\n }\n );\n }\n if (!this.#inPlay.has(card)) return;\n this.#states.scoring -= 1;\n await this.#score(card, above, court);\n }\n\n #launched(card: CardView): void {\n const hadFocus = this.shadowRoot?.activeElement === card.element;\n this.#staged = this.#staged.filter((staged) => staged !== card);\n this.#inPlay.add(card);\n card.element.inert = true;\n this.#renderStack();\n if (hadFocus) {\n (this.#staged.at(-1)?.element ?? this.#hoop.dropzone).focus();\n }\n }\n\n #missed(card: CardView): void {\n if (!this.#inPlay.delete(card)) return;\n card.element.inert = false;\n this.#staged.push(card);\n this.#renderStack();\n this.#emit('shot', { file: card.file, result: 'miss' });\n this.#liveRegion.announce(this.#messages.missed(card.file.name));\n }\n\n /**\n * Through the net, then into the basket: the \"+1\", the counter and the\n * upload only come once the card is out of the net, as in the design.\n */\n async #score(card: CardView, from: Pose, court: Court): Promise<void> {\n if (!this.#inPlay.has(card)) return;\n const reduced = prefersReducedMotion();\n this.#states.scoring += 1;\n this.#syncStates();\n\n if (!reduced) {\n const { width, height } = card.size();\n const below: Pose = {\n x: rimCenter(court).x,\n y: court.netBottom + (height * PHYSICS.depthScale) / 2 - height * 0.06,\n rotation: uprightOf(from.rotation),\n scale: PHYSICS.depthScale,\n };\n this.#hoop.swish();\n await play(\n card.element,\n [poseStyle(from, width, height), poseStyle(below, width, height)],\n {\n duration: 600,\n easing: 'cubic-bezier(0.45, 0, 0.7, 0.6)',\n commit: true,\n }\n );\n }\n if (!this.#inPlay.has(card)) return;\n\n this.#states.scoring -= 1;\n this.#syncStates();\n this.#hoop.celebrate(reduced);\n this.#inPlay.delete(card);\n this.#leaving.add(card);\n this.#queue.add(card.file);\n this.#emit('shot', { file: card.file, result: 'score' });\n this.#liveRegion.announce(this.#messages.scored(card.file.name));\n\n await play(\n card.element,\n [\n { opacity: 1 },\n { opacity: 0.6, offset: 0.2 },\n { opacity: 0.6, offset: 0.6 },\n { opacity: 0 },\n ],\n { duration: reduced ? 240 : 1200, commit: true }\n );\n this.#leaving.delete(card);\n card.dispose();\n }\n\n #renderStack(): void {\n const top = this.#staged.length - 1;\n this.#staged.forEach((card, index) => {\n const depth = top - index;\n const { element } = card;\n element.dataset.depth = depth < VISIBLE_STACK ? String(depth) : 'hidden';\n element.style.zIndex = String(index + 1);\n const interactive = depth === 0 && !this.#isDisabled;\n element.inert = !interactive;\n element.tabIndex = interactive ? 0 : -1;\n });\n }\n\n #handleItems(items: readonly UploadItem[]): void {\n this.#list.render(items, this.#messages);\n this.#header.setCount(items.length, !prefersReducedMotion());\n this.#syncForm();\n\n const signature = items.map((item) => `${item.id}:${item.status}`).join();\n if (signature === this.#changeSignature) return;\n\n this.#changeSignature = signature;\n this.#emit('change', { items });\n }\n\n #syncForm(): void {\n const internals = this.#internals;\n if (!internals) return;\n const files = this.files;\n const name = this.name;\n\n if (name && files.length > 0) {\n const data = new FormData();\n for (const file of files) data.append(name, file);\n internals.setFormValue(data);\n } else {\n internals.setFormValue(null);\n }\n\n if (this.required && files.length === 0) {\n internals.setValidity(\n { valueMissing: true },\n this.#messages.required,\n this.#hoop.dropzone\n );\n } else {\n internals.setValidity({});\n }\n }\n\n /**\n * Converts client coordinates to the card layer's.\n */\n #toLayer(point: Vector): Vector {\n const layer = this.#layer.getBoundingClientRect();\n return { x: point.x - layer.left, y: point.y - layer.top };\n }\n\n #measure(): Court | null {\n const host = this.#layer.getBoundingClientRect();\n if (host.width === 0 || host.height === 0) return null;\n const court = courtFromRectangles({\n host,\n board: this.#hoop.dropzone.getBoundingClientRect(),\n square: this.#hoop.square.getBoundingClientRect(),\n rim: this.#hoop.rim.getBoundingClientRect(),\n net: this.#hoop.net.getBoundingClientRect(),\n spot: this.#spot.getBoundingClientRect(),\n });\n return court.unit > 0 ? court : null;\n }\n\n /**\n * Publishes where staged cards rest, for the CSS that draws them there.\n */\n #syncRest(): void {\n const layer = this.#layer.getBoundingClientRect();\n const spot = this.#spot.getBoundingClientRect();\n if (layer.width === 0) return;\n const x = spot.left - layer.left + spot.width / 2;\n const y = spot.top - layer.top + spot.height / 2;\n this.#layer.style.setProperty('--_rest-x', `${x}px`);\n this.#layer.style.setProperty('--_rest-y', `${y}px`);\n }\n\n #isOverBoard(point: Vector): boolean {\n const board = this.#hoop.dropzone.getBoundingClientRect();\n return (\n point.x >= board.left &&\n point.x <= board.right &&\n point.y >= board.top &&\n point.y <= board.bottom\n );\n }\n\n readonly #handleDragOver = (dragEvent: Event): void => {\n const event = dragEvent as DragEvent;\n if (!hasFiles(event)) return;\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = this.#isDisabled ? 'none' : 'copy';\n }\n if (this.#isDisabled) return;\n this.#states.dragging = true;\n this.#states.dropOverBoard = this.#isOverBoard({\n x: event.clientX,\n y: event.clientY,\n });\n this.#syncStates();\n };\n\n readonly #handleDragLeave = (dragEvent: Event): void => {\n const event = dragEvent as DragEvent;\n const box = this.getBoundingClientRect();\n const inside =\n event.clientX > box.left &&\n event.clientX < box.right &&\n event.clientY > box.top &&\n event.clientY < box.bottom;\n if (inside) return;\n this.#states.dragging = false;\n this.#states.dropOverBoard = false;\n this.#syncStates();\n };\n\n readonly #handleDrop = (dragEvent: Event): void => {\n const event = dragEvent as DragEvent;\n if (!hasFiles(event)) return;\n event.preventDefault();\n const point = { x: event.clientX, y: event.clientY };\n const overBoard = this.#isOverBoard(point);\n this.#states.dragging = false;\n this.#states.dropOverBoard = false;\n this.#syncStates();\n\n const files = [...(event.dataTransfer?.files ?? [])];\n if (overBoard || this.instant) this.#dunk(files, point);\n else this.#stage(files, point);\n };\n}\n\n// Typed `addEventListener` for the events dispatched above.\nexport interface BasketballUploadElement {\n /**\n * Typed for the events of `BasketballUploadEventMap`.\n */\n addEventListener<TType extends keyof BasketballUploadEventMap>(\n type: TType,\n listener: (\n this: BasketballUploadElement,\n event: BasketballUploadEventMap[TType]\n ) => void,\n options?: boolean | AddEventListenerOptions\n ): void;\n\n /**\n * Any other event, as on `HTMLElement`.\n */\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions\n ): void;\n\n /**\n * Typed for the events of `BasketballUploadEventMap`.\n */\n removeEventListener<TType extends keyof BasketballUploadEventMap>(\n type: TType,\n listener: (\n this: BasketballUploadElement,\n event: BasketballUploadEventMap[TType]\n ) => void,\n options?: boolean | EventListenerOptions\n ): void;\n\n /**\n * Any other event, as on `HTMLElement`.\n */\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions\n ): void;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'basketball-upload': BasketballUploadElement;\n }\n}\n","import { BasketballUploadElement } from './basketball-upload-element.ts';\n\n/**\n * Options of `registerBasketballUpload`.\n */\nexport interface RegisterBasketballUploadOptions {\n /**\n * Custom element name. Defaults to `basketball-upload`.\n */\n tagName?: string | undefined;\n}\n\n/**\n * Name the element is registered with when no `tagName` is given.\n */\nexport const DEFAULT_TAG_NAME = 'basketball-upload';\n\n/**\n * Defines the custom element. Idempotent, and a no-op where custom elements\n * do not exist (SSR), so it is safe to call from any module.\n */\nexport function registerBasketballUpload(\n options: RegisterBasketballUploadOptions = {}\n): void {\n const tagName = options.tagName ?? DEFAULT_TAG_NAME;\n\n if (typeof customElements === 'undefined') return;\n if (customElements.get(tagName)) return;\n\n customElements.define(\n tagName,\n tagName === DEFAULT_TAG_NAME\n ? BasketballUploadElement\n : class extends BasketballUploadElement {}\n );\n}\n","import type { Uploader } from './types.ts';\n\n/**\n * Options of `createXhrUploader`.\n */\nexport interface XhrUploaderOptions {\n /**\n * Endpoint, or a function of the file for one URL per file.\n */\n url: string | URL | ((file: File) => string | URL);\n\n /**\n * Defaults to `POST`.\n */\n method?: string | undefined;\n\n /**\n * Form field the file is sent under, as `multipart/form-data`. Defaults to\n * `file`. `null` sends the file itself as the request body.\n */\n fieldName?: string | null | undefined;\n\n /**\n * Extra form fields, sent before the file. Ignored when `fieldName` is `null`.\n */\n fields?:\n | Record<string, string | Blob>\n | ((file: File) => Record<string, string | Blob>)\n | undefined;\n\n /**\n * Request headers, or a function of the file.\n */\n headers?:\n | Record<string, string>\n | ((file: File) => Record<string, string>)\n | undefined;\n\n /**\n * Sends cookies with cross-origin requests. Defaults to `false`.\n */\n withCredentials?: boolean | undefined;\n}\n\n/**\n * Rejection reason of `createXhrUploader` for a non-2xx response or a network error.\n */\nexport class UploadError extends Error {\n /**\n * HTTP status, or 0 when the request did not complete.\n */\n readonly status: number;\n\n /**\n * Response text, or an empty string when the request did not complete.\n */\n readonly body: string;\n\n constructor(status: number, body: string) {\n super(\n status === 0 ? 'Network error' : `Upload failed with status ${status}`\n );\n this.name = 'UploadError';\n this.status = status;\n this.body = body;\n }\n}\n\nfunction resolve<TValue>(\n value: TValue | ((file: File) => TValue),\n file: File\n): TValue {\n return typeof value === 'function'\n ? (value as (file: File) => TValue)(file)\n : value;\n}\n\nfunction parseResponse(request: XMLHttpRequest): unknown {\n const type = request.getResponseHeader('content-type') ?? '';\n if (!type.includes('json')) return request.responseText;\n try {\n return JSON.parse(request.responseText) as unknown;\n } catch {\n return request.responseText;\n }\n}\n\n/**\n * An `Uploader` built on `XMLHttpRequest`, the one browser API that reports\n * the progress of a request body. Resolves with the parsed JSON response (or\n * its text), rejects with an `UploadError`, or with the abort reason.\n */\nexport function createXhrUploader(options: XhrUploaderOptions): Uploader {\n return (file, { signal, onProgress }) =>\n new Promise((resolvePromise, reject) => {\n if (signal.aborted) {\n reject(signal.reason);\n return;\n }\n\n const request = new XMLHttpRequest();\n request.open(\n options.method ?? 'POST',\n String(resolve(options.url, file))\n );\n request.withCredentials = options.withCredentials ?? false;\n for (const [name, value] of Object.entries(\n resolve(options.headers ?? {}, file)\n )) {\n request.setRequestHeader(name, value);\n }\n\n request.upload.addEventListener('progress', (event) => {\n onProgress(\n event.loaded,\n event.lengthComputable ? event.total : undefined\n );\n });\n request.addEventListener('load', () => {\n if (request.status >= 200 && request.status < 300) {\n resolvePromise(parseResponse(request));\n } else {\n reject(new UploadError(request.status, request.responseText));\n }\n });\n request.addEventListener('error', () => reject(new UploadError(0, '')));\n request.addEventListener('abort', () => reject(signal.reason));\n const abort = (): void => request.abort();\n signal.addEventListener('abort', abort, { once: true });\n request.addEventListener('loadend', () =>\n signal.removeEventListener('abort', abort)\n );\n\n const fieldName =\n options.fieldName === undefined ? 'file' : options.fieldName;\n if (fieldName === null) {\n request.send(file);\n return;\n }\n const body = new FormData();\n for (const [name, value] of Object.entries(\n resolve(options.fields ?? {}, file)\n )) {\n body.append(name, value);\n }\n body.append(fieldName, file, file.name);\n request.send(body);\n });\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@sehv-oss/basketball-upload",
3
+ "version": "1.0.0",
4
+ "description": "Basketball-themed drag and drop file upload Web Component: drop your files, or take the shot.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/basketball-upload.d.ts",
9
+ "default": "./dist/basketball-upload.js"
10
+ },
11
+ "./package.json": "./package.json"
12
+ },
13
+ "files": [
14
+ "./dist",
15
+ "NOTICE.md"
16
+ ],
17
+ "keywords": [
18
+ "file-upload",
19
+ "upload",
20
+ "dropzone",
21
+ "drag-and-drop",
22
+ "dnd",
23
+ "basketball",
24
+ "web-component",
25
+ "custom-element"
26
+ ],
27
+ "license": "ISC",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/sehv-oss/basketball-upload.git",
31
+ "directory": "packages/core"
32
+ },
33
+ "homepage": "https://sehv-oss.github.io/basketball-upload/",
34
+ "bugs": {
35
+ "url": "https://github.com/sehv-oss/basketball-upload/issues"
36
+ },
37
+ "engines": {
38
+ "node": ">=24 <27"
39
+ },
40
+ "devDependencies": {
41
+ "@sehv-oss/typescript-config": "0.0.1",
42
+ "@types/node": "26.6.4",
43
+ "@vitest/browser-playwright": "5.0.3",
44
+ "tsdown": "0.23.0",
45
+ "typescript": "7.0.2",
46
+ "vitest": "5.0.3"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc --project tsconfig.json && tsc --project tsconfig.tests.json && tsdown"
50
+ }
51
+ }